1 /* @source ajtaxdb ************************************************************
2 **
3 ** AJAX taxonomy database functions
4 **
5 ** These functions control all aspects of AJAX taxonomy database access
6 **
7 ** @author Copyright (C) 2010 Peter Rice
8 ** @version $Revision: 1.21 $
9 ** @modified Oct 2010 pmr first version
10 ** @modified $Date: 2012/07/14 14:52:39 $ by $Author: rice $
11 ** @@
12 **
13 ** This library is free software; you can redistribute it and/or
14 ** modify it under the terms of the GNU Lesser General Public
15 ** License as published by the Free Software Foundation; either
16 ** version 2.1 of the License, or (at your option) any later version.
17 **
18 ** This library is distributed in the hope that it will be useful,
19 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 ** Lesser General Public License for more details.
22 **
23 ** You should have received a copy of the GNU Lesser General Public
24 ** License along with this library; if not, write to the Free Software
25 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26 ** MA  02110-1301,  USA.
27 **
28 ******************************************************************************/
29 
30 
31 #include "ajlib.h"
32 
33 #include "ajtaxdb.h"
34 #include "ajtaxread.h"
35 #include "ajindex.h"
36 #include "ajnam.h"
37 #include "ajquery.h"
38 #include "ajfileio.h"
39 #include "ajcall.h"
40 
41 
42 #include <ctype.h>
43 #include <limits.h>
44 #include <stdarg.h>
45 #include <sys/types.h>
46 #include <errno.h>
47 #include <signal.h>
48 
49 
50 #ifndef WIN32
51 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 
55 #include <netdb.h>
56 
57 #include <dirent.h>
58 #include <unistd.h>
59 #else
60 #include <winsock2.h>
61 #include <ws2tcpip.h>
62 #endif
63 
64 
65 
66 
67 /* @datastatic TaxPEmbossQry *************************************************
68 **
69 ** Btree 'emboss' query structure
70 **
71 ** @alias TaxSEmbossQry
72 ** @alias TaxOEmbossQry
73 **
74 ** @attr idcache [AjPBtcache] ID cache
75 ** @attr Caches [AjPList] Caches for each query field
76 ** @attr files [AjPStr*] database filenames
77 ** @attr reffiles [AjPStr**] database reference filenames
78 ** @attr Skip [AjBool*] files numbers to exclude
79 ** @attr libs [AjPFile] Primary (database source) file
80 ** @attr libr [AjPFile] Secondary (database bibliographic source) file
81 ** @attr div [ajuint] division number of currently open database file
82 ** @attr refcount [ajuint] number of reference file(s) per entry
83 ** @attr nentries [ajint] number of entries in the filename array(s)
84 **                        -1 when done
85 ** @attr Samefile [AjBool] true if the same file is passed to
86 **                         ajFilebuffReopenFile
87 ** @@
88 ******************************************************************************/
89 
90 typedef struct TaxSEmbossQry
91 {
92     AjPBtcache idcache;
93     AjPList Caches;
94 
95     AjPStr *files;
96     AjPStr **reffiles;
97     AjBool *Skip;
98 
99     AjPFile libs;
100     AjPFile libr;
101 
102     ajuint div;
103     ajuint refcount;
104     ajint nentries;
105 
106     AjBool Samefile;
107 } TaxOEmbossQry;
108 
109 #define TaxPEmbossQry TaxOEmbossQry*
110 
111 
112 
113 
114 static AjBool 	  taxEmbossTaxAll(AjPTaxin taxin);
115 static void       taxEmbossTaxLoadBuff(AjPTaxin taxin);
116 static AjBool     taxEmbossTaxReadNode(AjPTaxin taxin);
117 static AjBool     taxEmbossTaxReadRef(AjPTaxin taxin);
118 static AjBool	  taxEmbossOpenCache(AjPQuery qry, const char *ext,
119 				     AjPBtcache *cache);
120 static AjBool     taxEmbossQryClose(AjPQuery qry);
121 static AjBool     taxEmbossQryEntry(AjPQuery qry);
122 static AjBool     taxEmbossQryNext(AjPQuery qry);
123 static AjBool     taxEmbossQryOpen(AjPQuery qry);
124 static AjBool     taxEmbossQryQuery(AjPQuery qry);
125 static AjBool     taxEmbossQryReuse(AjPQuery qry);
126 
127 
128 
129 
130 
131 
132 static AjBool     taxAccessEmbossTax(AjPTaxin taxin);
133 
134 
135 
136 
137 /* @funclist taxAccess ********************************************************
138 **
139 ** Functions to access each database or taxonomy access method
140 **
141 ******************************************************************************/
142 
143 static AjOTaxAccess taxAccess[] =
144 {
145     /*  Name     AccessFunction   FreeFunction
146         Qlink    Description
147         Alias    Entry    Query    All      Chunk   Padding */
148     {
149         "embosstax", &taxAccessEmbossTax, NULL,
150         "",      "emboss dbxtax indexed",
151         AJFALSE, AJTRUE,  AJTRUE,  AJTRUE,  AJFALSE, AJFALSE
152     },
153     {
154         NULL, NULL, NULL,
155         NULL, NULL,
156         AJFALSE, AJFALSE, AJFALSE, AJFALSE, AJFALSE, AJFALSE
157     },
158 };
159 
160 
161 
162 
163 /* @section B+tree NCBI Taxonomy Indexing *************************************
164 **
165 ** These functions manage the EMBOSS B+tree NCBI taxonomy access methods.
166 **
167 ******************************************************************************/
168 
169 
170 
171 
172 /* @funcstatic taxAccessEmbossTax *********************************************
173 **
174 ** Reads taxon(s) from an NCBI taxonomy database, using B+tree index
175 ** files. Returns with the file pointer set to the position in the
176 ** buffered taxonomy file.
177 **
178 ** @param [u] taxin [AjPTaxin] Taxon input.
179 ** @return [AjBool] ajTrue on success.
180 **
181 ** @release 6.4.0
182 ** @@
183 ******************************************************************************/
184 
taxAccessEmbossTax(AjPTaxin taxin)185 static AjBool taxAccessEmbossTax(AjPTaxin taxin)
186 {
187     AjBool retval = ajFalse;
188 
189     AjPQuery qry;
190     TaxPEmbossQry qryd = NULL;
191 
192 
193     qry = taxin->Input->Query;
194     qryd = qry->QryData;
195     ajDebug("taxAccessEmbossTax type %d\n", qry->QueryType);
196 
197     if(!ajNamDbGetDbalias(qry->DbName, &qry->DbAlias))
198 	ajStrAssignS(&qry->DbAlias, qry->DbName);
199 
200     if(qry->QueryType == AJQUERY_ALL)
201 	return taxEmbossTaxAll(taxin);
202 
203 
204     if(!qry->QryData)
205     {
206 	if(!taxEmbossQryOpen(qry))
207             return ajFalse;
208 
209 	qryd = qry->QryData;
210 	taxin->Input->Single = ajTrue;
211 	ajFilebuffDel(&taxin->Input->Filebuff);
212 	taxin->Input->Filebuff = ajFilebuffNewNofile();
213 
214 	if(qry->QueryType == AJQUERY_ENTRY)
215 	{
216 	    if(!taxEmbossQryEntry(qry))
217 		ajDebug("embosstax B+tree Entry failed\n");
218 	}
219 
220 	if(qry->QueryType == AJQUERY_QUERY)
221 	{
222 	    if(!taxEmbossQryQuery(qry))
223 		ajDebug("embosstax B+tree Query failed\n");
224 	}
225     }
226     else
227     {
228         if(!taxEmbossQryReuse(qry))
229         {
230             taxEmbossQryClose(qry);
231             return ajFalse;
232         }
233 	ajFilebuffClear(taxin->Input->Filebuff, -1);
234     }
235 
236     if(ajListGetLength(qry->ResultsList))
237     {
238 	retval = taxEmbossQryNext(qry);
239 
240 	if(retval)
241         {
242 	    taxEmbossTaxLoadBuff(taxin);
243             ajStrAssignS(&taxin->Input->Db, qry->DbName);
244         }
245     }
246 
247     if(!ajListGetLength(qry->ResultsList)) /* could be emptied by code above */
248     {
249 	taxEmbossQryClose(qry);
250 	ajFileClose(&qryd->libs);
251 	ajFileClose(&qryd->libr);
252     }
253 
254     return retval;
255 }
256 
257 
258 
259 
260 /* @funcstatic taxEmbossTaxAll ************************************************
261 **
262 ** Opens the first or next taxonomy file for further reading
263 **
264 ** @param [u] taxin [AjPTaxin] Taxon input.
265 ** @return [AjBool] ajTrue on success.
266 **
267 ** @release 6.4.0
268 ** @@
269 ******************************************************************************/
270 
taxEmbossTaxAll(AjPTaxin taxin)271 static AjBool taxEmbossTaxAll(AjPTaxin taxin)
272 {
273     AjPQuery qry;
274     TaxPEmbossQry qryd;
275     static ajint i   = 0;
276     ajuint iref;
277     AjPStr name      = NULL;
278     AjBool ok        = ajFalse;
279 /*
280     AjPStrTok handle = NULL;
281     AjPStr wildname  = NULL;
282     AjBool found     = ajFalse;
283 */
284 
285     qry = taxin->Input->Query;
286     qryd = qry->QryData;
287 
288     ajDebug("taxEmbossTaxAll\n");
289 
290 
291     if(!qry->QryData)
292     {
293 	ajDebug("taxEmbossTaxAll initialising\n");
294 
295 	qry->QryData = AJNEW0(qryd);
296 	qryd = qry->QryData;
297 	i = -1;
298 	ajBtreeReadEntriesS(qry->DbAlias,qry->IndexDir,
299                             qry->Directory,
300                             &qryd->files,
301                             &qryd->reffiles,
302                             &qryd->refcount);
303 
304 	taxin->Input->Single = ajTrue;
305     }
306 
307     qryd = qry->QryData;
308     ajFilebuffDel(&taxin->Input->Filebuff);
309     taxin->Input->Filebuff = ajFilebuffNewNofile();
310 
311     if(!qryd->libs)
312     {
313 	while(!ok && qryd->files[++i])
314 	{
315 	    ajStrAssignS(&name,qryd->files[i]);
316 	    if(ajFilenameTestInclude(name, qry->Exclude, qry->Filename))
317 		ok = ajTrue;
318 	}
319 
320 	ajStrDel(&name);
321 
322 /*	if(qry->Exclude)
323 	{
324 	    ok = ajFalse;
325 	    wildname = ajStrNew();
326 	    name     = ajStrNew();
327 	    while(!ok)
328 	    {
329 		ajStrAssignS(&name,qryd->files[i]);
330 		ajFilenameTrimPath(&name);
331 		handle = ajStrTokenNewC(qry->Exclude," \n");
332 		found = ajFalse;
333 		while(ajStrTokenNextParseC(&handle," \n",&wildname))
334 		    if(ajStrMatchWildS(name,wildname))
335 		    {
336 			found = ajTrue;
337 			break;
338 		    }
339 		ajStrTokenDel(&handle);
340 		if(!found)
341 		    ok = ajTrue;
342 		else
343 		{
344 		    ++i;
345 		    if(!qryd->files[i])
346 			ok = ajTrue;
347 		}
348 	    }
349 
350 	    ajStrDel(&wildname);
351 	    ajStrDel(&name);
352 	}
353 */
354 
355 	if(!qryd->files[i])
356 	{
357 	    ajDebug("taxEmbossTaxAll finished\n");
358 	    i=0;
359 
360 	    while(qryd->files[i])
361 	    {
362 		ajStrDel(&qryd->files[i]);
363 
364                 if(qryd->reffiles)
365                 {
366                     for(iref=0; iref < qryd->refcount; iref++)
367                         ajStrDel(&qryd->reffiles[i][iref]);
368                 }
369 
370 		++i;
371 	    }
372 
373 	    AJFREE(qryd->files);
374 	    AJFREE(qryd->reffiles);
375 
376 	    AJFREE(qry->QryData);
377 	    qry->QryData = NULL;
378 
379 	    return ajFalse;
380 	}
381 
382 
383 	qryd->libs = ajFileNewInNameS(qryd->files[i]);
384 
385 	if(!qryd->libs)
386 	{
387 	    ajDebug("taxEmbossTaxAll: cannot open nodes file\n");
388 
389 	    return ajFalse;
390 	}
391 
392 
393 	qryd->libr = ajFileNewInNameS(qryd->reffiles[i][0]);
394 
395 	if(!qryd->libr)
396 	{
397 	    ajDebug("taxEmbossTaxAll: cannot open names file\n");
398 
399 	    return ajFalse;
400 	}
401     }
402 
403     taxEmbossTaxLoadBuff(taxin);
404 
405     if(!qry->CaseId)
406 	qry->QryDone = ajTrue;
407 
408     return ajTrue;
409 }
410 
411 
412 
413 
414 /* @funcstatic taxEmbossTaxLoadBuff *******************************************
415 **
416 ** Copies text data to a buffered file, and taxon data for an
417 ** AjPTaxin internal data structure for reading later
418 **
419 ** @param [u] taxin [AjPTaxin] Taxon input object
420 ** @return [void]
421 **
422 ** @release 6.4.0
423 ** @@
424 ******************************************************************************/
425 
taxEmbossTaxLoadBuff(AjPTaxin taxin)426 static void taxEmbossTaxLoadBuff(AjPTaxin taxin)
427 {
428     AjPQuery qry;
429     TaxPEmbossQry qryd;
430 
431     qry  = taxin->Input->Query;
432     qryd = qry->QryData;
433 
434     if(!qry->QryData)
435 	ajFatal("taxEmbossTaxLoadBuff Query Data not initialised");
436     /* read the taxon record */
437     taxEmbossTaxReadNode(taxin);
438 
439     /* copy all the ref data */
440 
441     taxEmbossTaxReadRef(taxin);
442 
443     /* ajFilebuffTraceFull(taxin->Input->Filebuff, 9999, 100); */
444 
445     if(!qryd->libr)
446 	ajFileClose(&qryd->libs);
447 
448     return;
449 }
450 
451 
452 
453 
454 /* @funcstatic taxEmbossTaxReadRef ********************************************
455 **
456 ** Copies text data to a buffered file for reading later
457 **
458 ** @param [u] taxin [AjPTaxin] Taxon input object
459 ** @return [AjBool] ajTrue on success
460 **
461 ** @release 6.4.0
462 ** @@
463 ******************************************************************************/
464 
taxEmbossTaxReadRef(AjPTaxin taxin)465 static AjBool taxEmbossTaxReadRef(AjPTaxin taxin)
466 {
467     AjPStr line = NULL;
468     AjPQuery qry;
469     TaxPEmbossQry qryd;
470     const char *p = NULL;
471     ajuint taxid = 0;
472     ajuint firstid = 0;
473 
474     qry  = taxin->Input->Query;
475     qryd = qry->QryData;
476 
477     ajDebug("taxEmbossTaxReadRef pos: %Ld\n", ajFileResetPos(qryd->libr));
478     while(ajReadline(qryd->libr, &line))
479     {
480         taxid = 0;
481         p = ajStrGetPtr(line);
482         while(isdigit((int)*p))
483             taxid = 10*taxid + (*p++ - '0');
484         if(!firstid)
485             firstid = taxid;
486         if(taxid != firstid)
487             break;
488         ajFilebuffLoadS(taxin->Input->Filebuff, line);
489     }
490 
491     /* at end of file */
492 
493     ajFileClose(&qryd->libr);
494     ajStrDel(&line);
495 
496     return ajTrue;
497 }
498 
499 
500 
501 
502 /* @funcstatic taxEmbossTaxReadNode *******************************************
503 **
504 ** Copies taxon data with a reformatted taxon to the input file.
505 **
506 ** @param [u] taxin [AjPTaxin] Taxon input object
507 ** @return [AjBool] ajTrue on success
508 **
509 ** @release 6.4.0
510 ** @@
511 ******************************************************************************/
512 
taxEmbossTaxReadNode(AjPTaxin taxin)513 static AjBool taxEmbossTaxReadNode(AjPTaxin taxin)
514 {
515     AjPStr line = NULL;
516     AjPQuery qry;
517     TaxPEmbossQry qryd;
518 
519     qry  = taxin->Input->Query;
520     qryd = qry->QryData;
521 
522     ajDebug("taxEmbossTaxReadNode pos: %Ld\n", ajFileResetPos(qryd->libs));
523 
524     if(!ajReadline(qryd->libs, &line))	/* end of file */
525 	return ajFalse;
526 
527     ajFilebuffLoadS(taxin->Input->Filebuff, line);
528 
529     ajStrDel(&line);
530 
531     return ajTrue;
532 }
533 
534 
535 
536 
537 /* @section B+tree Database Indexing *****************************************
538 **
539 ** These functions manage the B+tree index access methods.
540 **
541 ******************************************************************************/
542 
543 
544 
545 
546 /* @funcstatic taxEmbossQryReuse **********************************************
547 **
548 ** Tests whether the B+tree index query data can be reused or it's finished.
549 **
550 ** Clears qryData structure when finished.
551 **
552 ** @param [u] qry [AjPQuery] Query data
553 ** @return [AjBool] ajTrue if reusable,
554 **                  ajFalse if finished.
555 **
556 ** @release 6.4.0
557 ** @@
558 ******************************************************************************/
559 
taxEmbossQryReuse(AjPQuery qry)560 static AjBool taxEmbossQryReuse(AjPQuery qry)
561 {
562     TaxPEmbossQry qryd;
563 
564     qryd = qry->QryData;
565 
566     if(!qry || !qryd)
567 	return ajFalse;
568 
569 
570     if(!qry->ResultsList)
571     {
572 	ajDebug("taxEmbossQryReuse: query data all finished\n");
573 	AJFREE(qry->QryData);
574 	qryd = NULL;
575 
576 	return ajFalse;
577     }
578     else
579     {
580 	ajDebug("taxEmbossQryReuse: reusing data from previous call %x "
581                 "listsize:%Lu\n",
582 		qry->QryData, ajListGetLength(qry->ResultsList));
583 	/*ajListTrace(qry->ResultsList);*/
584     }
585 
586 
587     qryd->nentries = -1;
588 
589 
590     return ajTrue;
591 }
592 
593 
594 
595 
596 /* @funcstatic taxEmbossQryOpen ***********************************************
597 **
598 ** Open caches (etc) for B+tree search
599 **
600 ** @param [u] qry [AjPQuery] Query data
601 ** @return [AjBool] ajTrue if we can continue,
602 **                  ajFalse if all is done.
603 **
604 ** @release 6.4.0
605 ** @@
606 ******************************************************************************/
607 
taxEmbossQryOpen(AjPQuery qry)608 static AjBool taxEmbossQryOpen(AjPQuery qry)
609 {
610     TaxPEmbossQry qryd;
611     ajint i;
612     AjPStr name     = NULL;
613     AjIList iter = NULL;
614     AjPQueryField field = NULL;
615     AjPBtcache cache = NULL;
616 
617     qry->QryData = AJNEW0(qryd);
618     qryd = qry->QryData;
619     qryd->div = -1;
620     qryd->nentries = -1;
621 
622     qryd->Caches = ajListNew();
623 
624     if(!ajStrGetLen(qry->IndexDir))
625     {
626 	ajDebug("no indexdir defined for database '%S'\n", qry->DbName);
627 	ajErr("no indexdir defined for database '%S'", qry->DbName);
628 	return ajFalse;
629     }
630 
631     if(!taxEmbossOpenCache(qry,"id",&qryd->idcache))
632         return ajFalse;
633 
634     iter = ajListIterNewread(qry->QueryFields);
635     while(!ajListIterDone(iter))
636     {
637         field = ajListIterGet(iter);
638 
639         ajStrFmtLower(&field->Wildquery);
640         if(!taxEmbossOpenCache(qry, MAJSTRGETPTR(field->Field), &cache))
641             return ajFalse;
642         ajListPushAppend(qryd->Caches, cache);
643         cache = NULL;
644     }
645     ajListIterDel(&iter);
646 
647 
648     ajDebug("directory '%S'fields: %Lu hasacc:%B\n",
649 	    qry->IndexDir, ajListGetLength(qry->QueryFields), qry->HasAcc);
650 
651 
652     if(ajStrGetLen(qry->Exclude) && qryd->nentries >= 0)
653     {
654 	AJCNEW0(qryd->Skip,qryd->nentries);
655 	name     = ajStrNew();
656 
657 	for(i=0; i < qryd->nentries; ++i)
658 	{
659 	    ajStrAssignS(&name,qryd->files[i]);
660 
661 	    if(!ajFilenameTestInclude(name, qry->Exclude, qry->Filename))
662 		qryd->Skip[i] = ajTrue;
663 	}
664 
665 	ajStrDel(&name);
666     }
667 
668     return ajTrue;
669 }
670 
671 
672 
673 
674 /* @funcstatic taxEmbossOpenCache *********************************************
675 **
676 ** Create primary B+tree index cache
677 **
678 ** @param [u] qry [AjPQuery] Query data
679 ** @param [r] ext [const char*] Index file extension
680 ** @param [w] cache [AjPBtcache*] cache
681 ** @return [AjBool] True on success
682 **
683 ** @release 6.4.0
684 ** @@
685 ******************************************************************************/
686 
taxEmbossOpenCache(AjPQuery qry,const char * ext,AjPBtcache * cache)687 static AjBool taxEmbossOpenCache(AjPQuery qry, const char *ext,
688                                  AjPBtcache *cache)
689 {
690     TaxPEmbossQry qryd;
691     AjPStr indexextname = NULL;
692 
693     qryd = qry->QryData;
694 
695     indexextname = ajStrNewS(ajBtreeFieldGetExtensionC(ext));
696 
697     *cache = ajBtreeCacheNewReadS(qry->DbAlias,indexextname,
698                                   qry->IndexDir);
699     ajStrDel(&indexextname);
700 
701     if(!*cache)
702     {
703 	qryd->nentries = -1;
704 
705 	return ajFalse;
706     }
707 
708     if(qryd->nentries == -1)
709 	qryd->nentries = ajBtreeReadEntriesS(qry->DbAlias,
710                                              qry->IndexDir,
711                                              qry->Directory,
712                                              &qryd->files,
713                                              &qryd->reffiles,
714                                              &qryd->refcount);
715 
716     return ajTrue;
717 }
718 
719 
720 
721 
722 
723 /* @funcstatic taxEmbossQryEntry **********************************************
724 **
725 ** Queries for a single entry in a B+tree index
726 **
727 ** @param [u] qry [AjPQuery] Query data
728 ** @return [AjBool] ajTrue if can continue,
729 **                  ajFalse if all is done.
730 **
731 ** @release 6.4.0
732 ** @@
733 ******************************************************************************/
734 
taxEmbossQryEntry(AjPQuery qry)735 static AjBool taxEmbossQryEntry(AjPQuery qry)
736 {
737     TaxPEmbossQry qryd;
738     const AjPList fdlist;
739     const AjPList cachelist;
740     AjIList iter;
741     AjIList icache;
742     AjPBtcache cache;
743     AjPQueryField fd;
744 
745     qryd = qry->QryData;
746 
747     ajDebug("taxEmbossQryEntry fields: %Lu hasacc:%B qrylist:%Lu\n",
748 	    ajListGetLength(qry->QueryFields), qry->HasAcc,
749             ajListGetLength(qry->ResultsList));
750 
751     fdlist = ajQueryGetallFields(qry);
752     cachelist = qryd->Caches;
753 
754     iter= ajListIterNewread(fdlist);
755     icache = ajListIterNewread(cachelist);
756     while(!ajListIterDone(iter))
757     {
758         fd = ajListIterGet(iter);
759         cache = ajListIterGet(icache);
760 
761         ajDebug("qry type:%d field '%S' wild '%S'\n",
762                 fd->Link, fd->Field, fd->Wildquery);
763 
764         if((fd->Link == AJQLINK_ELSE) && ajListGetLength(qry->ResultsList))
765                 continue;
766 
767         if(!ajBtreeCacheIsSecondary(cache))
768         {
769 	    ajBtreeIdentFetchHitref(cache,fd->Wildquery,
770                                     qry->ResultsList);
771         }
772     }
773 
774     ajListIterDel(&iter);
775     ajListIterDel(&icache);
776 
777     ajDebug("  qrylist:%Lu\n", ajListGetLength(qry->ResultsList));
778 
779     if(!ajListGetLength(qry->ResultsList))
780 	return ajFalse;
781 
782     if(!qry->CaseId)
783 	qry->QryDone = ajTrue;
784 
785     return ajTrue;
786 }
787 
788 
789 
790 
791 /* @funcstatic taxEmbossQryNext ***********************************************
792 **
793 ** Processes the next query for a B+tree index
794 **
795 ** @param [u] qry [AjPQuery] Query data
796 ** @return [AjBool] ajTrue if successful
797 **
798 ** @release 6.4.0
799 ** @@
800 ******************************************************************************/
801 
taxEmbossQryNext(AjPQuery qry)802 static AjBool taxEmbossQryNext(AjPQuery qry)
803 {
804     AjPBtHitref entry;
805     TaxPEmbossQry qryd;
806     void* item;
807     AjBool ok = ajFalse;
808 
809 
810     qryd = qry->QryData;
811 
812     if(!ajListGetLength(qry->ResultsList))
813 	return ajFalse;
814 
815     /*ajListTrace(qry->ResultsList);*/
816 
817 
818     if(!qryd->Skip)
819     {
820 	ajListPop(qry->ResultsList, &item);
821 	entry = (AjPBtHitref) item;
822     }
823     else
824     {
825 	ok = ajFalse;
826 
827 	while(!ok)
828 	{
829 	    ajListPop(qry->ResultsList, &item);
830 	    entry = (AjPBtHitref) item;
831 
832 	    if(!qryd->Skip[entry->dbno])
833 		ok = ajTrue;
834 	    else
835 	    {
836 		ajBtreeHitrefDel(&entry);
837 
838 		if(!ajListGetLength(qry->ResultsList))
839 		    return ajFalse;
840 	    }
841 	}
842     }
843 
844     qryd->Samefile = ajTrue;
845 
846     if(entry->dbno != qryd->div)
847     {
848 	qryd->Samefile = ajFalse;
849 	qryd->div = entry->dbno;
850 	ajFileClose(&qryd->libs);
851 
852 	if(qryd->reffiles)
853 	    ajFileClose(&qryd->libr);
854     }
855 
856     if(!qryd->libs)
857     {
858 	qryd->libs = ajFileNewInNameS(qryd->files[entry->dbno]);
859 
860 	if(!qryd->libs)
861 	{
862 	    ajBtreeHitrefDel(&entry);
863 
864 	    return ajFalse;
865 	}
866     }
867 
868     if(qryd->reffiles && !qryd->libr)
869     {
870 	ajFileClose(&qryd->libr);
871 	qryd->libr = ajFileNewInNameS(qryd->reffiles[entry->dbno][0]);
872 
873 	if(!qryd->libr)
874 	{
875 	    ajBtreeHitrefDel(&entry);
876 
877 	    return ajFalse;
878 	}
879     }
880 
881 
882     ajFileSeek(qryd->libs, (ajlong) entry->offset, 0);
883     if(qryd->reffiles)
884       ajFileSeek(qryd->libr, (ajlong) entry->refoffset, 0);
885 
886     ajBtreeHitrefDel(&entry);
887 
888     if(!qry->CaseId)
889 	qry->QryDone = ajTrue;
890 
891     return ajTrue;
892 }
893 
894 
895 
896 
897 /* @funcstatic taxEmbossQryClose **********************************************
898 **
899 ** Closes query data for a B+tree index
900 **
901 ** @param [u] qry [AjPQuery] Query data
902 ** @return [AjBool] ajTrue if we can continue,
903 **                  ajFalse if all is done.
904 **
905 ** @release 6.4.0
906 ** @@
907 ******************************************************************************/
908 
taxEmbossQryClose(AjPQuery qry)909 static AjBool taxEmbossQryClose(AjPQuery qry)
910 {
911     TaxPEmbossQry qryd;
912     void* item;
913     ajint i;
914     ajuint iref;
915 
916     if(!qry)
917 	return ajFalse;
918 
919     if(!qry->QryData)
920 	return ajFalse;
921 
922     qryd = qry->QryData;
923 
924     ajDebug("taxEmbossQryClose clean up qryd %x size:%Lu\n",
925             qryd, ajListGetLength(qry->ResultsList));
926 
927     while(ajListGetLength(qryd->Caches))
928     {
929         ajListPop(qryd->Caches, &item);
930         ajBtreeCacheDel((AjPBtcache*) &item);
931     }
932     ajListFree(&qryd->Caches);
933     ajBtreeCacheDel(&qryd->idcache);
934 
935     if(qryd->Skip)
936     {
937 	AJFREE(qryd->Skip);
938 	qryd->Skip = NULL;
939     }
940 
941     if(qryd->files)
942     {
943 	i = 0;
944 
945 	while(qryd->files[i])
946 	{
947 	    ajStrDel(&qryd->files[i]);
948 
949             if(qryd->reffiles)
950             {
951                 for(iref=0; iref < qryd->refcount; iref++)
952                     ajStrDel(&qryd->reffiles[i][iref]);
953             }
954 
955 	    ++i;
956 	}
957 
958 	AJFREE(qryd->files);
959     }
960 
961     if(qryd->reffiles)
962     {
963         for(iref=0; iref < qryd->refcount; iref++)
964             AJFREE(qryd->reffiles[iref]);
965 
966 	AJFREE(qryd->reffiles);
967     }
968 
969     qryd->files = NULL;
970     qryd->reffiles = NULL;
971 
972 
973     /* keep QryData for use at top of loop */
974 
975     return ajTrue;
976 }
977 
978 
979 
980 
981 /* @funcstatic taxEmbossQryQuery **********************************************
982 **
983 ** Queries for one or more entries in an EMBOSS B+tree index
984 **
985 ** @param [u] qry [AjPQuery] Query data
986 ** @return [AjBool] ajTrue if we can continue,
987 **                  ajFalse if all is done.
988 **
989 ** @release 6.4.0
990 ** @@
991 ******************************************************************************/
992 
taxEmbossQryQuery(AjPQuery qry)993 static AjBool taxEmbossQryQuery(AjPQuery qry)
994 {
995     TaxPEmbossQry qryd;
996 
997     const AjPList fdlist;
998     const AjPList cachelist;
999     AjIList iter;
1000     AjIList icache;
1001     AjPBtcache cache;
1002     AjPQueryField fd;
1003     AjPBtHitref newhit;
1004     AjPBtHitref *allhits = NULL;
1005     AjPTable newtable = NULL;
1006 
1007     ajuint i;
1008     ajulong lasthits = 0UL;
1009     ajulong fdhits = 0UL;
1010 
1011     if(!qry->CaseId)
1012 	qry->QryDone = ajTrue;
1013 
1014     qryd = qry->QryData;
1015 
1016     cachelist = qryd->Caches;
1017 
1018     ajTableSetDestroy(qry->ResultsTable, NULL, &ajBtreeHitrefDelVoid);
1019     ajTableSettypeUser(qry->ResultsTable,
1020                        &ajBtreeHitrefCmp, &ajBtreeHitrefHash);
1021 
1022     fdlist = ajQueryGetallFields(qry);
1023 
1024     ajDebug("taxEmbossQryQuery wild: %B list:%Lu fields:%Lu\n",
1025             qry->Wild, ajListGetLength(qry->ResultsList),
1026             ajListGetLength(fdlist));
1027 
1028     iter = ajListIterNewread(fdlist);
1029     icache = ajListIterNewread(cachelist);
1030 
1031     while(!ajListIterDone(iter))
1032     {
1033         fd = ajListIterGet(iter);
1034         cache = ajListIterGet(icache);
1035 
1036         ajDebug("field '%S' query: '%S'\n", fd->Field, fd->Wildquery);
1037 
1038         if((fd->Link == AJQLINK_ELSE) && (lasthits > 0))
1039         {
1040             continue;
1041         }
1042 
1043         /* is this a primary or secondary key (check the cache)? */
1044 
1045         if(ajBtreeCacheIsSecondary(cache))
1046         {
1047             if(!qry->Wild)
1048             {
1049                 ajBtreeKeyFetchHitref(cache, qryd->idcache,
1050                                       fd->Wildquery, qry->ResultsList);
1051             }
1052             else
1053             {
1054                 ajBtreeKeyFetchwildHitref(cache, qryd->idcache,
1055                                           fd->Wildquery, qry->ResultsList);
1056             }
1057         }
1058         else
1059         {
1060             ajBtreeIdentFetchwildHitref(cache,fd->Wildquery,qry->ResultsList);
1061             ajDebug("ajBtreeIdentFetchwild results:%Lu\n",
1062                     ajListGetLength(qry->ResultsList));
1063 
1064         }
1065 
1066         fdhits = ajListGetLength(qry->ResultsList);
1067 
1068         switch(fd->Link)
1069         {
1070             case AJQLINK_INIT:
1071                 while(ajListPop(qry->ResultsList, (void**)&newhit))
1072                     ajTablePutClean(qry->ResultsTable, newhit, newhit,
1073                                     NULL, &ajBtreeHitrefDelVoid);
1074                 break;
1075 
1076             case AJQLINK_OR:
1077                 newtable = ajTableNewFunctionLen(fdhits,
1078                                                  &ajBtreeHitrefCmp,
1079                                                  &ajBtreeHitrefHash,
1080                                                  NULL, &ajBtreeHitrefDelVoid);
1081                 while(ajListPop(qry->ResultsList, (void**)&newhit))
1082                     ajTablePutClean(newtable, newhit, newhit,
1083                                     NULL, &ajBtreeHitrefDelVoid);
1084 
1085                 ajTableMergeOr(qry->ResultsTable, newtable);
1086                 ajTableDel(&newtable);
1087                 break;
1088 
1089             case AJQLINK_AND:
1090                 newtable = ajTableNewFunctionLen(fdhits,
1091                                                  &ajBtreeHitrefCmp,
1092                                                  &ajBtreeHitrefHash,
1093                                                  NULL, &ajBtreeHitrefDelVoid);
1094                 while(ajListPop(qry->ResultsList, (void**)&newhit))
1095                     ajTablePutClean(newtable, newhit, newhit,
1096                                     NULL, &ajBtreeHitrefDelVoid);
1097 
1098                 ajTableMergeAnd(qry->ResultsTable, newtable);
1099                 ajTableDel(&newtable);
1100                 break;
1101 
1102             case AJQLINK_EOR:
1103             case AJQLINK_ELSE:
1104                 newtable = ajTableNewFunctionLen(fdhits,
1105                                                  &ajBtreeHitrefCmp,
1106                                                  &ajBtreeHitrefHash,
1107                                                  NULL, &ajBtreeHitrefDelVoid);
1108                 while(ajListPop(qry->ResultsList, (void**)&newhit))
1109                     ajTablePutClean(newtable, newhit, newhit,
1110                                     NULL, &ajBtreeHitrefDelVoid);
1111 
1112                 ajTableMergeEor(qry->ResultsTable, newtable);
1113                 ajTableDel(&newtable);
1114                 break;
1115 
1116             case AJQLINK_NOT:
1117                 newtable = ajTableNewFunctionLen(fdhits,
1118                                                  &ajBtreeHitrefCmp,
1119                                                  &ajBtreeHitrefHash,
1120                                                  NULL, &ajBtreeHitrefDelVoid);
1121                 while(ajListPop(qry->ResultsList, (void**)&newhit))
1122                     ajTablePutClean(newtable, newhit, newhit,
1123                                     NULL, &ajBtreeHitrefDelVoid);
1124 
1125                 ajTableMergeNot(qry->ResultsTable, newtable);
1126                 ajTableDel(&newtable);
1127                 break;
1128 
1129             default:
1130                 ajErr("Unexpected query link operator number '%u'",
1131                       fd->Link);
1132                 break;
1133         }
1134 
1135         lasthits = fdhits;
1136     }
1137 
1138     ajListIterDel(&iter);
1139     ajListIterDel(&icache);
1140 
1141     ajTableToarrayValues(qry->ResultsTable, (void***)&allhits);
1142     for(i=0; allhits[i]; i++)
1143         ajListPushAppend(qry->ResultsList, (void*) allhits[i]);
1144 
1145     AJFREE(allhits);
1146 
1147     ajTableClear(qry->ResultsTable);
1148 
1149     if(ajListGetLength(qry->ResultsList))
1150         return ajTrue;
1151 
1152     return ajFalse;
1153 }
1154 
1155 
1156 
1157 
1158 /* @func ajTaxdbInit **********************************************************
1159 **
1160 ** Initialise taxonomy database internals
1161 **
1162 ** @return [void]
1163 **
1164 ** @release 6.4.0
1165 ******************************************************************************/
1166 
ajTaxdbInit(void)1167 void ajTaxdbInit(void)
1168 {
1169     AjPTable table;
1170     ajuint i = 0;
1171 
1172     table = ajTaxaccessGetDb();
1173 
1174     while(taxAccess[i].Name)
1175     {
1176         ajCallTableRegister(table, taxAccess[i].Name,
1177                             (void*) &taxAccess[i]);
1178 	i++;
1179     }
1180 
1181     return;
1182 }
1183 
1184 
1185 
1186 
1187 /* @func ajTaxdbPrintAccess ***************************************************
1188 **
1189 ** Reports the internal data structures
1190 **
1191 ** @param [u] outf [AjPFile] Output file
1192 ** @param [r] full [AjBool] Full report (usually ajFalse)
1193 ** @return [void]
1194 **
1195 ** @release 6.4.0
1196 ** @@
1197 ******************************************************************************/
1198 
ajTaxdbPrintAccess(AjPFile outf,AjBool full)1199 void ajTaxdbPrintAccess(AjPFile outf, AjBool full)
1200 {
1201     ajint i = 0;
1202 
1203     ajFmtPrintF(outf, "\n");
1204     ajFmtPrintF(outf, "# Taxonomy access methods\n");
1205     ajFmtPrintF(outf, "# Name       Alias Entry Query   All Description\n");
1206     ajFmtPrintF(outf, "\n");
1207     ajFmtPrintF(outf, "method {\n");
1208 
1209     for(i=0; taxAccess[i].Name; i++)
1210 	if(full || !taxAccess[i].Alias)
1211 	    ajFmtPrintF(outf, "  %-10s %5B %5B %5B %5B \"%s\"\n",
1212 			taxAccess[i].Name,  taxAccess[i].Alias,
1213 			taxAccess[i].Entry, taxAccess[i].Query,
1214 			taxAccess[i].All,   taxAccess[i].Desc);
1215 
1216     ajFmtPrintF(outf, "}\n\n");
1217 
1218     return;
1219 }
1220 
1221 
1222 
1223 
1224 /* @func ajTaxdbExit **********************************************************
1225 **
1226 ** Cleans up taxonomy database processing internal memory
1227 **
1228 ** @return [void]
1229 **
1230 ** @release 6.4.0
1231 ** @@
1232 ******************************************************************************/
1233 
ajTaxdbExit(void)1234 void ajTaxdbExit(void)
1235 {
1236     return;
1237 }
1238