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