]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-ndb/search.cpp
Happy New Year!
[openldap] / servers / slapd / back-ndb / search.cpp
index 27ff48c993e09e7f64d8951b5d368ca1804f11e8..fe9c5e691ecf8c6e4a9d877797ff446b57cf8754 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 2008 The OpenLDAP Foundation.
+ * Copyright 2008-2012 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -110,7 +110,7 @@ static int ndb_filter_check( struct ndb_info *ni, Filter *f,
 }
 
 static int ndb_filter_set( Operation *op, struct ndb_info *ni, Filter *f, int indexed,
-       NdbIndexScanOperation *scan, NdbScanFilter **sf, int *bounds )
+       NdbIndexScanOperation *scan, NdbScanFilter *sf, int *bounds )
 {
        AttributeDescription *ad = NULL;
        ber_tag_t choice = f->f_choice;
@@ -130,10 +130,16 @@ static int ndb_filter_set( Operation *op, struct ndb_info *ni, Filter *f, int in
                        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;
@@ -156,10 +162,10 @@ static int ndb_filter_set( Operation *op, struct ndb_info *ni, Filter *f, int in
                }
                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;
-                               int rc;
 
                                switch(choice) {
                                case LDAP_FILTER_PRESENT:
@@ -194,7 +200,68 @@ static int ndb_filter_set( Operation *op, struct ndb_info *ni, Filter *f, int in
                                default:
                                        break;
                                }
-                       } else {
+                       } else if ( sf ) {
+                               char *buf, *ptr;
+                               NdbScanFilter::BinaryCondition bc;
+
+                               switch(choice) {
+                               case LDAP_FILTER_PRESENT:
+                                       rc = sf->isnotnull( ai->na_column );
+                                       break;
+                               case LDAP_FILTER_EQUALITY:
+                               case LDAP_FILTER_APPROX:
+                                       bc = NdbScanFilter::COND_EQ;
+                                       goto setf;
+                               case LDAP_FILTER_GE:
+                                       bc = NdbScanFilter::COND_GE;
+                                       goto setf;
+                               case LDAP_FILTER_LE:
+                                       bc = NdbScanFilter::COND_LE;
+                               setf:
+                                       rc = sf->cmp( bc, ai->na_column, f->f_av_value.bv_val, f->f_av_value.bv_len );
+                                       break;
+                               case LDAP_FILTER_SUBSTRINGS:
+                                       rc = 0;
+                                       if ( f->f_sub_initial.bv_val )
+                                               rc += f->f_sub_initial.bv_len + 1;
+                                       if ( f->f_sub_any ) {
+                                               int i;
+                                               if ( !rc ) rc++;
+                                               for (i=0; f->f_sub_any[i].bv_val; i++)
+                                                       rc += f->f_sub_any[i].bv_len + 1;
+                                       }
+                                       if ( f->f_sub_final.bv_val ) {
+                                               if ( !rc ) rc++;
+                                               rc += f->f_sub_final.bv_len;
+                                       }
+                                       buf = (char *)op->o_tmpalloc( rc+1, op->o_tmpmemctx );
+                                       ptr = buf;
+                                       if ( f->f_sub_initial.bv_val ) {
+                                               memcpy( ptr, f->f_sub_initial.bv_val, f->f_sub_initial.bv_len );
+                                               ptr += f->f_sub_initial.bv_len;
+                                               *ptr++ = '%';
+                                       }
+                                       if ( f->f_sub_any ) {
+                                               int i;
+                                               if ( ptr == buf )
+                                                       *ptr++ = '%';
+                                               for (i=0; f->f_sub_any[i].bv_val; i++) {
+                                                       memcpy( ptr, f->f_sub_any[i].bv_val, f->f_sub_any[i].bv_len );
+                                                       ptr += f->f_sub_any[i].bv_len;
+                                                       *ptr++ = '%';
+                                               }
+                                       }
+                                       if ( f->f_sub_final.bv_val ) {
+                                               if ( ptr == buf )
+                                                       *ptr++ = '%';
+                                               memcpy( ptr, f->f_sub_final.bv_val, f->f_sub_final.bv_len );
+                                               ptr += f->f_sub_final.bv_len;
+                                       }
+                                       *ptr = '\0';
+                                       rc = sf->cmp( NdbScanFilter::COND_LIKE, ai->na_column, buf, ptr - buf );
+                                       op->o_tmpfree( buf, op->o_tmpmemctx );
+                                       break;
+                               }
                        }
                }
        }
@@ -211,7 +278,7 @@ static int ndb_oc_search( Operation *op, SlapReply *rs, Ndb *ndb, NdbTransaction
        NdbIndexScanOperation *scan;
        NdbIndexOperation *ixop;
        NdbScanFilter *sf = NULL;
-       struct berval *ocs, matched;
+       struct berval *ocs;
        NdbRecAttr *scanID, *scanOC, *scanDN[NDB_MAX_RDNS];
        char dnBuf[2048], *ptr;
        NdbRdns rdns;
@@ -221,12 +288,18 @@ static int ndb_oc_search( Operation *op, SlapReply *rs, Ndb *ndb, NdbTransaction
        int i, rc, bounds;
        Entry e = {0};
        Uint64 eid;
+       time_t stoptime;
+       int manageDSAit;
+
+       stoptime = op->o_time + op->ors_tlimit;
+       manageDSAit = get_manageDSAit( op );
 
        myTable = myDict->getTable( oci->no_table.bv_val );
        if ( indexed ) { 
                scan = txn->getNdbIndexScanOperation( INDEX_NAME, DN2ID_TABLE );
                if ( !scan )
                        return LDAP_OTHER;
+               scan->readTuples( NdbOperation::LM_CommittedRead );
        } else {
                myIndex = myDict->getIndex( "eid$unique", DN2ID_TABLE );
                if ( !myIndex ) {
@@ -237,6 +310,8 @@ static int ndb_oc_search( Operation *op, SlapReply *rs, Ndb *ndb, NdbTransaction
                scan = (NdbIndexScanOperation *)txn->getNdbScanOperation( myTable );
                if ( !scan )
                        return LDAP_OTHER;
+               scan->readTuples( NdbOperation::LM_CommittedRead );
+#if 1
                sf = new NdbScanFilter(scan);
                if ( !sf )
                        return LDAP_OTHER;
@@ -251,13 +326,14 @@ static int ndb_oc_search( Operation *op, SlapReply *rs, Ndb *ndb, NdbTransaction
                                goto leave;
                        }
                }
+#endif
        }
-       scan->readTuples( NdbOperation::LM_CommittedRead );
 
        bounds = 0;
-       rc = ndb_filter_set( op, ni, op->ors_filter, indexed, scan, &sf, &bounds );
+       rc = ndb_filter_set( op, ni, op->ors_filter, indexed, scan, sf, &bounds );
        if ( rc )
                goto leave;
+       if ( sf ) sf->end();
        
        scanID = scan->getValue( EID_COLUMN, idbuf );
        if ( indexed ) {
@@ -276,10 +352,22 @@ static int ndb_oc_search( Operation *op, SlapReply *rs, Ndb *ndb, NdbTransaction
        e.e_name.bv_val = dnBuf;
        NA.e = &e;
        NA.ndb = ndb;
-       while ( scan->nextResult() == 0 ) {
+       while ( scan->nextResult( true, true ) == 0 ) {
                NdbTransaction *tx2;
-               if ( op->o_abandon )
+               if ( op->o_abandon ) {
+                       rs->sr_err = SLAPD_ABANDON;
+                       break;
+               }
+               if ( slapd_shutdown ) {
+                       rs->sr_err = LDAP_UNAVAILABLE;
                        break;
+               }
+               if ( op->ors_tlimit != SLAP_NO_LIMIT &&
+                       slap_get_time() > stoptime ) {
+                       rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
+                       break;
+               }
+
                eid = scanID->u_64_value();
                e.e_id = eid;
                if ( !indexed ) {
@@ -311,7 +399,7 @@ static int ndb_oc_search( Operation *op, SlapReply *rs, Ndb *ndb, NdbTransaction
                        }
                }
 
-               ocs = ndb_ref2oclist( ocbuf );
+               ocs = ndb_ref2oclist( ocbuf, op->o_tmpmemctx );
                for ( i=0; i<NDB_MAX_RDNS; i++ ) {
                        if ( scanDN[i]->isNULL() || !rdns.nr_buf[i][0] )
                                break;
@@ -357,9 +445,9 @@ static int ndb_oc_search( Operation *op, SlapReply *rs, Ndb *ndb, NdbTransaction
 
                dnNormalize( 0, NULL, NULL, &e.e_name, &e.e_nname, op->o_tmpmemctx );
                {
-#ifdef notdef          /* NDBapi is broken here */
+#if 1  /* NDBapi was broken here but seems to work now */
                        Ndb::Key_part_ptr keys[2];
-                       char xbuf[32];
+                       char xbuf[512];
                        keys[0].ptr = &eid;
                        keys[0].len = sizeof(eid);
                        keys[1].ptr = NULL;
@@ -374,19 +462,31 @@ static int ndb_oc_search( Operation *op, SlapReply *rs, Ndb *ndb, NdbTransaction
                        }
                        NA.txn = tx2;
                        NA.ocs = ocs;
-                       rc = ndb_entry_get_data( op->o_bd, &NA, 0 );
+                       rc = ndb_entry_get_data( op, &NA, 0 );
                        tx2->close();
                }
-               ber_bvarray_free( ocs );
-               rc = test_filter( op, &e, op->ors_filter );
-               if ( rc == LDAP_COMPARE_TRUE ) {
-                       rs->sr_entry = &e;
-                       rs->sr_attrs = op->ors_attrs;
-                       rs->sr_flags = 0;
-                       rc = send_search_entry( op, rs );
-                       rs->sr_entry = NULL;
-               } else {
-                       rc = 0;
+               ber_bvarray_free_x( ocs, op->o_tmpmemctx );
+               if ( !manageDSAit && is_entry_referral( &e )) {
+                       BerVarray erefs = get_entry_referrals( op, &e );
+                       rs->sr_ref = referral_rewrite( erefs, &e.e_name, NULL,
+                               op->ors_scope == LDAP_SCOPE_ONELEVEL ?
+                                       LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
+                       rc = send_search_reference( op, rs );
+                       ber_bvarray_free( rs->sr_ref );
+                       ber_bvarray_free( erefs );
+                       rs->sr_ref = NULL;
+               } else if ( manageDSAit || !is_entry_glue( &e )) {
+                       rc = test_filter( op, &e, op->ors_filter );
+                       if ( rc == LDAP_COMPARE_TRUE ) {
+                               rs->sr_entry = &e;
+                               rs->sr_attrs = op->ors_attrs;
+                               rs->sr_flags = 0;
+                               rc = send_search_entry( op, rs );
+                               rs->sr_entry = NULL;
+                               rs->sr_attrs = NULL;
+                       } else {
+                               rc = 0;
+                       }
                }
                attrs_free( e.e_attrs );
                e.e_attrs = NULL;
@@ -402,7 +502,7 @@ extern "C"
 int ndb_back_search( Operation *op, SlapReply *rs )
 {
        struct ndb_info *ni = (struct ndb_info *) op->o_bd->be_private;
-       NdbTransaction *txn, *tx2;
+       NdbTransaction *txn;
        NdbIndexScanOperation *scan;
        NdbScanFilter *sf = NULL;
        Entry e = {0};
@@ -415,10 +515,15 @@ int ndb_back_search( Operation *op, SlapReply *rs )
        NdbRdns rdns;
        NdbOcInfo *oci;
        NdbArgs NA;
+       slap_mask_t mask;
+       time_t stoptime;
+       int manageDSAit;
 
        rc = ndb_thread_handle( op, &NA.ndb );
        rdns.nr_num = 0;
 
+       manageDSAit = get_manageDSAit( op );
+
        txn = NA.ndb->startTransaction();
        if ( !txn ) {
                Debug( LDAP_DEBUG_TRACE,
@@ -431,22 +536,64 @@ int ndb_back_search( Operation *op, SlapReply *rs )
 
        NA.txn = txn;
        e.e_name = op->o_req_dn;
+       e.e_nname = op->o_req_ndn;
        NA.e = &e;
        NA.rdns = &rdns;
-       NA.ocs = op->ors_scope == LDAP_SCOPE_BASE ? NULL : &matched;
+       NA.ocs = NULL;
 
-       rs->sr_err = ndb_entry_get_info( op->o_bd, &NA, 0, &matched );
+       rs->sr_err = ndb_entry_get_info( op, &NA, 0, &matched );
        if ( rs->sr_err ) {
-               if ( rs->sr_err == LDAP_NO_SUCH_OBJECT )
+               if ( rs->sr_err == LDAP_NO_SUCH_OBJECT ) {
                        rs->sr_matched = matched.bv_val;
+                       if ( NA.ocs )
+                               ndb_check_referral( op, rs, &NA );
+               }
                goto leave;
        }
 
+       if ( !access_allowed_mask( op, &e, slap_schema.si_ad_entry,
+               NULL, ACL_SEARCH, NULL, &mask )) {
+               if ( !ACL_GRANT( mask, ACL_DISCLOSE ))
+                       rs->sr_err = LDAP_NO_SUCH_OBJECT;
+               else
+                       rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+               ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
+               goto leave;
+       }
+
+       rs->sr_err = ndb_entry_get_data( op, &NA, 0 );
+       ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
+       if ( rs->sr_err )
+               goto leave;
+
+       if ( !manageDSAit && is_entry_referral( &e )) {
+               rs->sr_ref = get_entry_referrals( op, &e );
+               rs->sr_err = LDAP_REFERRAL;
+               if ( rs->sr_ref )
+                       rs->sr_flags |= REP_REF_MUSTBEFREED;
+               rs->sr_matched = e.e_name.bv_val;
+               attrs_free( e.e_attrs );
+               e.e_attrs = NULL;
+               goto leave;
+       }
+
+       if ( !manageDSAit && is_entry_glue( &e )) {
+               rs->sr_err = LDAP_NO_SUCH_OBJECT;
+               goto leave;
+       }
+
+       if ( get_assert( op ) && test_filter( op, &e, (Filter *)get_assertion( op )) !=
+               LDAP_COMPARE_TRUE ) {
+               rs->sr_err = LDAP_ASSERTION_FAILED;
+               attrs_free( e.e_attrs );
+               e.e_attrs = NULL;
+               goto leave;
+       }
+
+       /* admin ignores tlimits */
+       stoptime = op->o_time + op->ors_tlimit;
+
        if ( op->ors_scope == LDAP_SCOPE_BASE ) {
-               e.e_name = op->o_req_dn;
-               e.e_nname = op->o_req_ndn;
-               rc = ndb_entry_get_data( op->o_bd, &NA, 0 );
-               ber_bvarray_free( NA.ocs );
                rc = test_filter( op, &e, op->ors_filter );
                if ( rc == LDAP_COMPARE_TRUE ) {
                        rs->sr_entry = &e;
@@ -459,11 +606,15 @@ int ndb_back_search( Operation *op, SlapReply *rs )
                e.e_attrs = NULL;
                rs->sr_err = LDAP_SUCCESS;
                goto leave;
-       } else if ( rdns.nr_num == NDB_MAX_RDNS ) {
-               if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ||
-                       op->ors_scope == LDAP_SCOPE_CHILDREN )
-               rs->sr_err = LDAP_SUCCESS;
-               goto leave;
+       } else {
+               attrs_free( e.e_attrs );
+               e.e_attrs = NULL;
+               if ( rdns.nr_num == NDB_MAX_RDNS ) {
+                       if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ||
+                               op->ors_scope == LDAP_SCOPE_CHILDREN )
+                       rs->sr_err = LDAP_SUCCESS;
+                       goto leave;
+               }
        }
 
        /* See if we can handle the filter. Filtering on objectClass is only done
@@ -484,9 +635,17 @@ int ndb_back_search( Operation *op, SlapReply *rs )
        }
 
        scan = txn->getNdbIndexScanOperation( "PRIMARY", DN2ID_TABLE );
+       if ( !scan ) {
+               rs->sr_err = LDAP_OTHER;
+               goto leave;
+       }
        scan->readTuples( NdbOperation::LM_CommittedRead );
        rc = ndb_dn2bound( scan, &rdns );
 
+       /* TODO: if ( ocfilter ) set up scanfilter for objectclass matches
+        * column COND_LIKE "% <class> %"
+        */
+
        switch( op->ors_scope ) {
        case LDAP_SCOPE_ONELEVEL:
                sf = new NdbScanFilter(scan);
@@ -517,11 +676,22 @@ int ndb_back_search( Operation *op, SlapReply *rs )
        }
 
        e.e_name.bv_val = dnBuf;
-       while ( scan->nextResult() == 0 ) {
-               if ( op->o_abandon )
+       while ( scan->nextResult( true, true ) == 0 ) {
+               if ( op->o_abandon ) {
+                       rs->sr_err = SLAPD_ABANDON;
+                       break;
+               }
+               if ( slapd_shutdown ) {
+                       rs->sr_err = LDAP_UNAVAILABLE;
+                       break;
+               }
+               if ( op->ors_tlimit != SLAP_NO_LIMIT &&
+                       slap_get_time() > stoptime ) {
+                       rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
                        break;
+               }
                e.e_id = scanID->u_64_value();
-               NA.ocs = ndb_ref2oclist( ocbuf );
+               NA.ocs = ndb_ref2oclist( ocbuf, op->o_tmpmemctx );
                for ( i=0; i<NDB_MAX_RDNS; i++ ) {
                        if ( scanDN[i]->isNULL() || !rdns.nr_buf[i][0] )
                                break;
@@ -540,18 +710,29 @@ int ndb_back_search( Operation *op, SlapReply *rs )
                e.e_name.bv_len = ptr - dnBuf;
                dnNormalize( 0, NULL, NULL, &e.e_name, &e.e_nname, op->o_tmpmemctx );
                NA.txn = NA.ndb->startTransaction();
-               rc = ndb_entry_get_data( op->o_bd, &NA, 0 );
+               rc = ndb_entry_get_data( op, &NA, 0 );
                NA.txn->close();
-               ber_bvarray_free( NA.ocs );
-               rc = test_filter( op, &e, op->ors_filter );
-               if ( rc == LDAP_COMPARE_TRUE ) {
-                       rs->sr_entry = &e;
-                       rs->sr_attrs = op->ors_attrs;
-                       rs->sr_flags = 0;
-                       rc = send_search_entry( op, rs );
-                       rs->sr_entry = NULL;
-               } else {
-                       rc = 0;
+               ber_bvarray_free_x( NA.ocs, op->o_tmpmemctx );
+               if ( !manageDSAit && is_entry_referral( &e )) {
+                       BerVarray erefs = get_entry_referrals( op, &e );
+                       rs->sr_ref = referral_rewrite( erefs, &e.e_name, NULL,
+                               op->ors_scope == LDAP_SCOPE_ONELEVEL ?
+                                       LDAP_SCOPE_BASE : LDAP_SCOPE_SUBTREE );
+                       rc = send_search_reference( op, rs );
+                       ber_bvarray_free( rs->sr_ref );
+                       ber_bvarray_free( erefs );
+                       rs->sr_ref = NULL;
+               } else if ( manageDSAit || !is_entry_glue( &e )) {
+                       rc = test_filter( op, &e, op->ors_filter );
+                       if ( rc == LDAP_COMPARE_TRUE ) {
+                               rs->sr_entry = &e;
+                               rs->sr_attrs = op->ors_attrs;
+                               rs->sr_flags = 0;
+                               rc = send_search_entry( op, rs );
+                               rs->sr_entry = NULL;
+                       } else {
+                               rc = 0;
+                       }
                }
                attrs_free( e.e_attrs );
                e.e_attrs = NULL;
@@ -561,11 +742,14 @@ int ndb_back_search( Operation *op, SlapReply *rs )
 leave:
        if ( sf )
                delete sf;
-       txn->close();
+       if ( txn )
+               txn->close();
        send_ldap_result( op, rs );
        return rs->sr_err;
 }
 
+extern NdbInterpretedCode *ndb_lastrow_code;   /* init.cpp */
+
 extern "C" int
 ndb_has_children(
        NdbArgs *NA,
@@ -580,7 +764,7 @@ ndb_has_children(
                *hasChildren = LDAP_COMPARE_FALSE;
                return 0;
        }
-               
+
        scan = NA->txn->getNdbIndexScanOperation( "PRIMARY", DN2ID_TABLE );
        if ( !scan )
                return LDAP_OTHER;
@@ -589,15 +773,20 @@ ndb_has_children(
        if ( rc < NDB_MAX_RDNS ) {
                scan->setBound( rc, NdbIndexScanOperation::BoundLT, "\0" );
        }
+#if 0
        scan->interpret_exit_last_row();
+#else
+       scan->setInterpretedCode(ndb_lastrow_code);
+#endif
        scan->getValue( EID_COLUMN, idbuf );
        if ( NA->txn->execute( NdbTransaction::NoCommit, NdbOperation::AO_IgnoreError, 1 )) {
                return LDAP_OTHER;
        }
-       if (rc < NDB_MAX_RDNS && scan->nextResult() == 0 )
+       if (rc < NDB_MAX_RDNS && scan->nextResult( true, true ) == 0 )
                *hasChildren = LDAP_COMPARE_TRUE;
        else
                *hasChildren = LDAP_COMPARE_FALSE;
+       scan->close();
        return 0;
 }
 
@@ -638,11 +827,16 @@ ndb_operational(
 
        assert( rs->sr_entry != NULL );
 
-       for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next )
-               /* just count */ ;
+       for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) {
+               if ( (*ap)->a_desc == slap_schema.si_ad_hasSubordinates ) {
+                       break;
+               }
+       }
 
-       if ( SLAP_OPATTRS( rs->sr_attr_flags ) ||
-                       ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) )
+       if ( *ap == NULL &&
+               attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL &&
+               ( SLAP_OPATTRS( rs->sr_attr_flags ) ||
+                       ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) )
        {
                int     hasSubordinates, rc;