1 /* idl.c - ldap id list handling routines */
4 * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved.
5 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
11 #include <ac/string.h>
16 #define IDL_MAX(x,y) ( x > y ? x : y )
17 #define IDL_MIN(x,y) ( x < y ? x : y )
19 #define IDL_CMP(x,y) ( x < y ? -1 : ( x > y ? 1 : 0 ) )
22 static void idl_check( ID *ids )
24 if( BDB_IDL_IS_RANGE( ids ) ) {
25 assert( BDB_IDL_RANGE_FIRST(ids) <= BDB_IDL_RANGE_LAST(ids) );
28 for( i=1; i < ids[0]; i++ ) {
29 assert( ids[i+1] > ids[i] );
35 static void idl_dump( ID *ids )
37 if( BDB_IDL_IS_RANGE( ids ) ) {
39 LDAP_LOG( INDEX, INFO, "IDL: range (%ld - %ld)\n",
40 (long) BDB_IDL_RANGE_FIRST( ids ),
41 (long) BDB_IDL_RANGE_LAST( ids ), 0 );
43 Debug( LDAP_DEBUG_ANY,
44 "IDL: range ( %ld - %ld )\n",
45 (long) BDB_IDL_RANGE_FIRST( ids ),
46 (long) BDB_IDL_RANGE_LAST( ids ) );
52 LDAP_LOG( INDEX, INFO, "IDL: size %ld", (long) ids[0], 0, 0 );
54 Debug( LDAP_DEBUG_ANY, "IDL: size %ld", (long) ids[0], 0, 0 );
57 for( i=1; i<=ids[0]; i++ ) {
59 Debug( LDAP_DEBUG_ANY, "\n", 0, 0, 0 );
62 LDAP_LOG( INDEX, INFO, "%02lx",(long)ids[i], 0, 0 );
64 Debug( LDAP_DEBUG_ANY, " %02lx", (long) ids[i], 0, 0 );
68 Debug( LDAP_DEBUG_ANY, "\n", 0, 0, 0 );
73 #endif /* IDL_DEBUG > 1 */
74 #endif /* IDL_DEBUG > 0 */
76 unsigned bdb_idl_search( ID *ids, ID id )
78 #define IDL_BINARY_SEARCH 1
79 #ifdef IDL_BINARY_SEARCH
81 * binary search of id in ids
82 * if found, returns position of id
83 * if not found, returns first postion greater than id
96 cursor = base + pivot;
97 val = IDL_CMP( id, ids[cursor + 1] );
102 } else if ( val > 0 ) {
118 /* (reverse) linear search */
125 for( i=ids[0]; i; i-- ) {
135 int bdb_idl_insert( ID *ids, ID id )
137 unsigned x = bdb_idl_search( ids, id );
141 LDAP_LOG( INDEX, DETAIL1, "insert: %04lx at %d\n", (long) id, x, 0 );
143 Debug( LDAP_DEBUG_ANY, "insert: %04lx at %d\n", (long) id, x, 0 );
157 if ( x <= ids[0] && ids[x] == id ) {
162 if ( ++ids[0] >= BDB_IDL_DB_MAX ) {
165 ids[2] = ids[ids[0]-1];
166 } else if ( ids[ids[0]-1] < id ) {
169 ids[2] = ids[ids[0]-1];
175 AC_MEMCPY( &ids[x+1], &ids[x], (ids[0]-x) * sizeof(ID) );
188 static int idl_delete( ID *ids, ID id )
190 unsigned x = bdb_idl_search( ids, id );
194 LDAP_LOG( INDEX, DETAIL1, "delete: %04lx at %d\n", (long) id, x, 0 );
196 Debug( LDAP_DEBUG_ANY, "delete: %04lx at %d\n", (long) id, x, 0 );
210 if( x > ids[0] || ids[x] != id ) {
214 } else if ( --ids[0] == 0 ) {
220 AC_MEMCPY( &ids[x], &ids[x+1], (1+ids[0]-x) * sizeof(ID) );
237 if ( key->size == sizeof( ID ) ) {
238 unsigned char *c = key->data;
239 sprintf( buf, "[%02x%02x%02x%02x]", c[0], c[1], c[2], c[3] );
254 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
264 LDAP_LOG( INDEX, ARGS,
265 "bdb_idl_fetch_key: %s\n",
266 bdb_show_key( key, buf ), 0, 0 );
268 Debug( LDAP_DEBUG_ARGS,
269 "bdb_idl_fetch_key: %s\n",
270 bdb_show_key( key, buf ), 0, 0 );
273 assert( ids != NULL );
278 /* buf must be large enough to grab the entire IDL in one
279 * get(), otherwise BDB 4 will leak resources on subsequent
280 * get's. We can safely call get() twice - once for the data,
281 * and once to get the DB_NOTFOUND result meaning there's
282 * no more data. See ITS#2040 for details.
284 ID buf[BDB_IDL_DB_SIZE*5];
289 int flags = bdb->bi_db_opflags | DB_MULTIPLE;
291 data.ulen = sizeof(buf);
292 data.flags = DB_DBT_USERMEM;
297 rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
300 LDAP_LOG( INDEX, ERR,
301 "bdb_idl_fetch_key: cursor failed: %s (%d)\n",
302 db_strerror(rc), rc, 0 );
304 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
305 "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 );
309 rc = cursor->c_get( cursor, key, &data, flags | DB_SET );
315 DB_MULTIPLE_INIT( ptr, &data );
317 DB_MULTIPLE_NEXT(ptr, &data, j, len);
320 AC_MEMCPY( i, j, sizeof(ID) );
323 rc = cursor->c_get( cursor, key, &data, flags | DB_NEXT_DUP );
325 if ( rc == DB_NOTFOUND ) rc = 0;
327 /* On disk, a range is denoted by 0 in the first element */
329 if (ids[0] != BDB_IDL_RANGE_SIZE) {
331 LDAP_LOG( INDEX, ERR,
332 "=> bdb_idl_fetch_key: range size mismatch: "
333 "expected %ld, got %ld\n",
334 BDB_IDL_RANGE_SIZE, ids[0], 0 );
336 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
337 "range size mismatch: expected %d, got %ld\n",
338 BDB_IDL_RANGE_SIZE, ids[0], 0 );
340 cursor->c_close( cursor );
343 BDB_IDL_RANGE( ids, ids[2], ids[3] );
345 data.size = BDB_IDL_SIZEOF(ids);
347 rc2 = cursor->c_close( cursor );
350 LDAP_LOG( INDEX, ERR,
351 "bdb_idl_fetch_key: close failed: %s (%d)\n",
352 db_strerror(rc2), rc2, 0 );
354 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
355 "close failed: %s (%d)\n", db_strerror(rc2), rc2, 0 );
359 #else /* BDB_IDL_MULTI */
361 data.ulen = BDB_IDL_UM_SIZEOF;
362 data.flags = DB_DBT_USERMEM;
364 rc = db->get( db, tid, key, &data, bdb->bi_db_opflags );
365 #endif /* BDB_IDL_MULTI */
367 if( rc == DB_NOTFOUND ) {
370 } else if( rc != 0 ) {
372 LDAP_LOG( INDEX, ERR,
373 "bdb_idl_fetch_key: get failed: %s (%d)\n",
374 db_strerror(rc), rc, 0 );
376 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
377 "get failed: %s (%d)\n",
378 db_strerror(rc), rc, 0 );
382 } else if ( data.size == 0 || data.size % sizeof( ID ) ) {
383 /* size not multiple of ID size */
385 LDAP_LOG( INDEX, ERR,
386 "bdb_idl_fetch_key: odd size: expected %ld multiple, got %ld\n",
387 (long) sizeof( ID ), (long) data.size, 0 );
389 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
390 "odd size: expected %ld multiple, got %ld\n",
391 (long) sizeof( ID ), (long) data.size, 0 );
395 } else if ( data.size != BDB_IDL_SIZEOF(ids) ) {
398 LDAP_LOG( INDEX, ERR,
399 "bdb_idl_fetch_key: get size mismatch: expected %ld, got %ld\n",
400 (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
402 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
403 "get size mismatch: expected %ld, got %ld\n",
404 (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
421 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
429 ID ids[BDB_IDL_DB_SIZE];
435 LDAP_LOG( INDEX, ARGS,
436 "bdb_idl_insert_key: %lx %s\n",
437 (long) id, bdb_show_key( key, buf ), 0 );
439 Debug( LDAP_DEBUG_ARGS,
440 "bdb_idl_insert_key: %lx %s\n",
441 (long) id, bdb_show_key( key, buf ), 0 );
445 assert( id != NOID );
449 data.size = sizeof( ID );
450 data.ulen = data.size;
451 data.flags = DB_DBT_USERMEM;
453 rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
456 LDAP_LOG( INDEX, ERR,
457 "bdb_idl_insert_key: cursor failed: %s (%d)\n",
458 db_strerror(rc), rc, 0 );
460 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
461 "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 );
466 /* Fetch the first data item for this key, to see if it
467 * exists and if it's a range.
469 rc = cursor->c_get( cursor, key, &data, DB_SET | DB_RMW );
473 /* not a range, count the number of items */
475 rc = cursor->c_count( cursor, &count, 0 );
480 if ( count >= BDB_IDL_DB_MAX ) {
481 /* No room, convert to a range */
484 key2.dlen = key2.ulen;
485 key2.flags |= DB_DBT_PARTIAL;
489 rc = cursor->c_get( cursor, &key2, &data, DB_NEXT_NODUP );
490 if ( rc != 0 && rc != DB_NOTFOUND ) {
491 err = "c_get next_nodup";
494 if ( rc == DB_NOTFOUND ) {
495 rc = cursor->c_get( cursor, key, &data, DB_LAST );
501 rc = cursor->c_get( cursor, key, &data, DB_PREV );
511 rc = db->del( db, tid, key, 0 );
518 rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST );
524 rc = cursor->c_put( cursor, key, &data, DB_KEYLAST );
530 rc = cursor->c_put( cursor, key, &data, DB_KEYLAST );
536 /* There's room, just store it */
540 /* It's a range, see if we need to rewrite
545 rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP );
552 rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP );
558 if ( id < lo || id > hi ) {
559 /* Delete the current lo/hi */
560 rc = cursor->c_del( cursor, 0 );
566 rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST );
573 } else if ( rc == DB_NOTFOUND ) {
574 put1: data.data = &id;
575 rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST );
576 /* Don't worry if it's already there */
577 if ( rc != 0 && rc != DB_KEYEXIST ) {
582 /* initial c_get failed, nothing was done */
585 LDAP_LOG( INDEX, ERR,
586 "bdb_idl_insert_key: %s failed: %s (%d)\n",
587 err, db_strerror(rc), rc );
589 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
590 "%s failed: %s (%d)\n", err, db_strerror(rc), rc );
592 cursor->c_close( cursor );
595 rc = cursor->c_close( cursor );
596 #else /* !BDB_IDL_MULTI */
598 data.ulen = sizeof ids;
599 data.flags = DB_DBT_USERMEM;
601 /* fetch the key for read/modify/write */
602 rc = db->get( db, tid, key, &data, DB_RMW | bdb->bi_db_opflags );
604 if( rc == DB_NOTFOUND ) {
607 data.size = 2 * sizeof( ID );
609 } else if ( rc != 0 ) {
611 LDAP_LOG( INDEX, ERR, "bdb_idl_insert_key: get failed: %s (%d)\n",
612 db_strerror(rc), rc, 0 );
614 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
615 "get failed: %s (%d)\n",
616 db_strerror(rc), rc, 0 );
620 } else if ( data.size == 0 || data.size % sizeof( ID ) ) {
621 /* size not multiple of ID size */
623 LDAP_LOG( INDEX, ERR,
624 "bdb_idl_insert_key: odd size: expected %ld multiple, got %ld\n",
625 (long) sizeof( ID ), (long) data.size, 0 );
627 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
628 "odd size: expected %ld multiple, got %ld\n",
629 (long) sizeof( ID ), (long) data.size, 0 );
633 } else if ( data.size != BDB_IDL_SIZEOF(ids) ) {
636 LDAP_LOG( INDEX, ERR,
637 "bdb_idl_insert_key: odd size: expected %ld multiple, got %ld\n",
638 (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
640 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
641 "get size mismatch: expected %ld, got %ld\n",
642 (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
646 } else if ( BDB_IDL_IS_RANGE(ids) ) {
649 } else if ( ids[2] > id ) {
656 rc = bdb_idl_insert( ids, id );
660 LDAP_LOG( INDEX, DETAIL1, "bdb_idl_insert_key: dup\n", 0, 0, 0 );
662 Debug( LDAP_DEBUG_TRACE, "=> bdb_idl_insert_key: dup\n",
669 LDAP_LOG( INDEX, ERR,
670 "bdb_idl_insert_key: insert failed: (%d)\n", rc, 0, 0 );
672 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
673 "bdb_idl_insert failed (%d)\n",
680 data.size = BDB_IDL_SIZEOF( ids );
684 rc = db->put( db, tid, key, &data, 0 );
686 if( rc != 0 && rc != DB_KEYEXIST ) {
688 LDAP_LOG( INDEX, ERR,
689 "bdb_idl_insert_key: put failed: %s (%d)\n",
690 db_strerror(rc), rc, 0 );
692 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: "
693 "put failed: %s (%d)\n",
694 db_strerror(rc), rc, 0 );
708 struct bdb_info *bdb = (struct bdb_info *) be->be_private;
716 ID ids[BDB_IDL_DB_SIZE];
722 LDAP_LOG( INDEX, ARGS,
723 "bdb_idl_delete_key: %lx %s\n",
724 (long) id, bdb_show_key( key, buf ), 0 );
726 Debug( LDAP_DEBUG_ARGS,
727 "bdb_idl_delete_key: %lx %s\n",
728 (long) id, bdb_show_key( key, buf ), 0 );
731 assert( id != NOID );
737 data.size = sizeof( id );
738 data.ulen = data.size;
739 data.flags = DB_DBT_USERMEM;
741 rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
744 LDAP_LOG( INDEX, ERR,
745 "bdb_idl_delete_key: cursor failed: %s (%d)\n",
746 db_strerror(rc), rc, 0 );
748 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
749 "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 );
753 /* Fetch the first data item for this key, to see if it
754 * exists and if it's a range.
756 rc = cursor->c_get( cursor, key, &data, DB_SET | DB_RMW );
760 /* Not a range, just delete it */
762 /* position to correct item */
764 rc = cursor->c_get( cursor, key, &data,
765 DB_GET_BOTH | DB_RMW );
771 rc = cursor->c_del( cursor, 0 );
777 /* It's a range, see if we need to rewrite
782 rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP );
789 rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP );
795 if ( id == lo || id == hi ) {
799 } else if ( id == hi ) {
804 /* The range has collapsed... */
805 rc = db->del( db, tid, key, 0 );
811 rc = cursor->c_del( cursor, 0 );
819 rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST );
828 /* initial c_get failed, nothing was done */
831 LDAP_LOG( INDEX, ERR,
832 "bdb_idl_delete_key: %s failed: %s (%d)\n",
833 err, db_strerror(rc), rc );
835 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
836 "%s failed: %s (%d)\n", err, db_strerror(rc), rc );
838 cursor->c_close( cursor );
841 rc = cursor->c_close( cursor );
843 #else /* BDB_IDL_MULTI */
846 data.ulen = sizeof( ids );
847 data.flags = DB_DBT_USERMEM;
849 /* fetch the key for read/modify/write */
850 rc = db->get( db, tid, key, &data, DB_RMW | bdb->bi_db_opflags );
854 LDAP_LOG( INDEX, ERR, "bdb_idl_delete_key: get failed: %s (%d)\n",
855 db_strerror(rc), rc, 0 );
857 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
858 "get failed: %s (%d)\n",
859 db_strerror(rc), rc, 0 );
863 } else if ( data.size == 0 || data.size % sizeof( ID ) ) {
864 /* size not multiple of ID size */
866 LDAP_LOG( INDEX, ERR,
867 "bdb_idl_delete_key: odd size: expected: %ld multiple, got %ld\n",
868 (long) sizeof( ID ), (long) data.size, 0 );
870 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
871 "odd size: expected %ld multiple, got %ld\n",
872 (long) sizeof( ID ), (long) data.size, 0 );
876 } else if ( BDB_IDL_IS_RANGE(ids) ) {
879 } else if ( data.size != (1 + ids[0]) * sizeof( ID ) ) {
882 LDAP_LOG( INDEX, ERR,
883 "bdb_idl_delete_key: get size mismatch: expected: %ld, got %ld\n",
884 (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
886 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
887 "get size mismatch: expected %ld, got %ld\n",
888 (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
893 rc = idl_delete( ids, id );
897 LDAP_LOG( INDEX, ERR,
898 "bdb_idl_delete_key: delete failed: (%d)\n", rc, 0, 0 );
900 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
901 "idl_delete failed (%d)\n",
909 rc = db->del( db, tid, key, 0 );
912 LDAP_LOG( INDEX, ERR,
913 "bdb_idl_delete_key: delete failed: %s (%d)\n",
914 db_strerror(rc), rc, 0 );
916 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
917 "delete failed: %s (%d)\n",
918 db_strerror(rc), rc, 0 );
924 data.size = (ids[0]+1) * sizeof( ID );
928 rc = db->put( db, tid, key, &data, 0 );
930 #endif /* BDB_IDL_MULTI */
934 LDAP_LOG( INDEX, ERR, "bdb_idl_delete_key: put failed: %s (%d)\n",
935 db_strerror(rc), rc, 0 );
937 Debug( LDAP_DEBUG_ANY,
938 "=> bdb_idl_delete_key: put failed: %s (%d)\n",
939 db_strerror(rc), rc, 0 );
948 * idl_intersection - return a = a intersection b
951 bdb_idl_intersection(
957 ID cursora = 0, cursorb = 0, cursorc;
960 if ( BDB_IDL_IS_ZERO( a ) || BDB_IDL_IS_ZERO( b ) ) {
965 idmin = IDL_MAX( BDB_IDL_FIRST(a), BDB_IDL_FIRST(b) );
966 idmax = IDL_MIN( BDB_IDL_LAST(a), BDB_IDL_LAST(b) );
967 if ( idmin > idmax ) {
970 } else if ( idmin == idmax ) {
976 if ( BDB_IDL_IS_RANGE( a ) && BDB_IDL_IS_RANGE(b) ) {
982 if ( BDB_IDL_IS_RANGE( a ) ) {
989 if ( BDB_IDL_IS_RANGE( b ) && BDB_IDL_FIRST( b ) <= idmin &&
990 BDB_IDL_LAST( b ) >= idmax) {
991 if (idmax - idmin + 1 == a[0])
1000 ida = bdb_idl_first( a, &cursora );
1001 idb = bdb_idl_first( b, &cursorb );
1004 while( ida < idmin )
1005 ida = bdb_idl_next( a, &cursora );
1006 while( idb < idmin )
1007 idb = bdb_idl_next( b, &cursorb );
1009 while( ida <= idmax || idb <= idmax ) {
1012 ida = bdb_idl_next( a, &cursora );
1013 idb = bdb_idl_next( b, &cursorb );
1014 } else if ( ida < idb ) {
1015 ida = bdb_idl_next( a, &cursora );
1017 idb = bdb_idl_next( b, &cursorb );
1023 BDB_IDL_CPY( b, a );
1030 * idl_union - return a = a union b
1038 ID cursora = 0, cursorb = 0, cursorc;
1040 if ( BDB_IDL_IS_ZERO( b ) ) {
1044 if ( BDB_IDL_IS_ZERO( a ) ) {
1045 BDB_IDL_CPY( a, b );
1049 if ( BDB_IDL_IS_RANGE( a ) || BDB_IDL_IS_RANGE(b) ) {
1050 over: ida = IDL_MIN( BDB_IDL_FIRST(a), BDB_IDL_FIRST(b) );
1051 idb = IDL_MAX( BDB_IDL_LAST(a), BDB_IDL_LAST(b) );
1058 ida = bdb_idl_first( a, &cursora );
1059 idb = bdb_idl_first( b, &cursorb );
1063 /* The distinct elements of a are cat'd to b */
1064 while( ida != NOID || idb != NOID ) {
1066 if( ++cursorc > BDB_IDL_UM_MAX ) {
1070 ida = bdb_idl_next( a, &cursora );
1074 ida = bdb_idl_next( a, &cursora );
1075 idb = bdb_idl_next( b, &cursorb );
1079 /* b is copied back to a in sorted order */
1084 while (cursorb <= b[0] || cursorc <= a[0]) {
1089 if (cursorb <= b[0] && b[cursorb] < idb)
1090 a[cursora++] = b[cursorb++];
1103 * bdb_idl_notin - return a intersection ~b (or a minus b)
1112 ID cursora = 0, cursorb = 0;
1114 if( BDB_IDL_IS_ZERO( a ) ||
1115 BDB_IDL_IS_ZERO( b ) ||
1116 BDB_IDL_IS_RANGE( b ) )
1118 BDB_IDL_CPY( ids, a );
1122 if( BDB_IDL_IS_RANGE( a ) ) {
1123 BDB_IDL_CPY( ids, a );
1127 ida = bdb_idl_first( a, &cursora ),
1128 idb = bdb_idl_first( b, &cursorb );
1132 while( ida != NOID ) {
1133 if ( idb == NOID ) {
1134 /* we could shortcut this */
1135 ids[++ids[0]] = ida;
1136 ida = bdb_idl_next( a, &cursora );
1138 } else if ( ida < idb ) {
1139 ids[++ids[0]] = ida;
1140 ida = bdb_idl_next( a, &cursora );
1142 } else if ( ida > idb ) {
1143 idb = bdb_idl_next( b, &cursorb );
1146 ida = bdb_idl_next( a, &cursora );
1147 idb = bdb_idl_next( b, &cursorb );
1155 ID bdb_idl_first( ID *ids, ID *cursor )
1159 if ( ids[0] == 0 ) {
1164 if ( BDB_IDL_IS_RANGE( ids ) ) {
1165 if( *cursor < ids[1] ) {
1174 pos = bdb_idl_search( ids, *cursor );
1176 if( pos > ids[0] ) {
1184 ID bdb_idl_next( ID *ids, ID *cursor )
1186 if ( BDB_IDL_IS_RANGE( ids ) ) {
1187 if( ids[2] < ++(*cursor) ) {
1193 if ( ++(*cursor) <= ids[0] ) {
1194 return ids[*cursor];