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;
258 /* buf must be large enough to grab the entire IDL in one
259 * get(), otherwise BDB 4 will leak resources on subsequent
260 * get's. We can safely call get() twice - once for the data,
261 * and once to get the DB_NOTFOUND result meaning there's
262 * no more data. See ITS#2040 for details.
264 ID buf[BDB_IDL_DB_SIZE*5];
270 int flags = bdb->bi_db_opflags | DB_MULTIPLE;
276 LDAP_LOG( INDEX, ARGS,
277 "bdb_idl_fetch_key: %s\n",
278 bdb_show_key( key, buf ), 0, 0 );
280 Debug( LDAP_DEBUG_ARGS,
281 "bdb_idl_fetch_key: %s\n",
282 bdb_show_key( key, buf ), 0, 0 );
285 assert( ids != NULL );
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_NODUPDATA );
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 */
830 if ( rc != DB_NOTFOUND ) {
832 LDAP_LOG( INDEX, ERR,
833 "bdb_idl_delete_key: %s failed: %s (%d)\n",
834 err, db_strerror(rc), rc );
836 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
837 "%s failed: %s (%d)\n", err, db_strerror(rc), rc );
840 cursor->c_close( cursor );
843 rc = cursor->c_close( cursor );
845 #else /* BDB_IDL_MULTI */
848 data.ulen = sizeof( ids );
849 data.flags = DB_DBT_USERMEM;
851 /* fetch the key for read/modify/write */
852 rc = db->get( db, tid, key, &data, DB_RMW | bdb->bi_db_opflags );
856 LDAP_LOG( INDEX, ERR, "bdb_idl_delete_key: get failed: %s (%d)\n",
857 db_strerror(rc), rc, 0 );
859 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
860 "get failed: %s (%d)\n",
861 db_strerror(rc), rc, 0 );
865 } else if ( data.size == 0 || data.size % sizeof( ID ) ) {
866 /* size not multiple of ID size */
868 LDAP_LOG( INDEX, ERR,
869 "bdb_idl_delete_key: odd size: expected: %ld multiple, got %ld\n",
870 (long) sizeof( ID ), (long) data.size, 0 );
872 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
873 "odd size: expected %ld multiple, got %ld\n",
874 (long) sizeof( ID ), (long) data.size, 0 );
878 } else if ( BDB_IDL_IS_RANGE(ids) ) {
881 } else if ( data.size != (1 + ids[0]) * sizeof( ID ) ) {
884 LDAP_LOG( INDEX, ERR,
885 "bdb_idl_delete_key: get size mismatch: expected: %ld, got %ld\n",
886 (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
888 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
889 "get size mismatch: expected %ld, got %ld\n",
890 (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 );
895 rc = idl_delete( ids, id );
899 LDAP_LOG( INDEX, ERR,
900 "bdb_idl_delete_key: delete failed: (%d)\n", rc, 0, 0 );
902 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
903 "idl_delete failed (%d)\n",
911 rc = db->del( db, tid, key, 0 );
914 LDAP_LOG( INDEX, ERR,
915 "bdb_idl_delete_key: delete failed: %s (%d)\n",
916 db_strerror(rc), rc, 0 );
918 Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: "
919 "delete failed: %s (%d)\n",
920 db_strerror(rc), rc, 0 );
926 data.size = (ids[0]+1) * sizeof( ID );
930 rc = db->put( db, tid, key, &data, 0 );
932 #endif /* BDB_IDL_MULTI */
936 LDAP_LOG( INDEX, ERR, "bdb_idl_delete_key: put failed: %s (%d)\n",
937 db_strerror(rc), rc, 0 );
939 Debug( LDAP_DEBUG_ANY,
940 "=> bdb_idl_delete_key: put failed: %s (%d)\n",
941 db_strerror(rc), rc, 0 );
950 * idl_intersection - return a = a intersection b
953 bdb_idl_intersection(
959 ID cursora = 0, cursorb = 0, cursorc;
962 if ( BDB_IDL_IS_ZERO( a ) || BDB_IDL_IS_ZERO( b ) ) {
967 idmin = IDL_MAX( BDB_IDL_FIRST(a), BDB_IDL_FIRST(b) );
968 idmax = IDL_MIN( BDB_IDL_LAST(a), BDB_IDL_LAST(b) );
969 if ( idmin > idmax ) {
972 } else if ( idmin == idmax ) {
978 if ( BDB_IDL_IS_RANGE( a ) && BDB_IDL_IS_RANGE(b) ) {
984 if ( BDB_IDL_IS_RANGE( a ) ) {
991 if ( BDB_IDL_IS_RANGE( b ) && BDB_IDL_FIRST( b ) <= idmin &&
992 BDB_IDL_LAST( b ) >= idmax) {
993 if (idmax - idmin + 1 == a[0])
1002 ida = bdb_idl_first( a, &cursora );
1003 idb = bdb_idl_first( b, &cursorb );
1006 while( ida < idmin )
1007 ida = bdb_idl_next( a, &cursora );
1008 while( idb < idmin )
1009 idb = bdb_idl_next( b, &cursorb );
1011 while( ida <= idmax || idb <= idmax ) {
1014 ida = bdb_idl_next( a, &cursora );
1015 idb = bdb_idl_next( b, &cursorb );
1016 } else if ( ida < idb ) {
1017 ida = bdb_idl_next( a, &cursora );
1019 idb = bdb_idl_next( b, &cursorb );
1025 BDB_IDL_CPY( b, a );
1032 * idl_union - return a = a union b
1040 ID cursora = 0, cursorb = 0, cursorc;
1042 if ( BDB_IDL_IS_ZERO( b ) ) {
1046 if ( BDB_IDL_IS_ZERO( a ) ) {
1047 BDB_IDL_CPY( a, b );
1051 if ( BDB_IDL_IS_RANGE( a ) || BDB_IDL_IS_RANGE(b) ) {
1052 over: ida = IDL_MIN( BDB_IDL_FIRST(a), BDB_IDL_FIRST(b) );
1053 idb = IDL_MAX( BDB_IDL_LAST(a), BDB_IDL_LAST(b) );
1060 ida = bdb_idl_first( a, &cursora );
1061 idb = bdb_idl_first( b, &cursorb );
1065 /* The distinct elements of a are cat'd to b */
1066 while( ida != NOID || idb != NOID ) {
1068 if( ++cursorc > BDB_IDL_UM_MAX ) {
1072 ida = bdb_idl_next( a, &cursora );
1076 ida = bdb_idl_next( a, &cursora );
1077 idb = bdb_idl_next( b, &cursorb );
1081 /* b is copied back to a in sorted order */
1086 while (cursorb <= b[0] || cursorc <= a[0]) {
1091 if (cursorb <= b[0] && b[cursorb] < idb)
1092 a[cursora++] = b[cursorb++];
1105 * bdb_idl_notin - return a intersection ~b (or a minus b)
1114 ID cursora = 0, cursorb = 0;
1116 if( BDB_IDL_IS_ZERO( a ) ||
1117 BDB_IDL_IS_ZERO( b ) ||
1118 BDB_IDL_IS_RANGE( b ) )
1120 BDB_IDL_CPY( ids, a );
1124 if( BDB_IDL_IS_RANGE( a ) ) {
1125 BDB_IDL_CPY( ids, a );
1129 ida = bdb_idl_first( a, &cursora ),
1130 idb = bdb_idl_first( b, &cursorb );
1134 while( ida != NOID ) {
1135 if ( idb == NOID ) {
1136 /* we could shortcut this */
1137 ids[++ids[0]] = ida;
1138 ida = bdb_idl_next( a, &cursora );
1140 } else if ( ida < idb ) {
1141 ids[++ids[0]] = ida;
1142 ida = bdb_idl_next( a, &cursora );
1144 } else if ( ida > idb ) {
1145 idb = bdb_idl_next( b, &cursorb );
1148 ida = bdb_idl_next( a, &cursora );
1149 idb = bdb_idl_next( b, &cursorb );
1157 ID bdb_idl_first( ID *ids, ID *cursor )
1161 if ( ids[0] == 0 ) {
1166 if ( BDB_IDL_IS_RANGE( ids ) ) {
1167 if( *cursor < ids[1] ) {
1176 pos = bdb_idl_search( ids, *cursor );
1178 if( pos > ids[0] ) {
1186 ID bdb_idl_next( ID *ids, ID *cursor )
1188 if ( BDB_IDL_IS_RANGE( ids ) ) {
1189 if( ids[2] < ++(*cursor) ) {
1195 if ( ++(*cursor) <= ids[0] ) {
1196 return ids[*cursor];