X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-mdb%2Fid2entry.c;h=4356363ea7184639bcb59bef27a0ce07ba6422d0;hb=8300eee0179798abe4a55cad6170044d1a80cf99;hp=3d3463a88d3aab66eb33b306afb1b686a2d700b3;hpb=cdcf70eeb6b863d4d135ccb010da7f69e52b6723;p=openldap diff --git a/servers/slapd/back-mdb/id2entry.c b/servers/slapd/back-mdb/id2entry.c index 3d3463a88d..4356363ea7 100644 --- a/servers/slapd/back-mdb/id2entry.c +++ b/servers/slapd/back-mdb/id2entry.c @@ -2,7 +2,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2000-2014 The OpenLDAP Foundation. + * Copyright 2000-2017 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,10 +23,12 @@ #include "back-mdb.h" typedef struct Ecount { - ber_len_t len; + ber_len_t len; /* total entry size */ + ber_len_t dlen; /* contiguous data size */ int nattrs; int nvals; int offset; + Attribute *multi; } Ecount; static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e, @@ -35,6 +37,228 @@ static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *ec); static Entry *mdb_entry_alloc( Operation *op, int nattrs, int nvals ); +#define ID2VKSZ (sizeof(ID)+2) + +int +mdb_id2v_compare( + const MDB_val *usrkey, + const MDB_val *curkey +) +{ + unsigned short *uv, *cv; + ID ui, ci; + int rc; + + memcpy(&ui, usrkey->mv_data, sizeof(ID)); + memcpy(&ci, curkey->mv_data, sizeof(ID)); + if (ui < ci) + return -1; + if (ui > ci) + return 1; + uv = usrkey->mv_data; + cv = curkey->mv_data; + return uv[sizeof(ID)/2] - cv[sizeof(ID)/2]; +} + +/* usrkey[0] is the key in DB format, as described at mdb_mval_put. + * usrkey[1] is the value we'll actually match against. + * usrkey[2] is the attributeDescription for this value. + */ +int +mdb_id2v_dupsort( + const MDB_val *usrkey, + const MDB_val *curkey +) +{ + AttributeDescription *ad = usrkey[2].mv_data; + struct berval bv1, bv2; + int rc, match, olen; + unsigned short s; + char *ptr; + + ptr = curkey->mv_data + curkey->mv_size - 2; + memcpy(&s, ptr, 2); + bv2.bv_val = curkey->mv_data; + bv2.bv_len = curkey->mv_size - 3; + if (s) + bv2.bv_len -= (s+1); + + bv1.bv_val = usrkey[1].mv_data; + bv1.bv_len = usrkey[1].mv_size; + + if (ad) { + MatchingRule *mr = ad->ad_type->sat_equality; + rc = mr->smr_match(&match, SLAP_MR_EQUALITY + | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX + | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH + | SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, + ad->ad_type->sat_syntax, mr, &bv1, &bv2); + } else { + match = ber_bvcmp(&bv1, &bv2); + } + + return match; +} + +/* Values are stored as + * [normalized-value NUL ] original-value NUL 2-byte-len + * The trailing 2-byte-len is zero if there is no normalized value. + * Otherwise, it is the length of the original-value. + */ +int mdb_mval_put(Operation *op, MDB_cursor *mc, ID id, Attribute *a) +{ + struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; + MDB_val key, data[3]; + char *buf; + char ivk[ID2VKSZ]; + unsigned i; + unsigned short s; + int rc, len; + + memcpy(ivk, &id, sizeof(id)); + s = mdb->mi_adxs[a->a_desc->ad_index]; + memcpy(ivk+sizeof(ID), &s, 2); + key.mv_data = &ivk; + key.mv_size = sizeof(ivk); + if ((a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED) || a->a_desc == slap_schema.si_ad_objectClass) + data[2].mv_data = NULL; + else + data[2].mv_data = a->a_desc; + + for (i=0; ia_numvals; i++) { + len = a->a_nvals[i].bv_len + 1 + 2; + if (a->a_nvals != a->a_vals) { + len += a->a_vals[i].bv_len + 1; + data[1].mv_data = a->a_nvals[i].bv_val; + data[1].mv_size = a->a_nvals[i].bv_len; + } else { + data[1].mv_data = a->a_vals[i].bv_val; + data[1].mv_size = a->a_vals[i].bv_len; + } + data[0].mv_size = len; + buf = op->o_tmpalloc( len, op->o_tmpmemctx ); + data[0].mv_data = buf; + memcpy(buf, a->a_nvals[i].bv_val, a->a_nvals[i].bv_len); + buf += a->a_nvals[i].bv_len; + *buf++ = 0; + if (a->a_nvals != a->a_vals) { + s = a->a_vals[i].bv_len; + memcpy(buf, a->a_vals[i].bv_val, a->a_vals[i].bv_len); + buf += a->a_vals[i].bv_len; + *buf++ = 0; + memcpy(buf, &s, 2); + } else { + *buf++ = 0; + *buf++ = 0; + } + rc = mdb_cursor_put(mc, &key, data, 0); + op->o_tmpfree( data[0].mv_data, op->o_tmpmemctx ); + if (rc) + return rc; + } + return 0; +} + +int mdb_mval_del(Operation *op, MDB_cursor *mc, ID id, Attribute *a) +{ + struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; + MDB_val key, data[3]; + char *ptr; + char ivk[ID2VKSZ]; + unsigned i; + int rc; + unsigned short s; + + memcpy(ivk, &id, sizeof(id)); + s = mdb->mi_adxs[a->a_desc->ad_index]; + memcpy(ivk+sizeof(ID), &s, 2); + key.mv_data = &ivk; + key.mv_size = sizeof(ivk); + if ((a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED) || a->a_desc == slap_schema.si_ad_objectClass) + data[2].mv_data = NULL; + else + data[2].mv_data = a->a_desc; + + if (a->a_numvals) { + for (i=0; ia_numvals; i++) { + data[0].mv_data = a->a_nvals[i].bv_val; + data[0].mv_size = a->a_nvals[i].bv_len+1; + if (a->a_nvals != a->a_vals) { + data[1].mv_data = a->a_nvals[i].bv_val; + data[1].mv_size = a->a_nvals[i].bv_len; + } else { + data[1].mv_data = a->a_vals[i].bv_val; + data[1].mv_size = a->a_vals[i].bv_len; + } + rc = mdb_cursor_get(mc, &key, data, MDB_GET_BOTH_RANGE); + if (rc) + return rc; + rc = mdb_cursor_del(mc, 0); + if (rc) + return rc; + } + } else { + rc = mdb_cursor_get(mc, &key, data, MDB_SET); + if (rc) + return rc; + rc = mdb_cursor_del(mc, MDB_NODUPDATA); + } + return rc; +} + +static int mdb_mval_get(Operation *op, MDB_cursor *mc, ID id, Attribute *a, int have_nvals) +{ + struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; + MDB_val key, data[3]; + char *ptr; + char ivk[ID2VKSZ]; + unsigned i; + int rc; + unsigned short s; + + memcpy(ivk, &id, sizeof(id)); + s = mdb->mi_adxs[a->a_desc->ad_index]; + memcpy(ivk+sizeof(ID), &s, 2); + key.mv_data = &ivk; + key.mv_size = sizeof(ivk); + + /* not needed */ + if ((a->a_desc->ad_type->sat_flags & SLAP_AT_ORDERED) || a->a_desc == slap_schema.si_ad_objectClass) + data[2].mv_data = NULL; + else + data[2].mv_data = a->a_desc; + + if (have_nvals) + a->a_nvals = a->a_vals + a->a_numvals + 1; + else + a->a_nvals = a->a_vals; + for (i=0; ia_numvals; i++) { + if (!i) + rc = mdb_cursor_get(mc, &key, data, MDB_SET); + else + rc = mdb_cursor_get(mc, &key, data, MDB_NEXT_DUP); + if (rc) + return rc; + ptr = (char*)data[0].mv_data + data[0].mv_size - 2; + memcpy(&s, ptr, 2); + if (have_nvals) { + a->a_nvals[i].bv_val = data[0].mv_data; + a->a_vals[i].bv_len = s; + a->a_vals[i].bv_val = ptr - a->a_vals[i].bv_len - 1; + a->a_nvals[i].bv_len = a->a_vals[i].bv_val - a->a_nvals[i].bv_val - 1; + } else { + assert(!s); + a->a_vals[i].bv_val = data[0].mv_data; + a->a_vals[i].bv_len = data[0].mv_size - 3; + } + } + BER_BVZERO(&a->a_vals[i]); + if (have_nvals) { + BER_BVZERO(&a->a_nvals[i]); + } + return 0; +} + #define ADD_FLAGS (MDB_NOOVERWRITE|MDB_APPEND) static int mdb_id2entry_put( @@ -47,7 +271,7 @@ static int mdb_id2entry_put( struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; Ecount ec; MDB_val key, data; - int rc; + int rc, adding = flag; /* We only store rdns, and they go in the dn2id database. */ @@ -63,8 +287,11 @@ static int mdb_id2entry_put( if (e->e_id < mdb->mi_nextid) flag &= ~MDB_APPEND; + if (mdb->mi_maxentrysize && ec.len > mdb->mi_maxentrysize) + return LDAP_ADMINLIMIT_EXCEEDED; + again: - data.mv_size = ec.len; + data.mv_size = ec.dlen; if ( mc ) rc = mdb_cursor_put( mc, &key, &data, flag ); else @@ -73,6 +300,31 @@ again: rc = mdb_entry_encode( op, e, &data, &ec ); if( rc != LDAP_SUCCESS ) return rc; + /* Handle adds of large multi-valued attrs here. + * Modifies handle them directly. + */ + if (adding && ec.multi) { + MDB_cursor *mvc; + Attribute *a; + rc = mdb_cursor_open( txn, mdb->mi_dbis[MDB_ID2VAL], &mvc ); + if( !rc ) { + for ( a = ec.multi; a; a=a->a_next ) { + if (!(a->a_flags & SLAP_ATTR_BIG_MULTI)) + continue; + rc = mdb_mval_put( op, mvc, e->e_id, a ); + if( rc ) + break; + } + mdb_cursor_close( mvc ); + } + if ( rc ) { + Debug( LDAP_DEBUG_ANY, + "mdb_id2entry_put: mdb_mval_put failed: %s(%d) \"%s\"\n", + mdb_strerror(rc), rc, + e->e_nname.bv_val ); + return LDAP_OTHER; + } + } } if (rc) { /* Was there a hole from slapadd? */ @@ -92,10 +344,7 @@ again: /* * This routine adds (or updates) an entry on disk. - * The cache should be already be updated. */ - - int mdb_id2entry_add( Operation *op, MDB_txn *txn, @@ -140,7 +389,6 @@ int mdb_id2entry( ID id, Entry **e ) { - struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; MDB_val key, data; int rc = 0; @@ -188,7 +436,7 @@ int mdb_id2entry( rc = MDB_NOTFOUND; if ( rc ) return rc; - rc = mdb_entry_decode( op, mdb_cursor_txn( mc ), &data, e ); + rc = mdb_entry_decode( op, mdb_cursor_txn( mc ), &data, id, e ); if ( rc ) return rc; (*e)->e_id = id; @@ -206,6 +454,7 @@ int mdb_id2entry_delete( struct mdb_info *mdb = (struct mdb_info *) be->be_private; MDB_dbi dbi = mdb->mi_id2entry; MDB_val key; + MDB_cursor *mvc; int rc; key.mv_data = &e->e_id; @@ -213,7 +462,29 @@ int mdb_id2entry_delete( /* delete from database */ rc = mdb_del( tid, dbi, &key, NULL ); + if (rc) + return rc; + rc = mdb_cursor_open( tid, mdb->mi_dbis[MDB_ID2VAL], &mvc ); + if (rc) + return rc; + rc = mdb_cursor_get( mvc, &key, NULL, MDB_SET_RANGE ); + if (rc) { + if (rc == MDB_NOTFOUND) + rc = MDB_SUCCESS; + return rc; + } + while (*(ID *)key.mv_data == e->e_id ) { + rc = mdb_cursor_del( mvc, MDB_NODUPDATA ); + if (rc) + return rc; + rc = mdb_cursor_get( mvc, &key, NULL, MDB_GET_CURRENT ); + if (rc) { + if (rc == MDB_NOTFOUND) + rc = MDB_SUCCESS; + break; + } + } return rc; } @@ -267,7 +538,6 @@ int mdb_entry_release( { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; struct mdb_op_info *moi = NULL; - int rc; /* slapMode : SLAP_SERVER_MODE, SLAP_TOOL_MODE, SLAP_TRUNCATE_MODE, SLAP_UNDEFINED_MODE */ @@ -281,7 +551,7 @@ int mdb_entry_release( mdb_entry_return( op, e ); moi = (mdb_op_info *)oex; /* If it was setup by entry_get we should probably free it */ - if ( moi->moi_flag & MOI_FREEIT ) { + if (( moi->moi_flag & (MOI_FREEIT|MOI_KEEPER)) == MOI_FREEIT ) { moi->moi_ref--; if ( moi->moi_ref < 1 ) { mdb_txn_reset( moi->moi_txn ); @@ -463,7 +733,10 @@ mdb_opinfo_get( Operation *op, struct mdb_info *mdb, int rdonly, mdb_op_info **m if (( slapMode & SLAP_TOOL_MODE ) && mdb_tool_txn ) { moi->moi_txn = mdb_tool_txn; } else { - rc = mdb_txn_begin( mdb->mi_dbenv, NULL, 0, &moi->moi_txn ); + int flag = 0; + if ( get_lazyCommit( op )) + flag |= MDB_NOMETASYNC; + rc = mdb_txn_begin( mdb->mi_dbenv, NULL, flag, &moi->moi_txn ); if (rc) { Debug( LDAP_DEBUG_ANY, "mdb_opinfo_get: err %s(%d)\n", mdb_strerror(rc), rc, 0 ); @@ -535,14 +808,22 @@ int mdb_txn( Operation *op, int txnop, OpExtra **ptr ) switch( txnop ) { case SLAP_TXN_BEGIN: - return mdb_opinfo_get( op, mdb, 0, moip ); + rc = mdb_opinfo_get( op, mdb, 0, moip ); + if ( !rc ) { + moi = *moip; + moi->moi_flag |= MOI_KEEPER; + } + return rc; case SLAP_TXN_COMMIT: rc = mdb_txn_commit( moi->moi_txn ); - op->o_tmpfree( op->o_tmpmemctx, moi ); + if ( rc ) + mdb->mi_numads = 0; + op->o_tmpfree( moi, op->o_tmpmemctx ); return rc; case SLAP_TXN_ABORT: + mdb->mi_numads = 0; mdb_txn_abort( moi->moi_txn ); - op->o_tmpfree( op->o_tmpmemctx, moi ); + op->o_tmpfree( moi, op->o_tmpmemctx ); return 0; } return LDAP_OTHER; @@ -553,11 +834,13 @@ int mdb_txn( Operation *op, int txnop, OpExtra **ptr ) static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e, Ecount *eh) { - ber_len_t len; - int i, nat = 0, nval = 0, nnval = 0; + ber_len_t len, dlen; + int i, nat = 0, nval = 0, nnval = 0, doff = 0; Attribute *a; + eh->multi = NULL; len = 4*sizeof(int); /* nattrs, nvals, ocflags, offset */ + dlen = len; for (a=e->e_attrs; a; a=a->a_next) { /* For AttributeDesc, we only store the attr index */ nat++; @@ -572,52 +855,79 @@ static int mdb_entry_partsize(struct mdb_info *mdb, MDB_txn *txn, Entry *e, return rc; } len += 2*sizeof(int); /* AD index, numvals */ + dlen += 2*sizeof(int); nval += a->a_numvals + 1; /* empty berval at end */ + if (a->a_numvals > mdb->mi_multi_hi) + a->a_flags |= SLAP_ATTR_BIG_MULTI; + if (a->a_flags & SLAP_ATTR_BIG_MULTI) + doff += a->a_numvals; for (i=0; ia_numvals; i++) { - len += a->a_vals[i].bv_len + 1 + sizeof(int); /* len */ + int alen = a->a_vals[i].bv_len + 1 + sizeof(int); /* len */ + len += alen; + if (a->a_flags & SLAP_ATTR_BIG_MULTI) { + if (!eh->multi) + eh->multi = a; + } else { + dlen += alen; + } } if (a->a_nvals != a->a_vals) { nval += a->a_numvals + 1; nnval++; + if (a->a_flags & SLAP_ATTR_BIG_MULTI) + doff += a->a_numvals; for (i=0; ia_numvals; i++) { - len += a->a_nvals[i].bv_len + 1 + sizeof(int);; + int alen = a->a_nvals[i].bv_len + 1 + sizeof(int); + len += alen; + if (!(a->a_flags & SLAP_ATTR_BIG_MULTI)) + dlen += alen; } } } /* padding */ - len = (len + sizeof(ID)-1) & ~(sizeof(ID)-1); + dlen = (dlen + sizeof(ID)-1) & ~(sizeof(ID)-1); eh->len = len; + eh->dlen = dlen; eh->nattrs = nat; eh->nvals = nval; - eh->offset = nat + nval - nnval; + eh->offset = nat + nval - nnval - doff; return 0; } -#define HIGH_BIT (1<<(sizeof(unsigned int)*CHAR_BIT-1)) +/* Flag bits for an encoded attribute */ +#define MDB_AT_SORTED (1<<(sizeof(unsigned int)*CHAR_BIT-1)) + /* the values are in sorted order */ +#define MDB_AT_MULTI (1<<(sizeof(unsigned int)*CHAR_BIT-2)) + /* the values of this multi-valued attr are stored separately */ + +#define MDB_AT_NVALS (1<<(sizeof(unsigned int)*CHAR_BIT-1)) + /* this attribute has normalized values */ /* Flatten an Entry into a buffer. The buffer starts with the count of the * number of attributes in the entry, the total number of values in the * entry, and the e_ocflags. It then contains a list of integers for each * attribute. For each attribute the first integer gives the index of the * matching AttributeDescription, followed by the number of values in the - * attribute. If the high bit of the attr index is set, the attribute's - * values are already sorted. - * If the high bit of numvals is set, the attribute also has normalized - * values present. (Note - a_numvals is an unsigned int, so this means - * it's possible to receive an attribute that we can't encode due to size - * overflow. In practice, this should not be an issue.) Then the length - * of each value is listed. If there are normalized values, their lengths - * come next. This continues for each attribute. After all of the lengths - * for the last attribute, the actual values are copied, with a NUL - * terminator after each value. The buffer is padded to the sizeof(ID). - * The entire buffer size is precomputed so that a single malloc can be - * performed. + * attribute. If the MDB_AT_SORTED bit of the attr index is set, the + * attribute's values are already sorted. If the MDB_AT_MULTI bit of the + * attr index is set, the values are stored separately. + * + * If the MDB_AT_NVALS bit of numvals is set, the attribute also has + * normalized values present. (Note - a_numvals is an unsigned int, so this + * means it's possible to receive an attribute that we can't encode due + * to size overflow. In practice, this should not be an issue.) + * + * Then the length of each value is listed. If there are normalized values, + * their lengths come next. This continues for each attribute. After all + * of the lengths for the last attribute, the actual values are copied, + * with a NUL terminator after each value. + * The buffer is padded to the sizeof(ID). The entire buffer size is + * precomputed so that a single malloc can be performed. */ static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; - ber_len_t len, i; - int rc; + ber_len_t i; Attribute *a; unsigned char *ptr; unsigned int *lp, l; @@ -640,31 +950,37 @@ static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh) if (!a->a_desc->ad_index) return LDAP_UNDEFINED_TYPE; l = mdb->mi_adxs[a->a_desc->ad_index]; + if (a->a_flags & SLAP_ATTR_BIG_MULTI) + l |= MDB_AT_MULTI; if (a->a_flags & SLAP_ATTR_SORTED_VALS) - l |= HIGH_BIT; + l |= MDB_AT_SORTED; *lp++ = l; l = a->a_numvals; if (a->a_nvals != a->a_vals) - l |= HIGH_BIT; + l |= MDB_AT_NVALS; *lp++ = l; - if (a->a_vals) { - for (i=0; a->a_vals[i].bv_val; i++); - assert( i == a->a_numvals ); - for (i=0; ia_numvals; i++) { - *lp++ = a->a_vals[i].bv_len; - memcpy(ptr, a->a_vals[i].bv_val, - a->a_vals[i].bv_len); - ptr += a->a_vals[i].bv_len; - *ptr++ = '\0'; - } - if (a->a_nvals != a->a_vals) { + if (a->a_flags & SLAP_ATTR_BIG_MULTI) { + continue; + } else { + if (a->a_vals) { + for (i=0; a->a_vals[i].bv_val; i++); + assert( i == a->a_numvals ); for (i=0; ia_numvals; i++) { - *lp++ = a->a_nvals[i].bv_len; - memcpy(ptr, a->a_nvals[i].bv_val, - a->a_nvals[i].bv_len); - ptr += a->a_nvals[i].bv_len; + *lp++ = a->a_vals[i].bv_len; + memcpy(ptr, a->a_vals[i].bv_val, + a->a_vals[i].bv_len); + ptr += a->a_vals[i].bv_len; *ptr++ = '\0'; } + if (a->a_nvals != a->a_vals) { + for (i=0; ia_numvals; i++) { + *lp++ = a->a_nvals[i].bv_len; + memcpy(ptr, a->a_nvals[i].bv_val, + a->a_nvals[i].bv_len); + ptr += a->a_nvals[i].bv_len; + *ptr++ = '\0'; + } + } } } } @@ -682,7 +998,7 @@ static int mdb_entry_encode(Operation *op, Entry *e, MDB_val *data, Ecount *eh) * structure. Attempting to do so will likely corrupt memory. */ -int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, Entry **e) +int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, ID id, Entry **e) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; int i, j, nattrs, nvals; @@ -690,10 +1006,10 @@ int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, Entry **e) Attribute *a; Entry *x; const char *text; - AttributeDescription *ad; unsigned int *lp = (unsigned int *)data->mv_data; unsigned char *ptr; BerVarray bptr; + MDB_cursor *mvc = NULL; Debug( LDAP_DEBUG_TRACE, "=> mdb_entry_decode:\n", @@ -712,43 +1028,48 @@ int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, Entry **e) ptr = (unsigned char *)(lp + i); for (;nattrs>0; nattrs--) { - int have_nval = 0; + int have_nval = 0, multi = 0; a->a_flags = SLAP_ATTR_DONT_FREE_DATA | SLAP_ATTR_DONT_FREE_VALS; i = *lp++; - if (i & HIGH_BIT) { - i ^= HIGH_BIT; + if (i & MDB_AT_SORTED) { + i ^= MDB_AT_SORTED; a->a_flags |= SLAP_ATTR_SORTED_VALS; } + if (i & MDB_AT_MULTI) { + i ^= MDB_AT_MULTI; + a->a_flags |= SLAP_ATTR_BIG_MULTI; + multi = 1; + } if (i > mdb->mi_numads) { rc = mdb_ad_read(mdb, txn); if (rc) - return rc; + goto leave; if (i > mdb->mi_numads) { Debug( LDAP_DEBUG_ANY, "mdb_entry_decode: attribute index %d not recognized\n", i, 0, 0 ); - return LDAP_OTHER; + rc = LDAP_OTHER; + goto leave; } } a->a_desc = mdb->mi_ads[i]; a->a_numvals = *lp++; - if (a->a_numvals & HIGH_BIT) { - a->a_numvals ^= HIGH_BIT; + if (a->a_numvals & MDB_AT_NVALS) { + a->a_numvals ^= MDB_AT_NVALS; have_nval = 1; } a->a_vals = bptr; - for (i=0; ia_numvals; i++) { - bptr->bv_len = *lp++;; - bptr->bv_val = (char *)ptr; - ptr += bptr->bv_len+1; - bptr++; - } - bptr->bv_val = NULL; - bptr->bv_len = 0; - bptr++; - - if (have_nval) { - a->a_nvals = bptr; + if (multi) { + if (!mvc) { + rc = mdb_cursor_open(txn, mdb->mi_dbis[MDB_ID2VAL], &mvc); + if (rc) + goto leave; + } + mdb_mval_get(op, mvc, id, a, have_nval); + bptr += a->a_numvals + 1; + if (have_nval) + bptr += a->a_numvals + 1; + } else { for (i=0; ia_numvals; i++) { bptr->bv_len = *lp++; bptr->bv_val = (char *)ptr; @@ -758,9 +1079,23 @@ int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, Entry **e) bptr->bv_val = NULL; bptr->bv_len = 0; bptr++; - } else { - a->a_nvals = a->a_vals; + + if (have_nval) { + a->a_nvals = bptr; + for (i=0; ia_numvals; i++) { + bptr->bv_len = *lp++; + bptr->bv_val = (char *)ptr; + ptr += bptr->bv_len+1; + bptr++; + } + bptr->bv_val = NULL; + bptr->bv_len = 0; + bptr++; + } else { + a->a_nvals = a->a_vals; + } } + /* FIXME: This is redundant once a sorted entry is saved into the DB */ if (( a->a_desc->ad_type->sat_flags & SLAP_AT_SORTED_VAL ) && !(a->a_flags & SLAP_ATTR_SORTED_VALS)) { @@ -772,7 +1107,7 @@ int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, Entry **e) Debug( LDAP_DEBUG_ANY, "mdb_entry_decode: attributeType %s value #%d provided more than once\n", a->a_desc->ad_cname.bv_val, j, 0 ); - return rc; + goto leave; } } a->a_next = a+1; @@ -780,9 +1115,13 @@ int mdb_entry_decode(Operation *op, MDB_txn *txn, MDB_val *data, Entry **e) } a[-1].a_next = NULL; done: - Debug(LDAP_DEBUG_TRACE, "<= mdb_entry_decode\n", 0, 0, 0 ); *e = x; - return 0; + rc = 0; + +leave: + if (mvc) + mdb_cursor_close(mvc); + return rc; }