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