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