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