/* Check that all filter terms reside in the same table. * * If any of the filter terms are indexed, then only an IndexScan of the OL_index * will be performed. If none are indexed, but all the terms reside in a single * table, a Scan can be performed with the LDAP filter transformed into a ScanFilter. * * Otherwise, a full scan of the DB must be done with all filtering done by slapd. */ static int ndb_filter_check( struct ndb_info *ni, Filter *f, NdbOcInfo **oci, int *indexed, int *ocfilter ) { AttributeDescription *ad = NULL; ber_tag_t choice = f->f_choice; int rc = 0, undef = 0; if ( choice & SLAPD_FILTER_UNDEFINED ) { choice &= SLAPD_FILTER_MASK; undef = 1; } switch( choice ) { case LDAP_FILTER_AND: case LDAP_FILTER_OR: case LDAP_FILTER_NOT: for ( f = f->f_list; f; f=f->f_next ) { rc = ndb_filter_check( ni, f, oci, indexed, ocfilter ); if ( rc ) return rc; } break; case LDAP_FILTER_PRESENT: ad = f->f_desc; break; case LDAP_FILTER_EQUALITY: case LDAP_FILTER_SUBSTRINGS: case LDAP_FILTER_GE: case LDAP_FILTER_LE: case LDAP_FILTER_APPROX: ad = f->f_av_desc; break; default: break; } if ( ad && !undef ) { NdbAttrInfo *ai; /* ObjectClass filtering is in dn2id table */ if ( ad == slap_schema.si_ad_objectClass ) { if ( choice == LDAP_FILTER_EQUALITY ) (*ocfilter)++; return 0; } ai = ndb_ai_find( ni, ad->ad_type ); if ( ai ) { if ( ai->na_flag & NDB_INFO_INDEX ) (*indexed)++; if ( *oci ) { if ( ai->na_oi != *oci ) rc = -1; } else { *oci = ai->na_oi; } } } return rc; }
int ndb_modify_internal( Operation *op, NdbArgs *NA, const char **text, char *textbuf, size_t textlen ) { struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private; Modification *mod; Modifications *ml; Modifications *modlist = op->orm_modlist; NdbAttrInfo **modai, *atmp; const NdbDictionary::Dictionary *myDict; const NdbDictionary::Table *myTable; int got_oc = 0, nmods = 0, nai = 0, i, j; int rc, indexed = 0; Attribute *old = NULL; Debug( LDAP_DEBUG_TRACE, "ndb_modify_internal: 0x%08lx: %s\n", NA->e->e_id, NA->e->e_dn, 0); if ( !acl_check_modlist( op, NA->e, modlist )) { return LDAP_INSUFFICIENT_ACCESS; } old = attrs_dup( NA->e->e_attrs ); for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { mod = &ml->sml_mod; nmods++; switch ( mod->sm_op ) { case LDAP_MOD_ADD: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: add %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); rc = modify_add_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case LDAP_MOD_DELETE: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: delete %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); rc = ndb_modify_delete( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen, NULL ); assert( rc != LDAP_TYPE_OR_VALUE_EXISTS ); if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case LDAP_MOD_REPLACE: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: replace %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); rc = modify_replace_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case LDAP_MOD_INCREMENT: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: increment %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); rc = modify_increment_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case SLAP_MOD_SOFTADD: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: softadd %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); mod->sm_op = LDAP_MOD_ADD; rc = modify_add_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); mod->sm_op = SLAP_MOD_SOFTADD; if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) { rc = LDAP_SUCCESS; } if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case SLAP_MOD_SOFTDEL: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: softdel %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); mod->sm_op = LDAP_MOD_DELETE; rc = modify_delete_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); mod->sm_op = SLAP_MOD_SOFTDEL; if ( rc == LDAP_NO_SUCH_ATTRIBUTE) { rc = LDAP_SUCCESS; } if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; case SLAP_MOD_ADD_IF_NOT_PRESENT: Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: add_if_not_present %s\n", mod->sm_desc->ad_cname.bv_val, 0, 0); if ( attr_find( NA->e->e_attrs, mod->sm_desc ) ) { rc = LDAP_SUCCESS; break; } mod->sm_op = LDAP_MOD_ADD; rc = modify_add_values( NA->e, mod, get_permissiveModify(op), text, textbuf, textlen ); mod->sm_op = SLAP_MOD_ADD_IF_NOT_PRESENT; if( rc != LDAP_SUCCESS ) { Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } break; default: Debug(LDAP_DEBUG_ANY, "ndb_modify_internal: invalid op %d\n", mod->sm_op, 0, 0); *text = "Invalid modify operation"; rc = LDAP_OTHER; Debug(LDAP_DEBUG_ARGS, "ndb_modify_internal: %d %s\n", rc, *text, 0); } if ( rc != LDAP_SUCCESS ) { attrs_free( old ); return rc; } /* If objectClass was modified, reset the flags */ if ( mod->sm_desc == slap_schema.si_ad_objectClass ) { NA->e->e_ocflags = 0; got_oc = 1; } } /* check that the entry still obeys the schema */ rc = entry_schema_check( op, NA->e, NULL, get_relax(op), 0, NULL, text, textbuf, textlen ); if ( rc != LDAP_SUCCESS || op->o_noop ) { if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "entry failed schema check: %s\n", *text, 0, 0 ); } attrs_free( old ); return rc; } if ( got_oc ) { rc = ndb_entry_put_info( op->o_bd, NA, 1 ); if ( rc ) { attrs_free( old ); return rc; } } /* apply modifications to DB */ modai = (NdbAttrInfo **)op->o_tmpalloc( nmods * sizeof(NdbAttrInfo*), op->o_tmpmemctx ); /* Get the unique list of modified attributes */ ldap_pvt_thread_rdwr_rlock( &ni->ni_ai_rwlock ); for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { /* Already took care of objectclass */ if ( ml->sml_desc == slap_schema.si_ad_objectClass ) continue; for ( i=0; i<nai; i++ ) { if ( ml->sml_desc->ad_type == modai[i]->na_attr ) break; } /* This attr was already updated */ if ( i < nai ) continue; modai[nai] = ndb_ai_find( ni, ml->sml_desc->ad_type ); if ( modai[nai]->na_flag & NDB_INFO_INDEX ) indexed++; nai++; } ldap_pvt_thread_rdwr_runlock( &ni->ni_ai_rwlock ); /* If got_oc, this was already done above */ if ( indexed && !got_oc) { rc = ndb_entry_put_info( op->o_bd, NA, 1 ); if ( rc ) { attrs_free( old ); return rc; } } myDict = NA->ndb->getDictionary(); /* sort modai so that OcInfo's are contiguous */ { int j, k; for ( i=0; i<nai; i++ ) { for ( j=i+1; j<nai; j++ ) { if ( modai[i]->na_oi == modai[j]->na_oi ) continue; for ( k=j+1; k<nai; k++ ) { if ( modai[i]->na_oi == modai[k]->na_oi ) { atmp = modai[j]; modai[j] = modai[k]; modai[k] = atmp; break; } } /* there are no more na_oi's that match modai[i] */ if ( k == nai ) { i = j; } } } } /* One call per table... */ for ( i=0; i<nai; i += j ) { atmp = modai[i]; for ( j=i+1; j<nai; j++ ) if ( atmp->na_oi != modai[j]->na_oi ) break; j -= i; myTable = myDict->getTable( atmp->na_oi->no_table.bv_val ); if ( !myTable ) continue; rc = ndb_oc_attrs( NA->txn, myTable, NA->e, atmp->na_oi, &modai[i], j, old ); if ( rc ) break; } attrs_free( old ); return rc; }
static int ndb_filter_set( Operation *op, struct ndb_info *ni, Filter *f, int indexed, NdbIndexScanOperation *scan, NdbScanFilter *sf, int *bounds ) { AttributeDescription *ad = NULL; ber_tag_t choice = f->f_choice; int undef = 0; if ( choice & SLAPD_FILTER_UNDEFINED ) { choice &= SLAPD_FILTER_MASK; undef = 1; } switch( choice ) { case LDAP_FILTER_NOT: /* no indexing for these */ break; case LDAP_FILTER_OR: /* FIXME: these bounds aren't right. */ if ( indexed ) { scan->end_of_bound( (*bounds)++ ); } case LDAP_FILTER_AND: if ( sf ) { sf->begin( choice == LDAP_FILTER_OR ? NdbScanFilter::OR : NdbScanFilter::AND ); } for ( f = f->f_list; f; f=f->f_next ) { if ( ndb_filter_set( op, ni, f, indexed, scan, sf, bounds )) return -1; } if ( sf ) { sf->end(); } break; case LDAP_FILTER_PRESENT: ad = f->f_desc; break; case LDAP_FILTER_EQUALITY: case LDAP_FILTER_SUBSTRINGS: case LDAP_FILTER_GE: case LDAP_FILTER_LE: case LDAP_FILTER_APPROX: ad = f->f_av_desc; break; default: break; } if ( ad && !undef ) { NdbAttrInfo *ai; /* ObjectClass filtering is in dn2id table */ if ( ad == slap_schema.si_ad_objectClass ) { return 0; } ai = ndb_ai_find( ni, ad->ad_type ); if ( ai ) { int rc; if ( ai->na_flag & NDB_INFO_INDEX ) { char *buf, *ptr; NdbIndexScanOperation::BoundType bt; switch(choice) { case LDAP_FILTER_PRESENT: rc = scan->setBound( ai->na_ixcol - IDX_COLUMN, NdbIndexScanOperation::BoundGT, NULL ); break; case LDAP_FILTER_EQUALITY: case LDAP_FILTER_APPROX: bt = NdbIndexScanOperation::BoundEQ; goto setit; case LDAP_FILTER_GE: bt = NdbIndexScanOperation::BoundGE; goto setit; case LDAP_FILTER_LE: bt = NdbIndexScanOperation::BoundLE; setit: rc = f->f_av_value.bv_len+1; if ( ai->na_len > 255 ) rc++; buf = (char *)op->o_tmpalloc( rc, op->o_tmpmemctx ); rc = f->f_av_value.bv_len; buf[0] = rc & 0xff; ptr = buf+1; if ( ai->na_len > 255 ) { buf[1] = (rc >> 8); ptr++; } memcpy( ptr, f->f_av_value.bv_val, f->f_av_value.bv_len ); rc = scan->setBound( ai->na_ixcol - IDX_COLUMN, bt, buf ); op->o_tmpfree( buf, op->o_tmpmemctx ); break; default: break; } } else if ( sf ) {