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 <kdb/extern.h>
28 
29 #include <kdb/rowset.h>
30 #include <kdb/rowset-impl.h>
31 #include <kfc/ctx.h>
32 #include <kfc/except.h>
33 #include <kfc/xc.h>
34 
35 KITFTOK_DEF ( KRowSet );
36 KITFTOK_DEF ( KRowSetIterator );
37 
38 /* MakeRowSet
39  *  may add others...
40  */
KTableMakeRowSet(struct KTable const * self,ctx_t ctx)41 KDB_EXTERN KRowSet * CC KTableMakeRowSet ( struct KTable const * self, ctx_t ctx )
42 {
43     return KTableMakeRowSetSimple ( self, ctx );
44 }
45 
46 /* Init
47  *  initialize a newly allocated rowset object
48  */
KRowSetInit(KRowSet * self,ctx_t ctx,const KVTable * kvt,const char * classname)49 KDB_EXTERN void CC KRowSetInit ( KRowSet *self, ctx_t ctx, const KVTable *kvt,
50     const char *classname )
51 {
52     FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcInitializing );
53 
54     if ( self == NULL )
55         INTERNAL_ERROR ( xcSelfNull, "KRowSetInit failed" );
56     else if ( kvt == NULL )
57         INTERNAL_ERROR ( xcParamNull, "KRowSetInit failed: vt is NULL" );
58     else
59     {
60         TRY ( KRefcountInit_v1 ( & self -> dad, ctx, kvt, classname ) )
61         {
62             const KRowSet_v1_vt *vt = KVTABLE_CAST ( kvt, ctx, KRowSet );
63             if ( vt == NULL )
64                 INTERNAL_ERROR ( xcInterfaceIncorrect, "vtable does not appear to implement KRowSet" );
65             else switch ( vt -> dad . min )
66             {
67             case 0:
68 #if _DEBUGGING
69                 if ( vt -> destroy_data == NULL         ||
70                      vt -> add_row_id_range == NULL     ||
71                      vt -> get_num_rows == NULL         ||
72                      vt -> has_row_id == NULL           ||
73                      vt -> get_iterator == NULL )
74                 {
75                     INTERNAL_ERROR ( xcInterfaceInvalid, "null method pointer(s)" );
76                     return;
77                 }
78 #endif
79                 break;
80             default:
81                 INTERNAL_ERROR ( xcInterfaceInvalid, "rowset has an invalid version" );
82             }
83 
84         }
85     }
86 }
87 
88 /* AddRowId
89  *  add a single row to set
90  *
91  *  "row_id" [ IN ] - row-id to be added
92  */
KRowSetAddRowId(KRowSet * self,ctx_t ctx,int64_t row_id)93 KDB_EXTERN void CC KRowSetAddRowId ( KRowSet * self, ctx_t ctx, int64_t row_id )
94 {
95     KRowSetAddRowIdRange ( self, ctx, row_id, 1 );
96 }
97 
98 /* AddRowIdRange
99  *  adds row-ids within specified range
100  *
101  *  "row_id" [ IN ] and "count" [ IN ] - range of row-ids to be added
102  */
KRowSetAddRowIdRange(KRowSet * self,ctx_t ctx,int64_t row_id,uint64_t count)103 KDB_EXTERN void CC KRowSetAddRowIdRange ( KRowSet * self, ctx_t ctx, int64_t row_id, uint64_t count )
104 {
105     if ( self == NULL )
106     {
107         FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcInserting );
108         INTERNAL_ERROR ( xcSelfNull, "failed to insert rows into rowset" );
109     }
110     else
111     {
112         const KRowSet_v1_vt * vt = KVTABLE_CAST ( TO_REFCOUNT_V1 ( self ) -> vt, ctx, KRowSet );
113         if ( vt == NULL )
114         {
115             FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcInserting );
116             INTERNAL_ERROR ( xcInterfaceIncorrect, "this object does not support the KRowSet interface" );
117         }
118         else
119             vt -> add_row_id_range ( self, ctx, row_id, count );
120     }
121 }
122 
123 /* GetNumRowIds
124  *  return the number of elements in set
125  */
KRowSetGetNumRowIds(const KRowSet * self,ctx_t ctx)126 KDB_EXTERN uint64_t CC KRowSetGetNumRowIds ( const KRowSet * self, ctx_t ctx )
127 {
128     if ( self == NULL )
129     {
130         FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcAccessing );
131         INTERNAL_ERROR ( xcSelfNull, "failed to get number of rows in rowset" );
132     }
133     else
134     {
135         const KRowSet_v1_vt * vt = KVTABLE_CAST ( TO_REFCOUNT_V1 ( self ) -> vt, ctx, KRowSet );
136         if ( vt == NULL )
137         {
138             FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcAccessing );
139             INTERNAL_ERROR ( xcInterfaceIncorrect, "this object does not support the KRowSet interface" );
140         }
141         else
142             return vt -> get_num_rows ( self, ctx );
143     }
144 
145     return 0;
146 }
147 
148 /* HasRowId
149  *  checks if element is present in set
150  */
KRowSetHasRowId(const KRowSet * self,ctx_t ctx,int64_t row_id)151 KDB_EXTERN bool CC KRowSetHasRowId ( const KRowSet * self, ctx_t ctx, int64_t row_id )
152 {
153     if ( self == NULL )
154     {
155         FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcAccessing );
156         INTERNAL_ERROR ( xcSelfNull, "failed to find row in rowset" );
157     }
158     else
159     {
160         const KRowSet_v1_vt * vt = KVTABLE_CAST ( TO_REFCOUNT_V1 ( self ) -> vt, ctx, KRowSet );
161         if ( vt == NULL )
162         {
163             FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcAccessing );
164             INTERNAL_ERROR ( xcInterfaceIncorrect, "this object does not support the KRowSet interface" );
165         }
166         else
167             return vt -> has_row_id ( self, ctx, row_id );
168     }
169 
170     return false;
171 }
172 
173 /* Visit
174  *  execute a function on each row-id in set
175  */
KRowSetVisit(const KRowSet * self,ctx_t ctx,void (CC * f)(ctx_t ctx,int64_t row_id,void * data),void * data)176 KDB_EXTERN void CC KRowSetVisit ( const KRowSet * self, ctx_t ctx,
177     void ( CC * f ) ( ctx_t ctx, int64_t row_id, void * data ), void * data )
178 {
179     FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcAccessing );
180     KRowSetIterator * it;
181 
182     if ( self == NULL )
183         INTERNAL_ERROR ( xcSelfNull, "failed to iterate over rowset" );
184     else
185     {
186         TRY ( it = KRowSetMakeIterator ( self, ctx ) )
187         {
188             while ( !FAILED() && KRowSetIteratorIsValid ( it ) )
189             {
190                 int64_t row_id;
191                 ON_FAIL ( row_id = KRowSetIteratorGetRowId ( it, ctx ) )
192                     break;
193 
194                 ON_FAIL ( f ( ctx, row_id, data ) )
195                     break;
196 
197                 KRowSetIteratorNext ( it, ctx );
198             }
199 
200             KRowSetIteratorRelease ( it, ctx );
201         }
202     }
203 }
204 
205 /* Intersect
206  *  performs an intersection between two sets and returns the result
207  */
KRowSetIntersect(ctx_t ctx,const KRowSet * a,const KRowSet * b)208 KDB_EXTERN KRowSet * CC KRowSetIntersect ( ctx_t ctx, const KRowSet * a, const KRowSet * b )
209 {
210     FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcProcessing );
211     KRowSet * result;
212 
213     if ( a -> table != b -> table )
214         USER_ERROR ( xcParamIncorrect, "cannot intersect rowsets from different tables" );
215     else
216     {
217         TRY ( result = KTableMakeRowSet ( a -> table, ctx ) )
218         {
219             KRowSetIterator * a_it;
220             KRowSetIterator * b_it;
221             TRY ( a_it = KRowSetMakeIterator ( a, ctx ) )
222             {
223                 TRY ( b_it = KRowSetMakeIterator ( b, ctx ) )
224                 {
225                     while ( !FAILED() && KRowSetIteratorIsValid ( a_it ) && KRowSetIteratorIsValid ( b_it ) )
226                     {
227                         int64_t a_row_id;
228                         int64_t b_row_id;
229                         ON_FAIL ( a_row_id = KRowSetIteratorGetRowId ( a_it, ctx ) )
230                             break;
231 
232                         ON_FAIL ( b_row_id = KRowSetIteratorGetRowId ( b_it, ctx ) )
233                             break;
234 
235                         if ( a_row_id < b_row_id )
236                             KRowSetIteratorNext ( a_it, ctx );
237                         else if ( a_row_id > b_row_id )
238                             KRowSetIteratorNext ( b_it, ctx );
239                         else
240                         {
241                             TRY ( KRowSetAddRowId ( result, ctx, a_row_id ) )
242                             {
243                                 TRY ( KRowSetIteratorNext ( a_it, ctx ) )
244                                 {
245                                     KRowSetIteratorNext ( b_it, ctx );
246                                 }
247                             }
248                         }
249                     }
250                     KRowSetIteratorRelease ( b_it, ctx );
251                 }
252                 KRowSetIteratorRelease ( a_it, ctx );
253             }
254             if ( !FAILED() )
255                 return result;
256 
257             KRowSetRelease ( result, ctx );
258         }
259     }
260 
261     return NULL;
262 }
263 
264 /* Union
265  *  performs a union between two sets and returns the result
266  */
KRowSetUnion(ctx_t ctx,const KRowSet * a,const KRowSet * b)267 KDB_EXTERN KRowSet * CC KRowSetUnion ( ctx_t ctx, const KRowSet * a, const KRowSet * b )
268 {
269     FUNC_ENTRY ( ctx, rcDB, rcRowSet, rcProcessing );
270     KRowSet * result;
271 
272     if ( a -> table != b -> table )
273         USER_ERROR ( xcParamIncorrect, "cannot intersect rowsets from different tables" );
274     else
275     {
276         TRY ( result = KTableMakeRowSet ( a -> table, ctx ) )
277         {
278             KRowSetIterator * a_it;
279             KRowSetIterator * b_it;
280             TRY ( a_it = KRowSetMakeIterator ( a, ctx ) )
281             {
282                 TRY ( b_it = KRowSetMakeIterator ( b, ctx ) )
283                 {
284                     while ( !FAILED() && KRowSetIteratorIsValid ( a_it ) && KRowSetIteratorIsValid ( b_it ) )
285                     {
286                         int64_t a_row_id;
287                         int64_t b_row_id;
288                         ON_FAIL ( a_row_id = KRowSetIteratorGetRowId ( a_it, ctx ) )
289                             break;
290 
291                         ON_FAIL ( b_row_id = KRowSetIteratorGetRowId ( b_it, ctx ) )
292                             break;
293 
294                         if ( a_row_id < b_row_id )
295                         {
296                             TRY ( KRowSetAddRowId ( result, ctx, a_row_id ) )
297                             {
298                                 KRowSetIteratorNext ( a_it, ctx );
299                             }
300                         }
301                         else if ( a_row_id > b_row_id )
302                         {
303                             TRY ( KRowSetAddRowId ( result, ctx, b_row_id ) )
304                             {
305                                 KRowSetIteratorNext ( b_it, ctx );
306                             }
307                         }
308                         else
309                         {
310                             TRY ( KRowSetAddRowId ( result, ctx, a_row_id ) )
311                             {
312                                 TRY ( KRowSetIteratorNext ( a_it, ctx ) )
313                                 {
314                                     KRowSetIteratorNext ( b_it, ctx );
315                                 }
316                             }
317                         }
318                     }
319                     while ( !FAILED() && KRowSetIteratorIsValid ( a_it ) )
320                     {
321                         int64_t a_row_id;
322                         TRY ( a_row_id = KRowSetIteratorGetRowId ( a_it, ctx ) )
323                         {
324                             TRY ( KRowSetAddRowId ( result, ctx, a_row_id ) )
325                             {
326                                 KRowSetIteratorNext ( a_it, ctx );
327                             }
328                         }
329                     }
330                     while ( !FAILED() && KRowSetIteratorIsValid ( b_it ) )
331                     {
332                         int64_t b_row_id;
333                         TRY ( b_row_id = KRowSetIteratorGetRowId ( b_it, ctx ) )
334                         {
335                             TRY ( KRowSetAddRowId ( result, ctx, b_row_id ) )
336                             {
337                                 KRowSetIteratorNext ( b_it, ctx );
338                             }
339                         }
340                     }
341                     KRowSetIteratorRelease ( b_it, ctx );
342                 }
343                 KRowSetIteratorRelease ( a_it, ctx );
344             }
345             if ( !FAILED() )
346                 return result;
347 
348             KRowSetRelease ( result, ctx );
349         }
350     }
351 
352     return NULL;
353 }
354 
355 /* MakeIterator
356  *  create an iterator on set
357  *  initially set to first row-id in set
358  */
KRowSetMakeIterator(const KRowSet * self,ctx_t ctx)359 KDB_EXTERN KRowSetIterator * CC KRowSetMakeIterator ( const KRowSet * self, ctx_t ctx )
360 {
361     if ( self == NULL )
362     {
363         FUNC_ENTRY ( ctx, rcDB, rcIterator, rcCreating );
364         INTERNAL_ERROR ( xcSelfNull, "failed to create rowset iterator" );
365     }
366     else
367     {
368         const KRowSet_v1_vt * vt = KVTABLE_CAST ( TO_REFCOUNT_V1 ( self ) -> vt, ctx, KRowSet );
369         if ( vt == NULL )
370         {
371             FUNC_ENTRY ( ctx, rcDB, rcIterator, rcCreating );
372             INTERNAL_ERROR ( xcInterfaceIncorrect, "this object does not support the KRowSet interface" );
373         }
374         else
375             return vt -> get_iterator ( self, ctx );
376     }
377 
378     return NULL;
379 }
380 
381 /* Init
382  *  initialize a newly allocated rowset iterator object
383  */
KRowSetIteratorInit(KRowSetIterator * self,ctx_t ctx,const KVTable * kvt,const char * classname)384 KDB_EXTERN void CC KRowSetIteratorInit ( KRowSetIterator *self, ctx_t ctx, const KVTable *kvt,
385     const char *classname )
386 {
387     FUNC_ENTRY ( ctx, rcDB, rcIterator, rcInitializing );
388 
389     if ( self == NULL )
390         INTERNAL_ERROR ( xcSelfNull, "KRowSetIteratorInit failed" );
391     else if ( kvt == NULL )
392         INTERNAL_ERROR ( xcParamNull, "KRowSetIteratorInit failed: vt is NULL" );
393     else
394     {
395         TRY ( KRefcountInit_v1 ( & self -> dad, ctx, kvt, classname ) )
396         {
397             const KRowSetIterator_v1_vt *vt = KVTABLE_CAST ( kvt, ctx, KRowSetIterator );
398             if ( vt == NULL )
399                 INTERNAL_ERROR ( xcInterfaceIncorrect, "vtable does not appear to implement KRowSetIterator" );
400             else switch ( vt -> dad . min )
401             {
402             case 0:
403 #if _DEBUGGING
404                 if ( vt -> next == NULL            ||
405                      vt -> is_valid == NULL        ||
406                      vt -> get_row_id == NULL )
407                 {
408                     INTERNAL_ERROR ( xcInterfaceNull, "KRowSetIteratorInit failed" );
409                     return;
410                 }
411 #endif
412                 break;
413             default:
414                 INTERNAL_ERROR ( xcInterfaceBadVersion, "rowset iterator has an invalid version" );
415             }
416 
417         }
418     }
419 }
420 
421 /* Next
422  *  advance iterator to next row-id
423 
424  *  advance to first row-id on initial invocation
425  *  advance to next row-id subsequently
426  *  returns rcDone if no more row-ids are available.
427  */
KRowSetIteratorNext(KRowSetIterator * self,ctx_t ctx)428 KDB_EXTERN bool CC KRowSetIteratorNext ( KRowSetIterator * self, ctx_t ctx )
429 {
430 
431     if ( self == NULL )
432     {
433         FUNC_ENTRY ( ctx, rcDB, rcIterator, rcPositioning );
434         INTERNAL_ERROR ( xcSelfNull, "failed to move rowset iterator" );
435     }
436     else
437     {
438         const KRowSetIterator_v1_vt * vt = KVTABLE_CAST ( TO_REFCOUNT_V1 ( self ) -> vt, ctx, KRowSetIterator );
439         if ( vt == NULL )
440         {
441             FUNC_ENTRY ( ctx, rcDB, rcIterator, rcPositioning );
442             INTERNAL_ERROR ( xcInterfaceIncorrect, "this object does not support the KRowSetIterator interface" );
443         }
444         else
445             return vt -> next ( self, ctx );
446     }
447 
448     return false;
449 }
450 
451 /*IsValid
452  * check if iterator points to a valid row
453  *
454  * returns false when iterator points somewhere outside of a row set
455  */
KRowSetIteratorIsValid(const KRowSetIterator * self)456 KDB_EXTERN bool CC KRowSetIteratorIsValid ( const KRowSetIterator * self )
457 {
458     if ( self != NULL )
459     {
460         HYBRID_FUNC_ENTRY ( rcDB, rcIterator, rcAccessing );
461         const KRowSetIterator_v1_vt * vt = KVTABLE_CAST ( TO_REFCOUNT_V1 ( self ) -> vt, ctx, KRowSetIterator );
462         if ( vt == NULL )
463             INTERNAL_ERROR ( xcInterfaceIncorrect, "this object does not support the KRowSetIterator interface" );
464         else
465             return vt -> is_valid ( self );
466     }
467 
468     return false;
469 }
470 
471 /* RowId
472  *  report current row id
473  */
KRowSetIteratorGetRowId(const KRowSetIterator * self,ctx_t ctx)474 KDB_EXTERN int64_t CC KRowSetIteratorGetRowId ( const KRowSetIterator * self, ctx_t ctx )
475 {
476     if ( self == NULL )
477     {
478         FUNC_ENTRY ( ctx, rcDB, rcIterator, rcAccessing );
479         INTERNAL_ERROR ( xcSelfNull, "failed to access rowset iterator" );
480     }
481     else
482     {
483         const KRowSetIterator_v1_vt * vt = KVTABLE_CAST ( TO_REFCOUNT_V1 ( self ) -> vt, ctx, KRowSetIterator );
484         if ( vt == NULL )
485         {
486             FUNC_ENTRY ( ctx, rcDB, rcIterator, rcAccessing );
487             INTERNAL_ERROR ( xcInterfaceIncorrect, "this object does not support the KRowSetIterator interface" );
488         }
489         else
490             return vt -> get_row_id ( self, ctx );
491     }
492 
493     return -1;
494 }
495