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 #define KONST const
30 #include "index-priv.h"
31 #include "dbmgr-priv.h"
32 #include "database-priv.h"
33 #include "table-priv.h"
34 #include "kdb-priv.h"
35 #undef KONST
36
37 #include <kdb/index.h>
38 #include <kfs/file.h>
39 #include <kfs/mmap.h>
40 #include <klib/refcount.h>
41 #include <klib/rc.h>
42 #include <os-native.h>
43 #include <sysalloc.h>
44
45 #include <limits.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <byteswap.h>
50 #include <assert.h>
51
52 /*--------------------------------------------------------------------------
53 * KIndex
54 * an object capable of mapping an object to integer oid
55 */
56 struct KIndex
57 {
58 const KDBManager *mgr;
59 const KDatabase *db;
60 const KTable *tbl;
61 KRefcount refcount;
62 uint32_t vers;
63 union
64 {
65 KTrieIndex_v1 txt1;
66 KTrieIndex_v2 txt234;
67 KU64Index_v3 u64_3;
68 } u;
69 bool converted_from_v1;
70 uint8_t type;
71 char path [ 1 ];
72 };
73
74
75 /* Whack
76 */
77 static
KIndexWhack(KIndex * self)78 rc_t KIndexWhack ( KIndex *self )
79 {
80 rc_t rc = 0;
81
82 KRefcountWhack ( & self -> refcount, "KIndex" );
83
84 /* release owner */
85 if ( self -> db != NULL )
86 {
87 rc = KDatabaseSever ( self -> db );
88 if ( rc == 0 )
89 self -> db = NULL;
90 }
91 else if ( self -> tbl != NULL )
92 {
93 rc = KTableSever ( self -> tbl );
94 if ( rc == 0 )
95 self -> tbl = NULL;
96 }
97
98 /* remove from mgr */
99 if ( rc == 0 )
100 rc = KDBManagerSever ( self -> mgr );
101 if ( rc == 0 )
102 {
103 self -> mgr = NULL;
104
105 /* complete */
106 rc = SILENT_RC ( rcDB, rcIndex, rcDestroying, rcIndex, rcBadVersion );
107
108 switch ( self -> type )
109 {
110 case kitText:
111 case kitText | kitProj:
112 switch ( self -> vers )
113 {
114 case 1:
115 KTrieIndexWhack_v1 ( & self -> u . txt1 );
116 rc = 0;
117 break;
118 case 2:
119 case 3:
120 case 4:
121 KTrieIndexWhack_v2 ( & self -> u . txt234 );
122 rc = 0;
123 break;
124 }
125 break;
126
127 case kitU64:
128 switch ( self -> vers )
129 {
130 case 3:
131 case 4:
132 rc = KU64IndexWhack_v3 ( & self -> u . u64_3 );
133 break;
134 }
135 break;
136
137 }
138
139 if ( rc == 0 )
140 {
141 free ( self );
142 return 0;
143 }
144 }
145
146 KRefcountInit ( & self -> refcount, 1, "KIndex", "whack", "kidx" );
147 return rc;
148 }
149
150
151 /* AddRef
152 * Release
153 * all objects are reference counted
154 * NULL references are ignored
155 */
KIndexAddRef(const KIndex * self)156 LIB_EXPORT rc_t CC KIndexAddRef ( const KIndex *self )
157 {
158 if ( self != NULL )
159 {
160 switch ( KRefcountAdd ( & self -> refcount, "KIndex" ) )
161 {
162 case krefLimit:
163 return RC ( rcDB, rcIndex, rcAttaching, rcRange, rcExcessive );
164 }
165 }
166 return 0;
167 }
168
KIndexRelease(const KIndex * self)169 LIB_EXPORT rc_t CC KIndexRelease ( const KIndex *self )
170 {
171 if ( self != NULL )
172 {
173 switch ( KRefcountDrop ( & self -> refcount, "KIndex" ) )
174 {
175 case krefWhack:
176 return KIndexWhack ( ( KIndex* ) self );
177 case krefNegative:
178 return RC ( rcDB, rcIndex, rcReleasing, rcRange, rcExcessive );
179 }
180 }
181 return 0;
182 }
183
184
185 /* Make
186 */
187 static
KIndexMake(KIndex ** idxp,const char * path)188 rc_t KIndexMake ( KIndex **idxp, const char *path )
189 {
190 rc_t rc;
191
192 if ( idxp == NULL )
193 rc = RC ( rcDB, rcIndex, rcCreating, rcParam, rcNull );
194 else
195 {
196 if ( path == NULL )
197 rc = RC ( rcDB, rcIndex, rcCreating, rcPath, rcNull );
198 else if ( path [ 0 ] == 0 )
199 rc = RC ( rcDB, rcIndex, rcCreating, rcPath, rcEmpty );
200 else
201 {
202 KIndex* idx = malloc ( sizeof *idx + strlen ( path ) );
203 if ( idx == NULL )
204 rc = RC ( rcDB, rcIndex, rcConstructing, rcMemory, rcExhausted );
205 else
206 {
207 memset ( idx, 0, sizeof * idx );
208 KRefcountInit ( & idx -> refcount, 1, "KIndex", "make", path );
209 strcpy ( idx -> path, path );
210 * idxp = idx;
211 return 0;
212 }
213 }
214 }
215
216 return rc;
217 }
218
219 static
KIndexAttach(KIndex * self,const KMMap * mm,bool * byteswap)220 rc_t KIndexAttach ( KIndex *self, const KMMap *mm, bool *byteswap )
221 {
222 size_t size;
223 rc_t rc = KMMapSize ( mm, & size );
224 if ( rc == 0 )
225 {
226 const void *addr;
227 rc = KMMapAddrRead ( mm, & addr );
228 if ( rc == 0 )
229 {
230 union
231 {
232 KIndexFileHeader_v1 v1;
233 KIndexFileHeader_v2 v2;
234 KIndexFileHeader_v3 v3;
235 } hdrs;
236
237 const KDBHdr *hdr = addr;
238 const KIndexFileHeader_v3 *fh = addr;
239
240 * byteswap = false;
241 rc = KDBHdrValidate ( hdr, size, 1, KDBINDEXVERS );
242 if ( GetRCState ( rc ) == rcIncorrect && GetRCObject ( rc ) == rcByteOrder )
243 {
244 hdrs . v1 . endian = bswap_32 ( hdr -> endian );
245 hdrs . v1 . version = bswap_32 ( hdr -> version );
246 rc = KDBHdrValidate ( & hdrs . v1, size, 1, KDBINDEXVERS );
247 if ( rc == 0 )
248 {
249 * byteswap = true;
250 switch ( hdrs . v1 . version )
251 {
252 case 1:
253 hdr = & hdrs . v1;
254 break;
255 case 2:
256 hdr = & hdrs . v2;
257 break;
258 case 3:
259 case 4:
260 hdrs . v3 . index_type = bswap_32 ( fh -> index_type );
261 hdrs . v3 . reserved1 = bswap_32 ( fh -> reserved1 );
262 hdr = & hdrs . v3 . h;
263 fh = & hdrs . v3;
264 break;
265 }
266 }
267 }
268 if ( rc == 0 )
269 {
270 self -> vers = hdr -> version;
271 switch ( hdr -> version )
272 {
273 case 1:
274 #if KDBINDEXVERS != 1
275 self -> converted_from_v1 = true;
276 #endif
277 case 2:
278 self -> type = kitText;
279 break;
280 case 3:
281 case 4:
282 {
283 self -> type = fh -> index_type;
284 switch ( self -> type )
285 {
286 case kitText:
287 case kitU64:
288 break;
289 default:
290 rc = RC(rcDB, rcIndex, rcConstructing, rcIndex, rcUnrecognized);
291 }
292 break;
293 }
294 default:
295 rc = RC ( rcDB, rcIndex, rcConstructing, rcIndex, rcBadVersion );
296 }
297 }
298 }
299 }
300 return rc;
301 }
302
303 static
KIndexMakeRead(KIndex ** idxp,const KDirectory * dir,const char * path)304 rc_t KIndexMakeRead ( KIndex **idxp,
305 const KDirectory *dir, const char *path )
306 {
307 const KFile *f;
308 rc_t rc = KDirectoryOpenFileRead ( dir, & f, "%s", path );
309 if ( rc == 0 )
310 {
311 const KMMap *mm;
312 rc = KMMapMakeRead ( & mm, f );
313 if ( rc == 0 )
314 {
315 rc = KIndexMake ( idxp, path );
316 if ( rc == 0 )
317 {
318 bool byteswap;
319 KIndex *idx = * idxp;
320 rc = KIndexAttach ( idx, mm, & byteswap );
321 if ( rc == 0 )
322 {
323 rc = RC ( rcDB, rcIndex, rcConstructing, rcIndex, rcBadVersion );
324
325 switch ( idx -> vers )
326 {
327 case 1:
328 /* open using v1 code only if KDBINDEXVERS is 1
329 if 2 or later, open as a v2 index */
330 #if KDBINDEXVERS == 1
331 rc = KTrieIndexOpen_v1 ( & idx -> u . txt1, mm );
332 if ( rc == 0 )
333 {
334 if ( idx -> u . txt1 . pt . id2node != NULL )
335 idx -> type = ( uint8_t ) ( kitText | kitProj );
336 else
337 idx -> type = ( uint8_t ) kitText;
338 }
339 break;
340 #else
341 case 2:
342 idx -> vers = 3;
343 case 3:
344 case 4:
345 switch ( idx -> type )
346 {
347 case kitText:
348 case kitText | kitProj:
349 /* will guess version in open */
350 rc = KTrieIndexOpen_v2 ( & idx -> u . txt234, mm, byteswap );
351 if( rc == 0 && idx -> u . txt234 . pt . ord2node != NULL )
352 idx -> type |= kitProj;
353 break;
354
355 case kitU64:
356 rc = KU64IndexOpen_v3 ( & idx -> u . u64_3, mm, byteswap );
357 break;
358 }
359 break;
360 #endif
361 }
362 }
363
364 if ( rc != 0 )
365 KIndexWhack ( idx );
366 }
367
368 KMMapRelease ( mm );
369 }
370
371 KFileRelease ( f );
372 }
373 return rc;
374 }
375
376
377 /* OpenIndexRead
378 * VOpenIndexRead
379 * open an index for read
380 *
381 * "idx" [ OUT ] - return parameter for newly opened index
382 *
383 * "name" [ IN ] - NUL terminated string in UTF-8 giving simple name of idx
384 */
385 static
KDBManagerOpenIndexReadInt(const KDBManager * self,KIndex ** idxp,const KDirectory * wd,const char * path)386 rc_t KDBManagerOpenIndexReadInt ( const KDBManager *self,
387 KIndex **idxp, const KDirectory *wd, const char *path )
388 {
389 char idxpath [ 4096 ];
390 rc_t rc = KDirectoryResolvePath ( wd, true,
391 idxpath, sizeof idxpath, "%s", path );
392 if ( rc == 0 )
393 {
394 KIndex *idx;
395
396 switch ( KDirectoryPathType ( wd, "%s", idxpath ) )
397 {
398 case kptNotFound:
399 return RC ( rcDB, rcMgr, rcOpening, rcIndex, rcNotFound );
400 case kptBadPath:
401 return RC ( rcDB, rcMgr, rcOpening, rcPath, rcInvalid );
402 case kptFile:
403 case kptFile | kptAlias:
404 break;
405 default:
406 return RC ( rcDB, rcMgr, rcOpening, rcPath, rcIncorrect );
407 }
408
409 rc = KIndexMakeRead ( & idx, wd, idxpath );
410 if ( rc == 0 )
411 {
412 idx -> mgr = KDBManagerAttach ( self );
413 * idxp = idx;
414 return 0;
415 }
416 }
417
418 return rc;
419 }
420
KDatabaseOpenIndexRead(struct KDatabase const * self,const KIndex ** idx,const char * name,...)421 LIB_EXPORT rc_t CC KDatabaseOpenIndexRead ( struct KDatabase const *self,
422 const KIndex **idx, const char *name, ... )
423 {
424 rc_t rc = 0;
425 va_list args;
426
427 va_start ( args, name );
428 rc = KDatabaseVOpenIndexRead ( self, idx, name, args );
429 va_end ( args );
430
431 return rc;
432 }
433
KDatabaseVOpenIndexRead(const KDatabase * self,const KIndex ** idxp,const char * name,va_list args)434 LIB_EXPORT rc_t CC KDatabaseVOpenIndexRead ( const KDatabase *self,
435 const KIndex **idxp, const char *name, va_list args )
436 {
437 rc_t rc = 0;
438 char path [ 256 ];
439
440 if ( idxp == NULL )
441 return RC ( rcDB, rcDatabase, rcOpening, rcParam, rcNull );
442
443 * idxp = NULL;
444
445 if ( self == NULL )
446 return RC ( rcDB, rcDatabase, rcOpening, rcSelf, rcNull );
447
448 rc = KDBVMakeSubPath ( self -> dir,
449 path, sizeof path, "idx", 3, name, args );
450 if ( rc == 0 )
451 {
452 KIndex *idx;
453 rc = KDBManagerOpenIndexReadInt ( self -> mgr,
454 & idx, self -> dir, path );
455 if ( rc == 0 )
456 {
457 idx -> db = KDatabaseAttach ( self );
458 * idxp = idx;
459 }
460 }
461 return rc;
462 }
463
KTableOpenIndexRead(struct KTable const * self,const KIndex ** idx,const char * name,...)464 LIB_EXPORT rc_t CC KTableOpenIndexRead ( struct KTable const *self,
465 const KIndex **idx, const char *name, ... )
466 {
467 rc_t rc = 0;
468 va_list args;
469
470 va_start ( args, name );
471 rc = KTableVOpenIndexRead ( self, idx, name, args );
472 va_end ( args );
473
474 return rc;
475 }
476
KTableVOpenIndexRead(const KTable * self,const KIndex ** idxp,const char * name,va_list args)477 LIB_EXPORT rc_t CC KTableVOpenIndexRead ( const KTable *self,
478 const KIndex **idxp, const char *name, va_list args )
479 {
480 rc_t rc = 0;
481 char path [ 256 ];
482
483 if ( idxp == NULL )
484 return RC ( rcDB, rcTable, rcOpening, rcParam, rcNull );
485
486 * idxp = NULL;
487
488 if ( self == NULL )
489 return RC ( rcDB, rcTable, rcOpening, rcSelf, rcNull );
490
491 if ( self -> prerelease )
492 {
493 int len;
494 /* VDB-4386: cannot treat va_list as a pointer! */
495 /*if ( args == 0 )
496 len = snprintf ( path, sizeof path, "%s", name );
497 else*/
498 if ( name != NULL )
499 len = vsnprintf ( path, sizeof path, name, args );
500 if ( len < 0 || ( size_t ) len >= sizeof path )
501 return RC ( rcDB, rcTable, rcOpening, rcPath, rcExcessive );
502 rc = 0;
503 }
504 else
505 {
506 rc = KDBVMakeSubPath ( self -> dir,
507 path, sizeof path, "idx", 3, name, args );
508 }
509
510 if ( rc == 0 )
511 {
512 KIndex *idx;
513 rc = KDBManagerOpenIndexReadInt ( self -> mgr,
514 & idx, self -> dir, path );
515 if ( rc == 0 )
516 {
517 idx -> tbl = KTableAttach ( self );
518 * idxp = idx;
519 }
520 }
521 return rc;
522 }
523
524
525 /* Locked
526 * returns non-zero if locked
527 */
KIndexLocked(const KIndex * self)528 LIB_EXPORT bool CC KIndexLocked ( const KIndex *self )
529 {
530 rc_t rc;
531 const KDirectory *dir;
532
533 if ( self == NULL )
534 return false;
535
536 assert ( self -> db != NULL || self -> tbl != NULL );
537 dir = ( self -> db != NULL ) ?
538 self -> db -> dir : self -> tbl -> dir;
539
540 rc = KDBWritable ( dir, self -> path );
541 return GetRCState ( rc ) == rcLocked;
542 }
543
544
545 /* Version
546 * returns the format version
547 */
KIndexVersion(const KIndex * self,uint32_t * version)548 LIB_EXPORT rc_t CC KIndexVersion ( const KIndex *self, uint32_t *version )
549 {
550 if ( version == NULL )
551 return RC ( rcDB, rcIndex, rcAccessing, rcParam, rcNull );
552
553 if ( self == NULL )
554 {
555 * version = 0;
556 return RC ( rcDB, rcIndex, rcAccessing, rcSelf, rcNull );
557 }
558
559 * version = self -> vers;
560 return 0;
561 }
562
563
564 /* Type
565 * returns the type of index
566 */
KIndexType(const KIndex * self,KIdxType * type)567 LIB_EXPORT rc_t CC KIndexType ( const KIndex *self, KIdxType *type )
568 {
569 if ( type == NULL )
570 return RC ( rcDB, rcIndex, rcAccessing, rcParam, rcNull );
571
572 if ( self == NULL )
573 {
574 * type = ( KIdxType ) 0;
575 return RC ( rcDB, rcIndex, rcAccessing, rcSelf, rcNull );
576 }
577
578 * type = ( KIdxType ) self -> type;
579 return 0;
580 }
581
582
583 /* CheckConsistency
584 * run a consistency check on the open index
585 *
586 * "level" [ IN ] - a measure of rigor of the exercise:
587 * 0 is the lightest
588 * 1 will test all id mappings
589 * 2 will perform key->id retrievals
590 * 3 will perform id->key retrievals if a projection index exists
591 *
592 * "start_id" [ OUT, NULL OKAY ] - returns the first id in index
593 *
594 * "id_range" [ OUT, NULL OKAY ] - returns the range of ids from first to last
595 *
596 * "num_keys" [ OUT, NULL OKAY ] - returns the number of key entries
597 *
598 * "num_rows" [ OUT, NULL OKAY ] - returns the number of key->id mappings
599 *
600 * "num_holes" [ OUT, NULL OKAY ] - returns the number of holes in the mapped id range
601 */
KIndexConsistencyCheck(const KIndex * self,uint32_t level,int64_t * start_id,uint64_t * id_range,uint64_t * num_keys,uint64_t * num_rows,uint64_t * num_holes)602 LIB_EXPORT rc_t CC KIndexConsistencyCheck ( const KIndex *self, uint32_t level,
603 int64_t *start_id, uint64_t *id_range, uint64_t *num_keys,
604 uint64_t *num_rows, uint64_t *num_holes )
605 {
606 rc_t rc;
607
608 if ( self == NULL )
609 rc = RC ( rcDB, rcIndex, rcValidating, rcSelf, rcNull );
610 else
611 {
612 bool key2id, id2key, all_ids;
613 switch ( level )
614 {
615 case 0:
616 key2id = id2key = all_ids = false;
617 break;
618 case 1:
619 key2id = id2key = false;
620 all_ids = true;
621 break;
622 case 2:
623 key2id = id2key = true;
624 all_ids = false;
625 break;
626 default:
627 key2id = id2key = all_ids = true;
628 }
629
630 switch ( self -> type )
631 {
632 case kitText:
633 id2key = false;
634 case kitText | kitProj:
635 switch ( self -> vers )
636 {
637 case 1:
638 rc = KTrieIndexCheckConsistency_v1 ( & self -> u . txt1,
639 start_id, id_range, num_keys, num_rows, num_holes,
640 self, key2id, id2key );
641 break;
642 case 2:
643 case 3:
644 case 4:
645 rc = KTrieIndexCheckConsistency_v2 ( & self -> u . txt234,
646 start_id, id_range, num_keys, num_rows, num_holes,
647 self, key2id, id2key, all_ids, self -> converted_from_v1 );
648 break;
649 default:
650 return RC ( rcDB, rcIndex, rcValidating, rcIndex, rcBadVersion );
651 }
652 break;
653
654 default:
655 rc = RC ( rcDB, rcIndex, rcValidating, rcFunction, rcUnsupported );
656 }
657 }
658
659 return rc;
660 }
661
662
663 /* Find
664 * finds a single mapping from key
665 */
KIndexFindText(const KIndex * self,const char * key,int64_t * start_id,uint64_t * id_count,int (CC * custom_cmp)(const void * item,struct PBSTNode const * n,void * data),void * data)666 LIB_EXPORT rc_t CC KIndexFindText ( const KIndex *self, const char *key, int64_t *start_id, uint64_t *id_count,
667 int ( CC * custom_cmp ) ( const void *item, struct PBSTNode const *n, void *data ),
668 void *data )
669 {
670 rc_t rc = 0;
671 uint32_t id32, span;
672
673 if ( id_count != NULL )
674 * id_count = 0;
675
676 if ( start_id == NULL )
677 return RC ( rcDB, rcIndex, rcSelecting, rcParam, rcNull );
678
679 * start_id = 0;
680
681 if ( self == NULL )
682 return RC ( rcDB, rcIndex, rcSelecting, rcSelf, rcNull );
683
684 if ( key == NULL )
685 return RC ( rcDB, rcIndex, rcSelecting, rcString, rcNull );
686 if ( key [ 0 ] == 0 )
687 return RC ( rcDB, rcIndex, rcSelecting, rcString, rcEmpty );
688
689 span = 1;
690
691 switch ( self -> type )
692 {
693 case kitText:
694 case kitText | kitProj:
695 switch ( self -> vers )
696 {
697 case 1:
698 rc = KTrieIndexFind_v1 ( & self -> u . txt1, key, & id32, custom_cmp, data );
699 if ( rc == 0 )
700 * start_id = id32;
701 break;
702 case 2:
703 case 3:
704 case 4:
705 #if V2FIND_RETURNS_SPAN
706 rc = KTrieIndexFind_v2 ( & self -> u . txt234, key, start_id, & span, custom_cmp, data, self -> converted_from_v1 );
707 #else
708 rc = KTrieIndexFind_v2 ( & self -> u . txt234, key, start_id, custom_cmp, data, self -> converted_from_v1 );
709 #endif
710 break;
711 default:
712 return RC ( rcDB, rcIndex, rcSelecting, rcIndex, rcBadVersion );
713 }
714 break;
715 default:
716 return RC ( rcDB, rcIndex, rcSelecting, rcNoObj, rcUnknown );
717 }
718
719 if ( id_count != NULL )
720 * id_count = span;
721
722 return rc;
723 }
724
725
726 /* FindAll
727 * finds all mappings from key
728 */
KIndexFindAllText(const KIndex * self,const char * key,rc_t (CC * f)(int64_t id,uint64_t id_count,void * data),void * data)729 LIB_EXPORT rc_t CC KIndexFindAllText ( const KIndex *self, const char *key,
730 rc_t ( CC * f ) ( int64_t id, uint64_t id_count, void *data ), void *data )
731 {
732 rc_t rc = 0;
733 int64_t id64;
734 uint32_t id32, span;
735
736 if ( self == NULL )
737 return RC ( rcDB, rcIndex, rcSelecting, rcSelf, rcNull );
738
739 if ( f == NULL )
740 return RC ( rcDB, rcIndex, rcSelecting, rcFunction, rcNull );
741
742 if ( key == NULL )
743 return RC ( rcDB, rcIndex, rcSelecting, rcString, rcNull );
744 if ( key [ 0 ] == 0 )
745 return RC ( rcDB, rcIndex, rcSelecting, rcString, rcEmpty );
746
747 span = 1;
748
749 switch ( self -> type )
750 {
751 case kitText:
752 case kitText | kitProj:
753 switch ( self -> vers )
754 {
755 case 1:
756 rc = KTrieIndexFind_v1 ( & self -> u . txt1, key, & id32, NULL, NULL );
757 if ( rc == 0 )
758 rc = ( * f ) ( id32, 1, data );
759 break;
760 case 2:
761 case 3:
762 case 4:
763 #if V2FIND_RETURNS_SPAN
764 rc = KTrieIndexFind_v2 ( & self -> u . txt234, key, & id64, & span, NULL, NULL, self -> converted_from_v1 );
765 #else
766 rc = KTrieIndexFind_v2 ( & self -> u . txt234, key, & id64, NULL, NULL, self -> converted_from_v1 );
767 #endif
768 if ( rc == 0 )
769 rc = ( * f ) ( id64, span, data );
770 break;
771 default:
772 return RC ( rcDB, rcIndex, rcSelecting, rcIndex, rcBadVersion );
773 }
774 break;
775 default:
776 return RC ( rcDB, rcIndex, rcSelecting, rcNoObj, rcUnknown );
777 }
778
779 return rc;
780 }
781
782
783 /* Project
784 * finds key(s) mapping to value/id if supported
785 */
KIndexProjectText(const KIndex * self,int64_t id,int64_t * start_id,uint64_t * id_count,char * key,size_t kmax,size_t * actsize)786 LIB_EXPORT rc_t CC KIndexProjectText ( const KIndex *self,
787 int64_t id, int64_t *start_id, uint64_t *id_count,
788 char *key, size_t kmax, size_t *actsize )
789 {
790 rc_t rc = 0;
791 int64_t dummy;
792 uint32_t span;
793
794 if ( start_id == NULL )
795 start_id = & dummy;
796
797 * start_id = 0;
798
799 if ( id_count != NULL )
800 * id_count = 0;
801
802 if ( key == NULL && kmax != 0 )
803 return RC ( rcDB, rcIndex, rcProjecting, rcBuffer, rcNull );
804
805 if ( kmax != 0 )
806 key [ 0 ] = 0;
807
808 if ( self == NULL )
809 return RC ( rcDB, rcIndex, rcProjecting, rcSelf, rcNull );
810
811 if ( ( ( KIdxType ) self -> type & kitProj ) == 0 )
812 return RC ( rcDB, rcIndex, rcProjecting, rcIndex, rcIncorrect );
813
814 if ( key == NULL )
815 return RC ( rcDB, rcIndex, rcProjecting, rcBuffer, rcNull );
816
817 span = 1;
818
819 switch ( self -> type )
820 {
821 case kitText | kitProj:
822 switch ( self -> vers )
823 {
824 case 1:
825 /* there is a limit on ids in v1 */
826 if ( id <= 0 || ( id >> 32 ) != 0 )
827 return RC ( rcDB, rcIndex, rcProjecting, rcId, rcNotFound );
828
829 rc = KTrieIndexProject_v1 ( & self -> u . txt1,
830 ( uint32_t ) id, key, kmax, actsize );
831 if ( rc == 0 )
832 * start_id = id;
833 break;
834 case 2:
835 case 3:
836 case 4:
837 #if V2FIND_RETURNS_SPAN
838 rc = KTrieIndexProject_v2 ( & self -> u . txt234, id, start_id, & span, key, kmax, actsize );
839 #else
840 rc = KTrieIndexProject_v2 ( & self -> u . txt234, id, key, kmax, actsize );
841 if ( rc == 0 )
842 * start_id = id;
843 #endif
844 break;
845 default:
846 return RC ( rcDB, rcIndex, rcProjecting, rcIndex, rcBadVersion );
847 }
848 break;
849 default:
850 return RC ( rcDB, rcIndex, rcProjecting, rcNoObj, rcUnknown );
851 }
852
853 if ( id_count != NULL )
854 * id_count = span;
855
856 return rc;
857 }
858
859
860 /* ProjectAll
861 * finds key(s) mapping to value/id if supported
862 */
KIndexProjectAllText(const KIndex * self,int64_t id,rc_t (CC * f)(int64_t start_id,uint64_t id_count,const char * key,void * data),void * data)863 LIB_EXPORT rc_t CC KIndexProjectAllText ( const KIndex *self, int64_t id,
864 rc_t ( CC * f ) ( int64_t start_id, uint64_t id_count, const char *key, void *data ),
865 void *data )
866 {
867 rc_t rc = 0;
868 char key [ 256 ];
869
870 uint32_t span;
871 int64_t start_id;
872
873 if ( self == NULL )
874 return RC ( rcDB, rcIndex, rcProjecting, rcSelf, rcNull );
875
876 if ( ( ( KIdxType ) self -> type & kitProj ) == 0 )
877 return RC ( rcDB, rcIndex, rcProjecting, rcIndex, rcIncorrect );
878
879 if ( f == NULL )
880 return RC ( rcDB, rcIndex, rcProjecting, rcFunction, rcNull );
881
882 span = 1;
883
884 switch ( self -> type )
885 {
886 case kitText | kitProj:
887 switch ( self -> vers )
888 {
889 case 1:
890 /* there is a limit on ids in v1 */
891 if ( id <= 0 || ( id >> 32 ) != 0 )
892 return RC ( rcDB, rcIndex, rcProjecting, rcId, rcNotFound );
893
894 rc = KTrieIndexProject_v1 ( & self -> u . txt1,
895 ( uint32_t ) id, key, sizeof key, NULL );
896 if ( rc == 0 )
897 rc = ( * f ) ( id, 1, key, data );
898 break;
899
900 case 2:
901 case 3:
902 case 4:
903 #if V2FIND_RETURNS_SPAN
904 rc = KTrieIndexProject_v2 ( & self -> u . txt234, id, & start_id, & span, key, sizeof key, NULL );
905 #else
906 rc = KTrieIndexProject_v2 ( & self -> u . txt234, start_id = id, key, sizeof key );
907 #endif
908 if ( rc == 0 )
909 rc = ( * f ) ( start_id, span, key, data );
910 break;
911
912 default:
913 return RC ( rcDB, rcIndex, rcProjecting, rcIndex, rcBadVersion );
914 }
915 break;
916 default:
917 return RC ( rcDB, rcIndex, rcProjecting, rcNoObj, rcUnknown );
918 }
919
920 return rc;
921 }
922
KIndexFindU64(const KIndex * self,uint64_t offset,uint64_t * key,uint64_t * key_size,int64_t * id,uint64_t * id_qty)923 LIB_EXPORT rc_t CC KIndexFindU64( const KIndex* self, uint64_t offset, uint64_t* key, uint64_t* key_size, int64_t* id, uint64_t* id_qty )
924 {
925 rc_t rc = 0;
926
927 if( key == NULL || key_size == NULL || id == NULL || id_qty == NULL ) {
928 return RC(rcDB, rcIndex, rcSelecting, rcParam, rcNull);
929 }
930 *key = *key_size = *id = *id_qty = 0;
931 if( self == NULL ) {
932 return RC(rcDB, rcIndex, rcSelecting, rcSelf, rcNull);
933 }
934
935 switch( self->type )
936 {
937 case kitU64:
938 switch( self->vers )
939 {
940 case 3:
941 case 4:
942 rc = KU64IndexFind_v3(&self->u.u64_3, offset, key, key_size, id, id_qty);
943 break;
944 default:
945 return RC(rcDB, rcIndex, rcSelecting, rcIndex, rcBadVersion);
946 }
947 break;
948 default:
949 return RC(rcDB, rcIndex, rcSelecting, rcNoObj, rcUnknown);
950 }
951 return rc;
952 }
953
KIndexFindAllU64(const KIndex * self,uint64_t offset,rc_t (CC * f)(uint64_t key,uint64_t key_size,int64_t id,uint64_t id_qty,void * data),void * data)954 LIB_EXPORT rc_t CC KIndexFindAllU64( const KIndex* self, uint64_t offset,
955 rc_t ( CC * f )(uint64_t key, uint64_t key_size, int64_t id, uint64_t id_qty, void* data ), void* data)
956 {
957 rc_t rc = 0;
958
959 if ( self == NULL )
960 return RC(rcDB, rcIndex, rcSelecting, rcSelf, rcNull);
961 if ( f == NULL )
962 return RC(rcDB, rcIndex, rcSelecting, rcFunction, rcNull);
963
964 switch ( self->type )
965 {
966 case kitU64:
967 switch ( self->vers )
968 {
969 case 3:
970 case 4:
971 rc = KU64IndexFindAll_v3(&self->u.u64_3, offset, f, data);
972 break;
973 default:
974 return RC(rcDB, rcIndex, rcSelecting, rcIndex, rcBadVersion);
975 }
976 break;
977 default:
978 return RC(rcDB, rcIndex, rcSelecting, rcNoObj, rcUnknown);
979 }
980
981 return rc;
982 }
983
984
985 /* SetMaxId
986 * certain legacy versions of skey were built to know only the starting id
987 * of the NAME_FMT column, but were never given a maximum id. allow them
988 * to be corrected here.
989 */
KIndexSetMaxRowId(const KIndex * cself,int64_t max_row_id)990 LIB_EXPORT void CC KIndexSetMaxRowId ( const KIndex *cself, int64_t max_row_id )
991 {
992 if ( cself != NULL ) switch ( cself -> type )
993 {
994 case kitText:
995 case kitText | kitProj:
996 switch ( cself -> vers )
997 {
998 case 2:
999 case 3:
1000 case 4:
1001 /* here we can repair the max row id */
1002 if ( cself -> u . txt234 . pt . maxid < max_row_id )
1003 ( ( KIndex* ) cself ) -> u . txt234 . pt . maxid = max_row_id;
1004 break;
1005 }
1006 break;
1007 }
1008 }
1009