struct slap_limits_set *limit = NULL;
        int isroot = 0;
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+       int             filter_hasSubordinates = 0;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
        u_int32_t       locker;
        DB_LOCK         lock;
 
                }
        }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+       /*
+        * is hasSubordinates used in the filter ?
+        * FIXME: we may compute this directly when parsing the filter
+        */
+       filter_hasSubordinates = filter_has_subordinates( filter );
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
        for ( id = bdb_idl_first( candidates, &cursor );
                id != NOID;
                id = bdb_idl_next( candidates, &cursor ) )
        {
                int             scopeok = 0;
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               Attribute       *hasSubordinates = NULL;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
 
                /* check for abandon */
                if ( op->o_abandon ) {
                        goto loop_continue;
                }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               /*
+                * if hasSubordinates is used in the filter,
+                * append it to the entry's attributes
+                */
+               if ( filter_hasSubordinates ) {
+                       int     hs;
+
+                       rc = bdb_hasSubordinates( be, conn, op, e, &hs);
+                       if ( rc != LDAP_SUCCESS ) {
+                               goto loop_continue;
+                       }
+
+                       hasSubordinates = slap_operational_hasSubordinate( hs == LDAP_COMPARE_TRUE );
+                       if ( hasSubordinates == NULL ) {
+                               goto loop_continue;
+                       }
+
+                       hasSubordinates->a_next = e->e_attrs;
+                       e->e_attrs = hasSubordinates;
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
                /* if it matches the filter and scope, send it */
                rc = test_filter( be, conn, op, e, filter );
+
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               if ( hasSubordinates ) {
+                       /*
+                        * FIXME: this is fairly inefficient, because 
+                        * if hasSubordinates is among the required
+                        * attrs, it will be added again later;
+                        * maybe we should leave it and check
+                        * check later if it's already present,
+                        * if required
+                        */
+                       e->e_attrs = e->e_attrs->a_next;
+                       attr_free( hasSubordinates );
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
                if ( rc == LDAP_COMPARE_TRUE ) {
                        struct berval   dn;
 
                        }
                } else {
 #ifdef NEW_LOGGING
-                               LDAP_LOG ( OPERATION, RESULTS,
-                                       "bdb_search: %ld does match filter\n", (long) id, 0, 0);
+                       LDAP_LOG ( OPERATION, RESULTS,
+                               "bdb_search: %ld does match filter\n", (long) id, 0, 0);
 #else
                        Debug( LDAP_DEBUG_TRACE,
                                "bdb_search: %ld does match filter\n",
 
        return rc;
 }
+
 
        struct slap_limits_set *limit = NULL;
        int isroot = 0;
                
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+       int             filter_hasSubordinates = 0;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
 #ifdef NEW_LOGGING
        LDAP_LOG( BACK_LDBM, ENTRY, "ldbm_back_search: enter\n", 0, 0, 0 );
 #else
        /* compute it anyway; root does not use it */
        stoptime = op->o_time + tlimit;
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+       /*
+        * is hasSubordinates used in the filter ?
+        * FIXME: we may compute this directly when parsing the filter
+        */
+       filter_hasSubordinates = filter_has_subordinates( filter );
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
        for ( id = idl_firstid( candidates, &cursor ); id != NOID;
            id = idl_nextid( candidates, &cursor ) )
        {
                int scopeok = 0;
+               int result = 0;
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               Attribute       *hasSubordinates = NULL;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
 
                /* check for abandon */
                if ( op->o_abandon ) {
                        goto loop_continue;
                }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               /*
+                * if hasSubordinates is used in the filter,
+                * append it to the entry's attributes
+                */
+               if ( filter_hasSubordinates ) {
+                       int     hs;
+
+                       hs = has_children( be, e );
+                       hasSubordinates = slap_operational_hasSubordinate( hs );
+                       if ( hasSubordinates == NULL ) {
+                               goto loop_continue;
+                       }
+
+                       hasSubordinates->a_next = e->e_attrs;
+                       e->e_attrs = hasSubordinates;
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
                /* if it matches the filter and scope, send it */
-               if ( test_filter( be, conn, op, e, filter ) == LDAP_COMPARE_TRUE ) {
+               result = test_filter( be, conn, op, e, filter );
+
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               if ( hasSubordinates ) {
+                       /*
+                        * FIXME: this is fairly inefficient, because 
+                        * if hasSubordinates is among the required
+                        * attrs, it will be added again later;
+                        * maybe we should leave it and check
+                        * check later if it's already present,
+                        * if required
+                        */
+                       e->e_attrs = e->e_attrs->a_next;
+                       attr_free( hasSubordinates );
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
+               if ( result == LDAP_COMPARE_TRUE ) {
                        struct berval   dn;
 
                        /* check scope */
                                }
 
                                if (e) {
-                                       int result = send_search_entry(be, conn, op,
+                                       result = send_search_entry(be, conn, op,
                                                e, attrs, attrsonly, NULL);
 
                                        switch (result) {
 
  *                             statements (needed by PostgreSQL)
  *       - upper_needs_cast    cast the argument of upper when required
  *                             (basically when building dn substring queries)
+ *   - added noop control
+ *   - added values return filter control
+ *   - hasSubordinate can be used in search filters (with limitations)
+ *   - eliminated oc->name; use oc->oc->soc_cname instead
  * 
  * Todo:
  *   - add security checks for SQL statements that can be injected (?)
  */
 #undef BACKSQL_TRACE
 
-
 typedef struct {
        char            *dbhost;
        int             dbport;
 
 #include <stdio.h>
 #include <sys/types.h>
 #include "ac/string.h"
+#include "lber_pvt.h"
 #include "ldap_pvt.h"
 #include "slap.h"
 #include "back-sql.h"
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
                "oc='%s' attr='%s' keyval=%ld\n",
-               // bsi->oc->name.bv_val, at->name.bv_val, 
-               bsi->oc->oc->soc_names[0], at->ad->ad_cname.bv_val, 
+               BACKSQL_OC_NAME( bsi->oc ), at->ad->ad_cname.bv_val, 
                bsi->c_eid->keyval );
 
        rc = backsql_Prepare( bsi->dbh, &sth, at->query, 0 );
 #if 0
                                backsql_entry_addattr( bsi->e, 
                                                &bv_n_objectclass,
-                                               &bsi->oc->name );
+                                               BACKSQL_OC_NAME( bsi->oc ) );
 #endif
                                continue;
                        }
                                        "attribute '%s' is not defined "
                                        "for objectlass '%s'\n",
                                        attr->an_name.bv_val, 
-                                       bsi->oc->name.bv_val, 0 );
+                                       BACKSQL_OC_NAME( bsi->oc ), 0 );
                        }
                }
 
                                bsi, 0, AVL_INORDER );
        }
 
-       if ( attr_merge_one( bsi->e, ad_oc, &bsi->oc->name ) ) {
+       if ( attr_merge_one( bsi->e, ad_oc, &bsi->oc->oc->soc_cname ) ) {
                entry_free( e );
                return NULL;
        }
                const char      *text = NULL;
                char            textbuf[ 1024 ];
                size_t          textlen = sizeof( textbuf );
-               struct berval   bv[ 2 ] = { bsi->oc->name, { 0, NULL } };
+               struct berval   bv[ 2 ] = { bsi->oc->oc->soc_cname, BER_BVNULL };
                struct berval   soc;
                AttributeDescription    *ad_soc
                        = slap_schema.si_ad_structuralObjectClass;
                        return NULL;
                }
 
-               if ( bsi->attr_flags | BSQL_SF_ALL_OPER 
+               if ( bsi->bsi_flags | BSQL_SF_ALL_OPER 
                                || an_find( bsi->attrs, &AllOper ) ) {
                        if ( attr_merge_one( bsi->e, ad_soc, &soc ) ) {
                                entry_free( e );
 
 sql_back_initialize(
        BackendInfo     *bi )
 { 
+       static char *controls[] = {
+#ifdef LDAP_CONTROL_NOOP
+               LDAP_CONTROL_NOOP,
+#endif
+#ifdef LDAP_CONTROL_VALUESRETURNFILTER
+               LDAP_CONTROL_VALUESRETURNFILTER,
+#endif
+               NULL
+       };
+
+       bi->bi_controls = controls;
+
        Debug( LDAP_DEBUG_TRACE,"==>backsql_initialize()\n", 0, 0, 0 );
        
        bi->bi_open = 0;
 
                 * or if a single operation on an attribute fails 
                 * for any reason
                 */
-               SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+               SQLTransact( SQL_NULL_HENV, dbh, 
+                               op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
        }
-       send_ldap_result( conn, op, res, "", text, NULL, NULL );
+       send_ldap_result( conn, op, res, NULL, text, NULL, NULL );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 );
 
        return 0;
                 * or if a single operation on an attribute fails for any
                 * reason
                 */
-               SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+               SQLTransact( SQL_NULL_HENV, dbh,
+                               op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
        }
 
 modrdn_return:
                                "attribute '%s' is not registered "
                                "in objectclass '%s'\n",
                                at->a_desc->ad_cname.bv_val,
-                               oc->name.bv_val, 0 );
+                               BACKSQL_OC_NAME( oc ), 0 );
 
                        if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
                                send_ldap_result( conn, op, 
                         * to build the entry
                         */
                        if ( at->a_desc == slap_schema.si_ad_objectClass ) {
-                               if ( ber_bvcmp( at_val, &oc->name ) == 0 ) {
+                               if ( bvmatch( at_val, &oc->oc->soc_cname ) ) {
                                        continue;
                                }
                        }
         * or if a single operation on an attribute fails 
         * for any reason
         */
-       SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+       SQLTransact( SQL_NULL_HENV, dbh, 
+                               op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
 
        send_ldap_result( conn, op, LDAP_SUCCESS, "",
                        NULL, NULL, NULL );
         * or if a single operation on an attribute fails 
         * for any reason
         */
-       SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+       SQLTransact( SQL_NULL_HENV, dbh, 
+                               op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
 
        send_ldap_result( conn, op, LDAP_SUCCESS, "", NULL, NULL, NULL );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
 
        backsql_info            *bi = (backsql_info*)be->be_private;
        SQLHDBC                 dbh = SQL_NULL_HDBC;
        Attribute               **aa = a;
-       int                     rc;
+       int                     rc = 0;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_operational(): entry '%s'\n",
                        e->e_nname.bv_val, 0, 0 );
 
 
-       if ( opattrs || ad_inlist( slap_schema.si_ad_hasSubordinates, attrs ) ) {
+       if ( ( opattrs || ad_inlist( slap_schema.si_ad_hasSubordinates, attrs ) ) 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+                       && attr_find( e->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+                       ) {
+               
                rc = backsql_get_db_conn( be, conn, &dbh );
                if ( rc != LDAP_SUCCESS ) {
                        goto no_connection;
 
 #include <sys/types.h>
 #include <string.h>
 #include "slap.h"
+#include "lber_pvt.h"
 #include "ldap_pvt.h"
 #include "back-sql.h"
 #include "sql-wrap.h"
 #include "schema-map.h"
 #include "util.h"
 
-/*
- * Deprecated
- */
-#if 0
-static int
-backsql_cmp_oc_name( backsql_oc_map_rec *m1, backsql_oc_map_rec *m2 )
-{
-       return BACKSQL_NCMP( &m1->name, &m2->name );
-}
-#endif
-
 /*
  * Uses the pointer to the ObjectClass structure
  */
        return ( m1->id < m2->id ? -1 : ( m1->id > m2->id ? 1 : 0 ) );
 }
 
-/*
- * Deprecated
- */
-#if 0
-static int
-backsql_cmp_attr_name( backsql_at_map_rec *m1, backsql_at_map_rec *m2 )
-{
-       return BACKSQL_NCMP( &m1->name, &m2->name );
-}
-#endif
-
 /*
  * Uses the pointer to the AttributeDescription structure
  */
        backsql_oc_map_rec      *oc_map,
        backsql_at_map_rec      *at_map )
 {
-       struct berval   tmps = { 0, NULL };
+       struct berval   tmps = BER_BVNULL;
        ber_len_t       tmpslen = 0;
 
        backsql_strfcat( &tmps, &tmpslen, "lblblblbcbl", 
 
                oc_map->id = strtol( oc_row.cols[ 0 ], NULL, 0 );
 
-               ber_str2bv( oc_row.cols[ 1 ], 0, 1, &oc_map->name );
-               oc_map->oc = oc_bvfind( &oc_map->name );
+               oc_map->oc = oc_find( oc_row.cols[ 1 ] );
                if ( oc_map->oc == NULL ) {
                        Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                                "objectClass '%s' is not defined in schema\n", 
-                               oc_map->name.bv_val, 0, 0 );
+                               oc_row.cols[ 1 ], 0, 0 );
                        return LDAP_OTHER;      /* undefined objectClass ? */
                }
                
                oc_id = oc_map->id;
                Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                        "objectClass '%s': keytbl='%s' keycol='%s'\n",
-                       oc_map->name.bv_val, 
+                       BACKSQL_OC_NAME( oc_map ),
                        oc_map->keytbl.bv_val, oc_map->keycol.bv_val );
                if ( oc_map->create_proc ) {
                        Debug( LDAP_DEBUG_TRACE, "create_proc='%s'\n",
                                        "attribute '%s' for objectClass '%s' "
                                        "is not defined in schema: %s\n", 
                                        at_map->ad->ad_cname.bv_val, 
-                                       oc_map->name.bv_val, text );
+                                       BACKSQL_OC_NAME( oc_map ), text );
                                return LDAP_CONSTRAINT_VIOLATION;
                        }
                                
 #ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
-                       "found name='%s', id=%d\n", res->name, res->id, 0 );
+                       "found name='%s', id=%d\n", 
+                       BACKSQL_OC_NAME( res ), res->id, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
                        "not found\n", 0, 0, 0 );
        return res;
 }
 
-/*
- * Deprecated
- */
 backsql_oc_map_rec *
 backsql_name2oc( backsql_info *si, struct berval *oc_name )
 {
 #ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
-                       "found name='%s', id=%d\n", res->name, res->id, 0 );
+                       "found name='%s', id=%d\n", 
+                       BACKSQL_OC_NAME( res ), res->id, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
                        "not found\n", 0, 0, 0 );
 #ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
-                       "found name='%s', id=%d\n", res->name, res->id, 0 );
+                       "found name='%s', id=%d\n",
+                       BACKSQL_OC_NAME( res ), res->id, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
                        "not found\n", 0, 0, 0 );
 #ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_ad2at(): "
                "searching for attribute '%s' for objectclass '%s'\n",
-               attr, objclass->name, 0 );
+               attr, BACKSQL_OC_NAME( objclass ), 0 );
 #endif /* BACKSQL_TRACE */
 
        tmp.ad = ad;
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
                        "found name='%s', sel_expr='%s'\n",
-                       res->name, res->sel_expr.bv_val, 0 );
+                       res->ad->ad_cname.bv_val, res->sel_expr.bv_val, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
                        "not found\n", 0, 0, 0 );
 #ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_name2at(): "
                "searching for attribute '%s' for objectclass '%s'\n",
-               attr, objclass->name, 0 );
+               attr, BACKSQL_OC_NAME( objclass ), 0 );
 #endif /* BACKSQL_TRACE */
 
        if ( slap_bv2ad( attr, &tmp.ad, &text ) != LDAP_SUCCESS ) {
 backsql_free_oc( backsql_oc_map_rec *oc )
 {
        Debug( LDAP_DEBUG_TRACE, "==>free_oc(): '%s'\n", 
-                       oc->name.bv_val, 0, 0 );
+                       BACKSQL_OC_NAME( oc ), 0, 0 );
        avl_free( oc->attrs, (AVL_FREE)backsql_free_attr );
-       ch_free( oc->name.bv_val );
        ch_free( oc->keytbl.bv_val );
        ch_free( oc->keycol.bv_val );
        if ( oc->create_proc != NULL ) {
 
  */
 
 typedef struct {
-       /*
-        * FIXME: we explicitly keep the objectClass name because
-        * the ObjectClass structure does not use bervals (yet?)
-        */
-       struct berval   name;
        /*
         * Structure of corresponding LDAP objectClass definition
         */
        ObjectClass     *oc;
+#define BACKSQL_OC_NAME(ocmap) ((ocmap)->oc->soc_cname.bv_val)
+       
        struct berval   keytbl;
        struct berval   keycol;
        /* expected to return keyval of newly created entry */
 
 #include "entry-id.h"
 #include "util.h"
 
+static int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
+
 static int
 backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
 {
                return 1;
        }
 
+       /*
+        * clear the list (retrieve all attrs)
+        */
+       if ( ad == NULL ) {
+               ch_free( bsi->attrs );
+               bsi->attrs = NULL;
+               return 1;
+       }
+
        for ( ; bsi->attrs[ n_attrs ].an_name.bv_val; n_attrs++ ) {
                an = &bsi->attrs[ n_attrs ];
                
        bsi->be = be;
        bsi->conn = conn;
        bsi->op = op;
-       bsi->attr_flags = 0;
+       bsi->bsi_flags = 0;
 
-       /*
-        * FIXME: need to discover how to deal with 1.1 (NoAttrs)
-        */
-       
        /*
         * handle "*"
         */
                
                for ( p = attrs; p->an_name.bv_val; p++ ) {
                        /*
-                        * ignore "+"
+                        * ignore "1.1"; handle "+"
                         */
                        if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) {
+                               bsi->bsi_flags |= BSQL_SF_ALL_OPER;
                                continue;
 
                        } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
-                               bsi->attr_flags |= BSQL_SF_ALL_OPER;
                                continue;
                        }
 
        bsi->status = LDAP_SUCCESS;
 }
 
-int
+static int
 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
 {
        int             res;
        return 1;
 }
 
-int
+static int
 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f )
 {
        int                     i;
        return 1;
 }
 
-int
+static int
 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
 {
        backsql_at_map_rec      *at;
        backsql_at_map_rec      oc_attr = {
                slap_schema.si_ad_objectClass, BER_BVC(""), BER_BVC(""), 
-               { 0, NULL }, NULL, NULL, NULL };
+               BER_BVNULL, NULL, NULL, NULL };
        AttributeDescription    *ad = NULL;
        int                     done = 0;
        ber_len_t               len = 0;
                
        case LDAP_FILTER_AND:
                rc = backsql_process_filter_list( bsi, f->f_and,
-                               LDAP_FILTER_AND);
+                               LDAP_FILTER_AND );
                done = 1;
                break;
 
                ad = f->f_desc;
                break;
                
+       case LDAP_FILTER_EXT:
+               ad = f->f_mra->ma_desc;
+               break;
+               
        default:
                ad = f->f_av_desc;
                break;
                goto done;
        }
 
-       if ( ad != slap_schema.si_ad_objectClass ) {
-               at = backsql_ad2at( bsi->oc, ad );
-
-       } else {
+       /*
+        * Turn structuralObjectClass into objectClass
+        */
+       if ( ad == slap_schema.si_ad_objectClass 
+                       || ad == slap_schema.si_ad_structuralObjectClass ) {
                at = &oc_attr;
                backsql_strfcat( &at->sel_expr, &len, "cbc",
                                '\'', 
-                               &bsi->oc->name, 
+                               &bsi->oc->oc->soc_cname, 
                                '\'' );
+
+#if defined(SLAP_X_FILTER_HASSUBORDINATES) || defined(SLAP_X_MRA_MATCH_DNATTRS)
+       } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
+               /*
+                * FIXME: this is not robust; e.g. a filter
+                * '(!(hasSubordinates=TRUE))' fails because
+                * in SQL it would read 'NOT (1=1)' instead 
+                * of no condition.  
+                * Note however that hasSubordinates is boolean, 
+                * so a more appropriate filter would be 
+                * '(hasSubordinates=FALSE)'
+                */
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
+                               (ber_len_t)sizeof( "1=1" ) - 1, "1=1" );
+               if ( ad != NULL ) {
+                       /*
+                        * We use this flag since we need to parse
+                        * the filter anyway; we should have used
+                        * the frontend API function
+                        * filter_has_subordinates()
+                        */
+                       bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
+               } else {
+                       /*
+                        * clear attributes to fetch, to require ALL
+                        * and try extended match on all attributes
+                        */
+                       backsql_attrlist_add( bsi, NULL );
+               }
+               goto done;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES || SLAP_X_MRA_MATCH_DNATTRS */
+               
+       } else {
+               at = backsql_ad2at( bsi->oc, ad );
        }
 
        if ( at == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
                        "attribute '%s' is not defined for objectclass '%s'\n",
-                       ad->ad_cname.bv_val, bsi->oc->name.bv_val, 0 );
+                       ad->ad_cname.bv_val, BACKSQL_OC_NAME( bsi->oc ), 0 );
                backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
-                               (ber_len_t)sizeof( " 1=0 " ) - 1, " 1=0 " );
+                               (ber_len_t)sizeof( "1=0" ) - 1, "1=0" );
                goto impossible;
        }
 
                break;
 
        case LDAP_FILTER_GE:
+               /*
+                * FIXME: should we uppercase the operands?
+                */
                backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "cblbc",
                                '(' /* ) */ ,
                                &at->sel_expr,
                break;
                
        case LDAP_FILTER_LE:
+               /*
+                * FIXME: should we uppercase the operands?
+                */
                backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "cblbc",
                                '(' /* ) */ ,
                                &at->sel_expr,
                                &bi->strcast_func, 
                                (ber_len_t)sizeof( "('" /* ') */ ) - 1,
                                        "('" /* ') */ ,
-                               &bsi->oc->name,
+                               &bsi->oc->oc->soc_cname,
                                (ber_len_t)sizeof( /* (' */ "')" ) - 1,
                                        /* (' */ "')" );
        } else {
                backsql_strfcat( &bsi->sel, &bsi->sel_len, "cbc",
                                '\'',
-                               &bsi->oc->name,
+                               &bsi->oc->oc->soc_cname,
                                '\'' );
        }
        backsql_strfcat( &bsi->sel, &bsi->sel_len, "l",
        int                     j;
  
        Debug(  LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc='%s'\n",
-                       oc->name.bv_val, 0, 0 );
+                       BACKSQL_OC_NAME( oc ), 0, 0 );
 
        if ( bsi->n_candidates == -1 ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
         */
        for ( eid = srch_info.id_list; eid != NULL; 
                        eid = backsql_free_entryID( eid, 1 ) ) {
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               Attribute       *hasSubordinate = NULL,
+                               *a = NULL;
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
 
                /* check for abandon */
                if ( op->o_abandon ) {
                        continue;
                }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+               /*
+                * We use this flag since we need to parse the filter
+                * anyway; we should have used the frontend API function
+                * filter_has_subordinates()
+                */
+               if ( srch_info.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
+                       int             rc;
+
+                       rc = backsql_has_children( bi, dbh, &entry->e_nname );
+
+                       switch( rc ) {
+                       case LDAP_COMPARE_TRUE:
+                       case LDAP_COMPARE_FALSE:
+                               hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
+                               if ( hasSubordinate != NULL ) {
+                                       for ( a = entry->e_attrs; 
+                                                       a && a->a_next; 
+                                                       a = a->a_next );
+
+                                       a->a_next = hasSubordinate;
+                               }
+                               rc = 0;
+                               break;
+
+                       default:
+                               Debug(LDAP_DEBUG_TRACE, 
+                                       "backsql_search(): "
+                                       "has_children failed( %d)\n", 
+                                       rc, 0, 0 );
+                               rc = 1;
+                               break;
+                       }
+
+                       if ( rc ) {
+                               continue;
+                       }
+               }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
                if ( test_filter( be, conn, op, entry, filter ) 
                                == LDAP_COMPARE_TRUE ) {
-                       sres = send_search_entry( be, conn, op, entry,
-                                       attrs, attrsonly, NULL );
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+                       if ( hasSubordinate && !( srch_info.bsi_flags & BSQL_SF_ALL_OPER ) 
+                                       && !ad_inlist( slap_schema.si_ad_hasSubordinates, attrs ) ) {
+                               a->a_next = NULL;
+                               attr_free( hasSubordinate );
+                               hasSubordinate = NULL;
+                       }
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
+#if 0  /* noop is masked SLAP_CTRL_UPDATE */
+                       if ( op->o_noop ) {
+                               sres = 0;
+                       } else {
+#endif
+                               sres = send_search_entry( be, conn, op, entry,
+                                               attrs, attrsonly, NULL );
+#if 0
+                       }
+#endif
+
                        switch ( sres ) {
                        case 0:
                                nentries++;
 
 backsql_get_table_spec( char **p )
 {
        char            *s, *q;
-       struct berval   res = { 0, NULL };
+       struct berval   res = BER_BVNULL;
        ber_len_t       res_len = 0;
 
        assert( p );
 
        Connection              *conn;
        Operation               *op;
        AttributeName           *attrs;
-       int                     attr_flags;
-#define        BSQL_SF_ALL_OPER        0x0001
+       int                     bsi_flags;
+#define        BSQL_SF_ALL_OPER                0x0001
+#define BSQL_SF_FILTER_HASSUBORDINATE  0x0002
        Entry                   *e;
        /* 1 if the db is TimesTen; 0 if it's not */
        int                     use_reverse_dn; 
 } backsql_srch_info;
 
-int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
 void backsql_init_search( backsql_srch_info *bsi, backsql_info *bi,
                struct berval *nbase, int scope, int slimit, int tlimit,
                time_t stoptime, Filter *filter, SQLHDBC dbh,
 
 
 const struct berval slap_empty_bv = { 0, "" };
 
-#define SLAP_LDAPDN_PRETTY 0x1
-
-#define SLAP_LDAPDN_MAXLEN 8192
-
 /*
  * The DN syntax-related functions take advantage of the dn representation
  * handling functions ldap_str2dn/ldap_dn2str.  The latter are not schema-
        return LDAP_SUCCESS;
 }
 
+int
+dnPrettyNormalDN(
+       Syntax *syntax,
+       struct berval *val,
+       LDAPDN **dn,
+       int flags )
+{
+       assert( val );
+       assert( dn );
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, ">>> dn%sDN: <%s>\n", 
+                       flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
+                       val->bv_val, 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE, ">>> dn%sDN: <%s>\n", 
+                       flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal", 
+                       val->bv_val, 0 );
+#endif
+
+       if ( val->bv_len == 0 ) {
+               return LDAP_SUCCESS;
+
+       } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
+               return LDAP_INVALID_SYNTAX;
+
+       } else {
+               int             rc;
+
+               /* FIXME: should be liberal in what we accept */
+               rc = ldap_bv2dn( val, dn, LDAP_DN_FORMAT_LDAP );
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               assert( strlen( val->bv_val ) == val->bv_len );
+
+               /*
+                * Schema-aware rewrite
+                */
+               if ( LDAPDN_rewrite( *dn, flags ) != LDAP_SUCCESS ) {
+                       ldap_dnfree( *dn );
+                       *dn = NULL;
+                       return LDAP_INVALID_SYNTAX;
+               }
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "<<< dn%sDN\n", 
+                       flags == SLAP_LDAPDN_PRETTY ? "Pretty" : "Normal",
+                       0, 0 );
+
+       return LDAP_SUCCESS;
+}
+
 /*
  * Combination of both dnPretty and dnNormalize
  */
 
 
        case LDAP_FILTER_EXT:
                filter_escape_value( &f->f_mr_value, &tmp );
-
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
                fstr->bv_len = f->f_mr_desc->ad_cname.bv_len +
                        ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
                        ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
                        f->f_mr_rule_text.bv_len ? ":" : "",
                        f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
                        tmp.bv_val );
+#else /* SLAP_X_MRA_MATCH_DNATTRS */
+               {
+               struct berval ad;
+
+               if ( f->f_mr_desc ) {
+                       ad = f->f_mr_desc->ad_cname;
+               } else {
+                       ad.bv_len = 0;
+                       ad.bv_val = "";
+               }
+                       
+               fstr->bv_len = ad.bv_len +
+                       ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
+                       ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
+                       tmp.bv_len + ( sizeof("(:=)") - 1 );
+               fstr->bv_val = malloc( fstr->bv_len + 1 );
+
+               snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
+                       ad.bv_val,
+                       f->f_mr_dnattrs ? ":dn" : "",
+                       f->f_mr_rule_text.bv_len ? ":" : "",
+                       f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
+                       tmp.bv_val );
+               }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
                ber_memfree( tmp.bv_val );
                break;
 
        case LDAP_FILTER_EXT:
                filter_escape_value( &f->f_mr_value, &tmp );
 
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
                fstr->bv_len = f->f_mr_desc->ad_cname.bv_len +
                        ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
                        ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
                        f->f_mr_rule_text.bv_len ? ":" : "",
                        f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
                        tmp.bv_val );
+#else /* SLAP_X_MRA_MATCH_DNATTRS */
+               {
+               struct berval ad;
+
+               if ( f->f_mr_desc ) {
+                       ad = f->f_mr_desc->ad_cname;
+               } else {
+                       ad.bv_len = 0;
+                       ad.bv_val = "";
+               }
+                       
+               fstr->bv_len = ad.bv_len +
+                       ( f->f_mr_dnattrs ? sizeof(":dn")-1 : 0 ) +
+                       ( f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_len+1 : 0 ) +
+                       tmp.bv_len + ( sizeof("(:=)") - 1 );
+               fstr->bv_val = malloc( fstr->bv_len + 1 );
+
+               snprintf( fstr->bv_val, fstr->bv_len + 1, "(%s%s%s%s:=%s)",
+                       ad.bv_val,
+                       f->f_mr_dnattrs ? ":dn" : "",
+                       f->f_mr_rule_text.bv_len ? ":" : "",
+                       f->f_mr_rule_text.bv_len ? f->f_mr_rule_text.bv_val : "",
+                       tmp.bv_val );
+               }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
+
                ber_memfree( tmp.bv_val );
                break;
 
        return( LDAP_SUCCESS );
 }
 
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+static int filter_has_subordinates_list(
+       Filter          *filter );
+
+/*
+ * FIXME: we could detect the need to filter
+ * for hasSubordinates when parsing the filter ...
+ */
+
+static int
+filter_has_subordinates_list(
+       Filter          *fl )
+{
+       Filter                  *f;
+
+       for ( f = fl; f != NULL; f = f->f_next ) {
+               int     rc;
+
+               rc = filter_has_subordinates( f );
+
+               if ( rc ) {
+                       return rc;
+               }
+       }
+
+       return 0;
+}
+
+int
+filter_has_subordinates(
+       Filter          *f )
+{
+       AttributeDescription    *ad = NULL;
+
+       switch ( f->f_choice ) {
+       case LDAP_FILTER_PRESENT:
+               ad = f->f_desc;
+               break;
+
+       case LDAP_FILTER_EQUALITY:
+       case LDAP_FILTER_APPROX:
+       case LDAP_FILTER_GE:
+       case LDAP_FILTER_LE:
+               ad = f->f_ava->aa_desc;
+               break;
+
+       case LDAP_FILTER_SUBSTRINGS:
+               ad = f->f_sub_desc;
+               break;
+
+       case LDAP_FILTER_EXT:
+               /* could be null; however here it is harmless */
+               ad = f->f_mra->ma_desc;
+               break;
+
+       case LDAP_FILTER_NOT:
+               return filter_has_subordinates( f->f_not );
+
+       case LDAP_FILTER_AND:
+               return filter_has_subordinates_list( f->f_and );
+
+       case LDAP_FILTER_OR:
+               return filter_has_subordinates_list( f->f_or );
+
+       case SLAPD_FILTER_COMPUTED:
+               /*
+                * something wrong?
+                */
+               return 0;
+
+       default:
+               /*
+                * this means a new type of filter has been implemented,
+                * which is not handled yet in this function; we should
+                * issue a developer's warning, e.g. an assertion
+                */
+               assert( 0 );
+               return -1;
+       }
+
+       if ( ad == slap_schema.si_ad_hasSubordinates ) {
+               return 1;
+       }
+
+       return 0;
+}
+
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
+
 
 {
        Attribute       *a;
 
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
        if( !access_allowed( be, conn, op, e,
                mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
        {
                return LDAP_INSUFFICIENT_ACCESS;
        }
+#else /* SLAP_X_MRA_MATCH_DNATTRS */
+       if ( mra->ma_desc ) {
+               /*
+                * if ma_desc is available, then we're filtering for
+                * one attribute, and SEARCH permissions can be checked
+                * directly.
+                */
+               if( !access_allowed( be, conn, op, e,
+                       mra->ma_desc, &mra->ma_value, ACL_SEARCH, NULL ) )
+               {
+                       return LDAP_INSUFFICIENT_ACCESS;
+               }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
+
+               for(a = attrs_find( e->e_attrs, mra->ma_desc );
+                       a != NULL;
+                       a = attrs_find( a->a_next, mra->ma_desc ) )
+               {
+                       struct berval *bv;
+                       for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) {
+                               int ret;
+                               int rc;
+                               const char *text;
+       
+                               rc = value_match( &ret, a->a_desc, mra->ma_rule,
+                                       SLAP_MR_ASSERTION_SYNTAX_MATCH,
+                                       bv, &mra->ma_value, &text );
+       
+                               if( rc != LDAP_SUCCESS ) {
+                                       return rc;
+                               }
+       
+                               if ( ret == 0 ) {
+                                       return LDAP_COMPARE_TRUE;
+                               }
+                       }
+               }
+#ifdef SLAP_X_MRA_MATCH_DNATTRS
+       } else {
 
-       for(a = attrs_find( e->e_attrs, mra->ma_desc );
-               a != NULL;
-               a = attrs_find( a->a_next, mra->ma_desc ) )
-       {
-               struct berval *bv;
-               for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) {
-                       int ret;
-                       int rc;
-                       const char *text;
+               /*
+                * No attribute description: test all
+                */
+               for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+                       struct berval   *bv, value;
+                       const char      *text = NULL;
+                       int             rc;
+
+                       /* check if matching is appropriate */
+                       if ( strcmp( mra->ma_rule->smr_syntax->ssyn_oid,
+                               a->a_desc->ad_type->sat_syntax->ssyn_oid ) != 0 ) {
+                               continue;
+                       }
 
-                       rc = value_match( &ret, a->a_desc, mra->ma_rule,
-                               SLAP_MR_ASSERTION_SYNTAX_MATCH,
-                               bv, &mra->ma_value,
-                               &text );
+                       /* normalize for equality */
+                       rc = value_validate_normalize( a->a_desc, 
+                               SLAP_MR_EQUALITY,
+                               &mra->ma_value, &value, &text );
+                       if ( rc != LDAP_SUCCESS ) {
+                               continue;
+                       }
 
-                       if( rc != LDAP_SUCCESS ) {
-                               return rc;
+                       /* check search access */
+                       if ( !access_allowed( be, conn, op, e,
+                               a->a_desc, &value, ACL_SEARCH, NULL ) ) {
+                               continue;
                        }
 
-                       if ( ret == 0 ) {
-                               return LDAP_COMPARE_TRUE;
+                       /* check match */
+                       for ( bv = a->a_vals; bv->bv_val != NULL; bv++ ) {
+                               int ret;
+                               int rc;
+       
+                               rc = value_match( &ret, a->a_desc, mra->ma_rule,
+                                       SLAP_MR_ASSERTION_SYNTAX_MATCH,
+                                       bv, &value, &text );
+       
+                               if( rc != LDAP_SUCCESS ) {
+                                       return rc;
+                               }
+       
+                               if ( ret == 0 ) {
+                                       return LDAP_COMPARE_TRUE;
+                               }
+                       }
+               }
+       }
+
+       /* check attrs in DN AVAs if required */
+       if ( mra->ma_dnattrs ) {
+               LDAPDN          *dn = NULL;
+               int             iRDN, iAVA;
+               int             rc;
+
+               /* parse and pretty the dn */
+               rc = dnPrettyDN( NULL, &e->e_name, &dn );
+               if ( rc != LDAP_SUCCESS ) {
+                       return LDAP_INVALID_SYNTAX;
+               }
+
+               /* for each AVA of each RDN ... */
+               for ( iRDN = 0; dn[ 0 ][ iRDN ]; iRDN++ ) {
+                       LDAPRDN         *rdn = dn[ 0 ][ iRDN ];
+
+                       for ( iAVA = 0; rdn[ 0 ][ iAVA ]; iAVA++ ) {
+                               LDAPAVA         *ava = rdn[ 0 ][ iAVA ];
+                               struct berval   *bv = &ava->la_value, value;
+                               AttributeDescription *ad = (AttributeDescription *)ava->la_private;
+                               int ret;
+                               int rc;
+                               const char *text;
+
+                               assert( ad );
+
+                               if ( mra->ma_desc ) {
+                                       /* have a mra type? check for subtype */
+                                       if ( !is_ad_subtype( ad, mra->ma_desc ) ) {
+                                               continue;
+                                       }
+                                       value = mra->ma_value;
+
+                               } else {
+                                       const char      *text = NULL;
+
+                                       /* check if matching is appropriate */
+                                       if ( strcmp( mra->ma_rule->smr_syntax->ssyn_oid,
+                                               ad->ad_type->sat_syntax->ssyn_oid ) != 0 ) {
+                                               continue;
+                                       }
+
+                                       /* normalize for equality */
+                                       rc = value_validate_normalize( ad, SLAP_MR_EQUALITY,
+                                               &mra->ma_value, &value, &text );
+                                       if ( rc != LDAP_SUCCESS ) {
+                                               continue;
+                                       }
+
+                                       /* check search access */
+                                       if ( !access_allowed( be, conn, op, e,
+                                               ad, &value, ACL_SEARCH, NULL ) ) {
+                                               continue;
+                                       }
+                               }
+
+                               /* check match */
+                               rc = value_match( &ret, ad, mra->ma_rule,
+                                       SLAP_MR_ASSERTION_SYNTAX_MATCH,
+                                       bv, &value, &text );
+
+                               if( rc != LDAP_SUCCESS ) {
+                                       ldap_dnfree( dn );
+                                       return rc;
+                               }
+
+                               if ( ret == 0 ) {
+                                       ldap_dnfree( dn );
+                                       return LDAP_COMPARE_TRUE;
+                               }
                        }
                }
        }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
 
        return LDAP_COMPARE_FALSE;
 }
 
 
 #include "../../libraries/liblber/lber-int.h"
 
-static int test_mra_vrFilter(
+static int
+test_mra_vrFilter(
        Backend         *be,
        Connection      *conn,
        Operation       *op,
        return LDAP_SUCCESS;
 }
 
-static int test_mra_vrFilter(
+static int
+test_mra_vrFilter(
        Backend         *be,
        Connection      *conn,
        Operation       *op,
        int i, j;
 
        for ( i=0; a != NULL; a = a->a_next, i++ ) {
-               struct berval *bv;
-       
+               struct berval *bv, value;
+
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
                if ( !is_ad_subtype( a->a_desc, mra->ma_desc ) ) {
                        return( LDAP_SUCCESS );
                }
+               value = mra->ma_value;
+
+#else /* SLAP_X_MRA_MATCH_DNATTRS */
+               if ( mra->ma_desc ) {
+                       if ( !is_ad_subtype( a->a_desc, mra->ma_desc ) ) {
+                               return( LDAP_SUCCESS );
+                       }
+                       value = mra->ma_value;
+
+               } else {
+                       const char      *text = NULL;
+
+                       /* check if matching is appropriate */
+                       if ( strcmp( mra->ma_rule->smr_syntax->ssyn_oid,
+                               a->a_desc->ad_type->sat_syntax->ssyn_oid ) != 0 ) {
+                               continue;
+                       }
+
+                       /* normalize for equality */
+                       if ( value_validate_normalize( a->a_desc, 
+                               SLAP_MR_EQUALITY,
+                               &mra->ma_value, &value,
+                               &text ) != LDAP_SUCCESS ) {
+                               continue;
+                       }
+
+               }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
 
                for ( bv = a->a_vals, j = 0; bv->bv_val != NULL; bv++, j++ ) {
                        int ret;
 
                        rc = value_match( &ret, a->a_desc, mra->ma_rule,
                                SLAP_MR_ASSERTION_SYNTAX_MATCH,
-                               bv, &mra->ma_value,
+                               bv, &value,
                                &text );
 
                        if( rc != LDAP_SUCCESS ) {
 
                return SLAPD_DISCONNECT;
        }
 
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
+       /*
+        * Let's try to implement it
+        */
        if( ma->ma_dnattrs ) {
                *text = "matching with \":dn\" not supported";
                return LDAP_INAPPROPRIATE_MATCHING;
        }
+#endif /* !SLAP_X_MRA_MATCH_DNATTRS */
 
        if( type.bv_val != NULL ) {
                rc = slap_bv2ad( &type, &ma->ma_desc, text );
                        return rc;
                }
 
+#ifndef SLAP_X_MRA_MATCH_DNATTRS
        } else {
                *text = "matching without attribute description rule not supported";
                return LDAP_INAPPROPRIATE_MATCHING;
+#endif /* !SLAP_X_MRA_MATCH_DNATTRS */
        }
 
        if( ma->ma_rule_text.bv_val != NULL ) {
                }
        }
 
+       /*
+        * FIXME: is it correct that ma->ma_rule_text, if present,
+        * is looked-up, checked, and then replaced by the sat_equality
+        * of the given attribute?  I'd rather do smtg like use
+        * the attribute's equality rule only if no matching rule
+        * was given, otherwise I don't see any extension ...
+        */
+
+#if 1
+       if ( ma->ma_rule == NULL ) {
+#ifdef SLAP_X_MRA_MATCH_DNATTRS
+               /*
+                * Need either type or rule ...
+                */
+               if ( ma->ma_desc == NULL ) {
+                       mra_free( ma, 1 );
+                       *text = "matching rule not recognized";
+                       return LDAP_INAPPROPRIATE_MATCHING;
+               }
+#endif /* !SLAP_X_MRA_MATCH_DNATTRS */
+
+               if ( ma->ma_desc->ad_type->sat_equality != NULL &&
+                       ma->ma_desc->ad_type->sat_equality->smr_usage & SLAP_MR_EXT )
+               {
+                       /* no matching rule was provided, use the attribute's
+                          equality rule if it supports extensible matching. */
+                       ma->ma_rule = ma->ma_desc->ad_type->sat_equality;
+
+               } else {
+                       mra_free( ma, 1 );
+                       return LDAP_INAPPROPRIATE_MATCHING;
+               }
+       }
+#else
        if( ma->ma_desc != NULL &&
                ma->ma_desc->ad_type->sat_equality != NULL &&
                ma->ma_desc->ad_type->sat_equality->smr_usage & SLAP_MR_EXT )
                mra_free( ma, 1 );
                return LDAP_INAPPROPRIATE_MATCHING;
        }
+#endif
 
-       /* check to see if the matching rule is appropriate for
-          the syntax of the attribute.  This check will need
-          to be extended to support other kinds of extensible
-          matching rules */
-       if( strcmp( ma->ma_rule->smr_syntax->ssyn_oid,
-               ma->ma_desc->ad_type->sat_syntax->ssyn_oid ) != 0 )
-       {
-               mra_free( ma, 1 );
-               return LDAP_INAPPROPRIATE_MATCHING;
-       }
+#ifdef SLAP_X_MRA_MATCH_DNATTRS
+       if ( ma->ma_desc != NULL ) {
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
+               /* check to see if the matching rule is appropriate for
+                 the syntax of the attribute.  This check will need
+                  to be extended to support other kinds of extensible
+                  matching rules */
+               if( strcmp( ma->ma_rule->smr_syntax->ssyn_oid,
+                       ma->ma_desc->ad_type->sat_syntax->ssyn_oid ) != 0 )
+               {
+                       mra_free( ma, 1 );
+                       return LDAP_INAPPROPRIATE_MATCHING;
+               }
 
-       /*
-        * OK, if no matching rule, normalize for equality, otherwise
-        * normalize for the matching rule.
-        */
-       rc = value_validate_normalize( ma->ma_desc, SLAP_MR_EQUALITY,
-               &value, &ma->ma_value, text );
+               /*
+                * OK, if no matching rule, normalize for equality, otherwise
+                * normalize for the matching rule.
+                */
+               rc = value_validate_normalize( ma->ma_desc, SLAP_MR_EQUALITY,
+                       &value, &ma->ma_value, text );
+#ifdef SLAP_X_MRA_MATCH_DNATTRS
+       } else {
+               /*
+                * Need to normalize, but how?
+                */
+               ma->ma_value = value;
+               rc = value_validate( ma->ma_rule, &ma->ma_value, text );
+
+       }
+#endif /* SLAP_X_MRA_MATCH_DNATTRS */
 
        if( rc != LDAP_SUCCESS ) {
                mra_free( ma, 1 );
 
 
 LDAP_SLAPD_F (int) dnX509peerNormalize LDAP_P(( void *ssl, struct berval *dn ));
 
+LDAP_SLAPD_F (int) dnPrettyNormalDN LDAP_P(( Syntax *syntax, struct berval *val, LDAPDN **dn, int flags ));
+#define dnPrettyDN(syntax, val, dn) \
+       dnPrettyNormalDN((syntax),(val),(dn), SLAP_LDAPDN_PRETTY)
+#define dnNormalDN(syntax, val, dn) \
+       dnPrettyNormalDN((syntax),(val),(dn), 0)
+
+
 /*
  * entry.c
  */
 LDAP_SLAPD_F (void) filter_free LDAP_P(( Filter *f ));
 LDAP_SLAPD_F (void) filter2bv LDAP_P(( Filter *f, struct berval *bv ));
 
-LDAP_SLAPD_F (int) get_vrFilter( Connection *conn, BerElement *ber,
+LDAP_SLAPD_F (int) get_vrFilter LDAP_P(( Connection *conn, BerElement *ber,
        ValuesReturnFilter **f,
-       const char **text );
+       const char **text ));
 
-LDAP_SLAPD_F (void) vrFilter_free( ValuesReturnFilter *f );
-LDAP_SLAPD_F (void) vrFilter2bv( ValuesReturnFilter *f, struct berval *fstr );
+LDAP_SLAPD_F (void) vrFilter_free LDAP_P(( ValuesReturnFilter *f ));
+LDAP_SLAPD_F (void) vrFilter2bv LDAP_P(( ValuesReturnFilter *f, struct berval *fstr ));
 
+/*
+ * define to honor hasSubordinates operational attribute in search filters
+ */
+#define SLAP_X_FILTER_HASSUBORDINATES
+
+#ifdef SLAP_X_FILTER_HASSUBORDINATES
+LDAP_SLAPD_F (int) filter_has_subordinates LDAP_P(( Filter *filter ));
+#endif /* SLAP_X_FILTER_HASSUBORDINATES */
 
 /*
  * filterentry.c
  */
+
+/*
+ * define to enable dn components match in extended filter matching
+ */
+#define SLAP_X_MRA_MATCH_DNATTRS
+
 LDAP_SLAPD_F (int) test_filter LDAP_P((
        Backend *be, Connection *conn, Operation *op,
        Entry *e, Filter *f ));
 
                }
                e_flags = ch_calloc ( 1, i * sizeof(char *) + k );
                a_flags = (char *)(e_flags + i);
+               memset( a_flags, 0, k );
                for ( a = e->e_attrs, i=0; a != NULL; a = a->a_next, i++ ) {
                        for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
                        e_flags[i] = a_flags;
                }
        }
 
-       /* free e_flags */
-       if ( e_flags ) {
-               free( e_flags );
-               e_flags = NULL;
-       }
-
        /* eventually will loop through generated operational attributes */
        /* only have subschemaSubentry implemented */
        aa = backend_operational( be, conn, op, e, attrs, opattrs );
 
        if ( aa != NULL && op->vrFilter != NULL ) {
                int k = 0;
-               char *a_flags;
+               char *a_flags, **tmp;
 
                for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) {
                        for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) k++;
                }
-               e_flags = ch_calloc ( 1, i * sizeof(char *) + k );
+               /*
+                * Reuse previous memory - we likely need less space
+                * for operational attributes
+                */
+               tmp = ch_realloc ( e_flags, i * sizeof(char *) + k );
+               if ( tmp == NULL ) {
+#ifdef NEW_LOGGING
+                       LDAP_LOG( OPERATION, ERR, 
+                               "send_search_entry: conn %lu "
+                               "not enough memory "
+                               "for matched values filtering\n", 
+                               conn ? conn->c_connid : 0, 0, 0);
+#else
+                       Debug( LDAP_DEBUG_ANY,
+                               "send_search_entry: conn %lu "
+                               "not enough memory "
+                               "for matched values filtering\n",
+                               conn ? conn->c_connid : 0, 0, 0 );
+#endif
+                       ber_free( ber, 1 );
+
+                       send_ldap_result( conn, op, LDAP_NO_MEMORY,
+                               NULL, NULL, NULL, NULL );
+                       goto error_return;
+               }
+               e_flags = tmp;
                a_flags = (char *)(e_flags + i);
+               memset( a_flags, 0, k );
                for ( a = aa, i=0; a != NULL; a = a->a_next, i++ ) {
                        for ( j = 0; a->a_vals[j].bv_val != NULL; j++ );
                        e_flags[i] = a_flags;
                                "matched values filtering failed\n", 
                                conn ? conn->c_connid : 0, 0, 0);
 #else
-               Debug( LDAP_DEBUG_ANY,
+                       Debug( LDAP_DEBUG_ANY,
                                "matched values filtering failed\n", 0, 0, 0 );
 #endif
                        ber_free( ber, 1 );
 
 };
 #endif /* SLAPD_MONITOR */
 
+/*
+ * Better know these all around slapd
+ */
+#define SLAP_LDAPDN_PRETTY 0x1
+#define SLAP_LDAPDN_MAXLEN 8192
+
 LDAP_END_DECL
 
 #include "proto-slap.h"