only implemented for generalizedTime syntax.
((char *)key.data)[0] = prefix;
AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 );
- rc = bdb_idl_fetch_key( op->o_bd, db, NULL, &key, ids );
+ rc = bdb_idl_fetch_key( op->o_bd, db, NULL, &key, ids, NULL, 0 );
if( rc != 0 ) {
Debug( LDAP_DEBUG_TRACE,
AttributeAssertion *ava,
ID *ids,
ID *tmp );
+static int inequality_candidates(
+ Operation *op,
+ AttributeAssertion *ava,
+ ID *ids,
+ ID *tmp,
+ int gtorlt );
static int approx_candidates(
Operation *op,
AttributeAssertion *ava,
break;
case LDAP_FILTER_GE:
- /* no GE index, use pres */
+ /* if no GE index, use pres */
Debug( LDAP_DEBUG_FILTER, "\tGE\n", 0, 0, 0 );
- rc = presence_candidates( op, f->f_ava->aa_desc, ids );
+ if( f->f_ava->aa_desc->ad_type->sat_ordering &&
+ ( f->f_ava->aa_desc->ad_type->sat_ordering->smr_usage && SLAP_MR_ORDERED_INDEX ) )
+ rc = inequality_candidates( op, f->f_ava, ids, tmp, LDAP_FILTER_GE );
+ else
+ rc = presence_candidates( op, f->f_ava->aa_desc, ids );
break;
case LDAP_FILTER_LE:
- /* no LE index, use pres */
+ /* if no LE index, use pres */
Debug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 );
- rc = presence_candidates( op, f->f_ava->aa_desc, ids );
+ if( f->f_ava->aa_desc->ad_type->sat_ordering &&
+ ( f->f_ava->aa_desc->ad_type->sat_ordering->smr_usage && SLAP_MR_ORDERED_INDEX ) )
+ rc = inequality_candidates( op, f->f_ava, ids, tmp, LDAP_FILTER_LE );
+ else
+ rc = presence_candidates( op, f->f_ava->aa_desc, ids );
break;
case LDAP_FILTER_NOT:
return -1;
}
- rc = bdb_key_read( op->o_bd, db, NULL, &prefix, ids );
+ rc = bdb_key_read( op->o_bd, db, NULL, &prefix, ids, NULL, 0 );
if( rc == DB_NOTFOUND ) {
BDB_IDL_ZERO( ids );
}
for ( i= 0; keys[i].bv_val != NULL; i++ ) {
- rc = bdb_key_read( op->o_bd, db, NULL, &keys[i], tmp );
+ rc = bdb_key_read( op->o_bd, db, NULL, &keys[i], tmp, NULL, 0 );
if( rc == DB_NOTFOUND ) {
BDB_IDL_ZERO( ids );
}
for ( i= 0; keys[i].bv_val != NULL; i++ ) {
- rc = bdb_key_read( op->o_bd, db, NULL, &keys[i], tmp );
+ rc = bdb_key_read( op->o_bd, db, NULL, &keys[i], tmp, NULL, 0 );
if( rc == DB_NOTFOUND ) {
BDB_IDL_ZERO( ids );
}
for ( i= 0; keys[i].bv_val != NULL; i++ ) {
- rc = bdb_key_read( op->o_bd, db, NULL, &keys[i], tmp );
+ rc = bdb_key_read( op->o_bd, db, NULL, &keys[i], tmp, NULL, 0 );
if( rc == DB_NOTFOUND ) {
BDB_IDL_ZERO( ids );
return( rc );
}
+static int
+inequality_candidates(
+ Operation *op,
+ AttributeAssertion *ava,
+ ID *ids,
+ ID *tmp,
+ int gtorlt )
+{
+ struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private;
+ DB *db;
+ int i;
+ int rc;
+ slap_mask_t mask;
+ struct berval prefix = {0, NULL};
+ struct berval *keys = NULL;
+ MatchingRule *mr;
+ DBC * cursor = NULL;
+
+ Debug( LDAP_DEBUG_TRACE, "=> bdb_inequality_candidates (%s)\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+
+ BDB_IDL_ALL( bdb, ids );
+
+ rc = bdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY,
+ &db, &mask, &prefix );
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= bdb_inequality_candidates: (%s) "
+ "index_param failed (%d)\n",
+ ava->aa_desc->ad_cname.bv_val, rc, 0 );
+ return 0;
+ }
+
+ if ( db == NULL ) {
+ Debug( LDAP_DEBUG_ANY,
+ "<= bdb_inequality_candidates: (%s) not indexed\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ mr = ava->aa_desc->ad_type->sat_equality;
+ if( !mr ) {
+ return 0;
+ }
+
+ if( !mr->smr_filter ) {
+ return 0;
+ }
+
+ rc = (mr->smr_filter)(
+ LDAP_FILTER_EQUALITY,
+ mask,
+ ava->aa_desc->ad_type->sat_syntax,
+ mr,
+ &prefix,
+ &ava->aa_value,
+ &keys, op->o_tmpmemctx );
+
+ if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= bdb_inequality_candidates: (%s, %s) "
+ "MR filter failed (%d)\n",
+ prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc );
+ return 0;
+ }
+
+ if( keys == NULL ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= bdb_inequality_candidates: (%s) no keys\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+ return 0;
+ }
+
+ BDB_IDL_ZERO( ids );
+ while(1) {
+ rc = bdb_key_read( op->o_bd, db, NULL, &keys[0], tmp, &cursor, gtorlt );
+
+ if( rc == DB_NOTFOUND ) {
+ rc = 0;
+ break;
+ } else if( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= bdb_inequality_candidates: (%s) "
+ "key read failed (%d)\n",
+ ava->aa_desc->ad_cname.bv_val, rc, 0 );
+ break;
+ }
+
+ if( BDB_IDL_IS_ZERO( tmp ) ) {
+ Debug( LDAP_DEBUG_TRACE,
+ "<= bdb_inequality_candidates: (%s) NULL\n",
+ ava->aa_desc->ad_cname.bv_val, 0, 0 );
+ break;
+ }
+
+ bdb_idl_union( ids, tmp );
+
+ if( BDB_IDL_IS_ZERO( ids ) )
+ break;
+ i++;
+ }
+ ber_bvarray_free_x( keys, op->o_tmpmemctx );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "<= bdb_inequality_candidates: id=%ld, first=%ld, last=%ld\n",
+ (long) ids[0],
+ (long) BDB_IDL_FIRST(ids),
+ (long) BDB_IDL_LAST(ids) );
+ return( rc );
+}
DB *db,
DB_TXN *tid,
DBT *key,
- ID *ids )
+ ID *ids,
+ DBC **saved_cursor,
+ int get_flag )
{
struct bdb_info *bdb = (struct bdb_info *) be->be_private;
int rc;
- DBT data;
+ DBT data, key2, *kptr;
DBC *cursor;
ID *i;
void *ptr;
size_t len;
int rc2;
int flags = bdb->bi_db_opflags | DB_MULTIPLE;
+ int opflag;
/* If using BerkeleyDB 4.0, the buf must be large enough to
* grab the entire IDL in one get(), otherwise BDB will leak
assert( ids != NULL );
- if ( bdb->bi_idl_cache_size ) {
+ if ( saved_cursor && *saved_cursor ) {
+ opflag = DB_NEXT;
+ } else if ( get_flag == LDAP_FILTER_GE ) {
+ opflag = DB_SET_RANGE;
+ } else if ( get_flag == LDAP_FILTER_LE ) {
+ opflag = DB_FIRST;
+ } else {
+ opflag = DB_SET;
+ }
+
+ /* only non-range lookups can use the IDL cache */
+ if ( bdb->bi_idl_cache_size && opflag == DB_SET ) {
rc = bdb_idl_cache_get( bdb, db, key, ids );
if ( rc != LDAP_NO_SUCH_OBJECT ) return rc;
}
if ( tid ) flags |= DB_RMW;
- rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
+ /* If we're not reusing an existing cursor, get a new one */
+ if( opflag != DB_NEXT )
+ rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags );
+ else
+ cursor = *saved_cursor;
if( rc != 0 ) {
Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
"cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 );
return rc;
}
+
+ /* If this is a LE lookup, save original key so we can determine
+ * when to stop
+ */
+ if ( get_flag == LDAP_FILTER_LE ) {
+ DBTzero( &key2 );
+ key2.flags = DB_DBT_USERMEM;
+ key2.ulen = sizeof(keybuf);
+ key2.data = keybuf;
+ AC_MEMCPY( keybuf, key->data, key->size );
+ kptr = &key2;
+ } else {
+ kptr = key;
+ }
+ len = key->size;
+ rc = cursor->c_get( cursor, kptr, &data, flags | opflag );
- rc = cursor->c_get( cursor, key, &data, flags | DB_SET );
+ /* skip presence key on range inequality lookups */
+ while (rc == 0 && kptr->size != len) {
+ rc = cursor->c_get( cursor, kptr, &data, flags | DB_NEXT_NODUP );
+ }
+ /* If we're doing a LE compare and the new key is greater than
+ * our search key, we're done
+ */
+ if (rc == 0 && get_flag == LDAP_FILTER_LE && memcmp( kptr->data,
+ key->data, key->size ) > 0 ) {
+ rc = DB_NOTFOUND;
+ }
if (rc == 0) {
i = ids;
while (rc == 0) {
data.size = BDB_IDL_SIZEOF(ids);
}
- rc2 = cursor->c_close( cursor );
+ if ( saved_cursor && rc == 0 ) {
+ if ( !*saved_cursor )
+ *saved_cursor = cursor;
+ rc2 = 0;
+ }
+ else
+ rc2 = cursor->c_close( cursor );
if (rc2) {
Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: "
"close failed: %s (%d)\n", db_strerror(rc2), rc2, 0 );
DB *db,
DB_TXN *txn,
struct berval *k,
- ID *ids
+ ID *ids,
+ DBC **saved_cursor,
+ int get_flag
)
{
int rc;
key.ulen = key.size;
key.flags = DB_DBT_USERMEM;
- rc = bdb_idl_fetch_key( be, db, txn, &key, ids );
+ rc = bdb_idl_fetch_key( be, db, txn, &key, ids, saved_cursor, get_flag );
if( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_TRACE, "<= bdb_index_read: failed (%d)\n",
unsigned bdb_idl_search( ID *ids, ID id );
int bdb_idl_fetch_key(
- BackendDB *be,
- DB *db,
- DB_TXN *txn,
- DBT *key,
- ID *ids );
+ BackendDB *be,
+ DB *db,
+ DB_TXN *tid,
+ DBT *key,
+ ID *ids,
+ DBC **saved_cursor,
+ int get_flag );
int bdb_idl_insert( ID *ids, ID id );
DB *db,
DB_TXN *txn,
struct berval *k,
- ID *ids );
+ ID *ids,
+ DBC **saved_cursor,
+ int get_flags );
extern int
bdb_key_change(
#include <openssl/ssl.h>
#endif
+#include "lutil.h"
#include "lutil_hash.h"
#define HASH_BYTES LUTIL_HASH_BYTES
#define HASH_CONTEXT lutil_HASH_CTX
return LDAP_SUCCESS;
}
+/* Index generation function */
+int generalizedTimeIndexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp,
+ void *ctx )
+{
+ int i, j;
+ size_t slen, mlen;
+ BerVarray keys;
+ char tmp[5];
+ BerValue bvtmp; /* 40 bit index */
+ struct lutil_tm tm;
+ struct lutil_timet tt;
+
+ bvtmp.bv_len = sizeof(tmp);
+ bvtmp.bv_val = tmp;
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* just count them */
+ }
+
+ /* we should have at least one value at this point */
+ assert( i > 0 );
+
+ keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
+
+ /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
+ for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
+ assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
+ /* Use 40 bits of time for key */
+ if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
+ lutil_tm2time( &tm, &tt );
+ tmp[0] = tt.tt_gsec & 0xff;
+ tmp[4] = tt.tt_sec & 0xff;
+ tt.tt_sec >>= 8;
+ tmp[3] = tt.tt_sec & 0xff;
+ tt.tt_sec >>= 8;
+ tmp[2] = tt.tt_sec & 0xff;
+ tt.tt_sec >>= 8;
+ tmp[1] = tt.tt_sec & 0xff;
+
+ ber_dupbv_x(&keys[j++], &bvtmp, ctx );
+ }
+ }
+
+ keys[j].bv_val = NULL;
+ keys[j].bv_len = 0;
+
+ *keysp = keys;
+
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+int generalizedTimeFilter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertedValue,
+ BerVarray *keysp,
+ void *ctx )
+{
+ BerVarray keys;
+ char tmp[5];
+ BerValue bvtmp; /* 40 bit index */
+ BerValue *value = (BerValue *) assertedValue;
+ struct lutil_tm tm;
+ struct lutil_timet tt;
+
+ bvtmp.bv_len = sizeof(tmp);
+ bvtmp.bv_val = tmp;
+ keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
+
+ /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
+ assert(value->bv_val != NULL && value->bv_len >= 10);
+ /* Use 40 bits of time for key */
+ if ( lutil_parsetime( value->bv_val, &tm ) == 0 ) {
+ lutil_tm2time( &tm, &tt );
+ tmp[0] = tt.tt_gsec & 0xff;
+ tmp[4] = tt.tt_sec & 0xff;
+ tt.tt_sec >>= 8;
+ tmp[3] = tt.tt_sec & 0xff;
+ tt.tt_sec >>= 8;
+ tmp[2] = tt.tt_sec & 0xff;
+ tt.tt_sec >>= 8;
+ tmp[1] = tt.tt_sec & 0xff;
+
+ ber_dupbv_x(keys, &bvtmp, ctx );
+ } else {
+ keys[0].bv_val = NULL;
+ keys[0].bv_len = 0;
+ }
+
+ keys[1].bv_val = NULL;
+ keys[1].bv_len = 0;
+
+ *keysp = keys;
+
+ return LDAP_SUCCESS;
+}
+
static int
deliveryMethodValidate(
Syntax *syntax,
{"( 2.5.13.27 NAME 'generalizedTimeMatch' "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
- SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
+ SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
NULL, generalizedTimeNormalize, octetStringMatch,
- NULL, NULL,
+ generalizedTimeIndexer, generalizedTimeFilter,
NULL },
{"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
- SLAP_MR_ORDERING, NULL,
+ SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
NULL, NULL,
"generalizedTimeMatch" },
#define SLAP_MR_ORDERING 0x0200U
#define SLAP_MR_SUBSTR 0x0400U
#define SLAP_MR_EXT 0x0800U /* implicitly extensible */
+#define SLAP_MR_ORDERED_INDEX 0x1000U
#ifdef LDAP_COMP_MATCH
-#define SLAP_MR_COMPONENT 0x1000U
+#define SLAP_MR_COMPONENT 0x2000U
#endif
#define SLAP_MR_EQUALITY_APPROX ( SLAP_MR_EQUALITY | 0x0010U )