1 /*===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================
24  *
25  */
26 
27 #include <sra/extern.h>
28 
29 #include <sra/sradb.h>
30 #include <sra/srapath.h>
31 #include <sra/types.h>
32 #include <sra/sraschema.h>
33 #include <sra/sradb-priv.h>
34 #include <vdb/database.h>
35 #include <vdb/schema.h>
36 #include <vdb/table.h>
37 #include <vdb/cursor.h>
38 #include <vdb/vdb-priv.h>
39 #include <vdb/dependencies.h>
40 #include <kdb/meta.h>
41 #include <kdb/manager.h>
42 #include <kdb/table.h>
43 #include <kdb/database.h>
44 #include <kdb/kdb-priv.h>
45 #include <vfs/manager.h>
46 #include <vfs/path.h>
47 #include <vfs/path-priv.h>
48 #include <vfs/resolver.h>
49 #include <klib/refcount.h>
50 #include <klib/log.h>
51 #include <klib/debug.h>
52 #include <klib/rc.h>
53 #include <klib/text.h>
54 #include <klib/printf.h>
55 #include <kfs/toc.h>
56 #include <kfs/file.h>
57 #include <sysalloc.h>
58 
59 #include "sra-priv.h"
60 
61 #include <stdlib.h>
62 #include <stdarg.h>
63 #include <string.h>
64 #include <stdio.h>
65 #include <assert.h>
66 #include <va_copy.h>
67 
68 #ifdef __GNUC__
69 #pragma GCC diagnostic ignored "-Wpedantic"
70 #endif
71 
72 /* Destroy
73  */
74 static
column_release(void * item,void * ignore)75 void CC column_release ( void *item, void *ignore )
76 {
77     SRAColumn *self = item;
78     self -> tbl = NULL;
79     SRAColumnWhack ( self );
80 }
81 
SRATableDestroy(SRATable * self)82 void SRATableDestroy ( SRATable *self )
83 {
84     VectorWhack ( & self -> wcol, column_release, NULL );
85     VCursorRelease(self->curs);
86     KMetadataRelease ( self -> meta );
87     VTableRelease ( self -> vtbl );
88     SRAMgrSever ( self -> mgr );
89 
90     memset(self, 0, sizeof *self);
91 
92     free ( self );
93 }
94 
95 /* AddRef
96  * Release
97  *  see REFERENCE COUNTING, above
98  */
SRATableAddRef(const SRATable * self)99 LIB_EXPORT rc_t CC SRATableAddRef( const SRATable *self )
100 {
101     if ( self != NULL )
102     {
103         switch ( KRefcountAdd ( & self -> refcount, "SRATable" ) )
104         {
105         case krefLimit:
106             return RC ( rcSRA, rcTable, rcAttaching, rcRange, rcExcessive );
107         }
108     }
109     return 0;
110 }
111 
SRATableRelease(const SRATable * self)112 LIB_EXPORT rc_t CC SRATableRelease( const SRATable *self )
113 {
114     rc_t rc = 0;
115 
116     if (self)
117     {
118         switch (KRefcountDrop(&self->refcount, "SRATable"))
119         {
120         case krefWhack:
121             return SRATableWhack ( ( SRATable* ) self );
122         case krefNegative:
123             rc = RC (rcSRA, rcTable, rcDestroying, rcSelf, rcDestroyed);
124             PLOGERR (klogInt,(klogInt, rc, "Released an SRATable $(B) with no more references",
125                       PLOG_P(self)));
126             break;
127         }
128     }
129     return rc;
130 }
131 
132 /* Attach
133  * Sever
134  */
SRATableAttach(const SRATable * self)135 SRATable *SRATableAttach ( const SRATable *self )
136 {
137     if ( self != NULL )
138     {
139         switch ( KRefcountAddDep ( & self -> refcount, "SRATable" ) )
140         {
141         case krefLimit:
142             return NULL;
143         }
144     }
145     return ( SRATable* ) self;
146 }
147 
SRATableSever(const SRATable * self)148 rc_t SRATableSever ( const SRATable *self )
149 {
150     if ( self != NULL )
151     {
152         switch ( KRefcountDropDep ( & self -> refcount, "SRATable" ) )
153         {
154         case krefWhack:
155             return SRATableWhack ( ( SRATable* ) self );
156         case krefNegative:
157             return RC ( rcSRA, rcTable, rcReleasing, rcRange, rcExcessive );
158         }
159     }
160     return 0;
161 }
162 
163 
164 /* FillOutTableRead
165  *  creates an empty cursor
166  *  accesses metadata
167  */
ReadSpotSequence_v1(SRATable * self)168 static rc_t ReadSpotSequence_v1(SRATable *self)
169 {
170     const KMDataNode *n;
171     rc_t rc = KMetadataOpenNodeRead(self->meta, &n, ".seq");
172     if (rc == 0)
173     {
174         rc = KMDataNodeReadAsU64(n, &self->spot_count);
175         KMDataNodeRelease(n);
176     }
177     return rc;
178 }
179 
180 typedef enum {
181     eNotRead,
182     eNotFound,
183     eFailed,
184     eRead
185 } EState;
186 typedef struct {
187     EState state;
188     rc_t rc;
189 } State;
190 typedef struct {
191     uint64_t value;
192     State state;
193 } U64;
194 typedef struct {
195     uint32_t value;
196     State state;
197 } U32;
198 typedef struct {
199     U64 BASE_COUNT;
200     U32 MAX_SPOT_ID;
201     U32 MIN_SPOT_ID;
202     U64 SPOT_COUNT;
203 } PseudoMeta;
204 static
VCursor_ReadPseudoMeta(rc_t rc,const VCursor * self,const char * name,void * buffer,uint32_t blen,State * state)205 rc_t VCursor_ReadPseudoMeta(rc_t rc, const VCursor *self,
206     const char *name, void *buffer, uint32_t blen, State *state)
207 {
208     uint32_t idx = ~0;
209     uint32_t row_len = ~0;
210 
211     assert(state);
212     state->rc = 0;
213 
214     if (rc != 0)
215     {   return rc; }
216 
217     state->state = eNotRead;
218 
219     rc = VCursorAddColumn(self, &idx, "%s", name);
220 
221     if (rc != 0) {
222         state->rc = rc;
223 
224         if ( GetRCObject( rc ) == (enum RCObject)rcColumn && GetRCState( rc ) == rcNotFound ) {
225             rc = 0;
226             state->state = eNotFound;
227         }
228         else {
229             state->state = eFailed;
230         }
231     }
232 
233     if (state->rc == 0) {
234         rc = VCursorReadDirect(self, 1, idx, blen * 8, buffer, blen, &row_len);
235 
236         state->rc = rc;
237 
238         if (rc != 0)
239         {   state->state = eFailed; }
240         else
241         {   state->state = eRead; }
242 
243     }
244 
245     return rc;
246 }
247 
248 static
VCursor_ReadPseudoMetaU32(rc_t rc,const VCursor * self,const char * name,U32 * val)249 rc_t VCursor_ReadPseudoMetaU32(rc_t rc, const VCursor *self,
250     const char *name, U32 *val)
251 {
252     assert(val);
253     return VCursor_ReadPseudoMeta(rc, self,
254         name, &val->value, sizeof val->value, &val->state);
255 }
256 
257 static
VCursor_ReadPseudoMetaU64(rc_t rc,const VCursor * self,const char * name,U64 * val)258 rc_t VCursor_ReadPseudoMetaU64(rc_t rc, const VCursor *self,
259     const char *name, U64 *val)
260 {
261     assert(val);
262     return VCursor_ReadPseudoMeta(rc, self,
263         name, &val->value, sizeof val->value, &val->state);
264 }
265 
266 static
PseudoMetaInit(PseudoMeta * self,const VCursor * curs,bool readSpotCount,uint64_t spot_count)267 rc_t PseudoMetaInit(PseudoMeta *self, const VCursor *curs,
268     bool readSpotCount, uint64_t spot_count)
269 {
270     rc_t rc = 0;
271 
272     assert(self);
273 
274     memset(self, 0, sizeof *self);
275 
276     if (readSpotCount) {
277         rc =
278          VCursor_ReadPseudoMetaU64(rc, curs, "SPOT_COUNT", &self->SPOT_COUNT);
279     }
280     else {
281         self->SPOT_COUNT.value = spot_count;
282         self->SPOT_COUNT.state.state = eRead;
283     }
284 
285     rc = VCursor_ReadPseudoMetaU64(rc, curs, "BASE_COUNT", &self->BASE_COUNT);
286 
287     rc = VCursor_ReadPseudoMetaU32(rc, curs, "MIN_SPOT_ID", &self->MIN_SPOT_ID);
288 
289     rc = VCursor_ReadPseudoMetaU32(rc, curs, "MAX_SPOT_ID", &self->MAX_SPOT_ID);
290 
291     return rc;
292 }
293 
294 static
PseudoMetaFix(PseudoMeta * self)295 rc_t PseudoMetaFix(PseudoMeta *self)
296 {
297     rc_t rc = 0;
298 
299     assert(self);
300 
301     if (self->MIN_SPOT_ID.state.state != eRead)
302     {   self->MIN_SPOT_ID.value = 1; }
303 
304     if (self->SPOT_COUNT.state.state != eRead &&
305         self->MAX_SPOT_ID.state.state != eRead)
306     {
307         return self->SPOT_COUNT.state.rc;
308     }
309     else if (self->SPOT_COUNT.state.state == eRead) {
310         if (self->MAX_SPOT_ID.state.state != eRead) {
311             self->MAX_SPOT_ID.value
312                 = self->MIN_SPOT_ID.value + self->SPOT_COUNT.value - 1;
313         }
314         else if (self->MAX_SPOT_ID.value >= self->MIN_SPOT_ID.value) {
315 	    uint32_t delta = (uint32_t) (self->SPOT_COUNT.value - (self->MAX_SPOT_ID.value - self->MIN_SPOT_ID.value + 1)); /** SPOT_COUNT is 64 bit, but M*_SPOT_ID is 32; anticipate rollover **/
316             if ( delta )
317             {
318                 self->SPOT_COUNT.value
319                     = self->MAX_SPOT_ID.value - self->MIN_SPOT_ID.value + 1;
320             }
321         }
322     }
323     else {
324             self->SPOT_COUNT.value
325                 = self->MAX_SPOT_ID.value - self->MIN_SPOT_ID.value - 1;
326     }
327 
328     return rc;
329 }
330 
331 static
SRATableLoadMetadata(SRATable * self)332 rc_t SRATableLoadMetadata(SRATable * self)
333 {
334     rc_t rc = 0;
335     PseudoMeta meta;
336     bool readSpotCount = true;
337 
338     assert(self && self->curs != NULL);
339     assert(self->curs_open == true);
340 
341     readSpotCount = self->metavers > 1;
342     if (!readSpotCount) {
343         rc = ReadSpotSequence_v1(self);
344         if (rc != 0)
345         {   return rc; }
346     }
347 
348     rc = PseudoMetaInit(&meta, self->curs, readSpotCount, self->spot_count);
349     if (rc != 0)
350     {   return rc; }
351 
352     rc = PseudoMetaFix(&meta);
353     if (rc != 0)
354     {   return rc; }
355 
356     self->spot_count = meta.SPOT_COUNT.value;
357     self->base_count = meta.BASE_COUNT.value;
358     self->min_spot_id = meta.MIN_SPOT_ID.value;
359     self->max_spot_id = meta.MAX_SPOT_ID.value;
360 
361     {
362 	int64_t delta = self->spot_count - (self->max_spot_id-self->min_spot_id+1);
363 	if(delta>0 && ((uint32_t)delta)==0){/* there was a rollover*/
364 		self->max_spot_id = self->min_spot_id + self->spot_count - 1;
365 	}
366     }
367 
368     return rc;
369 }
370 
371 /* detect min and max spot-id from a temp. cursor */
SRATableGetMinMax(SRATable * self)372 static rc_t SRATableGetMinMax( SRATable * self )
373 {
374     const VCursor *temp_cursor;
375     rc_t rc;
376 
377     assert( self != NULL );
378     assert( self->vtbl != NULL);
379     rc = VTableCreateCursorRead( self->vtbl, &temp_cursor );
380     if ( rc == 0 )
381     {
382         uint32_t idx;
383         rc = VCursorAddColumn ( temp_cursor, &idx, "READ" );
384         if ( rc == 0 )
385         {
386             rc = VCursorOpen( temp_cursor );
387             if ( rc == 0 )
388             {
389                 int64_t  first;
390                 uint64_t count;
391                 rc = VCursorIdRange( temp_cursor, 0, &first, &count );
392                 if ( rc == 0 )
393                 {
394                     self->min_spot_id = first;
395                     self->max_spot_id = first + count;
396                     self->spot_count = count;
397                 }
398             }
399         }
400         VCursorRelease( temp_cursor );
401     }
402     return rc;
403 }
404 
SRATableFillOut(SRATable * self,bool update)405 rc_t SRATableFillOut ( SRATable *self, bool update )
406 {
407     rc_t rc;
408 
409     /* require these operations to succeed */
410     rc = VCursorPermitPostOpenAdd( self->curs );
411     if ( rc != 0 )
412         return rc;
413     rc = VCursorOpen( self->curs );
414     if ( rc != 0 )
415         return rc;
416     self -> curs_open = true;
417     if ( ! update )
418     {
419         rc = SRATableLoadMetadata( self );
420         if ( rc != 0 )
421             rc = SRATableGetMinMax( self );
422     }
423     return rc;
424 }
425 
426 
427 /* ResolveTablePath
428  *  takes either an accession or path
429  *  substitutes any arguments
430  *  resolves via SRAPath mgr if present
431  */
ResolveTablePath(const SRAMgr * mgr,char * path,size_t psize,const char * spec,va_list args)432 rc_t ResolveTablePath ( const SRAMgr *mgr,
433     char *path, size_t psize, const char *spec, va_list args )
434 {
435 #if OLD_SRAPATH_MGR
436     int len;
437     char tblpath [ 4096 ];
438     const SRAPath *pmgr = mgr -> _pmgr;
439 
440     /* if no path manager or if the spec string has embedded path separators,
441        then this can't be an accession - just print it out */
442     if ( mgr -> _pmgr == NULL || strchr( spec, '/' ) != NULL )
443     {
444         len = vsnprintf ( path, psize, spec, args );
445         if ( len < 0 || ( size_t ) len >= psize )
446             return RC ( rcSRA, rcTable, rcOpening, rcPath, rcExcessive );
447         return 0;
448     }
449 
450     /* create a copy - not likely to be too large */
451     len = vsnprintf ( tblpath, sizeof tblpath, spec, args );
452     if ( len < 0 || ( size_t ) len >= sizeof tblpath )
453         return RC ( rcSRA, rcTable, rcOpening, rcPath, rcExcessive );
454 
455     /* test if the path exists in current directory, i.e. with assumed dot */
456     if ( ! SRAPathTest ( pmgr, tblpath ) )
457     {
458         rc_t rc = SRAPathFind ( pmgr, tblpath, path, psize );
459         if ( rc == 0 )
460             return 0;
461     }
462 
463     /* use the path given */
464     if ( ( size_t ) len >= psize )
465         return RC ( rcSRA, rcTable, rcOpening, rcBuffer, rcInsufficient );
466     strcpy ( path, tblpath );
467 
468     return 0;
469 #else
470     VFSManager *vfs;
471     rc_t rc = VFSManagerMake ( & vfs );
472     if ( rc == 0 )
473     {
474         VPath *accession;
475         const VPath *tblpath = NULL;
476         rc = VFSManagerVMakePath ( vfs, & accession, spec, args );
477         if ( rc == 0 )
478         {
479             rc = VResolverLocal ( ( const VResolver* ) mgr -> _pmgr, accession, & tblpath );
480             if ( rc == 0 )
481             {
482                 size_t size;
483                 rc = VPathReadPath ( tblpath, path, psize, & size );
484                 VPathRelease ( tblpath );
485             }
486             VPathRelease ( accession );
487         }
488 
489         VFSManagerRelease ( vfs );
490     }
491     return rc;
492 #endif
493 }
494 
495 /* OpenRead
496  *  open an existing table
497  *
498  *  "tbl" [ OUT ] - return parameter for table
499  *
500  *  "spec" [ IN ] - NUL terminated UTF-8 string giving path
501  *  to table.
502  */
503 static
SRAMgrVOpenAltTableRead(const SRAMgr * self,const SRATable ** rslt,const char * altname,const char * spec,va_list args)504 rc_t CC SRAMgrVOpenAltTableRead ( const SRAMgr *self,
505     const SRATable **rslt, const char *altname, const char *spec, va_list args )
506 {
507     rc_t rc;
508 
509     if ( rslt == NULL )
510         rc = RC ( rcSRA, rcTable, rcOpening, rcParam, rcNull );
511     else
512     {
513         if ( self == NULL )
514             rc = RC ( rcSRA, rcMgr, rcAccessing, rcSelf, rcNull );
515         else if ( spec == NULL )
516             rc = RC ( rcSRA, rcTable, rcOpening, rcName, rcNull );
517         else if ( spec [ 0 ] == 0 )
518             rc = RC ( rcSRA, rcTable, rcOpening, rcName, rcEmpty );
519         else
520         {
521             SRATable *tbl = calloc ( 1, sizeof *tbl );
522             if ( tbl == NULL )
523                 rc = RC ( rcSRA, rcTable, rcConstructing, rcMemory, rcExhausted );
524             else
525             {
526                 VSchema *schema = NULL;
527 
528                 rc = VDBManagerMakeSRASchema(self -> vmgr, & schema);
529                 if ( rc == 0 )
530                 {
531                     va_list args_copy;
532                     va_copy ( args_copy, args );
533                     rc = VDBManagerVOpenTableRead ( self -> vmgr, & tbl -> vtbl, schema, spec, args );
534                     if ( rc != 0 && GetRCObject ( rc ) == (enum RCObject)rcTable && GetRCState ( rc ) == rcIncorrect )
535                     {
536                         const VDatabase *db;
537                         rc_t rc2 = VDBManagerVOpenDBRead ( self -> vmgr, & db, schema, spec, args_copy );
538                         if ( rc2 == 0 )
539                         {
540                             rc2 = VDatabaseOpenTableRead ( db, & tbl -> vtbl, "%s", altname );
541                             if ( rc2 == 0 )
542                                 rc = 0;
543 
544                             VDatabaseRelease ( db );
545                         }
546                     }
547                     va_end ( args_copy );
548 
549                     VSchemaRelease(schema);
550 
551                     if ( rc == 0 )
552                     {
553                         rc = VTableOpenMetadataRead ( tbl -> vtbl, & tbl -> meta );
554                         if ( rc == 0 )
555                         {
556                             rc = KMetadataVersion ( tbl -> meta, & tbl -> metavers );
557                             if ( rc == 0 )
558                             {
559                                 rc = VTableCreateCursorRead ( tbl -> vtbl, & tbl -> curs );
560                                 if ( rc == 0 )
561                                 {
562                                     tbl -> mode = self -> mode;
563                                     tbl -> read_only = true;
564                                     KRefcountInit ( & tbl -> refcount, 1, "SRATable", "OpenTableRead", spec );
565 
566                                     rc = SRATableFillOut ( tbl, false );
567                                     if ( rc == 0 )
568                                     {
569                                         * rslt = tbl;
570                                         return 0;
571                                     }
572                                 }
573                             }
574                         }
575                     }
576 
577                 }
578                 SRATableWhack ( tbl );
579             }
580         }
581 
582         * rslt = NULL;
583     }
584     return rc;
585 }
586 
587 /* OpenRead
588  *  open an existing table
589  *
590  *  "tbl" [ OUT ] - return parameter for table
591  *
592  *  "spec" [ IN ] - NUL terminated UTF-8 string giving path
593  *  to table.
594  */
SRAMgrVOpenTableRead(const SRAMgr * self,const SRATable ** crslt,const char * spec,va_list args)595 LIB_EXPORT rc_t CC SRAMgrVOpenTableRead ( const SRAMgr *self,
596         const SRATable **crslt, const char *spec, va_list args )
597 {
598     rc_t rc;
599     char tblpath [ 4096 ];
600     int num_writ = vsnprintf ( tblpath, sizeof tblpath, spec, args );
601     if ( num_writ < 0 || ( size_t ) num_writ >= sizeof tblpath )
602         rc = RC ( rcSRA, rcMgr, rcOpening, rcPath, rcExcessive );
603     else
604     {
605         SRATable **rslt = (SRATable **)crslt; /* to avoid "const_casts" below */
606         rc = SRACacheGetTable( self->cache, tblpath, crslt );
607         if  (rc == 0 )
608         {
609             if ( *crslt == NULL )
610             {
611                 rc = SRAMgrOpenAltTableRead ( self, crslt, "SEQUENCE", tblpath );
612                 if ( rc == 0 )
613                 {
614                     rc = SRACacheAddTable( self->cache, tblpath, *rslt);
615                     if ( GetRCObject(rc) == rcParam && GetRCState(rc) == rcExists )
616                     {           /* the same object has appeared in the cache since our call to SRACacheGetTable above;  */
617                        rc = 0;  /* return the new object, never mind the cache */
618                     }
619                     else if ( ! SRACacheMetricsLessThan(&self->cache->current, &self->cache->hardThreshold) )
620                        rc = SRACacheFlush(self->cache);
621                 }
622             }
623         }
624         else if ( (GetRCObject(rc) == rcName && GetRCState(rc) == rcInvalid) ||   /* accessions with irregular names are not cached */
625                   (GetRCObject(rc) == rcParam && GetRCState(rc) == rcBusy)    )   /* in cache but in use */
626         {
627             rc = SRAMgrOpenAltTableRead ( self, crslt, "SEQUENCE", tblpath );
628             if (rc == 0)
629                 (*rslt)->mgr = SRAMgrAttach(self);
630         }
631     }
632 
633     return rc;
634 }
635 
SRAMgrOpenTableRead(const SRAMgr * self,const SRATable ** tbl,const char * spec,...)636 LIB_EXPORT rc_t CC SRAMgrOpenTableRead ( const SRAMgr *self,
637         const SRATable **tbl, const char *spec, ... )
638 {
639     rc_t rc;
640 
641     va_list args;
642     va_start ( args, spec );
643 
644     rc = SRAMgrVOpenTableRead ( self, tbl, spec, args );
645 
646     va_end ( args );
647 
648     return rc;
649 }
650 
651 
652 /* Read - PRIVATE
653  *  column message sent via table
654  */
SRATableRead(const SRATable * self,spotid_t id,uint32_t idx,const void ** base,bitsz_t * offset,bitsz_t * size)655 rc_t SRATableRead ( const SRATable *self, spotid_t id, uint32_t idx,
656     const void **base, bitsz_t *offset, bitsz_t *size )
657 {
658     rc_t rc;
659 
660     if ( base == NULL || offset == NULL || size == NULL )
661         rc = RC ( rcSRA, rcColumn, rcReading, rcParam, rcNull );
662     else if ( self == NULL )
663         rc = RC ( rcSRA, rcTable, rcAccessing, rcSelf, rcNull );
664     else
665     {
666         rc = 0;
667 
668         /* open cursor */
669         if ( ! self -> curs_open )
670         {
671             rc = VCursorOpen(self->curs);
672             if ( rc == 0 )
673                 ((SRATable *)self)->curs_open = true;
674         }
675 
676         if ( rc == 0 )
677         {
678             uint32_t elem_bits, elem_off, elem_cnt;
679             rc = VCursorCellDataDirect ( self -> curs, id, idx,
680                 & elem_bits, base, & elem_off, & elem_cnt );
681             if ( rc == 0 )
682             {
683                 * offset = elem_off * elem_bits;
684                 * size   = elem_cnt * elem_bits;
685                 return 0;
686             } else if( UIError(rc, NULL, self->vtbl) ) {
687                 UITableLOGError(rc, self->vtbl, true);
688             }
689         }
690     }
691 
692     if ( base != NULL )
693         * base = NULL;
694     if ( offset != NULL )
695         * offset = 0;
696     if ( size != NULL )
697         * size = 0;
698 
699     return rc;
700 }
701 
702 /* GetSpotId
703  *  convert spot name to spot id
704  *
705  *  "id" [ OUT ] - return parameter for min(spot_id)-max(spot_id)
706  *
707  *  "spot_name" [ IN ] - external spot name string
708  *  in platform canonical format.
709  */
SRATableGetSpotId(const SRATable * self,spotid_t * rslt,const char * spot_name)710 LIB_EXPORT rc_t CC SRATableGetSpotId ( const SRATable *self,
711         spotid_t *rslt, const char *spot_name )
712 {
713     rc_t rc;
714     if( self == NULL || spot_name == NULL){
715         rc=RC(rcSRA, rcTable, rcListing, rcSelf, rcName);
716     } else {
717         rc=VCursorParamsSet((struct VCursorParams*)self->curs,"QUERY_BY_NAME" ,spot_name);
718         if( rc == 0) {
719             struct {
720                 uint64_t start_id;
721                 uint64_t id_count;
722                 int64_t x;
723                 int64_t y;
724             } out;
725             uint32_t idx,len;
726             rc = VCursorAddColumn(self->curs, &idx, "SPOT_IDS_FOUND");
727             if( rc == 0 || GetRCState(rc) == rcExists){
728                 rc = VCursorReadDirect(self->curs,1,idx,sizeof(out) * 8,&out, 1 , &len);
729                 if ( rc == 0 ) {
730                     if(out.id_count==1) {
731                         if(rslt) *rslt=out.start_id;
732                         return 0;
733                     } else if(out.id_count > 1) { /*** doing table range scan in Name space - not relying on X and Y***/
734                         uint32_t x_idx;
735                         rc = VCursorAddColumn(self->curs, &x_idx, "X");
736                         if( rc == 0 || GetRCState(rc) == rcExists){
737                             uint32_t y_idx;
738                             rc = VCursorAddColumn(self->curs, &y_idx, "Y");
739                             if(rc == 0 || GetRCState(rc) == rcExists){
740                                 spotid_t rowid;
741                                 for(rowid = out.start_id; rowid < out.start_id + out.id_count; rowid ++){
742                                     int32_t x,y;
743                                     rc = VCursorReadDirect(self->curs,rowid,x_idx,32,&x,1, &len);
744                                     if(rc == 0){
745                                         rc = VCursorReadDirect(self->curs,rowid,y_idx,32,&y,1, &len);
746                                         if(rc == 0 && x==out.x && y==out.y){
747                                             if(rslt) *rslt=rowid;
748                                             return 0;
749                                         }
750                                     }
751                                 }
752                             }
753                         }
754                     }
755                     rc = RC ( rcSRA, rcIndex, rcSearching, rcColumn, rcNotFound );
756                 }
757             }
758         }
759     }
760     return rc;
761 }
762 
763 
764 /* ListCol
765  *  returns a list of simple column names
766  *  each name represents at least one typed column
767  *
768  *  "names" [ out ] - return parameter for names list
769  */
SRATableListCol(const SRATable * self,SRANamelist ** rslt)770 LIB_EXPORT rc_t CC SRATableListCol( const SRATable *self, SRANamelist **rslt ) {
771     if ( self != NULL )
772         return VTableListCol ( self -> vtbl, (KNamelist **)rslt );
773     return RC(rcSRA, rcTable, rcListing, rcSelf, rcName);
774 }
775 
776 
777 /* ColDatatypes
778  *  returns list of typedecls for named column
779  *
780  *  "col" [ IN ] - column name
781  *
782  *  "dflt_idx" [ OUT, NULL OKAY ] - returns the zero-based index
783  *  into "typedecls" of the default datatype for the named column
784  *
785  *  "typedecls" [ OUT ] - list of datatypes available for named column
786  */
SRATableColDatatypes(const SRATable * self,const char * col,uint32_t * dflt_idx,SRANamelist ** rslt)787 LIB_EXPORT rc_t CC SRATableColDatatypes( const SRATable *self,
788         const char *col, uint32_t *dflt_idx, SRANamelist **rslt ) {
789     if ( self != NULL )
790         return VTableColumnDatatypes ( self -> vtbl, col, dflt_idx, (KNamelist **)rslt );
791     return RC(rcSRA, rcTable, rcListing, rcSelf, rcName);
792 }
793 
SRATableColDatatype(const SRATable * self,uint32_t idx,VTypedecl * type,VTypedef * def)794 rc_t SRATableColDatatype ( const SRATable *self,
795         uint32_t idx, VTypedecl *type, VTypedef *def )
796 {
797     rc_t rc;
798     if ( type == NULL && def == NULL )
799         rc = RC ( rcSRA, rcColumn, rcAccessing, rcParam, rcNull );
800     else
801     {
802         union { VTypedecl td; VTypedef def; } dummy;
803         if ( type == NULL )
804             type = & dummy . td;
805         else if ( def == NULL )
806             def = & dummy . def;
807 
808         if ( idx == 0 )
809             rc = RC ( rcSRA, rcColumn, rcAccessing, rcSelf, rcNull );
810         else if ( self == NULL )
811             rc = RC ( rcSRA, rcTable, rcAccessing, rcSelf, rcNull );
812         else
813         {
814             VTypedesc desc;
815             rc = VCursorDatatype ( self -> curs, idx, type, & desc );
816             if ( rc == 0 )
817             {
818                 rc = VSchemaDescribeTypedef ( VCursorGetSchema(self -> curs), def, type -> type_id );
819                 if ( rc == 0 )
820                     return 0;
821             }
822         }
823 
824         memset ( type, 0, sizeof * type );
825         memset ( def, 0, sizeof * def );
826     }
827     return rc;
828 }
829 
830 /* MetaRevision
831  *  returns current revision number
832  *  where 0(zero) means tip
833  */
SRATableMetaRevision(const SRATable * self,uint32_t * rslt)834 LIB_EXPORT rc_t CC SRATableMetaRevision( const SRATable *self, uint32_t *rslt )
835 {
836     if (self == NULL)
837         return RC(rcSRA, rcTable, rcAccessing, rcSelf, rcNull);
838     return KMetadataRevision (self->meta,rslt);
839 }
840 
841 
842 /* MaxRevision
843  *  returns the maximum revision available
844  */
SRATableMaxMetaRevision(const SRATable * self,uint32_t * rslt)845 LIB_EXPORT rc_t CC SRATableMaxMetaRevision( const SRATable *self, uint32_t *rslt )
846 {
847     if (self == NULL)
848         return RC(rcSRA, rcTable, rcAccessing, rcSelf, rcNull);
849     return KMetadataMaxRevision(self->meta,rslt);
850 }
851 
852 /* UseMetaRevision
853  *  opens indicated revision of metadata
854  *  all non-zero revisions are read-only
855  */
SRATableUseMetaRevision(const SRATable * cself,uint32_t revision)856 LIB_EXPORT rc_t CC SRATableUseMetaRevision ( const SRATable *cself, uint32_t revision )
857 {
858     rc_t rc;
859 
860     if ( cself == NULL )
861         rc = RC ( rcSRA, rcTable, rcUpdating, rcSelf, rcNull );
862     else if ( cself -> read_only == false )
863         rc = RC ( rcSRA, rcTable, rcUpdating, rcMetadata, rcBusy );
864     else
865     {
866         uint32_t cur;
867         rc = KMetadataRevision ( cself -> meta, & cur );
868         if ( rc == 0 && cur != revision )
869         {
870             SRATable *self = ( SRATable* ) cself;
871             const KMetadata *meta;
872             rc = KMetadataOpenRevision ( self -> meta, & meta, revision );
873             if ( rc == 0 )
874             {
875                 KMetadataRelease ( self -> meta );
876                 self -> meta = meta;
877             }
878         }
879     }
880 
881     return rc;
882 }
883 
884 /* OpenMDataNode
885  *  open a metadata node
886  *
887  *  "node" [ OUT ] - return parameter for metadata node
888  *
889  *  "path" [ IN ] - simple or hierarchical NUL terminated
890  *  path to node
891  */
SRATableOpenMDataNodeRead(const SRATable * self,struct KMDataNode const ** node,const char * path,...)892 LIB_EXPORT rc_t CC SRATableOpenMDataNodeRead( const SRATable *self,
893         struct KMDataNode const **node, const char *path, ... ) {
894     va_list va;
895     rc_t rc;
896 
897     va_start(va, path);
898     rc = SRATableVOpenMDataNodeRead(self, node, path, va);
899     va_end(va);
900     return rc;
901 }
902 
SRATableVOpenMDataNodeRead(const SRATable * self,struct KMDataNode const ** rslt,const char * path,va_list args)903 LIB_EXPORT rc_t CC SRATableVOpenMDataNodeRead( const SRATable *self,
904         struct KMDataNode const **rslt, const char *path, va_list args ) {
905     if (self == NULL)
906         return RC(rcSRA, rcTable, rcAccessing, rcSelf, rcNull);
907 
908     return KMetadataVOpenNodeRead(self->meta, rslt, path, args);
909 }
910 
911 /* private */
SRATableGetIdRange(const SRATable * self,uint32_t idx,spotid_t id,spotid_t * pfirst,spotid_t * plast)912 rc_t SRATableGetIdRange ( const SRATable *self,
913         uint32_t idx, spotid_t id, spotid_t *pfirst, spotid_t *plast )
914 {
915     rc_t rc;
916 
917     if ( pfirst == NULL && plast == NULL )
918         rc = RC ( rcSRA, rcColumn, rcAccessing, rcParam, rcNull );
919     else
920     {
921         spotid_t dummy;
922         if ( pfirst == NULL )
923             pfirst = & dummy;
924         else if ( plast == NULL )
925             plast = & dummy;
926 
927         if ( idx == 0 )
928             rc = RC ( rcSRA, rcColumn, rcAccessing, rcSelf, rcNull );
929         else if ( self == NULL )
930             rc = RC ( rcSRA, rcTable, rcAccessing, rcSelf, rcNull );
931         else
932         {
933             int64_t first, last;
934             rc = VCursorPageIdRange ( self -> curs, idx, id, & first, & last );
935             if ( rc == 0 )
936             {
937                 * pfirst = ( spotid_t ) first;
938                 * plast = ( spotid_t ) last;
939 
940                 if ( ( int64_t ) * pfirst == first && ( int64_t ) * plast == last )
941                     return 0;
942 
943                 rc = RC ( rcSRA, rcColumn, rcAccessing, rcRange, rcExcessive );
944             }
945         }
946 
947         * pfirst = * plast = 0;
948     }
949 
950     return rc;
951 }
952 
953 /* semi-private for sra-dbcc */
SRATableGetVTableRead(const SRATable * self,const VTable ** rslt)954 LIB_EXPORT rc_t CC SRATableGetVTableRead( const SRATable *self, const VTable **rslt )
955 {
956     if (rslt == NULL)
957         return RC(rcSRA, rcTable, rcAccessing, rcParam, rcNull);
958 
959     if (self == NULL)
960     {
961         * rslt = NULL;
962         return RC(rcSRA, rcTable, rcAccessing, rcSelf, rcNull);
963     }
964 
965     *rslt = self->vtbl;
966     return VTableAddRef(*rslt);
967 }
968 
SRATableGetKTableRead(const SRATable * self,struct KTable const ** ktbl)969 LIB_EXPORT rc_t CC SRATableGetKTableRead ( const SRATable *self, struct KTable const **ktbl )
970 {
971     rc_t rc;
972 
973     if ( ktbl == NULL )
974         rc = RC ( rcSRA, rcTable, rcAccessing, rcParam, rcNull );
975     else
976     {
977         if ( self == NULL )
978             rc = RC ( rcSRA, rcTable, rcAccessing, rcSelf, rcNull );
979         else
980         {
981             return VTableGetKTableRead ( self -> vtbl, ktbl );
982         }
983 
984         * ktbl = NULL;
985     }
986 
987     return rc;
988 }
989 
990 /* Locked
991  *  returns true if locked
992  */
SRATableLocked(const SRATable * self)993 LIB_EXPORT bool CC SRATableLocked( const SRATable *self )
994 {
995     return self ? VTableLocked(self->vtbl) : false;
996 }
997 
SRATableGetSchema(struct SRATable const * self)998 LIB_EXPORT struct VSchema const* CC SRATableGetSchema ( struct SRATable const *self )
999 {
1000         return self ? VCursorGetSchema( self->curs ) : NULL;
1001 }
1002 
1003 /* sfa_filter
1004  *  if a name is found in list, exclude it
1005  */
1006 #define DEBUG_SORT(msg) DBGMSG (DBG_SRA, DBG_FLAG(DBG_SRA_SORT), msg)
1007 
1008 /* sfa_sort
1009  *  reorders list
1010  */
1011 enum sfa_path_type_id
1012 {
1013     sfa_not_set = -1,
1014     sfa_exclude,
1015     sfa_non_column,
1016     sfa_required,
1017     sfa_preferred,
1018     sfa_optional
1019 };
1020 
1021 #if _DEBUGGING
1022 const char* sfa_path_type_id[] = {
1023     "not_set",
1024     "exclude",
1025     "non_column",
1026     "required",
1027     "preferred",
1028     "optional"
1029 };
1030 #endif
1031 
1032 typedef struct reorder_t_struct {
1033     const char * path;
1034     uint64_t     size;
1035     enum sfa_path_type_id type_id;
1036 } reorder_t;
1037 
1038 typedef enum sfa_path_type_id (CC *sfa_path_type_func)( const char *path );
1039 
1040 /*
1041 union u_void_sfa_path_type_func
1042 {
1043     void * func;
1044     sfa_path_type_func sptf;
1045 };
1046 
1047 static sfa_path_type_func void_to_sfa_path_type_func( void * func )
1048 {
1049     union u_void_sfa_path_type_func x;
1050     x.func = func;
1051     return x.sptf;
1052 }
1053 */
1054 
1055 static
1056 bool CC sfa_filter(const KDirectory *dir, const char *leaf, void* func)
1057 {
1058     bool ret = true;
1059     sfa_path_type_func f = (sfa_path_type_func)func; /* void_to_sfa_path_type_func( func ); */
1060     enum sfa_path_type_id type = f(leaf);
1061 
1062     ret = type >= sfa_non_column;
1063     DEBUG_SORT(("%s: %s %s %s\n", __func__, leaf, sfa_path_type_id[type + 1], ret ? "keep" : "drop"));
1064     return ret;
1065 }
1066 
1067 static
sfa_filter_light(const KDirectory * dir,const char * leaf,void * func)1068 bool CC sfa_filter_light(const KDirectory *dir, const char *leaf, void* func)
1069 {
1070     bool ret = true;
1071     sfa_path_type_func f = (sfa_path_type_func)func; /* void_to_sfa_path_type_func( func ); */
1072 
1073     enum sfa_path_type_id type = f(leaf);
1074 
1075     ret = type >= sfa_non_column && type < sfa_optional;
1076     DEBUG_SORT(("%s: %s %s %s\n", __func__, leaf, sfa_path_type_id[type + 1], ret ? "keep" : "drop"));
1077     return ret;
1078 }
1079 
1080 #define MATCH( ptr, str ) \
1081     ( (memcmp(ptr, str, sizeof(str) - 2) == 0 && \
1082        ((ptr)[sizeof(str) - 2] == '\0' || (ptr)[sizeof(str) - 2] == '/')) ? \
1083         (ptr) += sizeof(str) - (((ptr)[sizeof(str) - 2] == '/') ? 1 : 2) : (const char*) 0)
1084 
1085 static
sfa_path_type_tbl(const char * path)1086 enum sfa_path_type_id CC sfa_path_type_tbl( const char *path )
1087 {
1088     /* use first character as distinguisher for match */
1089     switch ( path [ 0 ] )
1090     {
1091     case 'c':
1092         /* perhaps it's a column */
1093         if ( MATCH ( path, "col/" ) )
1094         {
1095             switch ( path [ 0 ] )
1096             {
1097             case 'D':
1098                 if ( MATCH ( path, "DELETION_QV/" ) )
1099                     return sfa_optional;
1100                 if ( MATCH ( path, "DELETION_TAG/" ) )
1101                     return sfa_optional;
1102                 break;
1103             case 'H':
1104                 if ( MATCH ( path, "HOLE_NUMBER/" ) )
1105                     return sfa_optional;
1106                 if ( MATCH ( path, "HOLE_STATUS/" ) )
1107                     return sfa_optional;
1108                 break;
1109             case 'I':
1110                 if ( MATCH ( path, "INTENSITY/" ) )
1111                     return sfa_optional;
1112                 if ( MATCH ( path, "INSERTION_QV/" ) )
1113                     return sfa_optional;
1114                 break;
1115             case 'N':
1116                 if ( MATCH ( path, "NAME_FMT/" ) )
1117                     return sfa_preferred;
1118                 if ( MATCH ( path, "NAME/" ) )
1119                     return sfa_preferred;
1120                 if ( MATCH ( path, "NOISE/" ) )
1121                     return sfa_optional;
1122                 if ( MATCH ( path, "NUM_PASSES/" ) )
1123                     return sfa_optional;
1124                 break;
1125             case 'P':
1126                 if ( MATCH ( path, "POSITION/" ) )
1127                     return sfa_optional;
1128                 if ( MATCH ( path, "PRE_BASE_FRAMES/" ) )
1129                     return sfa_optional;
1130                 if ( MATCH ( path, "PULSE_INDEX/" ) )
1131                     return sfa_optional;
1132                 break;
1133             case 'Q':
1134                 if ( MATCH ( path, "QUALITY2/" ) )
1135                     return sfa_optional;
1136                 break;
1137             case 'S':
1138                 if ( MATCH ( path, "SIGNAL/" ) )
1139                     return sfa_optional;
1140                 if ( MATCH ( path, "SPOT_NAME/" ) )
1141                     return sfa_preferred;
1142                 if ( MATCH ( path, "SUBSTITUTION_QV/" ) )
1143                     return sfa_optional;
1144                 if ( MATCH ( path, "SUBSTITUTION_TAG/" ) )
1145                     return sfa_optional;
1146                 break;
1147             case 'W':
1148                 if ( MATCH ( path, "WIDTH_IN_FRAMES/" ) )
1149                     return sfa_optional;
1150                 break;
1151             case 'X':
1152             case 'Y':
1153                 if ( path [ 1 ] == '/' )
1154                     return sfa_preferred;
1155                 break;
1156             }
1157         }
1158         return sfa_required;
1159 
1160     case 'i':
1161         /* look for skey index */
1162         if ( MATCH ( path, "idx/skey" ) )
1163             if ( path [ 0 ] == 0 || strcmp ( path, ".md5" ) == 0 )
1164                 return sfa_preferred;
1165         if ( MATCH ( path, "idx/fuse-" ) )
1166             return sfa_exclude;
1167         break;
1168 
1169     case 's':
1170         /* look for old skey index */
1171         if ( MATCH ( path, "skey" ) )
1172             if ( path [ 0 ] == 0 || strcmp ( path, ".md5" ) == 0 )
1173                 return sfa_preferred;
1174         break;
1175     }
1176     /* anything not recognized is non-column required */
1177     return sfa_non_column;
1178 }
1179 
1180 static
sfa_path_type_db(const char * path)1181 enum sfa_path_type_id CC sfa_path_type_db ( const char *path )
1182 {
1183     /* use first character as distinguisher for match */
1184     switch ( path [ 0 ] )
1185     {
1186     case 't':
1187         /* perhaps it's a table */
1188         if ( MATCH ( path, "tbl/" ) )
1189         {
1190             switch ( path [ 0 ] )
1191             {
1192             case 0:
1193                 return sfa_non_column;
1194             case 'S':
1195                 if ( MATCH ( path, "SEQUENCE/" ) )
1196                     return sfa_path_type_tbl(path);
1197                 break;
1198             case 'C':
1199                 if ( MATCH ( path, "CONSENSUS/" ) )
1200                     return sfa_path_type_tbl(path);
1201                 break;
1202             case 'P':
1203                 if ( MATCH ( path, "PRIMARY_ALIGNMENT/" ) )
1204                     return sfa_path_type_tbl(path);
1205                 break;
1206             case 'R':
1207                 if ( MATCH ( path, "REFERENCE/" ) )
1208                     return sfa_path_type_tbl(path);
1209                 break;
1210             }
1211             /* all other tables are optional */
1212             return sfa_optional;
1213         }
1214     }
1215     /* anything not recognized is non-column required */
1216     return sfa_non_column;
1217 }
1218 #undef MATCH
1219 
1220 static
sfa_path_cmp(const void ** _a,const void ** _b,void * ignored)1221 int64_t CC sfa_path_cmp ( const void **_a, const void **_b, void * ignored )
1222 {
1223     const reorder_t * a = *_a;
1224     const reorder_t * b = *_b;
1225     int64_t ret;
1226 
1227     DEBUG_SORT(("%s enter\t%s %s %lu \t%s %s %lu", __func__,
1228                 a->path, sfa_path_type_id[a->type_id + 1], a->size,
1229                 b->path, sfa_path_type_id[b->type_id + 1], b->size));
1230 
1231     ret = a->type_id - b->type_id;
1232     if (ret == 0)
1233     {
1234         if (a->size > b->size)
1235             ret = 1;
1236         else if (a->size < b->size)
1237             ret = -1;
1238         else
1239             ret = strcmp (a->path, b->path);
1240     }
1241     DEBUG_SORT(("\t%d\n", ret));
1242     return ret;
1243 }
1244 
1245 typedef
1246 struct to_nv_data_struct
1247 {
1248     const KDirectory * d;
1249     Vector * v;
1250     rc_t rc;
1251     sfa_path_type_func path_type;
1252 } to_nv_data;
1253 
1254 static
to_nv(void * _item,void * _data)1255 void CC to_nv (void * _item, void * _data)
1256 {
1257     const char* path = _item;
1258     to_nv_data* data = _data;
1259     reorder_t* obj;
1260 
1261     if (data->rc == 0)
1262     {
1263         obj = malloc (sizeof (*obj));
1264         if (obj == NULL)
1265             data->rc = RC (rcSRA, rcVector, rcConstructing, rcMemory, rcExhausted);
1266         else
1267         {
1268             rc_t rc = KDirectoryFileSize (data->d, &obj->size, "%s", path);
1269             if (rc == 0)
1270             {
1271                 obj->path = path;
1272                 obj->type_id = data->path_type(path);
1273                 rc = VectorAppend (data->v, NULL, obj);
1274             }
1275 
1276             if (rc)
1277             {
1278                 free (obj);
1279                 data->rc = rc;
1280             }
1281         }
1282     }
1283 }
1284 
1285 static
item_whack(void * item,void * ignored)1286 void CC item_whack (void * item, void * ignored)
1287 {
1288     free (item);
1289 }
1290 
1291 static
sfa_sort(const KDirectory * dir,Vector * v,sfa_path_type_func func)1292 rc_t CC sfa_sort( const KDirectory *dir, Vector *v, sfa_path_type_func func )
1293 {
1294     /* assume "v" is a vector of paths - hopefully relative to "dir" */
1295     Vector nv;
1296     to_nv_data data;
1297     uint32_t base;
1298 
1299     DEBUG_SORT(("%s enter\n", __func__));
1300 
1301     base = VectorStart (v);
1302     VectorInit (&nv, base, VectorLength (v));
1303     data.d = dir;
1304     data.v = &nv;
1305     data.rc = 0;
1306     data.path_type = func;
1307 
1308     VectorForEach (v, false, to_nv, &data);
1309 
1310     if(data.rc == 0) {
1311         uint32_t idx = 0;
1312         uint32_t limit = VectorLength (v) + base;
1313 
1314         VectorReorder(&nv, sfa_path_cmp, NULL);
1315 
1316         for (idx = base; idx < limit; ++idx) {
1317             const reorder_t * tmp;
1318             void * ignore;
1319 
1320             tmp = VectorGet (&nv, idx);
1321             data.rc = VectorSwap (v, idx + base, tmp->path, &ignore);
1322             if(data.rc) {
1323                 break;
1324             }
1325         }
1326     }
1327     VectorWhack (&nv, item_whack, NULL);
1328     DEBUG_SORT(("%s exit %d %R\n", __func__, data.rc, data.rc));
1329     return data.rc;
1330 }
1331 
1332 static
sfa_sort_db(const KDirectory * dir,Vector * v)1333 rc_t CC sfa_sort_db( const KDirectory *dir, Vector *v )
1334 {
1335     return sfa_sort(dir, v, sfa_path_type_db);
1336 }
1337 
1338 static
sfa_sort_tbl(const KDirectory * dir,Vector * v)1339 rc_t CC sfa_sort_tbl( const KDirectory *dir, Vector *v )
1340 {
1341     return sfa_sort(dir, v, sfa_path_type_tbl);
1342 }
1343 
1344 /*
1345 union sptd_2_void
1346 {
1347     sfa_path_type_func func;
1348     void * ptr;
1349 };
1350 
1351 static void * sfa_path_type_func_to_void( sfa_path_type_func func )
1352 {
1353     union sptd_2_void u;
1354     u.func = func;
1355     return u.ptr;
1356 }
1357 */
1358 
1359 /* MakeSingleFileArchive
1360  *  makes a single-file-archive file from an SRA table
1361  *
1362  *  contents are ordered by frequency and necessity of access
1363  *
1364  *  "lightweight" [ IN ] - when true, include only those components
1365  *  required for read and quality operations.
1366  *
1367  *  "ext" [OUT,NULL] - optional file name extension to use for file
1368  */
SRATableMakeSingleFileArchive(const SRATable * self,const KFile ** sfa,bool lightweight,const char ** ext)1369 LIB_EXPORT rc_t CC SRATableMakeSingleFileArchive ( const SRATable *self, const KFile **sfa, bool lightweight, const char** ext)
1370 {
1371     rc_t rc;
1372 
1373     if ( sfa == NULL )
1374     {
1375         rc = RC( rcSRA, rcFile, rcConstructing, rcParam, rcNull );
1376     }
1377     else
1378     {
1379         *sfa = NULL;
1380         if ( self == NULL )
1381         {
1382             rc = RC( rcSRA, rcTable, rcAccessing, rcSelf, rcNull );
1383         }
1384         else
1385         {
1386             const VDatabase *db;
1387             rc = VTableOpenParentRead( self->vtbl, &db );
1388             if ( rc == 0 && db != NULL )
1389             {
1390                 const KDatabase *kdb;
1391                 rc = VDatabaseOpenKDatabaseRead( db, &kdb );
1392                 if ( rc == 0 )
1393                 {
1394                     const KDirectory *db_dir;
1395                     rc = KDatabaseOpenDirectoryRead( kdb, &db_dir );
1396                     if ( rc == 0 )
1397                     {
1398                         rc = KDirectoryOpenTocFileRead( db_dir,
1399                                                         sfa,
1400                                                         sraAlign4Byte,
1401                                                         lightweight ? sfa_filter_light : sfa_filter,
1402                                                         ( void * )sfa_path_type_db, /* sfa_path_type_func_to_void( sfa_path_type_db ), */
1403                                                         sfa_sort_db );
1404                         KDirectoryRelease( db_dir );
1405                         if ( ext != NULL )
1406                         {
1407                             *ext = CSRA_EXT( lightweight );
1408                         }
1409                     }
1410                     KDatabaseRelease( kdb );
1411                 }
1412                 VDatabaseRelease( db );
1413             }
1414             else
1415             {
1416                 const KTable *ktbl;
1417                 rc = SRATableGetKTableRead( self, &ktbl );
1418                 if ( rc == 0 )
1419                 {
1420                     const KDirectory *tbl_dir;
1421                     rc = KTableGetDirectoryRead( ktbl, &tbl_dir );
1422                     if ( rc == 0 )
1423                     {
1424                         rc = KDirectoryOpenTocFileRead( tbl_dir,
1425                                                         sfa,
1426                                                         sraAlign4Byte,
1427                                                         lightweight ? sfa_filter_light : sfa_filter,
1428                                                         ( void * )sfa_path_type_tbl, /* sfa_path_type_func_to_void( sfa_path_type_tbl ), */
1429                                                         sfa_sort_tbl );
1430                         KDirectoryRelease( tbl_dir );
1431                         if ( ext != NULL )
1432                         {
1433                             *ext = SRA_EXT( lightweight );
1434                         }
1435                     }
1436                     KTableRelease(ktbl);
1437                 }
1438             }
1439         }
1440     }
1441     return rc;
1442 }
1443 
1444 /* OpenAltTableRead
1445  *  opens a table within a database structure with a specific name
1446  */
SRAMgrOpenAltTableRead(const SRAMgr * self,const SRATable ** tbl,const char * altname,const char * spec,...)1447 SRA_EXTERN rc_t CC SRAMgrOpenAltTableRead ( const SRAMgr *self,
1448     const SRATable **tbl, const char *altname, const char *spec, ... )
1449 {
1450     rc_t rc;
1451 
1452     va_list args;
1453     va_start ( args, spec );
1454 
1455     if ( altname == NULL || altname [ 0 ] == 0 ) {
1456         altname = "SEQUENCE";
1457     }
1458     rc = SRAMgrVOpenAltTableRead ( self, tbl, altname, spec, args );
1459 
1460     va_end ( args );
1461     return rc;
1462 }
1463