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 "sqlite3ext.h"
28 
29 SQLITE_EXTENSION_INIT1
30 
31 /*
32 ** A macro to hint to the compiler that a function should not be
33 ** inlined.
34 */
35 #if defined(__GNUC__)
36 #  define CSV_NOINLINE  __attribute__((noinline))
37 #elif defined(_MSC_VER) && _MSC_VER>=1310
38 #  define CSV_NOINLINE  __declspec(noinline)
39 #else
40 #  define CSV_NOINLINE
41 #endif
42 
43 #include <stdio.h> /* because of printf( ) for verbosity in testing... */
44 
45 #include <klib/num-gen.h>
46 #include <klib/namelist.h>
47 #include <klib/vector.h>
48 #include <klib/text.h>
49 #include <klib/printf.h>
50 
51 #include <kdb/manager.h> /* because path-types are defined there! */
52 #include <vdb/manager.h>
53 #include <vdb/database.h>
54 #include <vdb/table.h>
55 #include <vdb/cursor.h>
56 #include <vdb/schema.h>
57 
58 #include <kfc/xcdefs.h>
59 #include <kfc/except.h>
60 #include <kfc/ctx.h>
61 #include <kfc/rsrc.h>
62 
63 #include <../ngs/NGS_ReadCollection.h>
64 #include <../ngs/NGS_Read.h>
65 #include <../ngs/NGS_Alignment.h>
66 #include <../ngs/NGS_ReadGroup.h>
67 #include <../ngs/NGS_Reference.h>
68 #include <../ngs/NGS_Pileup.h>
69 #include <../ngs/NGS_PileupEvent.h>
70 #include <../ngs/NGS_String.h>
71 
72 /* -------------------------------------------------------------------------------------- */
VNamelist_from_KNamelist(VNamelist ** dst,const KNamelist * src)73 static rc_t VNamelist_from_KNamelist( VNamelist ** dst, const KNamelist * src )
74 {
75 	rc_t rc = VNamelistMake( dst, 5 );
76 	if ( rc == 0 )
77 	{
78 		uint32_t idx, count;
79 		rc = KNamelistCount( src, &count );
80 		for ( idx = 0; rc == 0 && idx < count; ++idx )
81 		{
82 			const char * s = NULL;
83 			rc = KNamelistGet( src, idx, &s );
84 			if ( rc == 0 && s != NULL )
85 				rc = VNamelistAppend( *dst, s );
86 		}
87 	}
88 	return rc;
89 }
90 
91 /* -------------------------------------------------------------------------------------- */
92 typedef struct column_description
93 {
94     const char * typecast;
95     const char * name;
96 } column_description;
97 
98 
destroy_column_description(void * item,void * data)99 static void CC destroy_column_description( void * item, void * data )
100 {
101     if ( item != NULL )
102     {
103         column_description * desc = item;
104         if ( desc->typecast != NULL ) free( ( void * )desc->typecast );
105         if ( desc->name != NULL ) free( ( void * )desc->name );
106         free( desc );
107     }
108 }
109 
make_column_description(const char * decl)110 static column_description * make_column_description( const char * decl )
111 {
112     column_description * res = malloc( sizeof( * res ) );
113     if ( res != NULL )
114     {
115         rc_t rc = 0;
116         VNamelist * l;
117         memset( res, 0, sizeof( *res ) );
118         rc = VNamelistFromStr( &l, decl, ')' );
119         if ( rc == 0 )
120         {
121             uint32_t count;
122             rc = VNameListCount( l, &count );
123             if ( rc == 0 )
124             {
125                 const char * s;
126                 if ( count == 1 )
127                 {
128                     rc = VNameListGet( l, 0, &s );
129                     if ( rc == 0 )
130                         res->name = string_dup( s, string_size( s ) );
131                 }
132                 else if ( count == 2 )
133                 {
134                     rc = VNameListGet( l, 0, &s );
135                     if ( rc == 0 )
136                     {
137                         if ( s[ 0 ] == '(' )
138                         {
139                             const char * src = &s[ 1 ];
140                             res->typecast = string_dup( src, string_size( src ) );
141                         }
142                         else
143                             res->typecast = string_dup( s, string_size( s ) );
144                         rc = VNameListGet( l, 1, &s );
145                         if ( rc == 0 )
146                             res->name = string_dup( s, string_size( s ) );
147                     }
148                 }
149                 else
150                     rc = -1;
151             }
152             VNamelistRelease( l );
153         }
154         if ( rc != 0 || res->name == NULL )
155         {
156             destroy_column_description( res, NULL );
157             res = NULL;
158         }
159     }
160     return res;
161 }
162 
163 
copy_column_description(const column_description * src)164 static column_description * copy_column_description( const column_description * src )
165 {
166     column_description * res = malloc( sizeof( * res ) );
167     if ( res != NULL )
168     {
169         memset( res, 0, sizeof( *res ) );
170         res->name = string_dup( src->name, string_size( src->name ) );
171         if ( src->typecast != NULL )
172             res->typecast = string_dup( src->typecast, string_size( src->typecast ) );
173     }
174     return res;
175 }
176 
177 
178 /* -------------------------------------------------------------------------------------- */
179 typedef struct column_instance
180 {
181     const column_description * desc;
182     uint32_t vdb_cursor_idx;
183     VTypedecl vtype;
184     VTypedesc vdesc;
185     int64_t first;
186     uint64_t count;
187 } column_instance;
188 
destroy_column_instance(void * item,void * data)189 static void CC destroy_column_instance( void * item, void * data )
190 {
191     if ( item != NULL )
192     {
193         column_instance * inst = item;
194         destroy_column_description( ( column_description * )inst->desc, NULL );
195         sqlite3_free( inst );
196     }
197 }
198 
make_column_instance(const column_description * desc,const VCursor * curs)199 static column_instance * make_column_instance( const column_description * desc, const VCursor * curs )
200 {
201     column_instance * res = sqlite3_malloc( sizeof( * res ) );
202     if ( res != NULL )
203     {
204         rc_t rc = 0;
205         memset( res, 0, sizeof( *res ) );
206         res->desc = copy_column_description( desc );
207         if ( desc->typecast != NULL )
208             rc = VCursorAddColumn( curs, &res->vdb_cursor_idx, "(%s)%s", desc->typecast, desc->name );
209         else
210             rc = VCursorAddColumn( curs, &res->vdb_cursor_idx, "%s", desc->name );
211         if ( rc != 0 )
212         {
213             sqlite3_free( res );
214             res = NULL;
215         }
216     }
217     return res;
218 }
219 
column_instance_post_open(column_instance * inst,const VCursor * curs)220 static rc_t column_instance_post_open( column_instance * inst, const VCursor * curs )
221 {
222     rc_t rc = VCursorDatatype( curs, inst->vdb_cursor_idx, &inst->vtype, &inst->vdesc );
223     if ( rc == 0 )
224         rc = VCursorIdRange( curs, inst->vdb_cursor_idx, &inst->first, &inst->count );
225     return rc;
226 }
227 
print_bool_vector(const uint8_t * base,uint32_t count)228 static char * print_bool_vector( const uint8_t * base, uint32_t count )
229 {
230     size_t l = count * 4;
231     char * res = sqlite3_malloc( l );
232     if ( res != NULL )
233     {
234         uint32_t idx;
235         rc_t rc = 0;
236         char * dst = res;
237         for ( idx = 0; rc == 0 && idx < count; ++idx )
238         {
239             size_t num_writ;
240             uint8_t v = base[ idx ] > 0 ? 1 : 0;
241             if ( idx == 0 )
242                 rc = string_printf( dst, l, &num_writ, "%d", v );
243             else
244                 rc = string_printf( dst, l, &num_writ, ", %d", v );
245             l -= num_writ;
246             dst += num_writ;
247         }
248         if ( rc == 0 )
249             *dst = 0;
250         else
251         {
252             sqlite3_free( res );
253             res = NULL;
254         }
255     }
256     return res;
257 }
258 
259 
260 /* we are printing booleans ( booleans are always 8 bit )*/
col_inst_bool(column_instance * inst,const VCursor * curs,sqlite3_context * ctx,int64_t row_id)261 static void col_inst_bool( column_instance * inst, const VCursor * curs, sqlite3_context * ctx, int64_t row_id )
262 {
263     uint32_t elem_bits, boff, row_len;
264     const void * base;
265     rc_t rc = VCursorCellDataDirect( curs, row_id, inst->vdb_cursor_idx, &elem_bits, &base, &boff, &row_len );
266     if ( rc == 0 && row_len > 0 )
267     {
268         if ( row_len == 1 )
269         {
270             switch( elem_bits )
271             {
272                 case  8  : sqlite3_result_int( ctx, *( (  uint8_t * )base ) ); break;
273                 case 16  : sqlite3_result_int( ctx, *( ( uint16_t * )base ) ); break;
274                 case 32  : sqlite3_result_int( ctx, *( ( uint32_t * )base ) ); break;
275                 case 64  : sqlite3_result_int64( ctx, *( ( uint64_t * )base ) ); break;
276                 default  : sqlite3_result_int( ctx, *( (  uint8_t * )base ) ); break;
277             }
278         }
279         else
280         {
281             /* make a transient text from it ( booleans are always 8 bit ) */
282             char * txt = print_bool_vector( base, row_len );
283             if ( txt != NULL )
284             {
285                 sqlite3_result_text( ctx, txt, -1, SQLITE_TRANSIENT );
286                 sqlite3_free( txt );
287             }
288             else
289                 sqlite3_result_null( ctx );
290         }
291     }
292     else
293         sqlite3_result_null( ctx );
294 }
295 
296 
297 #define PRINT_VECTOR( T, factor, fmt1, fmt2 ) \
298 static char * print_##T##_vec( const T * base, uint32_t count ) \
299 { \
300     size_t l = ( count * factor ) + 10; \
301     char * res = sqlite3_malloc( l ); \
302     if ( res != NULL ) \
303     { \
304         uint32_t idx; \
305         rc_t rc = 0; \
306         char * dst = res; \
307         dst[ 0 ] = '{' ; \
308         dst[ 1 ] = '"' ; \
309         dst[ 2 ] = 'a' ; \
310         dst[ 3 ] = '"' ; \
311         dst[ 4 ] = ':' ; \
312         dst[ 5 ] = '[' ; \
313         dst += 6; \
314         for ( idx = 0; rc == 0 && idx < count; ++idx ) \
315         { \
316             size_t num_writ; \
317             if ( idx == 0 ) \
318                 rc = string_printf( dst, l, &num_writ, fmt1, base[ idx ] ); \
319             else \
320                 rc = string_printf( dst, l, &num_writ, fmt2, base[ idx ] ); \
321             l -= num_writ; \
322             dst += num_writ; \
323         } \
324         if ( rc == 0 ) \
325         { \
326             *dst = ']'; \
327             dst += 1; \
328             *dst = '}'; \
329             dst += 1; \
330             *dst = 0; \
331         } \
332         else \
333         { \
334             sqlite3_free( res ); \
335             res = NULL; \
336         } \
337     } \
338     return res; \
339 } \
340 
341 
342 PRINT_VECTOR( uint8_t, 5, "%u", ", %u" )
343 /* static char * print_uint8_t_vec( const uint8_t * base, uint32_t count ) */
344 
345 PRINT_VECTOR( uint16_t, 7, "%u", ", %u" )
346 /* static char * print_uint16_t_ve( const uint16_t * base, uint32_t count ) */
347 
348 PRINT_VECTOR( uint32_t, 12, "%u", ", %u" )
349 /* static char * print_uint32_t_ve( const uint32_t * base, uint32_t count ) */
350 
351 PRINT_VECTOR( uint64_t, 22, "%lu", ", %lu" )
352 /* static char * print_uint64_t_ve( const uint64_t * base, uint32_t count ) */
353 
354 
355 /* we are printing unsigned integers */
col_inst_Uint(column_instance * inst,const VCursor * curs,sqlite3_context * ctx,int64_t row_id)356 static void col_inst_Uint( column_instance * inst, const VCursor * curs, sqlite3_context * ctx, int64_t row_id )
357 {
358     uint32_t elem_bits, boff, row_len;
359     const void * base;
360     rc_t rc = VCursorCellDataDirect( curs, row_id, inst->vdb_cursor_idx, &elem_bits, &base, &boff, &row_len );
361     if ( rc == 0 && row_len > 0 )
362     {
363         if ( row_len == 1 )
364         {
365             switch( elem_bits )
366             {
367                 case  8  : sqlite3_result_int( ctx, *( (  uint8_t * )base ) ); break;
368                 case 16  : sqlite3_result_int( ctx, *( ( uint16_t * )base ) ); break;
369                 case 32  : sqlite3_result_int( ctx, *( ( uint32_t * )base ) ); break;
370                 case 64  : sqlite3_result_int64( ctx, *( ( uint64_t * )base ) ); break;
371                 default  : sqlite3_result_int( ctx, *( (  uint8_t * )base ) ); break;
372             }
373         }
374         else
375         {
376             char * txt = NULL;
377             switch( elem_bits )
378             {
379                 case 8  : txt = print_uint8_t_vec( base, row_len ); break;
380                 case 16 : txt = print_uint16_t_vec( base, row_len ); break;
381                 case 32 : txt = print_uint32_t_vec( base, row_len ); break;
382                 case 64 : txt = print_uint64_t_vec( base, row_len ); break;
383 
384             }
385             if ( txt != NULL )
386             {
387                 sqlite3_result_text( ctx, txt, -1, SQLITE_TRANSIENT );
388                 sqlite3_free( txt );
389             }
390             else
391                 sqlite3_result_null( ctx );
392         }
393     }
394     else
395         sqlite3_result_null( ctx );
396 }
397 
398 PRINT_VECTOR( int8_t, 6, "%d", ", %d" )
399 /* static char * print_int8_t_vec( const int8_t * base, uint32_t count ) */
400 
401 PRINT_VECTOR( int16_t, 8, "%d", ", %d" )
402 /* static char * print_int16_t_vec( const int16_t * base, uint32_t count ) */
403 
404 PRINT_VECTOR( int32_t, 13, "%d", ", %d" )
405 /* static char * print_int32_t_vec( const int32_t * base, uint32_t count ) */
406 
407 PRINT_VECTOR( int64_t, 23, "%ld", ", %ld" )
408 /* static char * print_int64_t_vec( const int64_t * base, uint32_t count ) */
409 
410 
411 /* we are printing signed integers */
col_inst_Int(column_instance * inst,const VCursor * curs,sqlite3_context * ctx,int64_t row_id)412 static void col_inst_Int( column_instance * inst, const VCursor * curs, sqlite3_context * ctx, int64_t row_id )
413 {
414     uint32_t elem_bits, boff, row_len;
415     const void * base;
416     rc_t rc = VCursorCellDataDirect( curs, row_id, inst->vdb_cursor_idx, &elem_bits, &base, &boff, &row_len );
417     if ( rc == 0 && row_len > 0 )
418     {
419         if ( row_len == 1 )
420         {
421             switch( elem_bits )
422             {
423                 case  8  : sqlite3_result_int( ctx, *( (  int8_t * )base ) ); break;
424                 case 16  : sqlite3_result_int( ctx, *( ( int16_t * )base ) ); break;
425                 case 32  : sqlite3_result_int( ctx, *( ( int32_t * )base ) ); break;
426                 case 64  : sqlite3_result_int64( ctx, *( ( int64_t * )base ) ); break;
427                 default  : sqlite3_result_int( ctx, *( (  int8_t * )base ) ); break;
428             }
429         }
430         else
431         {
432             char * txt = NULL;
433             switch( elem_bits )
434             {
435                 case 8  : txt = print_int8_t_vec( base, row_len ); break;
436                 case 16 : txt = print_int16_t_vec( base, row_len ); break;
437                 case 32 : txt = print_int32_t_vec( base, row_len ); break;
438                 case 64 : txt = print_int64_t_vec( base, row_len ); break;
439             }
440             if ( txt != NULL )
441             {
442                 sqlite3_result_text( ctx, txt, -1, SQLITE_TRANSIENT );
443                 sqlite3_free( txt );
444             }
445             else
446                 sqlite3_result_null( ctx );
447         }
448     }
449     else
450         sqlite3_result_null( ctx );
451 }
452 
453 #define MAX_CHARS_FOR_DOUBLE 26
454 #define BITSIZE_OF_FLOAT ( sizeof(float) * 8 )
455 #define BITSIZE_OF_DOUBLE ( sizeof(double) * 8 )
456 
457 PRINT_VECTOR( float, MAX_CHARS_FOR_DOUBLE, "%f", ", %f" )
458 /* static char * print_float_vec( const float * base, uint32_t count ) */
459 
460 PRINT_VECTOR( double, MAX_CHARS_FOR_DOUBLE, "%f", ", %f" )
461 /* static char * print_double_vec( const double * base, uint32_t count ) */
462 
463 /* we are printing signed floats */
col_inst_Float(column_instance * inst,const VCursor * curs,sqlite3_context * ctx,int64_t row_id)464 static void col_inst_Float( column_instance * inst, const VCursor * curs, sqlite3_context * ctx, int64_t row_id )
465 {
466     uint32_t elem_bits, boff, row_len;
467     const void * base;
468     rc_t rc = VCursorCellDataDirect( curs, row_id, inst->vdb_cursor_idx, &elem_bits, &base, &boff, &row_len );
469     if ( rc == 0 && row_len > 0 )
470     {
471         if ( row_len == 1 )
472         {
473             if ( elem_bits == BITSIZE_OF_FLOAT )
474             {
475                 const double v = *( ( const float * )base );
476                 sqlite3_result_double( ctx, v );
477             }
478             else if ( elem_bits == BITSIZE_OF_DOUBLE )
479                 sqlite3_result_double( ctx, *( ( const double * )base ) );
480             else
481                 sqlite3_result_null( ctx );
482         }
483         else
484         {
485             char * txt = NULL;
486             if ( elem_bits == BITSIZE_OF_FLOAT )
487                 txt = print_float_vec( base, row_len );
488             else if ( elem_bits == BITSIZE_OF_DOUBLE )
489                 txt = print_double_vec( base, row_len );
490             if ( txt != NULL )
491             {
492                 sqlite3_result_text( ctx, txt, -1, SQLITE_TRANSIENT );
493                 sqlite3_free( txt );
494             }
495             else
496                 sqlite3_result_null( ctx );
497         }
498     }
499     else
500         sqlite3_result_null( ctx );
501 }
502 
503 #undef PRINT_VECTOR
504 
505 /* we are printing text */
col_inst_Ascii(column_instance * inst,const VCursor * curs,sqlite3_context * ctx,int64_t row_id)506 static void col_inst_Ascii( column_instance * inst, const VCursor * curs, sqlite3_context * ctx, int64_t row_id )
507 {
508     uint32_t elem_bits, boff, row_len;
509     const void * base;
510     rc_t rc = VCursorCellDataDirect( curs, row_id, inst->vdb_cursor_idx, &elem_bits, &base, &boff, &row_len );
511     if ( rc == 0 && row_len > 0 )
512         sqlite3_result_text( ctx, (char *)base, row_len, SQLITE_TRANSIENT );
513     else
514         sqlite3_result_null( ctx );
515 }
516 
col_inst_cell(column_instance * inst,const VCursor * curs,sqlite3_context * ctx,int64_t row_id)517 static void col_inst_cell( column_instance * inst, const VCursor * curs, sqlite3_context * ctx, int64_t row_id )
518 {
519     switch( inst->vdesc.domain )
520     {
521         case vtdBool    : col_inst_bool( inst, curs, ctx, row_id ); break;
522         case vtdUint    : col_inst_Uint( inst, curs, ctx, row_id ); break;
523         case vtdInt     : col_inst_Int( inst, curs, ctx, row_id ); break;
524         case vtdFloat   : col_inst_Float( inst, curs, ctx, row_id ); break;
525         case vtdAscii   :
526         case vtdUnicode : col_inst_Ascii( inst, curs, ctx, row_id ); break;
527         default : sqlite3_result_null( ctx );
528     }
529 }
530 
531 /* -------------------------------------------------------------------------------------- */
532 
init_col_desc_list(Vector * dst,const String * decl)533 static bool init_col_desc_list( Vector * dst, const String * decl )
534 {
535     VNamelist * l;
536     VectorInit( dst, 0, 10 );
537     rc_t rc = VNamelistFromString( &l, decl, ';' );
538     if ( rc == 0 )
539     {
540         uint32_t count, idx;
541         rc = VNameListCount( l, &count );
542         if ( rc == 0 )
543         {
544             const char * s;
545             for ( idx = 0; rc == 0 && idx < count; ++idx )
546             {
547                 rc = VNameListGet( l, idx, &s );
548                 if ( rc == 0 )
549                 {
550                     column_description * desc = make_column_description( s );
551                     if ( desc != NULL )
552                     {
553                         rc = VectorAppend( dst, NULL, desc );
554                         if ( rc != 0 )
555                             destroy_column_description( desc, NULL );
556                     }
557                 }
558             }
559         }
560         VNamelistRelease( l );
561     }
562     return ( rc == 0 );
563 }
564 
565 
print_col_desc_list(const Vector * desc_list)566 static void print_col_desc_list( const Vector * desc_list )
567 {
568     if ( desc_list != NULL )
569     {
570         uint32_t idx, count;
571         for ( idx = 0, count = VectorLength( desc_list ); idx < count; ++idx )
572         {
573             column_description * desc = VectorGet( desc_list, idx );
574             if ( desc != NULL )
575             {
576                 if ( desc->typecast != NULL )
577                 {
578                     if ( idx == 0 )
579                         printf( "(%s)%s", desc->typecast, desc->name );
580                     else
581                         printf( ";(%s)%s", desc->typecast, desc->name );
582                 }
583                 else
584                 {
585                     if ( idx == 0 )
586                         printf( "%s", desc->name );
587                     else
588                         printf( ";%s", desc->name );
589                 }
590             }
591         }
592     }
593 }
594 
make_vdb_create_table_stm(const Vector * desc_list,const char * tbl_name)595 static char * make_vdb_create_table_stm( const Vector * desc_list, const char * tbl_name  )
596 {
597     char * res = NULL;
598     if ( desc_list != NULL && tbl_name != NULL )
599     {
600         res = sqlite3_mprintf( "CREATE TABLE %s ( ", tbl_name );
601         if ( res != NULL )
602         {
603             uint32_t idx, count;
604             for ( idx = 0, count = VectorLength( desc_list ); idx < count; ++idx )
605             {
606                 column_description * desc = VectorGet( desc_list, idx );
607                 if ( desc != NULL )
608                 {
609                     /* sqlite3-special-behavior: %z means free the ptr after inserting into result */
610                     if ( idx == 0 )
611                         res = sqlite3_mprintf( "%z%s", res, desc->name );
612                     else
613                         res = sqlite3_mprintf( "%z, %s ", res, desc->name );
614                 }
615             }
616             /* sqlite3-special-behavior: %z means free the ptr after inserting into result */
617             res = sqlite3_mprintf( "%z );", res );
618         }
619     }
620     return res;
621 }
622 
col_desc_list_check(Vector * desc_list,const VNamelist * available,const VNamelist * exclude)623 static rc_t col_desc_list_check( Vector * desc_list, const VNamelist * available, const VNamelist * exclude )
624 {
625     rc_t rc = -1;
626     if ( desc_list != NULL && available != NULL )
627     {
628         uint32_t idx, count = VectorLength( desc_list );
629         if ( count == 0 )
630         {
631             /* the user DID NOT give us a list of columns to use
632                 --> just use all available one's ( exclude the excluded one's ) */
633             rc = VNameListCount( available, &count );
634             for ( idx = 0; idx < count && rc == 0; ++idx )
635             {
636                 const char * s = NULL;
637                 rc = VNameListGet( available, idx, &s );
638                 if ( rc == 0 && s != NULL )
639                 {
640                     bool excluded = false;
641                     if ( exclude != NULL )
642                     {
643                         int32_t idx;
644                         if ( 0 == VNamelistContainsStr( exclude, s, &idx ) )
645                             excluded = ( idx >= 0 );
646                     }
647                     if ( !excluded )
648                     {
649                         column_description * desc = make_column_description( s );
650                         if ( desc != NULL )
651                         {
652                             rc = VectorAppend( desc_list, NULL, desc );
653                             if ( rc != 0 )
654                                 destroy_column_description( desc, NULL );
655                         }
656                     }
657                 }
658             }
659         }
660         else
661         {
662             /* the user DID give us a list of columns to use --> check if they are available */
663             uint32_t not_found = 0;
664             for ( idx = 0; idx < count; ++idx )
665             {
666                 column_description * desc = VectorGet( desc_list, idx );
667                 if ( desc != NULL )
668                 {
669                     if ( desc->name != NULL )
670                     {
671                         uint32_t found;
672                         if ( VNamelistIndexOf( ( VNamelist * )available, desc->name, &found ) != 0 )
673                             not_found++;
674                     }
675                 }
676             }
677             if ( not_found == 0 ) rc = 0;
678         }
679     }
680     return rc;
681 }
682 
683 
col_desc_list_make_instances(const Vector * desc_list,Vector * dst,const VCursor * curs)684 static rc_t col_desc_list_make_instances( const Vector * desc_list, Vector * dst, const VCursor * curs )
685 {
686     rc_t rc = 0;
687     uint32_t count, idx;
688     for ( idx = 0, count = VectorLength( desc_list ); rc == 0 && idx < count; ++idx )
689     {
690         column_description * desc = VectorGet( desc_list, idx );
691         if ( desc != NULL )
692         {
693             column_instance * inst = make_column_instance( desc, curs );
694             if ( inst != NULL )
695                 rc = VectorAppend( dst, NULL, inst );
696             else
697                 rc = -1;
698         }
699         else
700             rc = -1;
701     }
702     return rc;
703 }
704 
705 /* -------------------------------------------------------------------------------------- */
706 
707 /* this adds columns to the cursor, opens the cursor, takes a second round to extract types and row-ranges */
init_col_inst_list(Vector * dst,const Vector * desc_list,const VCursor * curs)708 static rc_t init_col_inst_list( Vector * dst, const Vector * desc_list, const VCursor * curs )
709 {
710     rc_t rc = 0;
711     VectorInit( dst, 0, VectorLength( desc_list ) );
712     rc = col_desc_list_make_instances( desc_list, dst, curs );
713     if ( rc == 0 )
714     {
715         rc = VCursorOpen( curs );
716         if ( rc == 0 )
717         {
718             uint32_t count, idx;
719             for ( idx = 0, count = VectorLength( dst ); rc == 0 && idx < count; ++idx )
720             {
721                 column_instance * inst = VectorGet( dst, idx );
722                 if ( inst != NULL )
723                     rc = column_instance_post_open( inst, curs );
724                 else
725                     rc = -1;
726             }
727         }
728     }
729     return rc;
730 }
731 
col_inst_list_get_row_range(const Vector * inst_list,int64_t * first,uint64_t * count)732 static void col_inst_list_get_row_range( const Vector * inst_list, int64_t * first, uint64_t * count )
733 {
734     uint32_t v_count, v_idx;
735     for ( v_idx = 0, v_count = VectorLength( inst_list ); v_idx < v_count; ++v_idx )
736     {
737         column_instance * inst = VectorGet( inst_list, v_idx );
738         if ( inst != NULL )
739         {
740             if ( inst->first < *first ) *first = inst->first;
741             if ( inst->count > *count ) *count = inst->count;
742         }
743     }
744 }
745 
746 /* produce output for a cell */
col_inst_list_cell(const Vector * inst_list,const VCursor * curs,sqlite3_context * ctx,int column_id,int64_t row_id)747 static void col_inst_list_cell( const Vector * inst_list, const VCursor * curs,
748                                 sqlite3_context * ctx, int column_id, int64_t row_id )
749 {
750     column_instance * inst = VectorGet( inst_list, column_id );
751     if ( inst != NULL )
752         col_inst_cell( inst, curs, ctx, row_id );
753     else
754         sqlite3_result_null( ctx );
755 }
756 
757 /* -------------------------------------------------------------------------------------- */
758 typedef struct vdb_obj_desc
759 {
760     const char * accession;
761     const char * table_name;
762     const char * row_range_str;
763     struct num_gen * row_range;
764     Vector column_descriptions;
765     VNamelist * excluded_columns;
766     size_t cache_size;
767     int verbosity;
768 } vdb_obj_desc;
769 
release_vdb_obj_desc(vdb_obj_desc * self)770 static void release_vdb_obj_desc( vdb_obj_desc * self )
771 {
772     if ( self->accession != NULL ) sqlite3_free( ( void * )self->accession );
773     if ( self->table_name != NULL ) sqlite3_free( ( void * )self->table_name );
774     if ( self->row_range_str != NULL ) sqlite3_free( ( void * )self->row_range_str );
775     if ( self->row_range != NULL ) num_gen_destroy( self->row_range );
776     VectorWhack( &self->column_descriptions, destroy_column_description, NULL );
777     if ( self->excluded_columns != NULL ) VNamelistRelease( self->excluded_columns );
778 }
779 
vdb_obj_desc_print(vdb_obj_desc * self)780 static void vdb_obj_desc_print( vdb_obj_desc * self )
781 {
782     printf( "---accession  = %s\n", self->accession != NULL ? self->accession : "None" );
783     printf( "---cache-size = %lu\n", self->cache_size );
784     printf( "---table      = %s\n", self->table_name != NULL ? self->table_name : "None" );
785     printf( "---rows       = %s\n", self->row_range_str != NULL ? self->row_range_str : "None" );
786     printf( "---columns    = " ); print_col_desc_list( &self->column_descriptions ); printf( "\n" );
787 }
788 
789 
trim_ws(String * S)790 static void trim_ws( String * S )
791 {
792     while( S->addr[ 0 ] == ' ' || S->addr[ 0 ] == '\t' )
793 	{
794 		S->addr++;
795 		S->len--;
796 		S->size--;
797 	}
798 
799     while( S->len > 0 && ( S->addr[ S->len - 1 ] == ' ' || S->addr[ S->len - 1 ] == '\t' ) )
800 	{
801 		S->len--;
802 		S->size--;
803 	}
804 }
805 
is_equal(const String * S,const char * s1,const char * s2)806 static bool is_equal( const String * S, const char * s1, const char * s2 )
807 {
808     String S_template;
809     StringInitCString( &S_template, s1 );
810     if ( StringCaseEqual( &S_template, S ) )
811         return true;
812     if ( s2 != NULL )
813     {
814         StringInitCString( &S_template, s2 );
815         return StringCaseEqual( &S_template, S );
816     }
817     return false;
818 }
819 
vdb_obj_desc_parse_arg2(vdb_obj_desc * self,const char * name,const char * value)820 static void vdb_obj_desc_parse_arg2( vdb_obj_desc * self, const char * name, const char * value )
821 {
822 	String S_name, S_value;
823     bool done = false;
824 
825 	StringInitCString( &S_name, name );
826 	trim_ws( &S_name );
827 	StringInitCString( &S_value, value );
828 	trim_ws( &S_value );
829 
830 	if ( is_equal( &S_name, "acc", "A" ) )
831     {
832 		self->accession = sqlite3_mprintf( "%.*s", S_value.len, S_value.addr );
833         done = true;
834     }
835 
836 	if ( !done && is_equal( &S_name, "table", "T" ) )
837 	{
838         self->table_name = sqlite3_mprintf( "%.*s", S_value.len, S_value.addr );
839         done = true;
840     }
841 
842     if ( !done && is_equal( &S_name, "columns", "C" ) )
843         done = init_col_desc_list( &self->column_descriptions, &S_value );
844 
845     if ( !done && is_equal( &S_name, "exclude", "X" ) )
846         done = ( 0 == VNamelistFromString( &self->excluded_columns, &S_value, ';' ) );
847 
848     if ( !done && is_equal( &S_name, "rows", "R" ) )
849     {
850         self->row_range_str = sqlite3_mprintf( "%.*s", S_value.len, S_value.addr );
851         done = ( 0 == num_gen_parse( self->row_range, self->row_range_str ) );
852     }
853 
854     if ( !done && is_equal( &S_name, "verbose", "v" ) )
855     {
856         self->verbosity = StringToU64( &S_value, NULL );
857         done = true;
858     }
859 
860     if ( !done && is_equal( &S_name, "cache", NULL ) )
861     {
862         self->cache_size = StringToU64( &S_value, NULL );
863         done = true;
864     }
865 
866     if ( !done )
867         printf( "unknown argument '%.*s' = '%.*s'\n", S_name.len, S_name.addr, S_value.len, S_value.addr );
868 }
869 
init_vdb_obj_desc(vdb_obj_desc * self,int argc,const char * const * argv)870 static rc_t init_vdb_obj_desc( vdb_obj_desc * self, int argc, const char * const * argv )
871 {
872     rc_t rc = -1;
873     num_gen_make( &self->row_range );
874     if ( argc > 3 )
875     {
876         int i;
877         for ( i = 3; i < argc; i++ )
878         {
879             VNamelist * parts;
880             rc = VNamelistFromStr( &parts, argv[ i ], '=' );
881             if ( rc == 0 )
882             {
883                 uint32_t count;
884                 rc = VNameListCount( parts, &count );
885                 if ( rc == 0 && count > 0 )
886                 {
887                     const char * arg_name = NULL;
888                     rc = VNameListGet( parts, 0, &arg_name );
889                     if ( rc == 0 && arg_name != NULL )
890                     {
891                         if ( count > 1 )
892                         {
893                             const char * arg_value = NULL;
894                             rc = VNameListGet( parts, 1, &arg_value );
895                             if ( rc == 0 && arg_value != NULL )
896                                 vdb_obj_desc_parse_arg2( self, arg_name, arg_value );
897                         }
898                         else
899                         {
900                             if ( self->accession == NULL )
901                                 self->accession = sqlite3_mprintf( "%s", arg_name );
902                         }
903                     }
904                 }
905                 VNamelistRelease( parts );
906                 if ( self->cache_size == 0 )
907                     self->cache_size = 1024 * 1024 * 32;
908             }
909         }
910     }
911     if ( self->verbosity > 0 )
912         vdb_obj_desc_print( self );
913     return rc;
914 }
915 
916 
917 /* -------------------------------------------------------------------------------------- */
918 typedef struct vdb_cursor
919 {
920     sqlite3_vtab cursor;            /* Base class.  Must be first */
921     const struct num_gen_iter * row_iter;
922     vdb_obj_desc * desc;            /* cursor does not own this! */
923     Vector column_instances;
924     const VCursor * curs;
925     int64_t current_row;
926     bool eof;
927 } vdb_cursor;
928 
929 
930 /* destroy the cursor, ---> release the VDB_Cursor */
destroy_vdb_cursor(vdb_cursor * c)931 static int destroy_vdb_cursor( vdb_cursor * c )
932 {
933     if ( c->desc->verbosity > 1 )
934         printf( "---sqlite3_vdb_Close()\n" );
935     if ( c->row_iter != NULL ) num_gen_iterator_destroy( c->row_iter );
936     VectorWhack( &c->column_instances, destroy_column_instance, NULL );
937     if ( c->curs != NULL ) VCursorRelease( c->curs );
938     sqlite3_free( c );
939     return SQLITE_OK;
940 }
941 
942 /* create a cursor from the obj-description ( mostly it's columns ) */
make_vdb_cursor(vdb_obj_desc * desc,const VTable * tbl)943 static vdb_cursor * make_vdb_cursor( vdb_obj_desc * desc, const VTable * tbl )
944 {
945     vdb_cursor * res = sqlite3_malloc( sizeof( * res ) );
946     if ( res != NULL )
947     {
948         rc_t rc;
949         memset( res, 0, sizeof( *res ) );
950         res->desc = desc;
951 
952         /* we first have to make column-instances, before we can adjust the row-ranges */
953 		rc = VTableCreateCachedCursorRead( tbl, &res->curs, desc->cache_size );
954         if ( rc == 0 )
955         {
956             /* this adds the columns to the cursor, opens the cursor, gets types, extracts row-range */
957             rc = init_col_inst_list( &res->column_instances, &desc->column_descriptions, res->curs );
958         }
959 
960         if ( rc == 0 )
961         {
962             int64_t  first = 0x7FFFFFFFFFFFFFFF;
963             uint64_t count = 0;
964             col_inst_list_get_row_range( &res->column_instances, &first, &count );
965 			if ( first == 0x7FFFFFFFFFFFFFFF )
966 				first = 0;
967             if ( num_gen_empty( desc->row_range ) )
968                 rc = num_gen_add( desc->row_range, first, count );
969             else
970                 rc = num_gen_trim( desc->row_range, first, count );
971         }
972 
973         if ( rc == 0 )
974         {
975             rc = num_gen_iterator_make( desc->row_range, &res->row_iter );
976             if ( rc == 0 )
977                 res->eof = !num_gen_iterator_next( res->row_iter, &res->current_row, NULL );
978             else
979                 res->eof = true;
980         }
981 
982         if ( res->eof )
983             rc = -1;
984 
985         if ( rc != 0 )
986         {
987             destroy_vdb_cursor( res );
988             res = NULL;
989         }
990     }
991     return res;
992 }
993 
994 /* advance to the next row ---> num_gen_iterator_next() */
vdb_cursor_next(vdb_cursor * c)995 static int vdb_cursor_next( vdb_cursor * c )
996 {
997     if ( c->desc->verbosity > 2 )
998         printf( "---sqlite3_vdb_Next()\n" );
999     c->eof = !num_gen_iterator_next( c->row_iter, &c->current_row, NULL );
1000     return SQLITE_OK;
1001 }
1002 
1003 /* are we done? ---> inspect c->eof */
vdb_cursor_eof(vdb_cursor * c)1004 static int vdb_cursor_eof( vdb_cursor * c )
1005 {
1006     if ( c->desc->verbosity > 2 )
1007         printf( "---sqlite3_vdb_Eof()\n" );
1008     if ( c->eof )
1009         return SQLITE_ERROR; /* anything else than SQLITE_OK means EOF */
1010     return SQLITE_OK;
1011 }
1012 
1013 /* print a column ---> get a cell from vdb and translate it into text */
vdb_cursor_column(vdb_cursor * c,sqlite3_context * ctx,int column_id)1014 static int vdb_cursor_column( vdb_cursor * c, sqlite3_context * ctx, int column_id )
1015 {
1016     if ( c->desc->verbosity > 2 )
1017         printf( "---sqlite3_vdb_Column( %d )\n", column_id );
1018     col_inst_list_cell( &c->column_instances, c->curs, ctx, column_id, c->current_row );
1019     return SQLITE_OK;
1020 }
1021 
1022 /* return the current row-id ---> return c->current_row */
vdb_cursor_row_id(vdb_cursor * c,sqlite_int64 * pRowid)1023 static int vdb_cursor_row_id( vdb_cursor * c, sqlite_int64 * pRowid )
1024 {
1025     if ( c->desc->verbosity > 2 )
1026         printf( "---sqlite3_vdb_Rowid()\n" );
1027     if ( pRowid != NULL )
1028         *pRowid = c->current_row;
1029     return SQLITE_OK;
1030 }
1031 
1032 
1033 /* -------------------------------------------------------------------------------------- */
1034 /* this object has to be made on the heap,
1035    it is passed back ( typecasted ) to the sqlite-library in sqlite3_vdb_[ Create / Connect ] */
1036 typedef struct vdb_obj
1037 {
1038     sqlite3_vtab base;              /* Base class.  Must be first */
1039     const VDBManager * mgr;         /* the vdb-manager */
1040     const VDatabase *db;            /* the database to be used */
1041     const VTable *tbl;              /* the table to be used */
1042     vdb_obj_desc desc;              /* description of the object to be iterated over */
1043 } vdb_obj;
1044 
1045 
1046 /* destroy the whole connection database, table, manager etc. */
destroy_vdb_obj(vdb_obj * self)1047 static int destroy_vdb_obj( vdb_obj * self )
1048 {
1049     if ( self->desc.verbosity > 1 )
1050         printf( "---sqlite3_vdb_Disconnect()\n" );
1051 
1052     if ( self->mgr != NULL ) VDBManagerRelease( self->mgr );
1053     if ( self->tbl != NULL ) VTableRelease( self->tbl );
1054     if ( self->db != NULL ) VDatabaseRelease( self->db );
1055     release_vdb_obj_desc( &self->desc );
1056 
1057     sqlite3_free( self );
1058     return SQLITE_OK;
1059 }
1060 
1061 /* check if all requested columns are available */
vdb_obj_common_table_handler(vdb_obj * self)1062 static rc_t vdb_obj_common_table_handler( vdb_obj * self )
1063 {
1064     struct KNamelist * readable_columns;
1065     rc_t rc = VTableListReadableColumns( self->tbl, &readable_columns );
1066     if ( rc == 0 )
1067     {
1068 		VNamelist * available;
1069 		rc = VNamelist_from_KNamelist( &available, readable_columns );
1070 		if ( rc == 0 )
1071 		{
1072 			rc = col_desc_list_check( &self->desc.column_descriptions, available, self->desc.excluded_columns );
1073 			VNamelistRelease( available );
1074 		}
1075 		KNamelistRelease( readable_columns );
1076 	}
1077     return rc;
1078 }
1079 
1080 
vdb_obj_get_table_names(const VDatabase * db,VNamelist ** list)1081 static rc_t vdb_obj_get_table_names( const VDatabase * db, VNamelist ** list )
1082 {
1083 	rc_t rc = VNamelistMake( list, 5 );
1084 	if ( rc == 0 )
1085 	{
1086 		KNamelist * names;
1087 		rc_t rc1 = VDatabaseListTbl( db, &names );
1088 		if ( rc1 == 0 )
1089 		{
1090 			uint32_t idx, count;
1091 			rc1 = KNamelistCount( names, &count );
1092 			for ( idx = 0; rc1 == 0 && idx < count; ++idx )
1093 			{
1094 				const char * s = NULL;
1095 				rc1 = KNamelistGet( names, idx, &s );
1096 				if ( rc1 == 0 && s != NULL )
1097 					rc1 = VNamelistAppend( *list, s );
1098 			}
1099 			KNamelistRelease( names );
1100 		}
1101 	}
1102 	return rc;
1103 }
1104 
vdb_obj_open_db_without_table_name(vdb_obj * self)1105 static rc_t vdb_obj_open_db_without_table_name( vdb_obj * self )
1106 {
1107 	VNamelist * list;
1108 	rc_t rc = vdb_obj_get_table_names( self->db, &list );
1109 	if ( rc == 0 )
1110 	{
1111 		int32_t idx;
1112 		rc = VNamelistContainsStr( list, "SEQUENCE", &idx );
1113 		if ( rc == 0 && idx >= 0 )
1114 		{
1115 			/* we have a SEQUENCE-table */
1116 			rc = VDatabaseOpenTableRead( self->db, &self->tbl, "SEQUENCE" );
1117 			if ( rc == 0 )
1118 				self->desc.table_name = sqlite3_mprintf( "SEQUENCE" );
1119 		}
1120 		else
1121 		{
1122 			/* we pick the first one */
1123 			const char * s = NULL;
1124 			rc = VNameListGet( list, 0, &s );
1125 			if ( rc == 0 )
1126 			{
1127 				self->desc.table_name = sqlite3_mprintf( "%s", s );
1128 				rc = VDatabaseOpenTableRead( self->db, &self->tbl, "%s", self->desc.table_name );
1129 			}
1130 		}
1131 		VNamelistRelease( list );
1132 	}
1133 	return rc;
1134 }
1135 
1136 
list_contains_value_starting_with(const VNamelist * list,const String * value,String * found)1137 static bool list_contains_value_starting_with( const VNamelist * list, const String * value, String * found )
1138 {
1139     bool res = false;
1140     uint32_t i, count;
1141     rc_t rc = VNameListCount( list, &count );
1142 	for ( i = 0; i < count && rc == 0 && !res; ++i )
1143 	{
1144 		const char *s = NULL;
1145 		rc = VNameListGet( list, i, &s );
1146 		if ( rc == 0 && s != NULL )
1147 		{
1148 			String item;
1149 			StringInitCString( &item, s );
1150 			if ( value->len <= item.len )
1151 			{
1152 				item.len = value->len;
1153 				item.size = value->size;
1154 				res = ( StringCompare ( &item, value ) == 0 );
1155 				if ( res )
1156 					StringInitCString( found, s );
1157 			}
1158 		}
1159 	}
1160     return res;
1161 }
1162 
vdb_obj_open_db_with_mismatched_table_name(vdb_obj * self)1163 static rc_t vdb_obj_open_db_with_mismatched_table_name( vdb_obj * self )
1164 {
1165 	VNamelist * list;
1166 	rc_t rc = vdb_obj_get_table_names( self->db, &list );
1167 	if ( rc == 0 )
1168 	{
1169 		String to_look_for, found;
1170 		StringInitCString( &to_look_for, self->desc.table_name );
1171 		if ( list_contains_value_starting_with( list, &to_look_for, &found ) )
1172 		{
1173 			self->desc.table_name = sqlite3_mprintf( "%.*s", found.len, found.addr );
1174 			rc = VDatabaseOpenTableRead( self->db, &self->tbl, "%s", self->desc.table_name );
1175 		}
1176 		else
1177 			rc = RC( rcApp, rcArgv, rcAccessing, rcSelf, rcInvalid );
1178 		VNamelistRelease( list );
1179 	}
1180 	return rc;
1181 }
1182 
1183 /* the requested object is a database */
vdb_obj_open_db(vdb_obj * self)1184 static rc_t vdb_obj_open_db( vdb_obj * self )
1185 {
1186     rc_t rc = VDBManagerOpenDBRead( self->mgr, &self->db, NULL, "%s", self->desc.accession );
1187     if ( rc == 0 )
1188     {
1189 		if ( self->desc.table_name == NULL )
1190 			rc = vdb_obj_open_db_without_table_name( self );
1191 		else
1192 		{
1193 			/* if the table-name does not fit, see if it is a shortened version of the existing ones... */
1194 			rc = VDatabaseOpenTableRead( self->db, &self->tbl, "%s", self->desc.table_name );
1195 			if ( rc != 0 )
1196 				rc = vdb_obj_open_db_with_mismatched_table_name( self );
1197 		}
1198 
1199         if ( rc == 0 )
1200             rc = vdb_obj_common_table_handler( self );
1201     }
1202     return rc;
1203 }
1204 
1205 /* the requested object is a table */
vdb_obj_open_tbl(vdb_obj * self)1206 static rc_t vdb_obj_open_tbl( vdb_obj * self )
1207 {
1208     rc_t rc = VDBManagerOpenTableRead( self->mgr, &self->tbl, NULL, "%s", self->desc.accession );
1209     if ( rc == 0 )
1210         rc = vdb_obj_common_table_handler( self );
1211     return rc;
1212 }
1213 
1214 
1215 /* make a database/table object, have a look if it exists, and has the columns we are asking for etc.  */
make_vdb_obj(int argc,const char * const * argv)1216 static vdb_obj * make_vdb_obj( int argc, const char * const * argv )
1217 {
1218     vdb_obj * res = sqlite3_malloc( sizeof( * res ) );
1219     if ( res != NULL )
1220     {
1221         memset( res, 0, sizeof( *res ) );
1222         rc_t rc = init_vdb_obj_desc( &res->desc, argc, argv );
1223         if ( rc == 0 )
1224         {
1225             rc = VDBManagerMakeRead( &( res->mgr ), NULL );
1226             if ( rc == 0 )
1227             {
1228                 /* types defined in <kdb/manager.h> !!! */
1229                 int pt = ( VDBManagerPathType( res->mgr, "%s", res->desc.accession ) & ~ kptAlias );
1230                 switch ( pt )
1231                 {
1232                     case kptDatabase      : rc = vdb_obj_open_db( res ); break;
1233                     case kptTable         :
1234                     case kptPrereleaseTbl : rc = vdb_obj_open_tbl( res ); break;
1235                     default : rc = -1; break;
1236                 }
1237             }
1238             if ( rc != 0 )
1239             {
1240                 destroy_vdb_obj( res );
1241                 res = NULL;
1242             }
1243         }
1244     }
1245     return res;
1246 }
1247 
1248 
1249 /* take the database/table-obj and open a cursor on it */
vdb_obj_open(vdb_obj * self,sqlite3_vtab_cursor ** ppCursor)1250 static int vdb_obj_open( vdb_obj * self, sqlite3_vtab_cursor ** ppCursor )
1251 {
1252     if ( self->desc.verbosity > 1 )
1253         printf( "---sqlite3_vdb_Open()\n" );
1254     vdb_cursor * c = make_vdb_cursor( &self->desc, self->tbl );
1255     if ( c != NULL )
1256     {
1257         *ppCursor = ( sqlite3_vtab_cursor * )c;
1258         return SQLITE_OK;
1259     }
1260     return SQLITE_ERROR;
1261 }
1262 
1263 
1264 /* -------------------------------------------------------------------------------------- */
1265 /* the common code for xxx_Create() and xxx_Connect */
sqlite3_vdb_CC(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr,const char * msg)1266 static int sqlite3_vdb_CC( sqlite3 *db, void *pAux, int argc, const char * const * argv,
1267                            sqlite3_vtab **ppVtab, char **pzErr, const char * msg )
1268 {
1269     const char * stm;
1270     vdb_obj * obj = make_vdb_obj( argc, argv );
1271     if ( obj == NULL )
1272         return SQLITE_ERROR;
1273 
1274     *ppVtab = ( sqlite3_vtab * )obj;
1275 
1276     if ( obj->desc.verbosity > 1 )
1277         printf( "%s", msg );
1278 
1279     stm = make_vdb_create_table_stm( &obj->desc.column_descriptions, "x" );
1280     if ( obj->desc.verbosity > 1 )
1281         printf( "stm = %s\n", stm );
1282     return sqlite3_declare_vtab( db, stm );
1283 }
1284 
1285 
1286 /* -------------------------------------------------------------------------------------- */
1287 /* create a new table-instance from scratch */
sqlite3_vdb_Create(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)1288 static int sqlite3_vdb_Create( sqlite3 *db, void *pAux, int argc, const char * const * argv,
1289                                sqlite3_vtab **ppVtab, char **pzErr )
1290 {
1291     return sqlite3_vdb_CC( db, pAux, argc, argv, ppVtab, pzErr, "---sqlite3_vdb_Create()\n" );
1292 }
1293 
1294 /* open a table-instance from something existing */
sqlite3_vdb_Connect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)1295 static int sqlite3_vdb_Connect( sqlite3 *db, void *pAux, int argc, const char * const * argv,
1296                                 sqlite3_vtab **ppVtab, char **pzErr )
1297 {
1298     return sqlite3_vdb_CC( db, pAux, argc, argv, ppVtab, pzErr, "---sqlite3_vdb_Connect()\n" );
1299 }
1300 
1301 /* query what index can be used ---> maybe vdb supports that in the future */
sqlite3_vdb_BestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)1302 static int sqlite3_vdb_BestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo )
1303 {
1304     int res = SQLITE_ERROR;
1305     if ( tab != NULL )
1306     {
1307         vdb_obj * self = ( vdb_obj * )tab;
1308         if ( self->desc.verbosity > 2 )
1309             printf( "---sqlite3_vdb_BestIndex()\n" );
1310         if ( pIdxInfo != NULL )
1311             pIdxInfo->estimatedCost = 1000000;
1312         res = SQLITE_OK;
1313     }
1314     return res;
1315 }
1316 
1317 /* disconnect from a table */
sqlite3_vdb_Disconnect(sqlite3_vtab * tab)1318 static int sqlite3_vdb_Disconnect( sqlite3_vtab *tab )
1319 {
1320     if ( tab != NULL )
1321         return destroy_vdb_obj( ( vdb_obj * )tab );
1322     return SQLITE_ERROR;
1323 }
1324 
1325 /* open a cursor on a table */
sqlite3_vdb_Open(sqlite3_vtab * tab,sqlite3_vtab_cursor ** ppCursor)1326 static int sqlite3_vdb_Open( sqlite3_vtab *tab, sqlite3_vtab_cursor **ppCursor )
1327 {
1328     if ( tab != NULL )
1329         return vdb_obj_open( ( vdb_obj * ) tab, ppCursor );
1330     return SQLITE_ERROR;
1331 }
1332 
1333 /* close the cursor */
sqlite3_vdb_Close(sqlite3_vtab_cursor * cur)1334 static int sqlite3_vdb_Close( sqlite3_vtab_cursor *cur )
1335 {
1336     if ( cur != NULL )
1337         destroy_vdb_cursor( ( vdb_cursor * )cur );
1338     return SQLITE_ERROR;
1339 }
1340 
1341 /* this is a NOOP, because we have no index ( yet ) */
sqlite3_vdb_Filter(sqlite3_vtab_cursor * cur,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)1342 static int sqlite3_vdb_Filter( sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr,
1343                         int argc, sqlite3_value **argv )
1344 {
1345     if ( cur != NULL )
1346     {
1347         vdb_cursor * self = ( vdb_cursor * )cur;
1348         if ( self->desc->verbosity > 2 )
1349             printf( "---sqlite3_vdb_Filter()\n" );
1350         return SQLITE_OK;
1351     }
1352     return SQLITE_ERROR;
1353 }
1354 
1355 /* advance to the next row */
sqlite3_vdb_Next(sqlite3_vtab_cursor * cur)1356 static int sqlite3_vdb_Next( sqlite3_vtab_cursor *cur )
1357 {
1358     if ( cur != NULL )
1359         return vdb_cursor_next( ( vdb_cursor * )cur );
1360     return SQLITE_ERROR;
1361 }
1362 
1363 /* check if we are at the end */
sqlite3_vdb_Eof(sqlite3_vtab_cursor * cur)1364 static int sqlite3_vdb_Eof( sqlite3_vtab_cursor *cur )
1365 {
1366     if ( cur != NULL )
1367         return vdb_cursor_eof( ( vdb_cursor * )cur );
1368     return SQLITE_ERROR;
1369 }
1370 
1371 /* request data for a cell */
sqlite3_vdb_Column(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int column_id)1372 static int sqlite3_vdb_Column( sqlite3_vtab_cursor *cur, sqlite3_context * ctx, int column_id )
1373 {
1374     if ( cur != NULL )
1375         return vdb_cursor_column( ( vdb_cursor * )cur, ctx, column_id );
1376     return SQLITE_ERROR;
1377 }
1378 
1379 /* request row-id */
sqlite3_vdb_Rowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)1380 static int sqlite3_vdb_Rowid( sqlite3_vtab_cursor *cur, sqlite_int64 * pRowid )
1381 {
1382     if ( cur != NULL )
1383         return vdb_cursor_row_id( ( vdb_cursor * )cur, pRowid );
1384     return SQLITE_ERROR;
1385 }
1386 
1387 sqlite3_module VDB_Module =
1388 {
1389   0,                            /* iVersion */
1390   sqlite3_vdb_Create,           /* xCreate */
1391   sqlite3_vdb_Connect,          /* xConnect */
1392   sqlite3_vdb_BestIndex,        /* xBestIndex */
1393   sqlite3_vdb_Disconnect,       /* xDisconnect */
1394   sqlite3_vdb_Disconnect,       /* xDestroy */
1395   sqlite3_vdb_Open,             /* xOpen - open a cursor */
1396   sqlite3_vdb_Close,            /* xClose - close a cursor */
1397   sqlite3_vdb_Filter,           /* xFilter - configure scan constraints */
1398   sqlite3_vdb_Next,             /* xNext - advance a cursor */
1399   sqlite3_vdb_Eof,              /* xEof - check for end of scan */
1400   sqlite3_vdb_Column,           /* xColumn - read data */
1401   sqlite3_vdb_Rowid,            /* xRowid - read data */
1402   NULL,                         /* xUpdate */
1403   NULL,                         /* xBegin */
1404   NULL,                         /* xSync */
1405   NULL,                         /* xCommit */
1406   NULL,                         /* xRollback */
1407   NULL,                         /* xFindMethod */
1408   NULL,                         /* xRename */
1409 };
1410 
1411 
1412 /* ========================================================================================================== */
1413 
1414 #define NGS_STYLE_READS 1
1415 #define NGS_STYLE_FRAGMENTS 2
1416 #define NGS_STYLE_ALIGNMENTS 3
1417 #define NGS_STYLE_PILEUP 4
1418 #define NGS_STYLE_READGROUPS 5
1419 #define NGS_STYLE_REFS 6
1420 
1421 /* -------------------------------------------------------------------------------------- */
1422 typedef struct ngs_obj_desc
1423 {
1424     const char * accession;     /* the accession we are processing */
1425     const char * style_string;  /* READS, FRAGMENTS, ALIGNMENTS, PILEUP-EVENTS etc. */
1426     const char * refname;       /* if we want slicing... */
1427     uint64_t first, count;
1428     int style, verbosity;
1429     bool prim, sec, full, partial, unaligned;
1430 } ngs_obj_desc;
1431 
release_ngs_obj_desc(ngs_obj_desc * self)1432 static void release_ngs_obj_desc( ngs_obj_desc * self )
1433 {
1434     if ( self->accession != NULL ) sqlite3_free( ( void * )self->accession );
1435     if ( self->style_string != NULL ) sqlite3_free( ( void * )self->style_string );
1436     if ( self->refname != NULL ) sqlite3_free( ( void * )self->refname );
1437 }
1438 
ngs_obj_desc_print(ngs_obj_desc * self)1439 static void ngs_obj_desc_print( ngs_obj_desc * self )
1440 {
1441     printf( "---accession  = %s\n", self->accession != NULL ? self->accession : "None" );
1442     printf( "---style      = %s\n", self->style_string != NULL ? self->style_string : "None" );
1443     printf( "---refname    = %s\n", self->refname != NULL ? self->refname : "None" );
1444     printf( "---prim       = %s\n", self->prim ? "yes" : "no" );
1445     printf( "---sec        = %s\n", self->sec ? "yes" : "no" );
1446     printf( "---full       = %s\n", self->full ? "yes" : "no" );
1447     printf( "---partial    = %s\n", self->partial ? "yes" : "no" );
1448     printf( "---unaligned  = %s\n", self->unaligned ? "yes" : "no" );
1449 }
1450 
ngs_obj_style_2_int(const char * style)1451 static int ngs_obj_style_2_int( const char * style )
1452 {
1453     int res = 0;
1454     String S;
1455     StringInitCString( &S, style );
1456 
1457     if ( is_equal( &S, "READS", "R" ) )
1458         res = NGS_STYLE_READS;
1459     else if ( is_equal( &S, "FRAGMENTS", "F" ) )
1460         res = NGS_STYLE_FRAGMENTS;
1461     else if ( is_equal( &S, "ALIGNMENTS", "A" ) )
1462         res = NGS_STYLE_ALIGNMENTS;
1463     else if ( is_equal( &S, "PILEUP", "P" ) )
1464         res = NGS_STYLE_PILEUP;
1465     else if ( is_equal( &S, "READGROUPS", "G" ) )
1466         res = NGS_STYLE_READGROUPS;
1467     else if ( is_equal( &S, "REFERENCES", "E" ) )
1468         res = NGS_STYLE_REFS;
1469 
1470     return res;
1471 }
1472 
ngs_obj_desc_parse_arg1(ngs_obj_desc * self,const char * name)1473 static void ngs_obj_desc_parse_arg1( ngs_obj_desc * self, const char * name )
1474 {
1475 	String S_name;
1476     bool done = false;
1477 
1478 	StringInitCString( &S_name, name );
1479 	trim_ws( &S_name );
1480 
1481 	if ( is_equal( &S_name, "prim", NULL ) )
1482     {
1483 		self->prim = true;
1484         done = true;
1485     }
1486 
1487 	if ( !done && is_equal( &S_name, "sec", NULL ) )
1488     {
1489 		self->sec = true;
1490         done = true;
1491     }
1492 
1493 	if ( !done && is_equal( &S_name, "full", NULL ) )
1494     {
1495 		self->full = true;
1496         done = true;
1497     }
1498 
1499 	if ( !done && is_equal( &S_name, "partial", NULL ) )
1500     {
1501 		self->partial = true;
1502         done = true;
1503     }
1504 
1505 	if ( !done && is_equal( &S_name, "unaligned", NULL ) )
1506     {
1507 		self->unaligned = true;
1508         done = true;
1509     }
1510 
1511     if ( !done )
1512         printf( "unknown argument '%.*s'\n", S_name.len, S_name.addr );
1513 }
1514 
ngs_obj_desc_parse_arg2(ngs_obj_desc * self,const char * name,const char * value)1515 static void ngs_obj_desc_parse_arg2( ngs_obj_desc * self, const char * name, const char * value )
1516 {
1517 	String S_name, S_value;
1518     bool done = false;
1519 
1520 	StringInitCString( &S_name, name );
1521 	trim_ws( &S_name );
1522 	StringInitCString( &S_value, value );
1523 	trim_ws( &S_value );
1524 
1525 	if ( is_equal( &S_name, "acc", "A" ) )
1526     {
1527 		self->accession = sqlite3_mprintf( "%.*s", S_value.len, S_value.addr );
1528         done = true;
1529     }
1530 
1531 	if ( !done && is_equal( &S_name, "style", "S" ) )
1532 	{
1533         self->style_string = sqlite3_mprintf( "%.*s", S_value.len, S_value.addr );
1534         self->style = ngs_obj_style_2_int( self->style_string );
1535         done = true;
1536     }
1537 
1538 	if ( !done && is_equal( &S_name, "ref", "R" ) )
1539 	{
1540         self->refname = sqlite3_mprintf( "%.*s", S_value.len, S_value.addr );
1541         done = true;
1542     }
1543 
1544     if ( !done && is_equal( &S_name, "verbose", "v" ) )
1545     {
1546         self->verbosity = StringToU64( &S_value, NULL );
1547         done = true;
1548     }
1549 
1550     if ( !done && is_equal( &S_name, "first", NULL ) )
1551     {
1552         self->first = StringToU64( &S_value, NULL );
1553         done = true;
1554     }
1555 
1556     if ( !done && is_equal( &S_name, "count", NULL ) )
1557     {
1558         self->count = StringToU64( &S_value, NULL );
1559         done = true;
1560     }
1561 
1562     if ( !done )
1563         printf( "unknown argument '%.*s' = '%.*s'\n", S_name.len, S_name.addr, S_value.len, S_value.addr );
1564 }
1565 
init_ngs_obj_desc(ngs_obj_desc * self,int argc,const char * const * argv)1566 static rc_t init_ngs_obj_desc( ngs_obj_desc * self, int argc, const char * const * argv )
1567 {
1568     rc_t rc = -1;
1569     if ( argc > 3 )
1570     {
1571         int i;
1572         for ( i = 3; i < argc; i++ )
1573         {
1574             VNamelist * parts;
1575             rc = VNamelistFromStr( &parts, argv[ i ], '=' );
1576             if ( rc == 0 )
1577             {
1578                 uint32_t count;
1579                 rc = VNameListCount( parts, &count );
1580                 if ( rc == 0 && count > 0 )
1581                 {
1582                     const char * arg_name = NULL;
1583                     rc = VNameListGet( parts, 0, &arg_name );
1584                     if ( rc == 0 && arg_name != NULL )
1585                     {
1586                         if ( count > 1 )
1587                         {
1588                             const char * arg_value = NULL;
1589                             rc = VNameListGet( parts, 1, &arg_value );
1590                             if ( rc == 0 && arg_value != NULL )
1591                                 ngs_obj_desc_parse_arg2( self, arg_name, arg_value );
1592                         }
1593                         else
1594                         {
1595                             if ( self->accession == NULL )
1596                                 self->accession = sqlite3_mprintf( "%s", arg_name );
1597                             else
1598                                 ngs_obj_desc_parse_arg1( self, arg_name );
1599                         }
1600                     }
1601                 }
1602                 VNamelistRelease( parts );
1603             }
1604         }
1605     }
1606     if ( self->style == 0 )
1607         self->style = NGS_STYLE_READS;
1608     if ( !self->prim && !self->sec )
1609         self->prim = true;
1610     if ( !self->full && !self->partial && !self->unaligned )
1611     {
1612         self->full = true;
1613         self->partial = true;
1614         self->unaligned = true;
1615     }
1616     if ( self->verbosity > 0 )
1617         ngs_obj_desc_print( self );
1618     return rc;
1619 }
1620 
make_ngs_create_table_stm(const ngs_obj_desc * desc,const char * tbl_name)1621 static char * make_ngs_create_table_stm( const ngs_obj_desc * desc, const char * tbl_name  )
1622 {
1623     char * res = sqlite3_mprintf( "CREATE TABLE %s (", tbl_name );
1624     if ( res != NULL )
1625     {
1626         switch( desc->style )
1627         {
1628             case NGS_STYLE_READS      : res = sqlite3_mprintf( "%z SEQ, QUAL, NAME, ID, GRP, CAT, NFRAGS );", res ); break;
1629             case NGS_STYLE_FRAGMENTS  : res = sqlite3_mprintf( "%z SEQ, QUAL, ID, PAIRED, ALIGNED );", res ); break;
1630             case NGS_STYLE_ALIGNMENTS : res = sqlite3_mprintf( "%z SEQ, QUAL, ID, REFSPEC, MAPQ, RDFILTER, REFBASES, GRP, ALIG, PRIM, REFPOS, LEN, REVERSE, TLEN, CIGARS, CIGARL, HASMATE, MATEID, MATEREF, MATEREVERSE, FIRST );", res ); break;
1631             case NGS_STYLE_PILEUP     : res = sqlite3_mprintf( "%z NAME, POS, BASE, DEPTH, MAPQ, ALIG, ALIG_POS, ALIG_FIRST, ALIG_LAST, MISMATCH, DELETION, INSERTION, REV_STRAND, START, STOP, ALIG_BASE, ALIG_QUAL, INS_BASE, INS_QUAL, REPEAT, INDEL );", res ); break;
1632             case NGS_STYLE_READGROUPS : res = sqlite3_mprintf( "%z NAME );", res ); break;
1633             case NGS_STYLE_REFS       : res = sqlite3_mprintf( "%z NAME, ID, CIRC, LEN );", res ); break;
1634             default : res = sqlite3_mprintf( "%z X );", res ); break;
1635         }
1636     }
1637     return res;
1638 }
1639 
1640 
1641 /* -------------------------------------------------------------------------------------- */
1642 /* this object has to be made on the heap,
1643    it is passed back ( typecasted ) to the sqlite-library in sqlite3_vdb_[ Create / Connect ] */
1644 typedef struct ngs_obj
1645 {
1646     sqlite3_vtab base;              /* Base class.  Must be first */
1647     ngs_obj_desc desc;              /* the description ( ACC, Style ) */
1648 } ngs_obj;
1649 
1650 
1651 /* destroy the whole connection database, table, manager etc. */
destroy_ngs_obj(ngs_obj * self)1652 static int destroy_ngs_obj( ngs_obj * self )
1653 {
1654     if ( self->desc.verbosity > 1 )
1655         printf( "---sqlite3_ngs_Disconnect()\n" );
1656 
1657     release_ngs_obj_desc( &self->desc );
1658 
1659     sqlite3_free( self );
1660     return SQLITE_OK;
1661 }
1662 
1663 /* gather what we want to open, check if it can be opened... */
make_ngs_obj(int argc,const char * const * argv)1664 static ngs_obj * make_ngs_obj( int argc, const char * const * argv )
1665 {
1666     ngs_obj * res = sqlite3_malloc( sizeof( * res ) );
1667     if ( res != NULL )
1668     {
1669         memset( res, 0, sizeof( *res ) );
1670         rc_t rc = init_ngs_obj_desc( &res->desc, argc, argv );
1671         if ( rc == 0 )
1672         {
1673             /* here we have to check if we can open the accession as a read-collection... */
1674             if ( rc != 0 )
1675             {
1676                 destroy_ngs_obj( res );
1677                 res = NULL;
1678             }
1679         }
1680     }
1681     return res;
1682 }
1683 
1684 /* -------------------------------------------------------------------------------------- */
1685 typedef struct ngs_cursor
1686 {
1687     sqlite3_vtab cursor;            /* Base class.  Must be first */
1688     ngs_obj_desc * desc;            /* cursor does not own this! */
1689     NGS_ReadCollection * rd_coll;   /* the read-collection we are operating on */
1690     NGS_Read * m_read;              /* the read-iterator */
1691     NGS_Alignment * m_alig;         /* the alignment-iterator */
1692     NGS_ReadGroup * m_rd_grp;       /* the read-group-iterator */
1693     NGS_Reference * m_refs;         /* the reference-iterator */
1694     NGS_Pileup * m_pileup;          /* the pileup-iterator */
1695     int64_t current_row;
1696     bool eof;
1697 } ngs_cursor;
1698 
1699 
destroy_ngs_cursor(ngs_cursor * self)1700 static int destroy_ngs_cursor( ngs_cursor * self )
1701 {
1702     HYBRID_FUNC_ENTRY( rcSRA, rcRow, rcAccessing );
1703 
1704     if ( self->desc->verbosity > 1 )
1705         printf( "---sqlite3_ngs_Close()\n" );
1706 
1707     if ( self->m_read != NULL )
1708         NGS_ReadRelease ( self->m_read, ctx );
1709 
1710     if ( self->m_alig != NULL )
1711         NGS_AlignmentRelease ( self->m_alig, ctx );
1712 
1713     if ( self->m_rd_grp != NULL )
1714         NGS_ReadGroupRelease( self->m_rd_grp, ctx );
1715 
1716     if ( self->m_pileup != NULL )
1717         NGS_PileupRelease( self->m_pileup, ctx );
1718 
1719     if ( self->m_refs != NULL )
1720         NGS_ReferenceRelease( self->m_refs, ctx );
1721 
1722     if ( self->rd_coll != NULL )
1723         NGS_RefcountRelease( ( NGS_Refcount * ) self->rd_coll, ctx );
1724 
1725     CLEAR();
1726     sqlite3_free( self );
1727     return SQLITE_OK;
1728 
1729 }
1730 
1731 /* =========================================================================================== */
make_ngs_cursor_READS(ngs_cursor * self,ctx_t ctx)1732 static void make_ngs_cursor_READS( ngs_cursor * self, ctx_t ctx )
1733 {
1734     if ( self->desc->count > 0 )
1735         /* the user did specify a range: process this as a row-range */
1736         self->m_read = NGS_ReadCollectionGetReadRange( self->rd_coll, ctx,
1737                         self->desc->first, self->desc->count,
1738                         self->desc->full, self->desc->partial, self->desc->unaligned );
1739     else
1740         self->m_read = NGS_ReadCollectionGetReads( self->rd_coll, ctx,
1741                         self->desc->full, self->desc->partial, self->desc->unaligned );
1742     if ( !FAILED() )
1743         self->eof = ! NGS_ReadIteratorNext( self->m_read, ctx );
1744 }
1745 
make_ngs_cursor_FRAGS(ngs_cursor * self,ctx_t ctx)1746 static void make_ngs_cursor_FRAGS( ngs_cursor * self, ctx_t ctx )
1747 {
1748     make_ngs_cursor_READS( self, ctx );
1749     if ( !FAILED() )
1750         self->eof = ! NGS_FragmentIteratorNext( ( NGS_Fragment * ) self->m_read, ctx );
1751 }
1752 
make_ngs_cursor_ALIGS(ngs_cursor * self,ctx_t ctx)1753 static void make_ngs_cursor_ALIGS( ngs_cursor * self, ctx_t ctx )
1754 {
1755     if ( self->desc->refname == NULL )
1756     {
1757         /* the user did not specify a reference: process either a row-range or all alignments */
1758         if ( self->desc->count > 0 )
1759             /* the user did specify a range: process this range */
1760             self->m_alig = NGS_ReadCollectionGetAlignmentRange( self->rd_coll, ctx,
1761                             self->desc->first, self->desc->count,
1762                             self->desc->prim, self->desc->sec );
1763         else
1764             /* the user did not specify a range: process all alignments */
1765             self->m_alig = NGS_ReadCollectionGetAlignments( self->rd_coll, ctx,
1766                             self->desc->prim, self->desc->sec );
1767     }
1768     else
1769     {
1770         /* the user did specify a reference: process a slice of alignments */
1771         self->m_refs = NGS_ReadCollectionGetReference( self->rd_coll, ctx, self->desc->refname );
1772         if ( !FAILED() )
1773         {
1774             /* the user specified reference was found ! */
1775             if ( self->desc->count > 0 )
1776                 /* the user did specify a range: process this as a slice */
1777                 self->m_alig = NGS_ReferenceGetAlignmentSlice( self->m_refs, ctx,
1778                             self->desc->first, self->desc->count,
1779                             self->desc->prim, self->desc->sec );
1780             else
1781             {
1782                 /* the user did not specify a range: process all alignments of this reference */
1783                 uint64_t len = NGS_ReferenceGetLength( self->m_refs, ctx );
1784                 if ( !FAILED() )
1785                     self->m_alig = NGS_ReferenceGetAlignmentSlice( self->m_refs, ctx,
1786                                 0, len,
1787                                 self->desc->prim, self->desc->sec );
1788             }
1789         }
1790     }
1791     if ( !FAILED() )
1792         self->eof = ! NGS_AlignmentIteratorNext( self->m_alig, ctx );
1793 }
1794 
make_ngs_cursor_REFS(ngs_cursor * self,ctx_t ctx)1795 static void make_ngs_cursor_REFS( ngs_cursor * self, ctx_t ctx )
1796 {
1797     self->m_refs = NGS_ReadCollectionGetReferences( self->rd_coll, ctx );
1798     if ( !FAILED() )
1799         self->eof = ! NGS_ReferenceIteratorNext( self->m_refs, ctx );
1800 }
1801 
make_ngs_cursor_PILEUP(ngs_cursor * self,ctx_t ctx)1802 static void make_ngs_cursor_PILEUP( ngs_cursor * self, ctx_t ctx )
1803 {
1804     if ( self->desc->refname == NULL )
1805         /* the user did not specify a reference: process all alignments */
1806         make_ngs_cursor_REFS( self, ctx );
1807     else
1808     {
1809         /* the user did specify a reference: process a slice of alignments */
1810         self->m_refs = NGS_ReadCollectionGetReference( self->rd_coll, ctx, self->desc->refname );
1811     }
1812 
1813     if ( !FAILED() )
1814     {
1815         if ( self->desc->count > 0 )
1816             self->m_pileup = NGS_ReferenceGetPileupSlice( self->m_refs, ctx,
1817                 self->desc->first, self->desc->count,
1818                 self->desc->prim, self->desc->sec );
1819         else
1820             self->m_pileup = NGS_ReferenceGetPileups( self->m_refs, ctx, self->desc->prim, self->desc->sec );
1821     }
1822     if ( !FAILED() )
1823         self->eof = ! NGS_PileupIteratorNext( self->m_pileup, ctx );
1824     if ( !FAILED() )
1825         self->eof = ! NGS_PileupEventIteratorNext( ( NGS_PileupEvent * )self->m_pileup, ctx );
1826 }
1827 
make_ngs_cursor_RD_GRP(ngs_cursor * self,ctx_t ctx)1828 static void make_ngs_cursor_RD_GRP( ngs_cursor * self, ctx_t ctx )
1829 {
1830     self->m_rd_grp = NGS_ReadCollectionGetReadGroups( self->rd_coll, ctx );
1831     if ( !FAILED() )
1832         self->eof = ! NGS_ReadGroupIteratorNext( self->m_rd_grp, ctx );
1833 }
1834 
1835 /* create a cursor from the obj-description ( mostly it's columns ) */
make_ngs_cursor(ngs_obj_desc * desc)1836 static ngs_cursor * make_ngs_cursor( ngs_obj_desc * desc )
1837 {
1838     ngs_cursor * res = sqlite3_malloc( sizeof( * res ) );
1839     if ( res != NULL )
1840     {
1841         HYBRID_FUNC_ENTRY( rcSRA, rcRow, rcAccessing );
1842 
1843         memset( res, 0, sizeof( *res ) );
1844         res->desc = desc;
1845 
1846         res->rd_coll = NGS_ReadCollectionMake( ctx, desc->accession );
1847         if ( !FAILED() )
1848         {
1849             switch( desc->style )
1850             {
1851                 case NGS_STYLE_READS      : make_ngs_cursor_READS( res, ctx ); break;
1852                 case NGS_STYLE_FRAGMENTS  : make_ngs_cursor_FRAGS( res, ctx ); break;
1853                 case NGS_STYLE_ALIGNMENTS : make_ngs_cursor_ALIGS( res, ctx ); break;
1854                 case NGS_STYLE_PILEUP     : make_ngs_cursor_PILEUP( res, ctx ); break;
1855                 case NGS_STYLE_READGROUPS : make_ngs_cursor_RD_GRP( res, ctx ); break;
1856                 case NGS_STYLE_REFS       : make_ngs_cursor_REFS( res, ctx ); break;
1857             }
1858         }
1859         if ( FAILED() )
1860         {
1861             CLEAR();
1862             destroy_ngs_cursor( res );
1863             res = NULL;
1864         }
1865     }
1866     return res;
1867 }
1868 
1869 /* =========================================================================================== */
ngs_cursor_next_fragment(ngs_cursor * self,ctx_t ctx)1870 static void ngs_cursor_next_fragment( ngs_cursor * self, ctx_t ctx )
1871 {
1872     self->eof = ! NGS_FragmentIteratorNext ( ( NGS_Fragment * ) self->m_read, ctx );
1873     if ( !FAILED() && self->eof )
1874     {
1875         self->eof = ! NGS_ReadIteratorNext( self->m_read, ctx );
1876         if ( !FAILED() && !self->eof )
1877             self->eof = ! NGS_FragmentIteratorNext ( ( NGS_Fragment * ) self->m_read, ctx );
1878     }
1879 }
1880 
1881 
ngs_cursor_next_pileup(ngs_cursor * self,ctx_t ctx)1882 static void ngs_cursor_next_pileup( ngs_cursor * self, ctx_t ctx )
1883 {
1884     self->eof = ! NGS_PileupEventIteratorNext( ( NGS_PileupEvent * )self->m_pileup, ctx );
1885     if ( !FAILED() && self->eof )
1886     {
1887         self->eof = ! NGS_PileupIteratorNext( self->m_pileup, ctx );
1888         if ( !FAILED() )
1889         {
1890             if ( !self->eof )
1891                 self->eof = ! NGS_PileupEventIteratorNext( ( NGS_PileupEvent * )self->m_pileup, ctx );
1892             else if ( self->desc->refname == NULL )
1893             {
1894                 /* only switch to the next reference if the user did not request a specific reference */
1895                 NGS_PileupRelease( self->m_pileup, ctx );
1896                 self->m_pileup = NULL;
1897                 if ( !FAILED() )
1898                 {
1899                     self->eof = ! NGS_ReferenceIteratorNext( self->m_refs, ctx );
1900                     if ( !FAILED() && !self->eof )
1901                     {
1902                         self->m_pileup = NGS_ReferenceGetPileups( self->m_refs, ctx, self->desc->prim, self->desc->sec );
1903                         if ( !FAILED() )
1904                             self->eof = ! NGS_PileupIteratorNext( self->m_pileup, ctx );
1905                         if ( !FAILED() )
1906                             self->eof = ! NGS_PileupEventIteratorNext( ( NGS_PileupEvent * )self->m_pileup, ctx );
1907                     }
1908                 }
1909             }
1910         }
1911     }
1912 }
1913 
ngs_cursor_next(ngs_cursor * self)1914 static int ngs_cursor_next( ngs_cursor * self )
1915 {
1916     HYBRID_FUNC_ENTRY( rcSRA, rcRow, rcAccessing );
1917 
1918     if ( self->desc->verbosity > 2 )
1919         printf( "---sqlite3_ngs_next()\n" );
1920 
1921     switch( self->desc->style )
1922     {
1923         case NGS_STYLE_READS      : self->eof = ! NGS_ReadIteratorNext( self->m_read, ctx ); break;
1924         case NGS_STYLE_FRAGMENTS  : ngs_cursor_next_fragment( self, ctx ); break;
1925         case NGS_STYLE_ALIGNMENTS : self->eof = ! NGS_AlignmentIteratorNext( self->m_alig, ctx ); break;
1926         case NGS_STYLE_PILEUP     : ngs_cursor_next_pileup( self, ctx ); break;
1927         case NGS_STYLE_READGROUPS : self->eof = ! NGS_ReadGroupIteratorNext( self->m_rd_grp, ctx ); break;
1928         case NGS_STYLE_REFS       : self->eof = ! NGS_ReferenceIteratorNext( self->m_refs, ctx ); break;
1929     }
1930     if ( FAILED() )
1931     {
1932         CLEAR();
1933         return SQLITE_ERROR;
1934     }
1935     if ( !self->eof )
1936         self->current_row++;
1937     return SQLITE_OK;
1938 }
1939 
1940 /* =========================================================================================== */
ngs_cursor_eof(ngs_cursor * self)1941 static int ngs_cursor_eof( ngs_cursor * self )
1942 {
1943     if ( self->desc->verbosity > 2 )
1944         printf( "---sqlite3_ngs_Eof()\n" );
1945     if ( self->eof )
1946         return SQLITE_ERROR; /* anything else than SQLITE_OK means EOF */
1947     return SQLITE_OK;
1948 }
1949 
1950 /* =========================================================================================== */
ngs_return_NGS_String(sqlite3_context * sql_ctx,ctx_t ctx,NGS_String * ngs_str)1951 static void ngs_return_NGS_String( sqlite3_context * sql_ctx, ctx_t ctx, NGS_String * ngs_str )
1952 {
1953     const char * s = NGS_StringData( ngs_str, ctx );
1954     if ( !FAILED() )
1955     {
1956         size_t len = NGS_StringSize( ngs_str, ctx );
1957         if ( !FAILED() )
1958             sqlite3_result_text( sql_ctx, (char *)s, len, SQLITE_TRANSIENT );
1959 
1960     }
1961     NGS_StringRelease( ngs_str, ctx );
1962 }
1963 
ngs_cursor_read_str(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,struct NGS_String * f (NGS_Read * read,ctx_t ctx))1964 static void ngs_cursor_read_str( ngs_cursor * self,
1965                                sqlite3_context * sql_ctx,
1966                                ctx_t ctx,
1967                                struct NGS_String * f( NGS_Read * read, ctx_t ctx ) )
1968 {
1969     NGS_String * m_seq = f( self->m_read, ctx );
1970     if ( !FAILED() )
1971         ngs_return_NGS_String( sql_ctx, ctx, m_seq );
1972 }
1973 
ngs_cursor_read_str_full(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,struct NGS_String * f (NGS_Read * read,ctx_t ctx,uint64_t offset,uint64_t length))1974 static void ngs_cursor_read_str_full( ngs_cursor * self,
1975                                sqlite3_context * sql_ctx,
1976                                ctx_t ctx,
1977                                struct NGS_String * f( NGS_Read * read, ctx_t ctx, uint64_t offset, uint64_t length ) )
1978 {
1979     NGS_String * m_seq = f( self->m_read, ctx, 0, ( size_t ) - 1 );
1980     if ( !FAILED() )
1981         ngs_return_NGS_String( sql_ctx, ctx, m_seq );
1982 }
1983 
ngs_cursor_column_read_CAT(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)1984 static void ngs_cursor_column_read_CAT( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
1985 {
1986     enum NGS_ReadCategory cat = NGS_ReadGetReadCategory( self->m_read, ctx );
1987     if ( !FAILED() )
1988         sqlite3_result_int( sql_ctx, cat );
1989 }
1990 
ngs_cursor_column_read_NFRAGS(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)1991 static void ngs_cursor_column_read_NFRAGS( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
1992 {
1993     uint32_t n = NGS_ReadNumFragments( self->m_read, ctx );
1994     if ( !FAILED() )
1995         sqlite3_result_int( sql_ctx, n );
1996 }
1997 
1998 /* >>>>>>>>>> columns for READ-STYLE <<<<<<<<<<<< */
ngs_cursor_column_read(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,int column_id)1999 static void ngs_cursor_column_read( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx, int column_id )
2000 {
2001     switch( column_id )
2002     {
2003         case 0 : ngs_cursor_read_str_full( self, sql_ctx, ctx, NGS_ReadGetReadSequence ); break; /* SEQ */
2004         case 1 : ngs_cursor_read_str_full( self, sql_ctx, ctx, NGS_ReadGetReadQualities ); break; /* QUAL */
2005         case 2 : ngs_cursor_read_str( self, sql_ctx, ctx, NGS_ReadGetReadName ); break; /* NAME */
2006         case 3 : ngs_cursor_read_str( self, sql_ctx, ctx, NGS_ReadGetReadId ); break; /* ID */
2007         case 4 : ngs_cursor_read_str( self, sql_ctx, ctx, NGS_ReadGetReadGroup ); break; /* GRP */
2008         case 5 : ngs_cursor_column_read_CAT( self, sql_ctx, ctx ); break; /* CAT */
2009         case 6 : ngs_cursor_column_read_NFRAGS( self, sql_ctx, ctx ); break; /* NFRAGS */
2010     }
2011 }
2012 
ngs_cursor_frag_str(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,struct NGS_String * f (NGS_Fragment * frag,ctx_t ctx))2013 static void ngs_cursor_frag_str( ngs_cursor * self,
2014                                sqlite3_context * sql_ctx,
2015                                ctx_t ctx,
2016                                struct NGS_String * f( NGS_Fragment * frag, ctx_t ctx ) )
2017 {
2018     NGS_String * m_seq = f( ( NGS_Fragment * )self->m_read, ctx );
2019     if ( !FAILED() )
2020         ngs_return_NGS_String( sql_ctx, ctx, m_seq );
2021 }
2022 
ngs_cursor_frag_str_full(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,struct NGS_String * f (NGS_Fragment * frag,ctx_t ctx,uint64_t offset,uint64_t length))2023 static void ngs_cursor_frag_str_full( ngs_cursor * self,
2024                                sqlite3_context * sql_ctx,
2025                                ctx_t ctx,
2026                                struct NGS_String * f( NGS_Fragment * frag, ctx_t ctx, uint64_t offset, uint64_t length ) )
2027 {
2028     NGS_String * m_seq = f( ( NGS_Fragment * )self->m_read, ctx, 0, ( size_t ) - 1 );
2029     if ( !FAILED() )
2030         ngs_return_NGS_String( sql_ctx, ctx, m_seq );
2031 }
2032 
ngs_cursor_frag_bool(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,bool f (NGS_Fragment * frag,ctx_t ctx))2033 static void ngs_cursor_frag_bool( ngs_cursor * self,
2034                                sqlite3_context * sql_ctx,
2035                                ctx_t ctx,
2036                                bool f( NGS_Fragment * frag, ctx_t ctx ) )
2037 {
2038     bool b = f( ( NGS_Fragment * )self->m_read, ctx );
2039     if ( !FAILED() )
2040         sqlite3_result_int( sql_ctx, b ? 1 : 0 );
2041 }
2042 
2043 /* >>>>>>>>>> columns for FRAGMENT-STYLE <<<<<<<<<<<< */
ngs_cursor_column_frag(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,int column_id)2044 static void ngs_cursor_column_frag( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx, int column_id )
2045 {
2046     switch( column_id )
2047     {
2048         case 0 : ngs_cursor_frag_str_full( self, sql_ctx, ctx, NGS_FragmentGetSequence ); break; /* SEQ */
2049         case 1 : ngs_cursor_frag_str_full( self, sql_ctx, ctx, NGS_FragmentGetQualities ); break; /* QUAL */
2050         case 2 : ngs_cursor_frag_str( self, sql_ctx, ctx, NGS_FragmentGetId ); break; /* ID */
2051         case 3 : ngs_cursor_frag_bool( self, sql_ctx, ctx, NGS_FragmentIsPaired ); break; /* PAIRED */
2052         case 4 : ngs_cursor_frag_bool( self, sql_ctx, ctx, NGS_FragmentIsAligned ); break; /* ALIGNED */
2053     }
2054 }
2055 
ngs_cursor_alig_str(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,struct NGS_String * f (NGS_Alignment * self,ctx_t ctx))2056 static void ngs_cursor_alig_str( ngs_cursor * self,
2057                                sqlite3_context * sql_ctx,
2058                                ctx_t ctx,
2059                                struct NGS_String * f( NGS_Alignment * self, ctx_t ctx ) )
2060 {
2061     NGS_String * m_seq = f( self->m_alig, ctx );
2062     if ( !FAILED() )
2063         ngs_return_NGS_String( sql_ctx, ctx, m_seq );
2064 }
2065 
ngs_cursor_alig_str_bool(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,struct NGS_String * f (NGS_Alignment * self,ctx_t ctx,bool b),bool b)2066 static void ngs_cursor_alig_str_bool( ngs_cursor * self,
2067                                sqlite3_context * sql_ctx,
2068                                ctx_t ctx,
2069                                struct NGS_String * f( NGS_Alignment * self, ctx_t ctx, bool b ),
2070                                bool b )
2071 {
2072     NGS_String * m_seq = f( self->m_alig, ctx, b );
2073     if ( !FAILED() )
2074         ngs_return_NGS_String( sql_ctx, ctx, m_seq );
2075 }
2076 
ngs_cursor_alig_bool(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,bool f (NGS_Alignment * self,ctx_t ctx))2077 static void ngs_cursor_alig_bool( ngs_cursor * self,
2078                                sqlite3_context * sql_ctx,
2079                                ctx_t ctx,
2080                                bool f( NGS_Alignment * self, ctx_t ctx ) )
2081 {
2082     bool b = f( self->m_alig, ctx );
2083     if ( !FAILED() )
2084         sqlite3_result_int( sql_ctx, b ? 1 : 0 );
2085 }
2086 
ngs_cursor_alig_uint64(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,uint64_t f (NGS_Alignment * self,ctx_t ctx))2087 static void ngs_cursor_alig_uint64( ngs_cursor * self,
2088                                sqlite3_context * sql_ctx,
2089                                ctx_t ctx,
2090                                uint64_t f( NGS_Alignment * self, ctx_t ctx ) )
2091 {
2092     uint64_t value = f( self->m_alig, ctx );
2093     if ( !FAILED() )
2094         sqlite3_result_int64( sql_ctx, value );
2095 }
2096 
2097 
ngs_cursor_column_alig_MAPQ(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2098 static void ngs_cursor_column_alig_MAPQ( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2099 {
2100     int mapq = NGS_AlignmentGetMappingQuality( self->m_alig, ctx );
2101     if ( !FAILED() )
2102         sqlite3_result_int( sql_ctx, mapq );
2103 }
2104 
ngs_cursor_column_alig_RDFILTER(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2105 static void ngs_cursor_column_alig_RDFILTER( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2106 {
2107     INSDC_read_filter rf = NGS_AlignmentGetReadFilter( self->m_alig, ctx );
2108     if ( !FAILED() )
2109         sqlite3_result_int( sql_ctx, rf );
2110 }
2111 
ngs_cursor_column_alig_REFPOS(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2112 static void ngs_cursor_column_alig_REFPOS( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2113 {
2114     int64_t pos = NGS_AlignmentGetAlignmentPosition( self->m_alig, ctx );
2115     if ( !FAILED() )
2116         sqlite3_result_int64( sql_ctx, pos );
2117 }
2118 
2119 /* >>>>>>>>>> columns for ALIGNMENT-STYLE <<<<<<<<<<<< */
ngs_cursor_column_alig(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,int column_id)2120 static void ngs_cursor_column_alig( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx, int column_id )
2121 {
2122     switch( column_id )
2123     {
2124         case 0  : ngs_cursor_alig_str( self, sql_ctx, ctx, NGS_AlignmentGetClippedFragmentBases ); break; /* SEQ */
2125         case 1  : ngs_cursor_alig_str( self, sql_ctx, ctx, NGS_AlignmentGetClippedFragmentQualities ); break; /* QUAL */
2126         case 2  : ngs_cursor_alig_str( self, sql_ctx, ctx, NGS_AlignmentGetAlignmentId ); break; /* ID */
2127         case 3  : ngs_cursor_alig_str( self, sql_ctx, ctx, NGS_AlignmentGetReferenceSpec ); break; /* REFSPEC */
2128         case 4  : ngs_cursor_column_alig_MAPQ( self, sql_ctx, ctx ); break; /* MAPQ */
2129         case 5  : ngs_cursor_column_alig_RDFILTER( self, sql_ctx, ctx ); break; /* RDFILTER */
2130         case 6  : ngs_cursor_alig_str( self, sql_ctx, ctx, NGS_AlignmentGetReferenceBases ); break; /* REFBASES */
2131         case 7  : ngs_cursor_alig_str( self, sql_ctx, ctx, NGS_AlignmentGetReadGroup ); break; /* GRP */
2132         case 8  : ngs_cursor_alig_str( self, sql_ctx, ctx, NGS_AlignmentGetAlignedFragmentBases ); break; /*ALIG */
2133         case 9  : ngs_cursor_alig_bool( self, sql_ctx, ctx, NGS_AlignmentIsPrimary ); break; /* PRIM */
2134         case 10 : ngs_cursor_column_alig_REFPOS( self, sql_ctx, ctx ); break; /* REFPOS */
2135         case 11 : ngs_cursor_alig_uint64( self, sql_ctx, ctx, NGS_AlignmentGetAlignmentLength ); break; /* LEN */
2136         case 12 : ngs_cursor_alig_bool( self, sql_ctx, ctx, NGS_AlignmentGetIsReversedOrientation ); break; /* REVERSE */
2137         case 13 : ngs_cursor_alig_uint64( self, sql_ctx, ctx, NGS_AlignmentGetTemplateLength ); break; /* TLEN */
2138         case 14 : ngs_cursor_alig_str_bool( self, sql_ctx, ctx, NGS_AlignmentGetShortCigar, true ); break; /* CIGARS */
2139         case 15 : ngs_cursor_alig_str_bool( self, sql_ctx, ctx, NGS_AlignmentGetLongCigar, true ); break; /* CIGARL */
2140         case 16 : ngs_cursor_alig_bool( self, sql_ctx, ctx, NGS_AlignmentHasMate ); break; /* HASMATE */
2141         case 17 : ngs_cursor_alig_str( self, sql_ctx, ctx, NGS_AlignmentGetMateAlignmentId ); /* MATEID */
2142         case 18 : ngs_cursor_alig_str( self, sql_ctx, ctx, NGS_AlignmentGetMateReferenceSpec ); /* MATEREF */
2143         case 19 : ngs_cursor_alig_bool( self, sql_ctx, ctx, NGS_AlignmentGetMateIsReversedOrientation ); break; /* MATEREVERSE */
2144         case 20 : ngs_cursor_alig_bool( self, sql_ctx, ctx, NGS_AlignmentIsFirst ); break; /* FIRST */
2145     }
2146 }
2147 
ngs_cursor_pileup_name(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2148 static void ngs_cursor_pileup_name( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2149 {
2150     NGS_String * refspec = NGS_PileupGetReferenceSpec( self->m_pileup, ctx );
2151     if ( !FAILED() )
2152         ngs_return_NGS_String( sql_ctx, ctx, refspec );
2153 }
2154 
ngs_cursor_pileup_pos(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2155 static void ngs_cursor_pileup_pos( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2156 {
2157     int64_t pos = NGS_PileupGetReferencePosition ( self->m_pileup, ctx );
2158     if ( !FAILED() )
2159         sqlite3_result_int64( sql_ctx, pos );
2160 }
2161 
ngs_cursor_pileup_base(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2162 static void ngs_cursor_pileup_base( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2163 {
2164     char base = NGS_PileupGetReferenceBase( self->m_pileup, ctx );
2165     if ( !FAILED() )
2166         sqlite3_result_text( sql_ctx, &base, 1, SQLITE_TRANSIENT );
2167 }
2168 
ngs_cursor_pileup_depth(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2169 static void ngs_cursor_pileup_depth( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2170 {
2171     unsigned int depth = NGS_PileupGetPileupDepth( self->m_pileup, ctx );
2172     if ( !FAILED() )
2173         sqlite3_result_int( sql_ctx, depth );
2174 }
2175 
ngs_cursor_pileupevent_i64(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,int64_t f (const NGS_PileupEvent * self,ctx_t ctx))2176 static void ngs_cursor_pileupevent_i64( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx,
2177                                         int64_t f ( const NGS_PileupEvent * self, ctx_t ctx ) )
2178 {
2179     int64_t pos = f( ( const NGS_PileupEvent * )self->m_pileup, ctx );
2180     if ( !FAILED() )
2181         sqlite3_result_int64( sql_ctx, pos );
2182 }
2183 
ngs_cursor_pileupevent_t(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,int mask)2184 static void ngs_cursor_pileupevent_t( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx, int mask )
2185 {
2186     int ev = NGS_PileupEventGetEventType( ( const NGS_PileupEvent * )self->m_pileup, ctx );
2187     if ( !FAILED() )
2188         sqlite3_result_int( sql_ctx, ( ( ev & mask ) != 0 ) ? 1 : 0 );
2189 }
2190 
ngs_cursor_pileupevent_char(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,char f (const NGS_PileupEvent * self,ctx_t ctx))2191 static void ngs_cursor_pileupevent_char( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx,
2192                                         char f ( const NGS_PileupEvent * self, ctx_t ctx ) )
2193 {
2194     char c = f( ( const NGS_PileupEvent * )self->m_pileup, ctx );
2195     if ( !FAILED() )
2196         sqlite3_result_text( sql_ctx, &c, 1, SQLITE_TRANSIENT );
2197 }
2198 
ngs_cursor_pileupevent_str(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,NGS_String * f (const NGS_PileupEvent * self,ctx_t ctx))2199 static void ngs_cursor_pileupevent_str( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx,
2200                                         NGS_String * f ( const NGS_PileupEvent * self, ctx_t ctx ) )
2201 {
2202     NGS_String * s = f( ( const NGS_PileupEvent * )self->m_pileup, ctx );
2203     if ( !FAILED() )
2204         ngs_return_NGS_String( sql_ctx, ctx, s );
2205 }
2206 
ngs_cursor_pileupevent_int(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,int f (const NGS_PileupEvent * self,ctx_t ctx))2207 static void ngs_cursor_pileupevent_int( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx,
2208                                         int f ( const NGS_PileupEvent * self, ctx_t ctx ) )
2209 {
2210     int value = f( ( const NGS_PileupEvent * )self->m_pileup, ctx );
2211     if ( !FAILED() )
2212         sqlite3_result_int( sql_ctx, value );
2213 }
2214 
ngs_cursor_pileupevent_repeat(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2215 static void ngs_cursor_pileupevent_repeat( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2216 {
2217     unsigned int n = NGS_PileupEventGetRepeatCount( ( const NGS_PileupEvent * )self->m_pileup, ctx );
2218     if ( !FAILED() )
2219         sqlite3_result_int( sql_ctx, n );
2220 }
2221 
2222 
2223 /* >>>>>>>>>> columns for PILEUP-STYLE <<<<<<<<<<<< */
ngs_cursor_column_pileup(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,int column_id)2224 static void ngs_cursor_column_pileup( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx, int column_id )
2225 {
2226     switch( column_id )
2227     {
2228         case 0  : ngs_cursor_pileup_name( self, sql_ctx, ctx ); break; /* NAME */
2229         case 1  : ngs_cursor_pileup_pos( self, sql_ctx, ctx ); break; /* POS */
2230         case 2  : ngs_cursor_pileup_base( self, sql_ctx, ctx ); break; /* BASE */
2231         case 3  : ngs_cursor_pileup_depth( self, sql_ctx, ctx ); break; /* DEPTH */
2232         case 4  : ngs_cursor_pileupevent_int( self, sql_ctx, ctx, NGS_PileupEventGetMappingQuality ); break; /* MAPQ */
2233         case 5  : ngs_cursor_pileupevent_str( self, sql_ctx, ctx, NGS_PileupEventGetAlignmentId ); break; /* ALIG */
2234         case 6  : ngs_cursor_pileupevent_i64( self, sql_ctx, ctx, NGS_PileupEventGetAlignmentPosition ); break; /* ALIG_POS */
2235         case 7  : ngs_cursor_pileupevent_i64( self, sql_ctx, ctx, NGS_PileupEventGetFirstAlignmentPosition ); break; /* ALIG_FIRST */
2236         case 8  : ngs_cursor_pileupevent_i64( self, sql_ctx, ctx, NGS_PileupEventGetLastAlignmentPosition ); break; /* ALIG_LAST */
2237         case 9  : ngs_cursor_pileupevent_t( self, sql_ctx, ctx, 0x01 ); break; /* MISMATCH */
2238         case 10 : ngs_cursor_pileupevent_t( self, sql_ctx, ctx, 0x02 ); break; /* DELETION */
2239         case 11 : ngs_cursor_pileupevent_t( self, sql_ctx, ctx, 0x08 ); break; /* INSERTION */
2240         case 12 : ngs_cursor_pileupevent_t( self, sql_ctx, ctx, 0x20 ); break; /* REV_STRAND */
2241         case 13 : ngs_cursor_pileupevent_t( self, sql_ctx, ctx, 0x40 ); break; /* START */
2242         case 14 : ngs_cursor_pileupevent_t( self, sql_ctx, ctx, 0x80 ); break; /* STOP */
2243         case 15 : ngs_cursor_pileupevent_char( self, sql_ctx, ctx, NGS_PileupEventGetAlignmentBase ); break; /*ALIG_BASE */
2244         case 16 : ngs_cursor_pileupevent_char( self, sql_ctx, ctx, NGS_PileupEventGetAlignmentQuality ); break; /*ALIG_QUAL */
2245         case 17 : ngs_cursor_pileupevent_str( self, sql_ctx, ctx, NGS_PileupEventGetInsertionBases ); break; /* INS_BASE */
2246         case 18 : ngs_cursor_pileupevent_str( self, sql_ctx, ctx, NGS_PileupEventGetInsertionQualities ); break; /* INS_QUAL */
2247         case 19 : ngs_cursor_pileupevent_repeat( self, sql_ctx, ctx ); break; /* REPEAT */
2248         case 20 : ngs_cursor_pileupevent_int( self, sql_ctx, ctx, NGS_PileupEventGetIndelType ); break; /* INDEL */
2249     }
2250 }
2251 
ngs_cursor_column_rd_grp_name(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2252 static void ngs_cursor_column_rd_grp_name( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2253 {
2254     NGS_String * m_seq = NGS_ReadGroupGetName( self->m_rd_grp, ctx );
2255     if ( !FAILED() )
2256         ngs_return_NGS_String( sql_ctx, ctx, m_seq );
2257 }
2258 
2259 /* >>>>>>>>>> columns for READGROUPS-STYLE <<<<<<<<<<<< */
ngs_cursor_column_rd_grp(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,int column_id)2260 static void ngs_cursor_column_rd_grp( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx, int column_id )
2261 {
2262     switch( column_id )
2263     {
2264         case 0 : ngs_cursor_column_rd_grp_name( self, sql_ctx, ctx ); break; /* NAME */
2265     }
2266 }
2267 
2268 
ngs_cursor_refs_str(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,struct NGS_String * f (NGS_Reference * self,ctx_t ctx))2269 static void ngs_cursor_refs_str( ngs_cursor * self,
2270                                sqlite3_context * sql_ctx,
2271                                ctx_t ctx,
2272                                struct NGS_String * f( NGS_Reference * self, ctx_t ctx ) )
2273 {
2274     NGS_String * name = f( self->m_refs, ctx );
2275     if ( !FAILED() )
2276         ngs_return_NGS_String( sql_ctx, ctx, name );
2277 }
2278 
ngs_cursor_refs_circular(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2279 static void ngs_cursor_refs_circular( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2280 {
2281     bool b = NGS_ReferenceGetIsCircular( self->m_refs, ctx );
2282     if ( !FAILED() )
2283         sqlite3_result_int( sql_ctx, b ? 1 : 0 );
2284 }
2285 
ngs_cursor_refs_length(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx)2286 static void ngs_cursor_refs_length( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx )
2287 {
2288     uint64_t value = NGS_ReferenceGetLength( self->m_refs, ctx );
2289     if ( !FAILED() )
2290         sqlite3_result_int64( sql_ctx, value );
2291 }
2292 
2293 /* >>>>>>>>>> columns for REFS-STYLE <<<<<<<<<<<< */
ngs_cursor_column_refs(ngs_cursor * self,sqlite3_context * sql_ctx,ctx_t ctx,int column_id)2294 static void ngs_cursor_column_refs( ngs_cursor * self, sqlite3_context * sql_ctx, ctx_t ctx, int column_id )
2295 {
2296     switch( column_id )
2297     {
2298         case 0 : ngs_cursor_refs_str( self, sql_ctx, ctx, NGS_ReferenceGetCommonName ); break; /* NAME */
2299         case 1 : ngs_cursor_refs_str( self, sql_ctx, ctx, NGS_ReferenceGetCanonicalName ); break; /* ID */
2300         case 2 : ngs_cursor_refs_circular( self, sql_ctx, ctx ); break; /* CIRC */
2301         case 3 : ngs_cursor_refs_length( self, sql_ctx, ctx ); break; /* LEN */
2302     }
2303 }
2304 
ngs_cursor_column(ngs_cursor * self,sqlite3_context * sql_ctx,int column_id)2305 static int ngs_cursor_column( ngs_cursor * self, sqlite3_context * sql_ctx, int column_id )
2306 {
2307     HYBRID_FUNC_ENTRY( rcSRA, rcRow, rcAccessing );
2308 
2309     if ( self->desc->verbosity > 2 )
2310         printf( "---sqlite3_ngs_Column( %d )\n", column_id );
2311 
2312     switch( self->desc->style )
2313     {
2314         case NGS_STYLE_READS      : ngs_cursor_column_read( self, sql_ctx, ctx, column_id ); break;
2315         case NGS_STYLE_FRAGMENTS  : ngs_cursor_column_frag( self, sql_ctx, ctx, column_id ); break;
2316         case NGS_STYLE_ALIGNMENTS : ngs_cursor_column_alig( self, sql_ctx, ctx, column_id ); break;
2317         case NGS_STYLE_PILEUP     : ngs_cursor_column_pileup( self, sql_ctx, ctx, column_id ); break;
2318         case NGS_STYLE_READGROUPS : ngs_cursor_column_rd_grp( self, sql_ctx, ctx, column_id ); break;
2319         case NGS_STYLE_REFS       : ngs_cursor_column_refs( self, sql_ctx, ctx, column_id ); break;
2320     }
2321 
2322     if ( FAILED() )
2323     {
2324         CLEAR();
2325         return SQLITE_ERROR;
2326     }
2327     return SQLITE_OK;
2328 }
2329 
ngs_cursor_row_id(ngs_cursor * self,sqlite_int64 * pRowid)2330 static int ngs_cursor_row_id( ngs_cursor * self, sqlite_int64 * pRowid )
2331 {
2332     if ( self->desc->verbosity > 2 )
2333         printf( "---sqlite3_ngs_Rowid()\n" );
2334     if ( pRowid != NULL )
2335         *pRowid = self->current_row;
2336     return SQLITE_OK;
2337 }
2338 
2339 /* -------------------------------------------------------------------------------------- */
2340 /* take ngs-obj and open a read-collection on it */
ngs_obj_open(ngs_obj * self,sqlite3_vtab_cursor ** ppCursor)2341 static int ngs_obj_open( ngs_obj * self, sqlite3_vtab_cursor ** ppCursor )
2342 {
2343     if ( self->desc.verbosity > 1 )
2344         printf( "---sqlite3_ngs_Open()\n" );
2345     ngs_cursor * c = make_ngs_cursor( &self->desc );
2346     if ( c != NULL )
2347     {
2348         *ppCursor = ( sqlite3_vtab_cursor * )c;
2349         return SQLITE_OK;
2350     }
2351     return SQLITE_ERROR;
2352 }
2353 
2354 /* -------------------------------------------------------------------------------------- */
2355 /* the common code for xxx_Create() and xxx_Connect */
sqlite3_ngs_CC(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr,const char * msg)2356 static int sqlite3_ngs_CC( sqlite3 *db, void *pAux, int argc, const char * const * argv,
2357                            sqlite3_vtab **ppVtab, char **pzErr, const char * msg )
2358 {
2359     const char * stm;
2360     ngs_obj * obj = make_ngs_obj( argc, argv );
2361     if ( obj == NULL )
2362         return SQLITE_ERROR;
2363 
2364     *ppVtab = ( sqlite3_vtab * )obj;
2365 
2366     if ( obj->desc.verbosity > 1 )
2367         printf( "%s", msg );
2368 
2369     stm = make_ngs_create_table_stm( &obj->desc, "X" );
2370     if ( obj->desc.verbosity > 1 )
2371         printf( "stm = %s\n", stm );
2372     return sqlite3_declare_vtab( db, stm );
2373 }
2374 
2375 
2376 /* -------------------------------------------------------------------------------------- */
2377 /* create a new table-instance from scratch */
sqlite3_ngs_Create(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)2378 static int sqlite3_ngs_Create( sqlite3 *db, void *pAux, int argc, const char * const * argv,
2379                                sqlite3_vtab **ppVtab, char **pzErr )
2380 {
2381     return sqlite3_ngs_CC( db, pAux, argc, argv, ppVtab, pzErr, "---sqlite3_ngs_Create()\n" );
2382 }
2383 
2384 /* open a table-instance from something existing */
sqlite3_ngs_Connect(sqlite3 * db,void * pAux,int argc,const char * const * argv,sqlite3_vtab ** ppVtab,char ** pzErr)2385 static int sqlite3_ngs_Connect( sqlite3 *db, void *pAux, int argc, const char * const * argv,
2386                                 sqlite3_vtab **ppVtab, char **pzErr )
2387 {
2388     return sqlite3_ngs_CC( db, pAux, argc, argv, ppVtab, pzErr, "---sqlite3_ngs_Connect()\n" );
2389 }
2390 
2391 /* query what index can be used ---> maybe vdb supports that in the future */
sqlite3_ngs_BestIndex(sqlite3_vtab * tab,sqlite3_index_info * pIdxInfo)2392 static int sqlite3_ngs_BestIndex( sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo )
2393 {
2394     int res = SQLITE_ERROR;
2395     if ( tab != NULL )
2396     {
2397         ngs_obj * self = ( ngs_obj * )tab;
2398         if ( self->desc.verbosity > 2 )
2399             printf( "---sqlite3_ngs_BestIndex()\n" );
2400         if ( pIdxInfo != NULL )
2401             pIdxInfo->estimatedCost = 1000000;
2402         res = SQLITE_OK;
2403     }
2404     return res;
2405 }
2406 
2407 /* disconnect from a table */
sqlite3_ngs_Disconnect(sqlite3_vtab * tab)2408 static int sqlite3_ngs_Disconnect( sqlite3_vtab *tab )
2409 {
2410     if ( tab != NULL )
2411         return destroy_ngs_obj( ( ngs_obj * )tab );
2412     return SQLITE_ERROR;
2413 }
2414 
2415 /* open a cursor on a table */
sqlite3_ngs_Open(sqlite3_vtab * tab,sqlite3_vtab_cursor ** ppCursor)2416 static int sqlite3_ngs_Open( sqlite3_vtab *tab, sqlite3_vtab_cursor **ppCursor )
2417 {
2418     if ( tab != NULL )
2419         return ngs_obj_open( ( ngs_obj * ) tab, ppCursor );
2420     return SQLITE_ERROR;
2421 }
2422 
2423 /* close the cursor */
sqlite3_ngs_Close(sqlite3_vtab_cursor * cur)2424 static int sqlite3_ngs_Close( sqlite3_vtab_cursor *cur )
2425 {
2426     if ( cur != NULL )
2427         destroy_ngs_cursor( ( ngs_cursor * )cur );
2428     return SQLITE_ERROR;
2429 }
2430 
2431 /* this is a NOOP, because we have no index ( yet ) */
sqlite3_ngs_Filter(sqlite3_vtab_cursor * cur,int idxNum,const char * idxStr,int argc,sqlite3_value ** argv)2432 static int sqlite3_ngs_Filter( sqlite3_vtab_cursor *cur, int idxNum, const char *idxStr,
2433                         int argc, sqlite3_value **argv )
2434 {
2435     if ( cur != NULL )
2436     {
2437         ngs_cursor * self = ( ngs_cursor * )cur;
2438         if ( self->desc->verbosity > 2 )
2439             printf( "---sqlite3_ngs_Filter()\n" );
2440         return SQLITE_OK;
2441     }
2442     return SQLITE_ERROR;
2443 }
2444 
2445 /* advance to the next row */
sqlite3_ngs_Next(sqlite3_vtab_cursor * cur)2446 static int sqlite3_ngs_Next( sqlite3_vtab_cursor *cur )
2447 {
2448     if ( cur != NULL )
2449         return ngs_cursor_next( ( ngs_cursor * )cur );
2450     return SQLITE_ERROR;
2451 }
2452 
2453 /* check if we are at the end */
sqlite3_ngs_Eof(sqlite3_vtab_cursor * cur)2454 static int sqlite3_ngs_Eof( sqlite3_vtab_cursor *cur )
2455 {
2456      if ( cur != NULL )
2457         return ngs_cursor_eof( ( ngs_cursor * )cur );
2458     return SQLITE_ERROR;
2459 }
2460 
2461 /* request data for a cell */
sqlite3_ngs_Column(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int column_id)2462 static int sqlite3_ngs_Column( sqlite3_vtab_cursor *cur, sqlite3_context * ctx, int column_id )
2463 {
2464     if ( cur != NULL )
2465         return ngs_cursor_column( ( ngs_cursor * )cur, ctx, column_id );
2466     return SQLITE_ERROR;
2467 }
2468 
2469 /* request row-id */
sqlite3_ngs_Rowid(sqlite3_vtab_cursor * cur,sqlite_int64 * pRowid)2470 static int sqlite3_ngs_Rowid( sqlite3_vtab_cursor *cur, sqlite_int64 * pRowid )
2471 {
2472     if ( cur != NULL )
2473         return ngs_cursor_row_id( ( ngs_cursor * )cur, pRowid );
2474     return SQLITE_ERROR;
2475 }
2476 
2477 
2478 sqlite3_module NGS_Module =
2479 {
2480   0,                            /* iVersion */
2481   sqlite3_ngs_Create,           /* xCreate */
2482   sqlite3_ngs_Connect,          /* xConnect */
2483   sqlite3_ngs_BestIndex,        /* xBestIndex */
2484   sqlite3_ngs_Disconnect,       /* xDisconnect */
2485   sqlite3_ngs_Disconnect,       /* xDestroy */
2486   sqlite3_ngs_Open,             /* xOpen - open a cursor */
2487   sqlite3_ngs_Close,            /* xClose - close a cursor */
2488   sqlite3_ngs_Filter,           /* xFilter - configure scan constraints */
2489   sqlite3_ngs_Next,             /* xNext - advance a cursor */
2490   sqlite3_ngs_Eof,              /* xEof - check for end of scan */
2491   sqlite3_ngs_Column,           /* xColumn - read data */
2492   sqlite3_ngs_Rowid,            /* xRowid - read data */
2493   NULL,                         /* xUpdate */
2494   NULL,                         /* xBegin */
2495   NULL,                         /* xSync */
2496   NULL,                         /* xCommit */
2497   NULL,                         /* xRollback */
2498   NULL,                         /* xFindMethod */
2499   NULL,                         /* xRename */
2500 };
2501 
2502 
2503 /* ========================================================================================================== */
2504 
2505 #ifdef _WIN32
2506 __declspec( dllexport )
2507 #endif
2508 
2509 /*
2510 ** This routine is called when the extension is loaded.  The new vdb/ngs virtual table module is
2511 ** registered with the calling database connection.
2512 */
sqlite3_vdbsqlite_init(sqlite3 * db,char ** pzErrMsg,const sqlite3_api_routines * pApi)2513 int sqlite3_vdbsqlite_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi )
2514 {
2515     int res = SQLITE_OK;
2516 #ifndef SQLITE_OMIT_VIRTUALTABLE
2517     SQLITE_EXTENSION_INIT2( pApi );
2518     res = sqlite3_create_module( db, "vdb", &VDB_Module, NULL );
2519     if ( res == SQLITE_OK )
2520         res = sqlite3_create_module( db, "ngs", &NGS_Module, NULL );
2521 #endif
2522     return res;
2523 }
2524