]> git.sur5r.net Git - openldap/commitdiff
import improvements from HEAD
authorPierangelo Masarati <ando@openldap.org>
Fri, 24 Sep 2004 16:09:15 +0000 (16:09 +0000)
committerPierangelo Masarati <ando@openldap.org>
Fri, 24 Sep 2004 16:09:15 +0000 (16:09 +0000)
15 files changed:
servers/slapd/back-sql/add.c
servers/slapd/back-sql/back-sql.h
servers/slapd/back-sql/bind.c
servers/slapd/back-sql/compare.c
servers/slapd/back-sql/config.c
servers/slapd/back-sql/delete.c
servers/slapd/back-sql/entry-id.c
servers/slapd/back-sql/external.h
servers/slapd/back-sql/init.c
servers/slapd/back-sql/modrdn.c
servers/slapd/back-sql/proto-sql.h
servers/slapd/back-sql/schema-map.c
servers/slapd/back-sql/search.c
servers/slapd/back-sql/sql-wrap.c
servers/slapd/back-sql/util.c

index a938b1697815a30348b39a53f429294ddcc45dd4..ea216b905e374e6320b9fa50f52ba26bb9643d52 100644 (file)
  * - the first occurrence of objectClass, which is used
  *   to determine how to build the SQL entry (FIXME ?!?)
  * - operational attributes
- *   empty attributes (FIXME ?!?)
+ * - empty attributes (FIXME ?!?)
  */
 #define        backsql_attr_skip(ad,vals) \
        ( \
                ( (ad) == slap_schema.si_ad_objectClass \
-                               && (vals)[ 1 ].bv_val == NULL ) \
+                               && BER_BVISNULL( &((vals)[ 1 ]) ) ) \
                || is_at_operational( (ad)->ad_type ) \
-               || ( (vals)[ 0 ].bv_val == NULL ) \
+               || ( (vals) && BER_BVISNULL( &((vals)[ 0 ]) ) ) \
        )
 
+int
+backsql_modify_delete_all_values(
+       Operation               *op,
+       SlapReply               *rs,
+       SQLHDBC                 dbh, 
+       backsql_entryID         *e_id,
+       backsql_at_map_rec      *at )
+{
+       backsql_info    *bi = (backsql_info *)op->o_bd->be_private;
+       RETCODE         rc;
+       SQLHSTMT        asth;
+       BACKSQL_ROW_NTS row;
+
+       rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       "   backsql_modify_delete_all_values(): "
+                       "error preparing query\n", 0, 0, 0 );
+               backsql_PrintErrors( bi->db_env, dbh, 
+                               asth, rc );
+
+               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                       rs->sr_text = "SQL-backend error";
+                       return rs->sr_err = LDAP_OTHER;
+               }
+               return LDAP_SUCCESS;
+       }
+
+#ifdef BACKSQL_ARBITRARY_KEY
+       rc = backsql_BindParamStr( asth, 1,
+                       e_id->eid_keyval.bv_val,
+                       BACKSQL_MAX_KEY_LEN );
+#else /* ! BACKSQL_ARBITRARY_KEY */
+       rc = backsql_BindParamID( asth, 1, &e_id->eid_keyval );
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       "   backsql_modify_delete_all_values(): "
+                       "error binding key value parameter\n",
+                       0, 0, 0 );
+               backsql_PrintErrors( bi->db_env, dbh, 
+                               asth, rc );
+               SQLFreeStmt( asth, SQL_DROP );
+
+               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                       rs->sr_text = "SQL-backend error";
+                       return rs->sr_err = LDAP_OTHER;
+               }
+
+               return LDAP_SUCCESS;
+       }
+                       
+       rc = SQLExecute( asth );
+       if ( !BACKSQL_SUCCESS( rc ) ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       "   backsql_modify_delete_all_values(): "
+                       "error executing attribute query\n",
+                       0, 0, 0 );
+               backsql_PrintErrors( bi->db_env, dbh, 
+                               asth, rc );
+               SQLFreeStmt( asth, SQL_DROP );
+
+               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                       rs->sr_text = "SQL-backend error";
+                       return rs->sr_err = LDAP_OTHER;
+               }
+
+               return LDAP_SUCCESS;
+       }
+
+       backsql_BindRowAsStrings( asth, &row );
+       for ( rc = SQLFetch( asth );
+                       BACKSQL_SUCCESS( rc );
+                       rc = SQLFetch( asth ) )
+       {
+               int                     i;
+               /* first parameter no, parameter order */
+               SQLUSMALLINT            pno, po;
+               /* procedure return code */
+               int                     prc;
+               
+               for ( i = 0; i < row.ncols; i++ ) {
+                       SQLHSTMT        sth;
+                       
+                       rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
+                       if ( rc != SQL_SUCCESS ) {
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "   backsql_modify_delete_all_values(): "
+                                       "error preparing query %s\n",
+                                       at->bam_delete_proc, 0, 0 );
+                               backsql_PrintErrors( bi->db_env, dbh, 
+                                               sth, rc );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       rs->sr_text = "SQL-backend error";
+                                       return rs->sr_err = LDAP_OTHER;
+                               }
+                               return LDAP_SUCCESS;
+                       }
+
+                       if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
+                               pno = 1;
+                               SQLBindParameter( sth, 1,
+                                       SQL_PARAM_OUTPUT,
+                                       SQL_C_ULONG,
+                                       SQL_INTEGER,
+                                       0, 0, &prc, 0, 0 );
+                       } else {
+                               pno = 0;
+                       }
+                       po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
+#ifdef BACKSQL_ARBITRARY_KEY
+                       SQLBindParameter( sth, pno + 1 + po,
+                               SQL_PARAM_INPUT,
+                               SQL_C_CHAR, SQL_VARCHAR,
+                               0, 0, e_id->eid_keyval.bv_val, 
+                               0, 0 );
+                       Debug( LDAP_DEBUG_TRACE,
+                               "   backsql_modify_delete_all_values() arg%d=%s\n",
+                               pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
+#else /* ! BACKSQL_ARBITRARY_KEY */
+                       SQLBindParameter( sth, pno + 1 + po,
+                               SQL_PARAM_INPUT,
+                               SQL_C_ULONG, SQL_INTEGER,
+                               0, 0, &e_id->eid_keyval, 0, 0 );
+                       Debug( LDAP_DEBUG_TRACE,
+                               "   backsql_modify_delete_all_values() arg%d=%lu\n",
+                               pno + 1 + po, e_id->eid_keyval, 0 );
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+
+                       /*
+                        * check for syntax needed here 
+                        * maybe need binary bind?
+                        */
+                       SQLBindParameter( sth, pno + 2 - po,
+                               SQL_PARAM_INPUT,
+                               SQL_C_CHAR, SQL_CHAR,
+                               0, 0, row.cols[ i ],
+                               strlen( row.cols[ i ] ), 0 );
+        
+                       Debug( LDAP_DEBUG_TRACE, 
+                               "   backsql_modify_delete_all_values(): "
+                               "arg%d=%s; executing \"%s\"\n",
+                               pno + 2 - po, row.cols[ i ],
+                               at->bam_delete_proc );
+                       rc = SQLExecute( sth );
+                       if ( rc != SQL_SUCCESS ) {
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "   backsql_modify_delete_all_values(): "
+                                       "delete_proc "
+                                       "execution failed\n",
+                                       0, 0, 0 );
+                               backsql_PrintErrors( bi->db_env,
+                                               dbh, sth, rc );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       SQLFreeStmt( sth, SQL_DROP );
+                                       rs->sr_text = "SQL-backend error";
+                                       return rs->sr_err = LDAP_OTHER;
+                               }
+                       }
+                       SQLFreeStmt( sth, SQL_DROP );
+               }
+       }
+       backsql_FreeRow( &row );
+       SQLFreeStmt( asth, SQL_DROP );
+
+       return LDAP_SUCCESS;
+}
+
 int
 backsql_modify_internal(
        Operation               *op,
@@ -62,34 +232,38 @@ backsql_modify_internal(
        Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): "
                "traversing modifications list\n", 0, 0, 0 );
 
-#ifndef BACKSQL_REALLOC_STMT
-       SQLAllocStmt( dbh, &sth );
-#endif /* BACKSQL_REALLOC_STMT */
-
        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
                AttributeDescription    *ad;
+               int                     sm_op;
+               static char             *sm_ops[] = { "add", "delete", "replace", "increment", NULL };
+
+               BerVarray               sm_values;
+#if 0
+               /* NOTE: some time we'll have to pass 
+                * the normalized values as well */
+               BerVarray               nvalues;
+#endif
                backsql_at_map_rec      *at = NULL;
                struct berval           *at_val;
-               Modification            *c_mod;
                int                     i;
                /* first parameter no, parameter order */
                SQLUSMALLINT            pno, po;
                /* procedure return code */
                int                     prc;
-
-#ifdef BACKSQL_REALLOC_STMT
-               SQLAllocStmt( dbh, &sth );
-#endif /* BACKSQL_REALLOC_STMT */
-
-               c_mod = &ml->sml_mod;
-               ad = c_mod->sm_desc;
+               
+               ad = ml->sml_mod.sm_desc;
+               sm_op = ( ml->sml_mod.sm_op & LDAP_MOD_OP );
+               sm_values = ml->sml_mod.sm_values;
+#if 0
+               sm_nvalues = ml->sml_mod.sm_nvalues;
+#endif
 
                Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
-                       "modifying attribute \"%s\" according to "
+                       "modifying attribute \"%s\" (%s) according to "
                        "mappings for objectClass \"%s\"\n",
-                       ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 0 );
+                       ad->ad_cname.bv_val, sm_ops[ sm_op ], BACKSQL_OC_NAME( oc ) );
 
-               if ( backsql_attr_skip( ad, c_mod->sm_values ) ) {
+               if ( backsql_attr_skip( ad, sm_values ) ) {
                        continue;
                }
 
@@ -98,7 +272,7 @@ backsql_modify_internal(
                        Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
                                "attribute \"%s\" is not registered "
                                "in objectClass \"%s\"\n",
-                               ad->ad_cname.bv_val, oc, 0 );
+                               ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 0 );
 
                        if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
                                rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
@@ -110,11 +284,8 @@ backsql_modify_internal(
                        continue;
                }
   
-               switch( c_mod->sm_op ) {
+               switch ( sm_op ) {
                case LDAP_MOD_REPLACE: {
-                       SQLHSTMT asth;
-                       BACKSQL_ROW_NTS row;
-                       
                        Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
                                "replacing values for attribute \"%s\"\n",
                                at->bam_ad->ad_cname.bv_val, 0, 0 );
@@ -162,141 +333,22 @@ backsql_modify_internal(
                        }
                        
 del_all:
-                       rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
-                       if ( rc != SQL_SUCCESS ) {
-                               Debug( LDAP_DEBUG_TRACE,
-                                       "   backsql_modify_internal(): "
-                                       "error preparing query\n", 0, 0, 0 );
-                               backsql_PrintErrors( bi->db_env, dbh, 
-                                               asth, rc );
-
-                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
-                                       rs->sr_err = LDAP_OTHER;
-                                       rs->sr_text = "SQL-backend error";
-                                       goto done;
-                               }
-
-                               break;
-                       }
-
-#ifdef BACKSQL_ARBITRARY_KEY
-                       rc = backsql_BindParamStr( asth, 1,
-                                       e_id->eid_keyval.bv_val,
-                                       BACKSQL_MAX_KEY_LEN );
-#else /* ! BACKSQL_ARBITRARY_KEY */
-                       rc = backsql_BindParamID( asth, 1, &e_id->eid_keyval );
-#endif /* ! BACKSQL_ARBITRARY_KEY */
-                       if ( rc != SQL_SUCCESS ) {
-                               Debug( LDAP_DEBUG_TRACE,
-                                       "   backsql_modify_internal(): "
-                                       "error binding key value parameter\n",
-                                       0, 0, 0 );
-                               backsql_PrintErrors( bi->db_env, dbh, 
-                                               asth, rc );
-                               SQLFreeStmt( asth, SQL_DROP );
-
-                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
-                                       rs->sr_err = LDAP_OTHER;
-                                       rs->sr_text = "SQL-backend error";
-                                       goto done;
-                               }
-
-                               break;
+                       rs->sr_err = backsql_modify_delete_all_values( op, rs, dbh, e_id, at );
+                       if ( rs->sr_err != LDAP_SUCCESS ) {
+                               goto done;
                        }
-                       
-                       rc = SQLExecute( asth );
-                       if ( !BACKSQL_SUCCESS( rc ) ) {
-                               Debug( LDAP_DEBUG_TRACE,
-                                       "   backsql_modify_internal(): "
-                                       "error executing attribute query\n",
-                                       0, 0, 0 );
-                               backsql_PrintErrors( bi->db_env, dbh, 
-                                               asth, rc );
-                               SQLFreeStmt( asth, SQL_DROP );
-
-                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
-                                       rs->sr_err = LDAP_OTHER;
-                                       rs->sr_text = "SQL-backend error";
-                                       goto done;
-                               }
 
+                       /* LDAP_MOD_DELETE gets here if all values must be deleted */
+                       if ( sm_op == LDAP_MOD_DELETE ) {
                                break;
                        }
-
-                       backsql_BindRowAsStrings( asth, &row );
-                       rc = SQLFetch( asth );
-                       for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) {
-                               for ( i = 0; i < row.ncols; i++ ) {
-                                       if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
-                                               pno = 1;
-                                               SQLBindParameter(sth, 1,
-                                                       SQL_PARAM_OUTPUT,
-                                                       SQL_C_ULONG,
-                                                       SQL_INTEGER,
-                                                       0, 0, &prc, 0, 0 );
-                                       } else {
-                                               pno = 0;
-                                       }
-                                       po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
-#ifdef BACKSQL_ARBITRARY_KEY
-                                       SQLBindParameter( sth, pno + 1 + po,
-                                               SQL_PARAM_INPUT,
-                                               SQL_C_CHAR, SQL_VARCHAR,
-                                               0, 0, e_id->eid_keyval.bv_val, 
-                                               0, 0 );
-#else /* ! BACKSQL_ARBITRARY_KEY */
-                                       SQLBindParameter( sth, pno + 1 + po,
-                                               SQL_PARAM_INPUT,
-                                               SQL_C_ULONG, SQL_INTEGER,
-                                               0, 0, &e_id->eid_keyval, 0, 0 );
-#endif /* ! BACKSQL_ARBITRARY_KEY */
-
-                                       /*
-                                        * check for syntax needed here 
-                                        * maybe need binary bind?
-                                        */
-                                       SQLBindParameter(sth, pno + 2 - po,
-                                               SQL_PARAM_INPUT,
-                                               SQL_C_CHAR, SQL_CHAR,
-                                               0, 0, row.cols[ i ],
-                                               strlen( row.cols[ i ] ), 0 );
-                        
-                                       Debug( LDAP_DEBUG_TRACE, 
-                                               "   backsql_modify_internal(): "
-                                               "executing \"%s\"\n",
-                                               at->bam_delete_proc, 0, 0 );
-                                       rc = SQLExecDirect( sth,
-                                               at->bam_delete_proc, SQL_NTS );
-                                       if ( rc != SQL_SUCCESS ) {
-                                               Debug( LDAP_DEBUG_TRACE,
-                                                       "   backsql_modify_internal(): "
-                                                       "delete_proc "
-                                                       "execution failed\n",
-                                                       0, 0, 0 );
-                                               backsql_PrintErrors( bi->db_env,
-                                                               dbh, sth, rc );
-
-                                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
-                                                       rs->sr_err = LDAP_OTHER;
-                                                       rs->sr_text = "SQL-backend error";
-                                                       goto done;
-                                               }
-                                       }
-#ifdef BACKSQL_REALLOC_STMT
-                                       SQLFreeStmt( sth, SQL_DROP );
-                                       SQLAllocStmt( dbh, &sth );
-#endif /* BACKSQL_REALLOC_STMT */
-                               }
-                       }
-                       backsql_FreeRow( &row );
-                       SQLFreeStmt( asth, SQL_DROP );
                }
 
                /*
                 * PASSTHROUGH - to add new attributes -- do NOT add break
                 */
                case LDAP_MOD_ADD:
-               case SLAP_MOD_SOFTADD:
+               /* case SLAP_MOD_SOFTADD: */
 add_only:;
                        if ( at->bam_add_proc == NULL ) {
                                Debug( LDAP_DEBUG_TRACE,
@@ -318,9 +370,23 @@ add_only:;
                        Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
                                "adding new values for attribute \"%s\"\n",
                                at->bam_ad->ad_cname.bv_val, 0, 0 );
-                       for ( i = 0, at_val = c_mod->sm_values;
-                                       at_val->bv_val != NULL; 
-                                       i++, at_val++ ) {
+                       for ( i = 0, at_val = sm_values;
+                                       !BER_BVISNULL( at_val ); 
+                                       i++, at_val++ )
+                       {
+                               rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 );
+                               if ( rc != SQL_SUCCESS ) {
+                                       Debug( LDAP_DEBUG_TRACE,
+                                               "   backsql_modify_internal(): "
+                                               "error preparing add query\n", 
+                                               0, 0, 0 );
+                                       backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+
+                                       rs->sr_err = LDAP_OTHER;
+                                       rs->sr_text = "SQL-backend error";
+                                       goto done;
+                               }
+
                                if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
                                        pno = 1;
                                        SQLBindParameter( sth, 1,
@@ -357,8 +423,7 @@ add_only:;
                                        "   backsql_modify_internal(): "
                                        "executing \"%s\"\n", 
                                        at->bam_add_proc, 0, 0 );
-                               rc = SQLExecDirect( sth, at->bam_add_proc, 
-                                               SQL_NTS );
+                               rc = SQLExecute( sth );
                                if ( rc != SQL_SUCCESS ) {
                                        Debug( LDAP_DEBUG_TRACE,
                                                "   backsql_modify_internal(): "
@@ -368,15 +433,13 @@ add_only:;
                                                        dbh, sth, rc );
 
                                        if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                               SQLFreeStmt( sth, SQL_DROP );
                                                rs->sr_err = LDAP_OTHER;
                                                rs->sr_text = "SQL-backend error";
                                                goto done;
                                        }
                                }
-#ifdef BACKSQL_REALLOC_STMT
                                SQLFreeStmt( sth, SQL_DROP );
-                               SQLAllocStmt( dbh, &sth );
-#endif /* BACKSQL_REALLOC_STMT */
                        }
                        break;
                        
@@ -398,7 +461,7 @@ add_only:;
                                break;
                        }
 
-                       if ( c_mod->sm_values == NULL ) {
+                       if ( sm_values == NULL ) {
                                Debug( LDAP_DEBUG_TRACE,
                                        "   backsql_modify_internal(): "
                                        "no values given to delete "
@@ -412,9 +475,23 @@ add_only:;
                                "deleting values for attribute \"%s\"\n",
                                at->bam_ad->ad_cname.bv_val, 0, 0 );
 
-                       for ( i = 0, at_val = c_mod->sm_values;
-                                       at_val->bv_val != NULL;
-                                       i++, at_val++ ) {
+                       for ( i = 0, at_val = sm_values;
+                                       !BER_BVISNULL( at_val );
+                                       i++, at_val++ )
+                       {
+                               rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
+                               if ( rc != SQL_SUCCESS ) {
+                                       Debug( LDAP_DEBUG_TRACE,
+                                               "   backsql_modify_internal(): "
+                                               "error preparing delete query\n", 
+                                               0, 0, 0 );
+                                       backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+
+                                       rs->sr_err = LDAP_OTHER;
+                                       rs->sr_text = "SQL-backend error";
+                                       goto done;
+                               }
+
                                if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
                                        pno = 1;
                                        SQLBindParameter( sth, 1,
@@ -450,8 +527,7 @@ add_only:;
                                        "   backsql_modify_internal(): "
                                        "executing \"%s\"\n", 
                                        at->bam_delete_proc, 0, 0 );
-                               rc = SQLExecDirect( sth, at->bam_delete_proc,
-                                               SQL_NTS );
+                               rc = SQLExecute( sth );
                                if ( rc != SQL_SUCCESS ) {
                                        Debug( LDAP_DEBUG_TRACE,
                                                "   backsql_modify_internal(): "
@@ -461,33 +537,32 @@ add_only:;
                                                        dbh, sth, rc );
 
                                        if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                               SQLFreeStmt( sth, SQL_DROP );
                                                rs->sr_err = LDAP_OTHER;
                                                rs->sr_text = "SQL-backend error";
                                                goto done;
                                        }
                                }
-#ifdef BACKSQL_REALLOC_STMT
                                SQLFreeStmt( sth, SQL_DROP );
-                               SQLAllocStmt( dbh, &sth );
-#endif /* BACKSQL_REALLOC_STMT */
+                       }
+                       break;
+
+               case LDAP_MOD_INCREMENT:
+                       Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
+                               "increment not supported yet\n", 0, 0, 0 );
+                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                               rs->sr_err = LDAP_OTHER;
+                               rs->sr_text = "SQL-backend error";
+                               goto done;
                        }
                        break;
                }
-#ifndef BACKSQL_REALLOC_STMT
-               SQLFreeStmt( sth, SQL_RESET_PARAMS );
-#else /* BACKSQL_REALLOC_STMT */
-               SQLFreeStmt( sth, SQL_DROP );
-#endif /* BACKSQL_REALLOC_STMT */
        }
 
 done:;
-       
-#ifndef BACKSQL_REALLOC_STMT
-       SQLFreeStmt( sth, SQL_DROP );
-#endif /* BACKSQL_REALLOC_STMT */
-
-       Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%d%s\n",
-               rs->sr_err, rs->sr_text ? ": " : "",
+       Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%s\n",
+               rs->sr_err,
+               rs->sr_text ? ": " : "",
                rs->sr_text ? rs->sr_text : "" );
 
        /*
@@ -496,6 +571,144 @@ done:;
        return rs->sr_err;
 }
 
+static int
+backsql_add_attr(
+       Operation               *op,
+       SlapReply               *rs,
+       SQLHDBC                 dbh,
+       backsql_oc_map_rec      *oc,
+       Attribute               *at,
+       unsigned long           new_keyval )
+{
+       backsql_info            *bi = (backsql_info*)op->o_bd->be_private;
+       backsql_at_map_rec      *at_rec = NULL;
+       struct berval           *at_val;
+       unsigned long           i;
+       RETCODE                 rc;
+       /* first parameter #, parameter order */
+       SQLUSMALLINT            pno, po;
+       /* procedure return code */
+       int                     prc;
+       SQLUSMALLINT            currpos;
+       SQLHSTMT                sth;
+
+       at_rec = backsql_ad2at( oc, at->a_desc ); 
+  
+       if ( at_rec == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
+                       "attribute \"%s\" is not registered "
+                       "in objectclass \"%s\"\n",
+                       op->oq_add.rs_e->e_name.bv_val,
+                       at->a_desc->ad_cname.bv_val,
+                       BACKSQL_OC_NAME( oc ) );
+
+               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                       rs->sr_text = "operation not permitted "
+                               "within namingContext";
+                       return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+               }
+
+               return LDAP_SUCCESS;
+       }
+       
+       if ( at_rec->bam_add_proc == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
+                       "add procedure is not defined "
+                       "for attribute \"%s\" "
+                       "of structuralObjectClass \"%s\"\n",
+                       op->oq_add.rs_e->e_name.bv_val,
+                       at->a_desc->ad_cname.bv_val,
+                       BACKSQL_OC_NAME( oc ) );
+
+               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                       rs->sr_text = "operation not permitted "
+                               "within namingContext";
+                       return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
+               }
+
+               return LDAP_SUCCESS;
+       }
+
+       for ( i = 0, at_val = &at->a_vals[ i ];
+                       !BER_BVISNULL( at_val );
+                       i++, at_val = &at->a_vals[ i ] )
+       {
+               char logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
+               
+               /*
+                * Do not deal with the objectClass that is used
+                * to build the entry
+                */
+               if ( at->a_desc == slap_schema.si_ad_objectClass ) {
+                       if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) )
+                       {
+                               continue;
+                       }
+               }
+
+               rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
+               if ( rc != SQL_SUCCESS ) {
+
+                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                               rs->sr_text = "SQL-backend error";
+                               return rs->sr_err = LDAP_OTHER;
+                       }
+
+                       return LDAP_SUCCESS;
+               }
+
+               if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
+                       pno = 1;
+                       SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
+                                       SQL_C_ULONG, SQL_INTEGER,
+                                       0, 0, &prc, 0, 0 );
+               } else {
+                       pno = 0;
+               }
+
+               po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
+               currpos = pno + 1 + po;
+               SQLBindParameter( sth, currpos,
+                               SQL_PARAM_INPUT, SQL_C_ULONG,
+                               SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
+               currpos = pno + 2 - po;
+
+               /*
+                * check for syntax needed here 
+                * maybe need binary bind?
+                */
+
+               backsql_BindParamStr( sth, currpos,
+                               at_val->bv_val, at_val->bv_len + 1 );
+
+#ifdef LDAP_DEBUG
+               snprintf( logbuf, sizeof( logbuf ), "val[%lu], id=%lu",
+                               i, new_keyval );
+               Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
+                       "executing \"%s\" %s\n", 
+                       op->oq_add.rs_e->e_name.bv_val,
+                       at_rec->bam_add_proc, logbuf );
+#endif
+               rc = SQLExecute( sth );
+               if ( rc != SQL_SUCCESS ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "   backsql_add_attr(\"%s\"): "
+                               "add_proc execution failed\n", 
+                               op->oq_add.rs_e->e_name.bv_val, 0, 0 );
+                       backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+
+                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                               SQLFreeStmt( sth, SQL_DROP );
+                               rs->sr_text = "SQL-backend error";
+                               return rs->sr_err = LDAP_OTHER;
+                       }
+               }
+               SQLFreeStmt( sth, SQL_DROP );
+       }
+
+       return LDAP_SUCCESS;
+}
+
 int
 backsql_add( Operation *op, SlapReply *rs )
 {
@@ -503,20 +716,15 @@ backsql_add( Operation *op, SlapReply *rs )
        SQLHDBC                 dbh;
        SQLHSTMT                sth;
        unsigned long           new_keyval = 0;
-       long                    i;
        RETCODE                 rc;
        backsql_oc_map_rec      *oc = NULL;
-       backsql_at_map_rec      *at_rec = NULL;
        backsql_entryID         parent_id = BACKSQL_ENTRYID_INIT;
        Entry                   p;
-       Attribute               *at;
-       struct berval           *at_val;
+       Attribute               *at,
+                               *at_objectClass = NULL;
        struct berval           pdn;
-       /* first parameter #, parameter order */
-       SQLUSMALLINT            pno, po;
-       /* procedure return code */
-       int                     prc;
-       struct berval           realdn, realpdn;
+       struct berval           realdn = BER_BVNULL,
+                               realpdn = BER_BVNULL;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
                        op->oq_add.rs_e->e_name.bv_val, 0, 0 );
@@ -616,9 +824,15 @@ backsql_add( Operation *op, SlapReply *rs )
        }
 
        /*
-        * Check if parent exists
+        * Get the parent dn and see if the corresponding entry exists.
         */
-       dnParent( &op->oq_add.rs_e->e_name, &pdn );
+       if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
+               pdn = slap_empty_bv;
+
+       } else {
+               dnParent( &op->oq_add.rs_e->e_nname, &pdn );
+       }
+
        realpdn = pdn;
        if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
                Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
@@ -640,60 +854,73 @@ backsql_add( Operation *op, SlapReply *rs )
                }
 
                /*
-                * Look for matched
+                * no parent!
+                *  if not attempting to add entry at suffix or with parent ""
                 */
-               while ( 1 ) {
-                       struct berval   dn;
-                       char            *matched = NULL;
-
-                       if ( realpdn.bv_val != pdn.bv_val ) {
-                               ch_free( realpdn.bv_val );
-                       }
-
-                       dn = pdn;
-                       dnParent( &dn, &pdn );
-
+               if ( ( ( !be_isroot( op ) && !be_shadow_update( op ) )
+                       || !BER_BVISEMPTY( &pdn ) ) && !is_entry_glue( op->oq_add.rs_e ) )
+               {
+                       Debug( LDAP_DEBUG_TRACE, "   backsql_add: %s denied\n",
+                               BER_BVISEMPTY( &pdn ) ? "suffix" : "entry at root",
+                               0, 0 );
                        /*
-                        * Empty DN ("") defaults to LDAP_SUCCESS
+                        * Look for matched
                         */
-                       realpdn = pdn;
-                       if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
-                               Debug( LDAP_DEBUG_TRACE,
-                                       "   backsql_add(\"%s\"): "
-                                       "backsql_api_dn2odbc failed\n", 
-                                       op->oq_add.rs_e->e_name.bv_val, 0, 0 );
-                               rs->sr_err = LDAP_OTHER;
-                               rs->sr_text = "SQL-backend error";
-                               goto done;
+                       while ( 1 ) {
+                               struct berval   dn;
+                               char            *matched = NULL;
+       
+                               if ( realpdn.bv_val != pdn.bv_val ) {
+                                       ch_free( realpdn.bv_val );
+                               }
+       
+                               dn = pdn;
+                               dnParent( &dn, &pdn );
+       
+                               /*
+                                * Empty DN ("") defaults to LDAP_SUCCESS
+                                */
+                               realpdn = pdn;
+                               if ( backsql_api_dn2odbc( op, rs, &realpdn ) ) {
+                                       Debug( LDAP_DEBUG_TRACE,
+                                               "   backsql_add(\"%s\"): "
+                                               "backsql_api_dn2odbc failed\n", 
+                                               op->oq_add.rs_e->e_name.bv_val, 0, 0 );
+                                       rs->sr_err = LDAP_OTHER;
+                                       rs->sr_text = "SQL-backend error";
+                                       goto done;
+                               }
+       
+                               rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realpdn );
+                               switch ( rs->sr_err ) {
+                               case LDAP_NO_SUCH_OBJECT:
+                                       if ( !BER_BVISEMPTY( &pdn ) ) {
+                                               break;
+                                       }
+                                       /* fail over to next case */
+                                       
+                               case LDAP_SUCCESS:
+                                       matched = pdn.bv_val;
+                                       /* fail over to next case */
+       
+                               default:
+                                       rs->sr_err = LDAP_NO_SUCH_OBJECT;
+                                       rs->sr_matched = matched;
+                                       goto done;
+                               } 
                        }
+               } else {
 
-                       rs->sr_err = backsql_dn2id( bi, NULL, dbh, &realpdn );
-                       switch ( rs->sr_err ) {
-                       case LDAP_NO_SUCH_OBJECT:
-                               if ( pdn.bv_len > 0 ) {
-                                       break;
-                               }
-                               /* fail over to next case */
-                               
-                       case LDAP_SUCCESS:
-                               matched = pdn.bv_val;
-                               /* fail over to next case */
-
-                       default:
-                               rs->sr_err = LDAP_NO_SUCH_OBJECT;
-                               rs->sr_matched = matched;
-                               goto done;
-                       } 
+#ifdef BACKSQL_ARBITRARY_KEY
+                       ber_str2bv( "SUFFIX", 0, 1, &parent_id.eid_id );
+#else /* ! BACKSQL_ARBITRARY_KEY */
+                       parent_id.eid_id = 0;
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+                       rs->sr_err = LDAP_SUCCESS;
                }
        }
 
-       /*
-        * create_proc is executed; if expect_return is set, then
-        * an output parameter is bound, which should contain 
-        * the id of the added row; otherwise the procedure
-        * is expected to return the id as the first column of a select
-        */
-
+       /* check "children" pseudo-attribute access to parent */
        p.e_attrs = NULL;
        p.e_name = pdn;
        dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname );
@@ -703,6 +930,13 @@ backsql_add( Operation *op, SlapReply *rs )
                goto done;
        }
 
+       /*
+        * create_proc is executed; if expect_return is set, then
+        * an output parameter is bound, which should contain 
+        * the id of the added row; otherwise the procedure
+        * is expected to return the id as the first column of a select
+        */
+
        rc = SQLAllocStmt( dbh, &sth );
        if ( rc != SQL_SUCCESS ) {
                rs->sr_err = LDAP_OTHER;
@@ -728,6 +962,7 @@ backsql_add( Operation *op, SlapReply *rs )
                rs->sr_text = "SQL-backend error";
                goto done;
        }
+
        if ( op->o_noop ) {
                SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
        }
@@ -737,9 +972,6 @@ backsql_add( Operation *op, SlapReply *rs )
                SQLINTEGER      value_len;
 
                if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
-#ifndef BACKSQL_REALLOC_STMT
-                       SQLFreeStmt( sth, SQL_RESET_PARAMS );
-#else /* BACKSQL_REALLOC_STMT */
                        SQLFreeStmt( sth, SQL_DROP );
                        rc = SQLAllocStmt( dbh, &sth );
                        if ( rc != SQL_SUCCESS ) {
@@ -747,7 +979,6 @@ backsql_add( Operation *op, SlapReply *rs )
                                rs->sr_text = "SQL-backend error";
                                goto done;
                        }
-#endif /* BACKSQL_REALLOC_STMT */
 
                        rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS );
                        if ( rc != SQL_SUCCESS ) {
@@ -820,19 +1051,13 @@ backsql_add( Operation *op, SlapReply *rs )
                }
        }
 
-#ifndef BACKSQL_REALLOC_STMT
-       SQLFreeStmt( sth, SQL_RESET_PARAMS );
-#else /* BACKSQL_REALLOC_STMT */
        SQLFreeStmt( sth, SQL_DROP );
-#endif /* BACKSQL_REALLOC_STMT */
 
        Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
                "create_proc returned keyval=%ld\n",
                op->oq_add.rs_e->e_name.bv_val, new_keyval, 0 );
 
        for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) {
-               SQLUSMALLINT    currpos;
-
                Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
                        "adding attribute \"%s\"\n", 
                        at->a_desc->ad_cname.bv_val, 0, 0 );
@@ -840,151 +1065,33 @@ backsql_add( Operation *op, SlapReply *rs )
                /*
                 * Skip:
                 * - the first occurrence of objectClass, which is used
-                *   to determine how to bulid the SQL entry (FIXME ?!?)
+                *   to determine how to build the SQL entry (FIXME ?!?)
                 * - operational attributes
-                *   empty attributes (FIXME ?!?)
+                * - empty attributes (FIXME ?!?)
                 */
                if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
                        continue;
                }
 
-               at_rec = backsql_ad2at( oc, at->a_desc ); 
-  
-               if ( at_rec == NULL ) {
-                       Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
-                               "attribute \"%s\" is not registered "
-                               "in objectclass \"%s\"\n",
-                               op->oq_add.rs_e->e_name.bv_val,
-                               at->a_desc->ad_cname.bv_val,
-                               BACKSQL_OC_NAME( oc ) );
-
-                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
-                               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
-                               rs->sr_text = "operation not permitted "
-                                       "within namingContext";
-                               goto done;
-                       }
-
+               if ( at->a_desc == slap_schema.si_ad_objectClass ) {
+                       at_objectClass = at;
                        continue;
                }
-               
-               if ( at_rec->bam_add_proc == NULL ) {
-                       Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
-                               "add procedure is not defined "
-                               "for attribute \"%s\" "
-                               "of structuralObjectClass \"%s\"\n",
-                               op->oq_add.rs_e->e_name.bv_val,
-                               at->a_desc->ad_cname.bv_val,
-                               BACKSQL_OC_NAME( oc ) );
 
-                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
-                               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
-                               rs->sr_text = "operation not permitted "
-                                       "within namingContext";
-                               goto done;
-                       }
-
-                       continue;
-               }
-
-#ifdef BACKSQL_REALLOC_STMT
-               rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
-               if ( rc != SQL_SUCCESS ) {
-
-                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
-                               rs->sr_err = LDAP_OTHER;
-                               rs->sr_text = "SQL-backend error";
-                               goto done;
-                       }
-
-                       continue;
-               }
-#endif /* BACKSQL_REALLOC_STMT */
-
-               if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
-                       pno = 1;
-                       SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
-                                       SQL_C_ULONG, SQL_INTEGER,
-                                       0, 0, &prc, 0, 0 );
-               } else {
-                       pno = 0;
-               }
-
-               po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
-               currpos = pno + 1 + po;
-               SQLBindParameter( sth, currpos,
-                               SQL_PARAM_INPUT, SQL_C_ULONG,
-                               SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
-               currpos = pno + 2 - po;
-
-               for ( i = 0, at_val = &at->a_vals[ i ];
-                               at_val->bv_val != NULL;
-                               i++, at_val = &at->a_vals[ i ] ) {
-                       char logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
-
-                       /*
-                        * Do not deal with the objectClass that is used
-                        * to build the entry
-                        */
-                       if ( at->a_desc == slap_schema.si_ad_objectClass ) {
-                               if ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) {
-                                       continue;
-                               }
-                       }
-
-                       /*
-                        * check for syntax needed here 
-                        * maybe need binary bind?
-                        */
-
-                       backsql_BindParamStr( sth, currpos,
-                                       at_val->bv_val, at_val->bv_len + 1 );
-
-#ifdef LDAP_DEBUG
-                       snprintf( logbuf, sizeof( logbuf ), "val[%d], id=%ld",
-                                       i, new_keyval );
-                       Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
-                               "executing \"%s\" %s\n", 
-                               op->oq_add.rs_e->e_name.bv_val,
-                               at_rec->bam_add_proc, logbuf );
-#endif
-#ifndef BACKSQL_REALLOC_STMT
-                       rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS );
-#else /* BACKSQL_REALLOC_STMT */
-                       rc = SQLExecute( sth );
-#endif /* BACKSQL_REALLOC_STMT */
-                       if ( rc != SQL_SUCCESS ) {
-                               Debug( LDAP_DEBUG_TRACE,
-                                       "   backsql_add(\"%s\"): "
-                                       "add_proc execution failed\n", 
-                                       op->oq_add.rs_e->e_name.bv_val, 0, 0 );
-                               backsql_PrintErrors( bi->db_env, dbh, sth, rc );
-
-                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
-                                       rs->sr_err = LDAP_OTHER;
-                                       rs->sr_text = "SQL-backend error";
-                                       goto done;
-                               }
-                       }
+               rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at, new_keyval );
+               if ( rs->sr_err != LDAP_SUCCESS ) {
+                       goto done;
                }
-#ifndef BACKSQL_REALLOC_STMT
-               SQLFreeStmt( sth, SQL_RESET_PARAMS ); 
-#else /* BACKSQL_REALLOC_STMT */
-               SQLFreeStmt( sth, SQL_DROP );
-#endif /* BACKSQL_REALLOC_STMT */
        }
 
-#ifdef BACKSQL_REALLOC_STMT
        rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
        if ( rc != SQL_SUCCESS ) {
                rs->sr_err = LDAP_OTHER;
                rs->sr_text = "SQL-backend error";
                goto done;
        }
-#endif /* BACKSQL_REALLOC_STMT */
        
-       backsql_BindParamStr( sth, 1, op->oq_add.rs_e->e_name.bv_val,
-                       BACKSQL_MAX_DN_LEN );
+       backsql_BindParamStr( sth, 1, realdn.bv_val, BACKSQL_MAX_DN_LEN );
        SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
                        0, 0, &oc->bom_id, 0, 0 );
 #ifdef BACKSQL_ARBITRARY_KEY
@@ -1008,11 +1115,7 @@ backsql_add( Operation *op, SlapReply *rs )
                        "parent_id=%ld, keyval=%ld\n",
                        oc->bom_id, parent_id.eid_id, new_keyval );
 #endif /* ! BACKSQL_ARBITRARY_KEY */
-#ifndef BACKSQL_REALLOC_STMT
-       rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
-#else /* BACKSQL_REALLOC_STMT */
        rc = SQLExecute( sth );
-#endif /* BACKSQL_REALLOC_STMT */
        if ( rc != SQL_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
                        "could not insert ldap_entries record\n",
@@ -1027,14 +1130,27 @@ backsql_add( Operation *op, SlapReply *rs )
                rs->sr_text = "SQL-backend error";
                goto done;
        }
-       
+
+       /* FIXME: need ldap_entries.id of newly added entry */
+       if ( at_objectClass ) {
+               rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at_objectClass, new_keyval );
+               if ( rs->sr_err != LDAP_SUCCESS ) {
+                       goto done;
+               }
+       }
+
        SQLFreeStmt( sth, SQL_DROP );
 
+done:;
        /*
         * Commit only if all operations succeed
         */
-       SQLTransact( SQL_NULL_HENV, dbh, 
-                       op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
+       if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
+               SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+
+       } else {
+               SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
+       }
 
        /*
         * FIXME: NOOP does not work for add -- it works for all 
@@ -1047,16 +1163,17 @@ backsql_add( Operation *op, SlapReply *rs )
         * in deleting that row.
         */
 
-done:;
        send_ldap_result( op, rs );
 
-       if ( realdn.bv_val != op->oq_add.rs_e->e_name.bv_val ) {
+       if ( !BER_BVISNULL( &realdn )
+                       && realdn.bv_val != op->oq_add.rs_e->e_name.bv_val )
+       {
                ch_free( realdn.bv_val );
        }
-       if ( realpdn.bv_val != pdn.bv_val ) {
+       if ( !BER_BVISNULL( &realpdn ) && realpdn.bv_val != pdn.bv_val ) {
                ch_free( realpdn.bv_val );
        }
-       if ( parent_id.eid_dn.bv_val != NULL ) {
+       if ( !BER_BVISNULL( &parent_id.eid_dn ) ) {
                backsql_free_entryID( &parent_id, 0 );
        }
 
index 4046bb30572038046834636255af0bbb535b64ab..08370e7abeda60f5b35a98cc9f5a57b82ac2d7d7 100644 (file)
  */
 #undef BACKSQL_ARBITRARY_KEY
 
+/*
+ * define to the appropriate aliasing string
+ */
+#define BACKSQL_ALIASING       "AS "
+/* #define     BACKSQL_ALIASING        "" */
+
+/*
+ * define to the appropriate quoting char
+ */
+/* #define BACKSQL_ALIASING_QUOTE      '"' */
+/* #define BACKSQL_ALIASING_QUOTE      '\'' */
+
 /*
  * API
  */
@@ -250,6 +262,7 @@ typedef struct backsql_srch_info {
        time_t                  bsi_stoptime;
 
        backsql_entryID         *bsi_id_list,
+                               **bsi_id_listtail,
                                *bsi_c_eid;
        int                     bsi_n_candidates;
        int                     bsi_abandon;
@@ -284,7 +297,10 @@ typedef struct {
        struct berval   subtree_cond;
        struct berval   children_cond;
        char            *oc_query, *at_query;
-       char            *insentry_query,*delentry_query;
+       char            *insentry_query,
+                       *delentry_query,
+                       *delobjclasses_query,
+                       *delreferrals_query;
        char            *id_query;
        char            *has_children_query;
 
@@ -336,6 +352,9 @@ typedef struct {
 #define BACKSQL_SUCCESS( rc ) \
        ( (rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO )
 
+#define BACKSQL_AVL_STOP               0
+#define BACKSQL_AVL_CONTINUE           1
+
 #endif /* __BACKSQL_H__ */
 
 
index 21906b22f4520c040efeeb1a91c8eee9eebde080..2f8d31c2c06c00e6d7c037a63c7b55a604dcce7c 100644 (file)
@@ -101,22 +101,33 @@ backsql_bind( Operation *op, SlapReply *rs )
 
        backsql_init_search( &bsi, &dn, LDAP_SCOPE_BASE, 
                        -1, -1, -1, NULL, dbh, op, rs, anlist );
-       e = backsql_id2entry( &bsi, &user_entry, &user_id );
-       if ( e == NULL ) {
+       bsi.bsi_e = &user_entry;
+       rc = backsql_id2entry( &bsi, &user_id );
+       if ( rc != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_bind(): "
-                       "error in backsql_id2entry() - auth failed\n",
-                       0, 0, 0 );
-               rs->sr_err = LDAP_OTHER;
+                       "error %d in backsql_id2entry() "
+                       "- auth failed\n", rc, 0, 0 );
+               rs->sr_err = LDAP_INVALID_CREDENTIALS;
                goto error_return;
        }
+       e = &user_entry;
 
        if ( ! access_allowed( op, e, password, NULL, ACL_AUTH, NULL ) ) {
+#if 1
+               rs->sr_err = LDAP_INVALID_CREDENTIALS;
+#else
                rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
+#endif
                goto error_return;
        }
 
-       if ( ( a = attr_find( e->e_attrs, password ) ) == NULL ) {
+       a = attr_find( e->e_attrs, password );
+       if ( a == NULL ) {
+#if 1
+               rs->sr_err = LDAP_INVALID_CREDENTIALS;
+#else
                rs->sr_err = LDAP_INAPPROPRIATE_AUTH;
+#endif
                goto error_return;
        }
 
index 3526389a429f6103b123bfc459a6f2f7210aa8c8..f92feb8327e77da3d50512a9204435b2756ff280 100644 (file)
@@ -35,7 +35,7 @@ backsql_compare( Operation *op, SlapReply *rs )
        backsql_entryID         user_id = BACKSQL_ENTRYID_INIT;
        SQLHDBC                 dbh;
        Entry                   *e = NULL, user_entry;
-       Attribute               *a = NULL, *a_op = NULL;
+       Attribute               *a = NULL;
        backsql_srch_info       bsi;
        int                     rc;
        AttributeName           anlist[2];
@@ -79,55 +79,42 @@ backsql_compare( Operation *op, SlapReply *rs )
                goto return_results;
        }
 
+       memset( &anlist[0], 0, 2 * sizeof( AttributeName ) );
        anlist[0].an_name = op->oq_compare.rs_ava->aa_desc->ad_cname;
        anlist[0].an_desc = op->oq_compare.rs_ava->aa_desc;
-       anlist[1].an_name.bv_val = NULL;
 
-       /*
-        * Try to get attr as dynamic operational
-        */
-       if ( is_at_operational( op->oq_compare.rs_ava->aa_desc->ad_type ) ) {
-               AttributeName   *an_old;
-               Entry           *e_old;
-
-               user_entry.e_attrs = NULL;
-               user_entry.e_name = op->o_req_dn;
-               user_entry.e_nname = op->o_req_ndn;
-
-               an_old = rs->sr_attrs;
-               e_old = rs->sr_entry;
-
-               rs->sr_attrs = anlist;
-               rs->sr_entry = &user_entry;
-               rs->sr_err = backsql_operational( op, rs, 0, &a_op );
-               rs->sr_attrs = an_old;
-               rs->sr_entry = e_old;
-
-               if ( rs->sr_err != LDAP_SUCCESS ) {
-                       goto return_results;
-               }
-               
-       }
-
-       /*
-        * attr was dynamic operational
-        */
-       if ( a_op != NULL ) {
-               user_entry.e_attrs = a_op;
-               e = &user_entry;
-
-       } else {
+       /*
+        * Try to get attr as dynamic operational
+        */
+       if ( is_at_operational( op->oq_compare.rs_ava->aa_desc->ad_type ) ) {
+               SlapReply       nrs = { 0 };
+               user_entry.e_attrs = NULL;
+               user_entry.e_name = op->o_req_dn;
+               user_entry.e_nname = op->o_req_ndn;
+               nrs.sr_attrs = anlist;
+               nrs.sr_entry = &user_entry;
+               rs->sr_err = backsql_operational( op, &nrs, 0, &user_entry.e_attrs );
+               if ( rs->sr_err != LDAP_SUCCESS ) {
+                       goto return_results;
+               }
+               
+       } else {
                backsql_init_search( &bsi, &dn, LDAP_SCOPE_BASE, 
-                               -1, -1, -1, NULL, dbh, op, rs, anlist );
-               e = backsql_id2entry( &bsi, &user_entry, &user_id );
-               if ( e == NULL ) {
+                                       -1, -1, -1, NULL, dbh, op, rs, anlist );
+               bsi.bsi_e = &user_entry;
+               rc = backsql_id2entry( &bsi, &user_id );
+               if ( rc != LDAP_SUCCESS ) {
                        Debug( LDAP_DEBUG_TRACE, "backsql_compare(): "
-                               "error in backsql_id2entry() "
-                               "- compare failed\n", 0, 0, 0 );
-                       rs->sr_err = LDAP_OTHER;
+                               "error %d in backsql_id2entry() "
+                               "- compare failed\n", rc, 0, 0 );
+                       rs->sr_err = rc;
                        goto return_results;
                }
        }
+       e = &user_entry;
 
        if ( ! access_allowed( op, e, op->oq_compare.rs_ava->aa_desc, 
                                &op->oq_compare.rs_ava->aa_value,
@@ -162,17 +149,7 @@ return_results:;
        }
 
        if ( e != NULL ) {
-               if ( e->e_name.bv_val != NULL ) {
-                       free( e->e_name.bv_val );
-               }
-
-               if ( e->e_nname.bv_val != NULL ) {
-                       free( e->e_nname.bv_val );
-               }
-
-               if ( e->e_attrs != NULL ) {
-                       attrs_free( e->e_attrs );
-               }
+               entry_clean( e );
        }
 
        Debug(LDAP_DEBUG_TRACE,"<==backsql_compare()\n",0,0,0);
index bce61980450cbfb0cb1c489b3d2e0e4017225a92..02795c64ef7287c44610e9ba8170bb85e7ae90dc 100644 (file)
@@ -274,6 +274,32 @@ backsql_db_config(
                Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
                        "delentry_query=%s\n", si->delentry_query, 0, 0 );
 
+       } else if ( !strcasecmp( argv[ 0 ], "delobjclasses_query" ) ) {
+               if ( argc < 2 ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<==backsql_db_config (%s line %d): "
+                               "missing SQL statement "
+                               "in \"delobjclasses_query\" directive\n",
+                               fname, lineno, 0 );
+                       return 1;
+               }
+               si->delobjclasses_query = ch_strdup( argv[ 1 ] );
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
+                       "delobjclasses_query=%s\n", si->delobjclasses_query, 0, 0 );
+
+       } else if ( !strcasecmp( argv[ 0 ], "delreferrals_query" ) ) {
+               if ( argc < 2 ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<==backsql_db_config (%s line %d): "
+                               "missing SQL statement "
+                               "in \"delreferrals_query\" directive\n",
+                               fname, lineno, 0 );
+                       return 1;
+               }
+               si->delreferrals_query = ch_strdup( argv[ 1 ] );
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
+                       "delreferrals_query=%s\n", si->delreferrals_query, 0, 0 );
+
        } else if ( !strcasecmp( argv[ 0 ], "has_ldapinfo_dn_ru") ) {
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE,
index 3f4cfb99a44f3b331720d3e3e1a028ddbceccc89..31d0ef8c107a82f560c4f52e68b69a3355d536a6 100644 (file)
 #include "ldap_pvt.h"
 #include "proto-sql.h"
 
+typedef struct backsql_delete_attr_t {
+       Operation               *op;
+       SlapReply               *rs;
+       SQLHDBC                 dbh; 
+       backsql_entryID         *e_id;
+} backsql_delete_attr_t;
+
+static int
+backsql_delete_attr_f( void *v_at, void *v_bda )
+{
+       backsql_at_map_rec      *at = (backsql_at_map_rec *)v_at;
+       backsql_delete_attr_t   *bda = (backsql_delete_attr_t *)v_bda;
+       int                     rc;
+
+       rc = backsql_modify_delete_all_values( bda->op,
+                       bda->rs, bda->dbh, bda->e_id, at );
+
+       if ( rc != LDAP_SUCCESS ) {
+               return BACKSQL_AVL_STOP;
+       }
+
+       return BACKSQL_AVL_CONTINUE;
+}
+
+static int
+backsql_delete_all_attrs(
+       Operation               *op,
+       SlapReply               *rs,
+       SQLHDBC                 dbh, 
+       backsql_entryID         *e_id,
+       backsql_oc_map_rec      *oc )
+{
+       backsql_delete_attr_t   bda;
+       int                     rc;
+
+       bda.op = op;
+       bda.rs = rs;
+       bda.dbh = dbh;
+       bda.e_id = e_id;
+       
+       rc = avl_apply( oc->bom_attrs, backsql_delete_attr_f, &bda,
+                       BACKSQL_AVL_STOP, AVL_INORDER );
+       if ( rc == BACKSQL_AVL_STOP ) {
+               return rs->sr_err;
+       }
+
+       return LDAP_SUCCESS;
+}
+
 int
 backsql_delete( Operation *op, SlapReply *rs )
 {
@@ -114,7 +163,11 @@ backsql_delete( Operation *op, SlapReply *rs )
                goto done;
        }
 
-       SQLAllocStmt( dbh, &sth );
+       /* avl_apply ... */
+       rs->sr_err = backsql_delete_all_attrs( op, rs, dbh, &e_id, oc );
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+               goto done;
+       }
 
        rc = backsql_Prepare( dbh, &sth, oc->bom_delete_proc, 0 );
        if ( rc != SQL_SUCCESS ) {
@@ -157,13 +210,91 @@ backsql_delete( Operation *op, SlapReply *rs )
                rs->sr_text = "SQL-backend error";
                goto done;
        }
-#ifndef BACKSQL_REALLOC_STMT
-       SQLFreeStmt( sth, SQL_RESET_PARAMS );
-#else /* BACKSQL_REALLOC_STMT */
        SQLFreeStmt( sth, SQL_DROP );
-       SQLAllocStmt( dbh, &sth );
-#endif /* BACKSQL_REALLOC_STMT */
 
+       /* delete "auxiliary" objectClasses, if any... */
+       rc = backsql_Prepare( dbh, &sth, bi->delobjclasses_query, 0 );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       "   backsql_delete(): "
+                       "error preparing ldap_entry_objclasses delete query\n", 
+                       0, 0, 0 );
+               backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+
+               rs->sr_err = LDAP_OTHER;
+               rs->sr_text = "SQL-backend error";
+               goto done;
+       }
+
+#ifdef BACKSQL_ARBITRARY_KEY
+       SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
+                       0, 0, e_id.eid_id.bv_val, 0, 0 );
+#else /* ! BACKSQL_ARBITRARY_KEY */
+       SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
+                       0, 0, &e_id.eid_id, 0, 0 );
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+       rc = SQLExecute( sth );
+       switch ( rc ) {
+       case SQL_NO_DATA:
+               /* apparently there were no "auxiliary" objectClasses
+                * for this entry... */
+       case SQL_SUCCESS:
+               break;
+
+       default:
+               Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
+                       "failed to delete record from ldap_entry_objclasses\n", 
+                       0, 0, 0 );
+               backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+               SQLFreeStmt( sth, SQL_DROP );
+               rs->sr_err = LDAP_OTHER;
+               rs->sr_text = "SQL-backend error";
+               goto done;
+       }
+       SQLFreeStmt( sth, SQL_DROP );
+
+       /* delete referrals, if any... */
+       rc = backsql_Prepare( dbh, &sth, bi->delreferrals_query, 0 );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       "   backsql_delete(): "
+                       "error preparing ldap_referrals delete query\n", 
+                       0, 0, 0 );
+               backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+
+               rs->sr_err = LDAP_OTHER;
+               rs->sr_text = "SQL-backend error";
+               goto done;
+       }
+
+#ifdef BACKSQL_ARBITRARY_KEY
+       SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
+                       0, 0, e_id.eid_id.bv_val, 0, 0 );
+#else /* ! BACKSQL_ARBITRARY_KEY */
+       SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
+                       0, 0, &e_id.eid_id, 0, 0 );
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+       rc = SQLExecute( sth );
+       switch ( rc ) {
+       case SQL_NO_DATA:
+               /* apparently there were no referrals
+                * for this entry... */
+       case SQL_SUCCESS:
+               break;
+
+       default:
+               Debug( LDAP_DEBUG_TRACE, "   backsql_delete(): "
+                       "failed to delete record from ldap_referrals\n", 
+                       0, 0, 0 );
+               backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+               SQLFreeStmt( sth, SQL_DROP );
+               rs->sr_err = LDAP_OTHER;
+               rs->sr_text = "SQL-backend error";
+               goto done;
+       }
+       SQLFreeStmt( sth, SQL_DROP );
+
+       /* delete entry... */
        rc = backsql_Prepare( dbh, &sth, bi->delentry_query, 0 );
        if ( rc != SQL_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE,
@@ -195,6 +326,7 @@ backsql_delete( Operation *op, SlapReply *rs )
                rs->sr_text = "SQL-backend error";
                goto done;
        }
+       SQLFreeStmt( sth, SQL_DROP );
 
        /*
         * Commit only if all operations succeed
index 051e4f12ad883b992a0fdf1091d6b7e4381155eb..26c2165379e0e3934c7b2b4c33870c5ccaa149ab 100644 (file)
@@ -341,6 +341,18 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
                return 1;
        }
 
+#ifdef BACKSQL_TRACE
+#ifdef BACKSQL_ARBITRARY_KEY
+       Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): "
+               "query=\"%s\" keyval=%s\n", at->bam_query,
+               bsi->bsi_c_eid->eid_keyval.bv_val, 0 );
+#else /* !BACKSQL_ARBITRARY_KEY */
+       Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): "
+               "query=\"%s\" keyval=%d\n", at->bam_query,
+               bsi->bsi_c_eid->eid_keyval, 0 );
+#endif /* ! BACKSQL_ARBITRARY_KEY */
+#endif /* BACKSQL_TRACE */
+
        rc = SQLExecute( sth );
        if ( ! BACKSQL_SUCCESS( rc ) ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): "
@@ -396,8 +408,8 @@ backsql_get_attr_vals( void *v_at, void *v_bsi )
        return 1;
 }
 
-Entry *
-backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
+int
+backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid )
 {
        int                     i;
        int                     rc;
@@ -405,35 +417,44 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 );
 
-       rc = dnPrettyNormal( NULL, &eid->eid_dn, &e->e_name, &e->e_nname,
+       assert( bsi->bsi_e );
+
+       memset( bsi->bsi_e, 0, sizeof( Entry ) );
+
+       rc = dnPrettyNormal( NULL, &eid->eid_dn,
+                       &bsi->bsi_e->e_name, &bsi->bsi_e->e_nname,
                        bsi->bsi_op->o_tmpmemctx );
        if ( rc != LDAP_SUCCESS ) {
-               return NULL;
+               return rc;
        }
 
+       bsi->bsi_e->e_attrs = NULL;
+       bsi->bsi_e->e_private = NULL;
+
        bsi->bsi_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
                        eid->eid_oc_id );
-       bsi->bsi_e = e;
        bsi->bsi_c_eid = eid;
-       e->e_attrs = NULL;
-       e->e_private = NULL;
 
 #ifndef BACKSQL_ARBITRARY_KEY  
-       e->e_id = eid->eid_id;
+       bsi->bsi_e->e_id = eid->eid_id;
 #endif /* ! BACKSQL_ARBITRARY_KEY */
  
+       rc = attr_merge_normalize_one( bsi->bsi_e, ad_oc,
+                               &bsi->bsi_oc->bom_oc->soc_cname,
+                               bsi->bsi_op->o_tmpmemctx );
+       if ( rc != LDAP_SUCCESS ) {
+               entry_clean( bsi->bsi_e );
+               return rc;
+       }
+
        if ( bsi->bsi_attrs != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
                        "custom attribute list\n", 0, 0, 0 );
                for ( i = 0; bsi->bsi_attrs[ i ].an_name.bv_val; i++ ) {
                        backsql_at_map_rec      **vat;
-                       AttributeName           *attr = &bsi->bsi_attrs[ i ];
+                       AttributeName           *an = &bsi->bsi_attrs[ i ];
                        int                     j;
 
-                       if ( attr->an_desc == ad_oc ) {
-                               continue;
-                       }
-
                        /* if one of the attributes listed here is
                         * a subtype of another, it must be ignored,
                         * because subtypes are already dealt with
@@ -446,18 +467,19 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                                }
 
                                /* skip subtypes */
-                               if ( is_at_subtype( attr->an_desc->ad_type, bsi->bsi_attrs[ j ].an_desc->ad_type ) )
+                               if ( is_at_subtype( an->an_desc->ad_type,
+                                                       bsi->bsi_attrs[ j ].an_desc->ad_type ) )
                                {
                                        goto next;
                                }
                        }
 
-                       rc = backsql_supad2at( bsi->bsi_oc, attr->an_desc, &vat );
+                       rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat );
                        if ( rc != 0 || vat == NULL ) {
                                Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
                                                "attribute \"%s\" is not defined "
                                                "for objectlass \"%s\"\n",
-                                               attr->an_name.bv_val, 
+                                               an->an_name.bv_val, 
                                                BACKSQL_OC_NAME( bsi->bsi_oc ), 0 );
                                continue;
                        }
@@ -478,13 +500,6 @@ next:;
                                bsi, 0, AVL_INORDER );
        }
 
-       if ( attr_merge_normalize_one( bsi->bsi_e, ad_oc,
-                               &bsi->bsi_oc->bom_oc->soc_cname,
-                               bsi->bsi_op->o_tmpmemctx ) ) {
-               entry_free( e );
-               return NULL;
-       }
-
        if ( global_schemacheck ) {
                const char      *text = NULL;
                char            textbuf[ 1024 ];
@@ -499,8 +514,12 @@ next:;
                rc = structural_class( bv, &soc, NULL, 
                                &text, textbuf, textlen );
                if ( rc != LDAP_SUCCESS ) {
-                       entry_free( e );
-                       return NULL;
+                       Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
+                               "structural_class() failed %d (%s)\n",
+                               bsi->bsi_e->e_name.bv_val,
+                               rc, text ? text : "" );
+                       entry_clean( bsi->bsi_e );
+                       return rc;
                }
 
                if ( ( bsi->bsi_flags | BSQL_SF_ALL_OPER )
@@ -509,15 +528,15 @@ next:;
                                        slap_schema.si_ad_structuralObjectClass,
                                        &soc, bsi->bsi_op->o_tmpmemctx );
                        if ( rc != LDAP_SUCCESS ) {
-                               entry_free( e );
-                               return NULL;
+                               entry_clean( bsi->bsi_e );
+                               return rc;
                        }
                }
        }
 
        Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 );
 
-       return e;
+       return LDAP_SUCCESS;
 }
 
 #endif /* SLAPD_SQL */
index 527172aa1b8e1d25ba1b2e4b5734832695c3fb49..57c05321be803b191586963571b35b3d51682e32 100644 (file)
@@ -23,7 +23,7 @@
 
 LDAP_BEGIN_DECL
 
-extern BI_init         sql_back_initialize;
+extern BI_init         backsql_initialize;
 extern BI_destroy      backsql_destroy;
 
 extern BI_db_init      backsql_db_init;
index b188a679df3239b28ed7457b530e1d7d7966856b..9924349930d8736a505569c13ca3eccdb5ce1218 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <stdio.h>
 #include <sys/types.h>
+#include "ac/string.h"
 
 #include "slap.h"
 #include "ldap_pvt.h"
@@ -40,7 +41,7 @@ init_module(
 
        memset( &bi, '\0', sizeof( bi ) );
        bi.bi_type = "sql";
-       bi.bi_init = sql_back_initialize;
+       bi.bi_init = backsql_initialize;
 
        backend_add( &bi );
        return 0;
@@ -49,7 +50,7 @@ init_module(
 #endif /* SLAPD_SQL == SLAPD_MOD_DYNAMIC */
 
 int
-sql_back_initialize(
+backsql_initialize(
        BackendInfo     *bi )
 { 
        static char *controls[] = {
@@ -161,6 +162,8 @@ backsql_db_destroy(
        free( si->at_query );
        free( si->insentry_query );
        free( si->delentry_query );
+       free( si->delobjclasses_query );
+       free( si->delreferrals_query );
        free( si );
        
        Debug( LDAP_DEBUG_TRACE, "<==backsql_db_destroy()\n", 0, 0, 0 );
@@ -176,7 +179,7 @@ backsql_db_open(
        ber_len_t       idq_len;
        struct berbuf   bb = BB_NULL;
 
-       Operation       otmp;
+       Operation       otmp = { 0 };
                
        Debug( LDAP_DEBUG_TRACE, "==>backsql_db_open(): "
                "testing RDBMS connection\n", 0, 0, 0 );
@@ -247,9 +250,9 @@ backsql_db_open(
                 */
                struct berval   concat;
                struct berval   values[] = {
-                       { sizeof( "'%'" ) - 1,  "'%'" },
-                       { sizeof( "?" ) - 1,    "?" },
-                       { 0,                    NULL }
+                       BER_BVC( "'%'" ),
+                       BER_BVC( "?" ),
+                       BER_BVNULL
                };
                struct berbuf   bb = BB_NULL;
 
@@ -273,7 +276,7 @@ backsql_db_open(
 
                        backsql_strfcat( &bb, "blbbb",
                                        &si->upper_func,
-                                       (ber_len_t)sizeof( "(ldap_entries.dn) LIKE " ) - 1,
+                                       (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ),
                                                "(ldap_entries.dn) LIKE ",
                                        &si->upper_func_open,
                                        &concat,
@@ -286,7 +289,7 @@ backsql_db_open(
                         */
 
                        backsql_strfcat( &bb, "lb",
-                                       (ber_len_t)sizeof( "ldap_entries.dn LIKE " ) - 1,
+                                       (ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ),
                                                "ldap_entries.dn LIKE ",
                                        &concat );
                }
@@ -309,10 +312,10 @@ backsql_db_open(
 
                        backsql_strfcat( &bb, "blbl",
                                        &si->upper_func,
-                                       (ber_len_t)sizeof( "(ldap_entries.dn)=" ) - 1,
+                                       (ber_len_t)STRLENOF( "(ldap_entries.dn)=" ),
                                                "(ldap_entries.dn)=",
                                        &si->upper_func,
-                                       (ber_len_t)sizeof( "(?)" ) - 1, "(?)" );
+                                       (ber_len_t)STRLENOF( "(?)" ), "(?)" );
 
                } else {
 
@@ -321,7 +324,7 @@ backsql_db_open(
                         */
 
                        backsql_strfcat( &bb, "l",
-                                       (ber_len_t)sizeof( "ldap_entries.dn=?" ) - 1,
+                                       (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
                                                "ldap_entries.dn=?");
                }
 
@@ -382,7 +385,29 @@ backsql_db_open(
                si->delentry_query = ch_strdup( backsql_def_delentry_query );
        }
 
-       otmp.o_connid = -1;
+       if ( si->delobjclasses_query == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "objclasses deletion SQL statement not specified "
+                       "(use \"delobjclasses_query\" directive in slapd.conf)\n",
+                       0, 0, 0 );
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "setting \"%s\" by default\n",
+                       backsql_def_delobjclasses_query, 0, 0 );
+               si->delobjclasses_query = ch_strdup( backsql_def_delobjclasses_query );
+       }
+
+       if ( si->delreferrals_query == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "referrals deletion SQL statement not specified "
+                       "(use \"delreferrals_query\" directive in slapd.conf)\n",
+                       0, 0, 0 );
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "setting \"%s\" by default\n",
+                       backsql_def_delreferrals_query, 0, 0 );
+               si->delreferrals_query = ch_strdup( backsql_def_delreferrals_query );
+       }
+
+       otmp.o_connid = (unsigned long)(-1);
        otmp.o_bd = bd;
        if ( backsql_get_db_conn( &otmp, &dbh ) != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
@@ -398,6 +423,7 @@ backsql_db_open(
 
        if ( si->upper_func.bv_val == NULL ) {
                backsql_strcat( &bb, backsql_id_query, "dn=?", NULL );
+
        } else {
                if ( BACKSQL_HAS_LDAPINFO_DN_RU( si ) ) {
                        backsql_strcat( &bb, backsql_id_query,
@@ -407,12 +433,12 @@ backsql_db_open(
                                backsql_strfcat( &bb, "sbl",
                                                backsql_id_query,
                                                &si->upper_func, 
-                                               (ber_len_t)sizeof( "(dn)=?" ) - 1, "(dn)=?" );
+                                               (ber_len_t)STRLENOF( "(dn)=?" ), "(dn)=?" );
                        } else {
                                backsql_strfcat( &bb, "sblbcb",
                                                backsql_id_query,
                                                &si->upper_func, 
-                                               (ber_len_t)sizeof( "(dn)=" ) - 1, "(dn)=",
+                                               (ber_len_t)STRLENOF( "(dn)=" ), "(dn)=",
                                                &si->upper_func_open, 
                                                '?', 
                                                &si->upper_func_close );
@@ -460,13 +486,14 @@ backsql_db_close(
 int
 backsql_connection_destroy( Backend *bd, Connection *c )
 {
-       Operation o;
+       Operation o = { 0 };
        o.o_bd = bd;
        o.o_connid = c->c_connid;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_connection_destroy()\n", 0, 0, 0 );
        backsql_free_db_conn( &o );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_connection_destroy()\n", 0, 0, 0 );
+
        return 0;
 }
 
index ee05c7d8f1c8e6af3723524de65d696083f8fd77..419065ccf6115663a01d5e35a06ad97fd9f37468 100644 (file)
@@ -39,16 +39,17 @@ backsql_modrdn( Operation *op, SlapReply *rs )
        RETCODE                 rc;
        backsql_entryID         e_id = BACKSQL_ENTRYID_INIT,
                                pe_id = BACKSQL_ENTRYID_INIT,
-                               new_pid = BACKSQL_ENTRYID_INIT;
+                               new_pe_id = BACKSQL_ENTRYID_INIT;
        backsql_oc_map_rec      *oc = NULL;
-       struct berval           p_dn, p_ndn,
+       struct berval           p_dn = BER_BVNULL, p_ndn = BER_BVNULL,
                                *new_pdn = NULL, *new_npdn = NULL,
-                               new_dn, new_ndn;
+                               new_dn = BER_BVNULL, new_ndn = BER_BVNULL;
        LDAPRDN                 new_rdn = NULL;
        LDAPRDN                 old_rdn = NULL;
        Entry                   e;
-       Modifications           *mod;
+       Modifications           *mod = NULL;
        struct berval           *newSuperior = op->oq_modrdn.rs_newSup;
+       char                    *next;
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry \"%s\", "
                        "newrdn=\"%s\", newSuperior=\"%s\"\n",
@@ -68,7 +69,8 @@ backsql_modrdn( Operation *op, SlapReply *rs )
        rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn );
        if ( rs->sr_err != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
-                       "could not lookup entry id\n", 0, 0, 0 );
+                       "could not lookup entry id (%d)\n",
+                       rs->sr_err, 0, 0 );
                rs->sr_text = ( rs->sr_err == LDAP_OTHER )
                        ?  "SQL-backend error" : NULL;
                send_ldap_result( op, rs );
@@ -174,9 +176,10 @@ backsql_modrdn( Operation *op, SlapReply *rs )
                goto modrdn_return;
        }
 
-       build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn, NULL );
+       build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn,
+                       op->o_tmpmemctx );
        rs->sr_err = dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn,
-               op->o_tmpmemctx );
+                       op->o_tmpmemctx );
        if ( rs->sr_err != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
                        "new dn is invalid (\"%s\") - aborting\n",
@@ -209,7 +212,7 @@ backsql_modrdn( Operation *op, SlapReply *rs )
 
        backsql_free_entryID( &pe_id, 0 );
 
-       rs->sr_err = backsql_dn2id( bi, &new_pid, dbh, new_npdn );
+       rs->sr_err = backsql_dn2id( bi, &new_pe_id, dbh, new_npdn );
        if ( rs->sr_err != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
                        "could not lookup new parent entry id\n", 0, 0, 0 );
@@ -221,16 +224,29 @@ backsql_modrdn( Operation *op, SlapReply *rs )
 
 #ifdef BACKSQL_ARBITRARY_KEY
        Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
-               "new parent entry id=%s\n", new_pid.eid_id.bv_val, 0, 0 );
+               "new parent entry id=%s\n", new_pe_id.eid_id.bv_val, 0, 0 );
 #else /* ! BACKSQL_ARBITRARY_KEY */
        Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
-               "new parent entry id=%ld\n", new_pid.eid_id, 0, 0 );
+               "new parent entry id=%ld\n", new_pe_id.eid_id, 0, 0 );
 #endif /* ! BACKSQL_ARBITRARY_KEY */
 
  
        Debug(  LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
                "executing delentry_query\n", 0, 0, 0 );
-       SQLAllocStmt( dbh, &sth );
+
+       rc = backsql_Prepare( dbh, &sth, bi->delentry_query, 0 );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       "   backsql_modrdn(): "
+                       "error preparing delentry_query\n", 0, 0, 0 );
+               backsql_PrintErrors( bi->db_env, dbh, 
+                               sth, rc );
+
+               rs->sr_text = "SQL-backend error";
+               rs->sr_err = LDAP_OTHER;
+               goto done;
+       }
+
 #ifdef BACKSQL_ARBITRARY_KEY
        SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
                        0, 0, e_id.eid_id.bv_val, 0, 0 );
@@ -238,100 +254,95 @@ backsql_modrdn( Operation *op, SlapReply *rs )
        SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
                        0, 0, &e_id.eid_id, 0, 0 );
 #endif /* ! BACKSQL_ARBITRARY_KEY */
-       rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
+       rc = SQLExecute( sth );
        if ( rc != SQL_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
                        "failed to delete record from ldap_entries\n",
                        0, 0, 0 );
                backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+               SQLFreeStmt( sth, SQL_DROP );
                rs->sr_err = LDAP_OTHER;
                rs->sr_text = "SQL-backend error";
                send_ldap_result( op, rs );
-               goto modrdn_return;
+               goto done;
        }
 
-       SQLFreeStmt( sth, SQL_RESET_PARAMS );
+       SQLFreeStmt( sth, SQL_DROP );
 
        Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
                "executing insentry_query\n", 0, 0, 0 );
+
+       rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE,
+                       "   backsql_modrdn(): "
+                       "error preparing insentry_query\n", 0, 0, 0 );
+               backsql_PrintErrors( bi->db_env, dbh, 
+                               sth, rc );
+
+               rs->sr_text = "SQL-backend error";
+               rs->sr_err = LDAP_OTHER;
+               goto done;
+       }
+
        backsql_BindParamStr( sth, 1, new_dn.bv_val, BACKSQL_MAX_DN_LEN );
        SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
                        0, 0, &e_id.eid_oc_id, 0, 0 );
 #ifdef BACKSQL_ARBITRARY_KEY
        SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
-                       0, 0, new_pid.eid_id.bv_val, 0, 0 );
+                       0, 0, new_pe_id.eid_id.bv_val, 0, 0 );
        SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR,
                        0, 0, e_id.eid_keyval.bv_val, 0, 0 );
 #else /* ! BACKSQL_ARBITRARY_KEY */
        SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
-                       0, 0, &new_pid.eid_id, 0, 0 );
+                       0, 0, &new_pe_id.eid_id, 0, 0 );
        SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
                        0, 0, &e_id.eid_keyval, 0, 0 );
 #endif /* ! BACKSQL_ARBITRARY_KEY */
-       rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS );
+       rc = SQLExecute( sth );
        if ( rc != SQL_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "   backsql_modrdn(): "
                        "could not insert ldap_entries record\n", 0, 0, 0 );
                backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+               SQLFreeStmt( sth, SQL_DROP );
                rs->sr_err = LDAP_OTHER;
                rs->sr_text = "SQL-backend error";
                send_ldap_result( op, rs );
-               goto modrdn_return;
+               goto done;
        }
+       SQLFreeStmt( sth, SQL_DROP );
 
        /*
         * Get attribute type and attribute value of our new rdn,
         * we will need to add that to our new entry
         */
-       if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn,
-                               (char **)&rs->sr_text, 
-                               LDAP_DN_FORMAT_LDAP ) ) {
-#ifdef NEW_LOGGING
-               LDAP_LOG ( OPERATION, ERR, 
-                       "   backsql_modrdn: can't figure out "
-                       "type(s)/values(s) of newrdn\n", 
-                       0, 0, 0 );
-#else
+       if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn, &next, 
+                               LDAP_DN_FORMAT_LDAP ) )
+       {
                Debug( LDAP_DEBUG_TRACE,
                        "   backsql_modrdn: can't figure out "
                        "type(s)/values(s) of newrdn\n", 
                        0, 0, 0 );
-#endif
                rs->sr_err = LDAP_INVALID_DN_SYNTAX;
-               goto modrdn_return;
+               goto done;
        }
 
-#ifdef NEW_LOGGING
-       LDAP_LOG ( OPERATION, RESULTS, 
-               "   backsql_modrdn: new_rdn_type=\"%s\", "
-               "new_rdn_val=\"%s\"\n",
-               new_rdn[ 0 ]->la_attr.bv_val, 
-               new_rdn[ 0 ]->la_value.bv_val, 0 );
-#else
        Debug( LDAP_DEBUG_TRACE,
                "   backsql_modrdn: new_rdn_type=\"%s\", "
                "new_rdn_val=\"%s\"\n",
                new_rdn[ 0 ]->la_attr.bv_val,
                new_rdn[ 0 ]->la_value.bv_val, 0 );
-#endif
 
        if ( op->oq_modrdn.rs_deleteoldrdn ) {
-               if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn,
-                                       (char **)&rs->sr_text,
-                                       LDAP_DN_FORMAT_LDAP ) ) {
-#ifdef NEW_LOGGING
-                       LDAP_LOG ( OPERATION, ERR, 
-                               "   backsql_modrdn: can't figure out "
-                               "type(s)/values(s) of old_rdn\n", 
-                               0, 0, 0 );
-#else
+               if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn, &next,
+                                       LDAP_DN_FORMAT_LDAP ) )
+               {
                        Debug( LDAP_DEBUG_TRACE,
                                "   backsql_modrdn: can't figure out "
                                "the old_rdn type(s)/value(s)\n", 
                                0, 0, 0 );
-#endif
                        rs->sr_err = LDAP_OTHER;
-                       goto modrdn_return;             
+                       goto done;              
                }
        }
 
@@ -350,24 +361,24 @@ backsql_modrdn( Operation *op, SlapReply *rs )
        oc = backsql_id2oc( bi, e_id.eid_oc_id );
        rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod );
 
-       if ( rs->sr_err == LDAP_SUCCESS ) {
+done:;
+       /*
+        * Commit only if all operations succeed
+        */
+       if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
+               SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
 
-               /*
-                * Commit only if all operations succeed
-                */
-               SQLTransact( SQL_NULL_HENV, dbh,
-                               op->o_noop ? SQL_ROLLBACK : SQL_COMMIT );
+       } else {
+               SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK );
        }
 
-modrdn_return:
-       SQLFreeStmt( sth, SQL_DROP );
-
-       if ( new_dn.bv_val ) {
-               ch_free( new_dn.bv_val );
+modrdn_return:;
+       if ( !BER_BVISNULL( &new_dn ) ) {
+               slap_sl_free( new_dn.bv_val, op->o_tmpmemctx );
        }
        
-       if ( new_ndn.bv_val ) {
-               ch_free( new_ndn.bv_val );
+       if ( !BER_BVISNULL( &new_ndn ) ) {
+               slap_sl_free( new_ndn.bv_val, op->o_tmpmemctx );
        }
        
        /* LDAP v2 supporting correct attribute handling. */
@@ -379,14 +390,14 @@ modrdn_return:
        }
        if ( mod != NULL ) {
                Modifications *tmp;
-               for (; mod; mod=tmp ) {
+               for (; mod; mod = tmp ) {
                        tmp = mod->sml_next;
                        free( mod );
                }
        }
 
-       if ( new_pid.eid_dn.bv_val ) {
-               backsql_free_entryID( &pe_id, 0 );
+       if ( new_pe_id.eid_dn.bv_val ) {
+               backsql_free_entryID( &new_pe_id, 0 );
        }
 
        send_ldap_result( op, rs );
index e57e9b4d4fe1ab1630d05d1de5d349b6019a4969..8e3fbc3e9994801be5f7492e22bf2c500b378b17 100644 (file)
 /*
  * add.c
  */
+int backsql_modify_delete_all_values(
+       Operation               *op,
+       SlapReply               *rs,
+       SQLHDBC                 dbh, 
+       backsql_entryID         *e_id,
+       backsql_at_map_rec      *at );
+
 int backsql_modify_internal(
        Operation               *op,
        SlapReply               *rs,
@@ -115,8 +122,7 @@ int backsql_has_children( backsql_info *bi, SQLHDBC dbh, struct berval *dn );
 backsql_entryID *backsql_free_entryID( backsql_entryID *id, int freeit );
 
 /* turns an ID into an entry */
-Entry *backsql_id2entry( backsql_srch_info *bsi, Entry *e, 
-               backsql_entryID *id );
+int backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *id );
 
 /*
  * schema-map.c
@@ -190,6 +196,8 @@ extern char
        backsql_def_at_query[],
        backsql_def_delentry_query[],
        backsql_def_insentry_query[],
+       backsql_def_delobjclasses_query[],
+       backsql_def_delreferrals_query[],
        backsql_def_subtree_cond[],
        backsql_def_upper_subtree_cond[],
        backsql_id_query[],
index 88ee4496c87522a0ba59e78d65bd106755a3f564..cd539e8316fc8c272b8065bae29fc6257837ea99 100644 (file)
 
 #define BACKSQL_DUPLICATE      (-1)
 
+/* NOTE: by default, cannot just compare pointers because
+ * objectClass/attributeType order would be machine-dependent
+ * (and tests would fail!); however, if you don't want to run
+ * tests, or see attributeTypes written in the same order
+ * they are defined, define */
+/* #undef BACKSQL_USE_PTR_CMP */
+
 /*
  * Uses the pointer to the ObjectClass structure
  */
 static int
 backsql_cmp_oc( const void *v_m1, const void *v_m2 )
 {
-       const backsql_oc_map_rec *m1 = v_m1, *m2 = v_m2;
+       const backsql_oc_map_rec        *m1 = v_m1,
+                                       *m2 = v_m2;
 
+#ifdef BACKSQL_USE_PTR_CMP
        return SLAP_PTRCMP( m1->bom_oc, m2->bom_oc );
+#else /* ! BACKSQL_USE_PTR_CMP */
+       return ber_bvcmp( &m1->bom_oc->soc_cname, &m2->bom_oc->soc_cname );
+#endif /* ! BACKSQL_USE_PTR_CMP */
 }
 
 static int
 backsql_cmp_oc_id( const void *v_m1, const void *v_m2 )
 {
-       const backsql_oc_map_rec *m1 = v_m1, *m2 = v_m2;
+       const backsql_oc_map_rec        *m1 = v_m1,
+                                       *m2 = v_m2;
 
        return ( m1->bom_id < m2->bom_id ? -1 : ( m1->bom_id > m2->bom_id ? 1 : 0 ) );
 }
@@ -58,18 +71,27 @@ backsql_cmp_oc_id( const void *v_m1, const void *v_m2 )
 static int
 backsql_cmp_attr( const void *v_m1, const void *v_m2 )
 {
-       const backsql_at_map_rec *m1 = v_m1, *m2 = v_m2;
+       const backsql_at_map_rec        *m1 = v_m1,
+                                       *m2 = v_m2;
 
+#ifdef BACKSQL_USE_PTR_CMP
        return SLAP_PTRCMP( m1->bam_ad, m2->bam_ad );
+#else /* ! BACKSQL_USE_PTR_CMP */
+       return ber_bvcmp( &m1->bam_ad->ad_cname, &m2->bam_ad->ad_cname );
+#endif /* ! BACKSQL_USE_PTR_CMP */
 }
 
 int
 backsql_dup_attr( void *v_m1, void *v_m2 )
 {
-       backsql_at_map_rec *m1 = v_m1, *m2 = v_m2;
+       backsql_at_map_rec              *m1 = v_m1,
+                                       *m2 = v_m2;
 
        assert( m1->bam_ad == m2->bam_ad );
-       
+
+       /* duplicate definitions of attributeTypes are appended;
+        * this allows to define multiple rules for the same 
+        * attributeType.  Use with care! */
        for ( ; m1->bam_next ; m1 = m1->bam_next );
        m1->bam_next = m2;
        m2->bam_next = NULL;
@@ -84,25 +106,54 @@ backsql_make_attr_query(
 {
        struct berbuf   bb = BB_NULL;
 
+#ifdef BACKSQL_ALIASING_QUOTE
+       backsql_strfcat( &bb, "lblcbclblbcbl", 
+                       (ber_len_t)STRLENOF( "SELECT " ), "SELECT ", 
+                       &at_map->bam_sel_expr, 
+                       (ber_len_t)STRLENOF( " " BACKSQL_ALIASING ), " " BACKSQL_ALIASING, 
+                       BACKSQL_ALIASING_QUOTE,
+                       &at_map->bam_ad->ad_cname,
+                       BACKSQL_ALIASING_QUOTE,
+                       (ber_len_t)STRLENOF( " FROM " ), " FROM ", 
+                       &at_map->bam_from_tbls, 
+                       (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", 
+                       &oc_map->bom_keytbl,
+                       '.', 
+                       &oc_map->bom_keycol,
+                       (ber_len_t)STRLENOF( "=?" ), "=?" );
+#else /* ! BACKSQL_ALIASING_QUOTE */
        backsql_strfcat( &bb, "lblblblbcbl", 
-                       (ber_len_t)sizeof( "SELECT " ) - 1, "SELECT ", 
+                       (ber_len_t)STRLENOF( "SELECT " ), "SELECT ", 
                        &at_map->bam_sel_expr, 
-                       (ber_len_t)sizeof( " AS " ) - 1, " AS "
+                       (ber_len_t)STRLENOF( " " BACKSQL_ALIASING ), " " BACKSQL_ALIASING
                        &at_map->bam_ad->ad_cname,
-                       (ber_len_t)sizeof( " FROM " ) - 1, " FROM ", 
+                       (ber_len_t)STRLENOF( " FROM " ), " FROM ", 
                        &at_map->bam_from_tbls, 
-                       (ber_len_t)sizeof( " WHERE " ) - 1, " WHERE ", 
+                       (ber_len_t)STRLENOF( " WHERE " ), " WHERE ", 
                        &oc_map->bom_keytbl,
                        '.', 
                        &oc_map->bom_keycol,
-                       (ber_len_t)sizeof( "=?" ) - 1, "=?" );
+                       (ber_len_t)STRLENOF( "=?" ), "=?" );
+#endif /* ! BACKSQL_ALIASING_QUOTE */
 
-       if ( at_map->bam_join_where.bv_val != NULL ) {
+       if ( !BER_BVISNULL( &at_map->bam_join_where ) ) {
                backsql_strfcat( &bb, "lb",
-                               (ber_len_t)sizeof( " AND ") - 1, " AND ", 
+                               (ber_len_t)STRLENOF( " AND " ), " AND ", 
                                &at_map->bam_join_where );
        }
 
+#ifdef BACKSQL_ALIASING_QUOTE
+       backsql_strfcat( &bb, "lcbc", 
+                       (ber_len_t)STRLENOF( " ORDER BY " ), " ORDER BY ",
+                       BACKSQL_ALIASING_QUOTE,
+                       &at_map->bam_sel_expr,
+                       BACKSQL_ALIASING_QUOTE );
+#else /* ! BACKSQL_ALIASING_QUOTE */
+       backsql_strfcat( &bb, "lb", 
+                       (ber_len_t)STRLENOF( " ORDER BY " ), " ORDER BY ",
+                       &at_map->bam_sel_expr );
+#endif /* ! BACKSQL_ALIASING_QUOTE */
+
        at_map->bam_query = bb.bb_val.bv_val;
        
        return 0;
@@ -113,13 +164,14 @@ backsql_add_sysmaps( backsql_oc_map_rec *oc_map )
 {
        backsql_at_map_rec      *at_map;
        char                    s[] = "+9223372036854775807L";
-       ber_len_t               slen;
+       struct berval           sbv;
        struct berbuf           bb;
        
-
+       sbv.bv_val = s;
        snprintf( s, sizeof( s ), "%ld", oc_map->bom_id );
-       slen = strlen( s );
+       sbv.bv_len = strlen( s );
 
+       /* extra objectClasses */
        at_map = (backsql_at_map_rec *)ch_calloc(1, 
                        sizeof( backsql_at_map_rec ) );
        at_map->bam_ad = slap_schema.si_ad_objectClass;
@@ -133,23 +185,56 @@ backsql_add_sysmaps( backsql_oc_map_rec *oc_map )
        backsql_merge_from_clause( &bb, &oc_map->bom_keytbl );
        at_map->bam_from_tbls = bb.bb_val;
 
-       bb.bb_val.bv_val = NULL;
-       bb.bb_val.bv_len = 0;
+       BER_BVZERO( &bb.bb_val );
        bb.bb_len = 0;
-       backsql_strfcat( &bb, "lbcbll",
-                       (ber_len_t)sizeof( "ldap_entries.id=ldap_entry_objclasses.entry_id and ldap_entries.keyval=" ) - 1,
-                               "ldap_entries.id=ldap_entry_objclasses.entry_id and ldap_entries.keyval=",
+       backsql_strfcat( &bb, "lbcblb",
+                       (ber_len_t)STRLENOF( "ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entries.keyval=" ),
+                               "ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entries.keyval=",
                        &oc_map->bom_keytbl, 
                        '.', 
                        &oc_map->bom_keycol,
-                       (ber_len_t)sizeof( " and ldap_entries.oc_map_id=" ) - 1
+                       (ber_len_t)STRLENOF( " and ldap_entries.oc_map_id=" )
                                " and ldap_entries.oc_map_id=", 
-                       slen, s );
+                       &sbv );
+       at_map->bam_join_where = bb.bb_val;
 
        at_map->bam_oc = oc_map->bom_oc;
-       at_map->bam_join_where = bb.bb_val;
+
        at_map->bam_add_proc = NULL;
+       {
+               char    tmp[] =
+                       "INSERT INTO ldap_entry_objclasses "
+                       "(entry_id,oc_name) VALUES "
+                       "((SELECT id FROM ldap_entries "
+                       "WHERE oc_map_id="
+                       "18446744073709551615UL "       /* 64 bit ULONG */
+                       "AND keyval=?),?)";
+               snprintf( tmp, sizeof(tmp), 
+                       "INSERT INTO ldap_entry_objclasses "
+                       "(entry_id,oc_name) VALUES "
+                       "((SELECT id FROM ldap_entries "
+                       "WHERE oc_map_id=%lu "
+                       "AND keyval=?),?)", oc_map->bom_id );
+               at_map->bam_add_proc = ch_strdup( tmp );
+       }
+
        at_map->bam_delete_proc = NULL;
+       {
+               char    tmp[] =
+                       "DELETE FROM ldap_entry_objclasses "
+                       "WHERE entry_id=(SELECT id FROM ldap_entries "
+                       "WHERE oc_map_id="
+                       "18446744073709551615UL "       /* 64 bit ULONG */
+                       "AND keyval=?) AND oc_name=?";
+               snprintf( tmp, sizeof(tmp), 
+                       "DELETE FROM ldap_entry_objclasses "
+                       "WHERE entry_id=(SELECT id FROM ldap_entries "
+                       "WHERE oc_map_id=%lu"
+                       "AND keyval=?) AND oc_name=?",
+                       oc_map->bom_id );
+               at_map->bam_delete_proc = ch_strdup( tmp );
+       }
+
        at_map->bam_param_order = 0;
        at_map->bam_expect_return = 0;
        at_map->bam_next = NULL;
@@ -162,35 +247,85 @@ backsql_add_sysmaps( backsql_oc_map_rec *oc_map )
                                oc_map->bom_oc->soc_cname.bv_val, 0 );
        }
 
+       /* FIXME: we need to correct the objectClass join_where 
+        * after the attribute query is built */
+       ch_free( at_map->bam_join_where.bv_val );
+       BER_BVZERO( &bb.bb_val );
+       bb.bb_len = 0;
+       backsql_strfcat( &bb, "lbcblb",
+                       (ber_len_t)STRLENOF( /* "ldap_entries.id=ldap_entry_objclasses.entry_id AND " */ "ldap_entries.keyval=" ),
+                               /* "ldap_entries.id=ldap_entry_objclasses.entry_id AND " */ "ldap_entries.keyval=",
+                       &oc_map->bom_keytbl, 
+                       '.', 
+                       &oc_map->bom_keycol,
+                       (ber_len_t)STRLENOF( " AND ldap_entries.oc_map_id=" ), 
+                               " AND ldap_entries.oc_map_id=", 
+                       &sbv );
+       at_map->bam_join_where = bb.bb_val;
+
+       /* referral attribute */
        at_map = (backsql_at_map_rec *)ch_calloc( 1, 
                        sizeof( backsql_at_map_rec ) );
        at_map->bam_ad = slap_schema.si_ad_ref;
        ber_str2bv( "ldap_referrals.url", 0, 1, &at_map->bam_sel_expr );
        ber_str2bv( "ldap_referrals,ldap_entries", 0, 1, &at_map->bam_from_tbls );
-       
-       bb.bb_val.bv_val = NULL;
-       bb.bb_val.bv_len = 0;
+
        bb.bb_len = at_map->bam_from_tbls.bv_len + 1;
+       bb.bb_val = at_map->bam_from_tbls;
        backsql_merge_from_clause( &bb, &oc_map->bom_keytbl );
        at_map->bam_from_tbls = bb.bb_val;
 
-       bb.bb_val.bv_val = NULL;
-       bb.bb_val.bv_len = 0;
+       BER_BVZERO( &bb.bb_val );
        bb.bb_len = 0;
-       backsql_strfcat( &bb, "lbcbll",
-                       (ber_len_t)sizeof( "ldap_entries.id=ldap_referrals.entry_id and ldap_entries.keyval=" ) - 1,
-                               "ldap_entries.id=ldap_referrals.entry_id and ldap_entries.keyval=",
+       backsql_strfcat( &bb, "lbcblb",
+                       (ber_len_t)STRLENOF( "ldap_entries.id=ldap_referrals.entry_id AND ldap_entries.keyval=" ),
+                               "ldap_entries.id=ldap_referrals.entry_id AND ldap_entries.keyval=",
                        &oc_map->bom_keytbl, 
                        '.', 
                        &oc_map->bom_keycol,
-                       (ber_len_t)sizeof( " and ldap_entries.oc_map_id=" ) - 1
-                               " and ldap_entries.oc_map_id=", 
-                       slen, s );
+                       (ber_len_t)STRLENOF( " AND ldap_entries.oc_map_id=" )
+                               " AND ldap_entries.oc_map_id=", 
+                       &sbv );
 
-       at_map->bam_oc = NULL;
        at_map->bam_join_where = bb.bb_val;
+
+       at_map->bam_oc = NULL;
+
        at_map->bam_add_proc = NULL;
+       {
+               char    tmp[] =
+                       "INSERT INTO ldap_referrals "
+                       "(entry_id,url) VALUES "
+                       "((SELECT id FROM ldap_entries "
+                       "WHERE oc_map_id="
+                       "18446744073709551615UL "       /* 64 bit ULONG */
+                       "AND keyval=?),?)";
+               snprintf( tmp, sizeof(tmp), 
+                       "INSERT INTO ldap_referrals "
+                       "(entry_id,url) VALUES "
+                       "((SELECT id FROM ldap_entries "
+                       "WHERE oc_map_id=%lu "
+                       "AND keyval=?),?)", oc_map->bom_id );
+               at_map->bam_add_proc = ch_strdup( tmp );
+       }
+
        at_map->bam_delete_proc = NULL;
+       {
+               char    tmp[] =
+                       "DELETE FROM ldap_referrals "
+                       "WHERE entry_id=(SELECT id FROM ldap_entries "
+                       "WHERE oc_map_id="
+                       "18446744073709551615UL "       /* 64 bit ULONG */
+                       "AND keyval=?) and url=?";
+               snprintf( tmp, sizeof(tmp), 
+                       "DELETE FROM ldap_referrals "
+                       "WHERE entry_id=(SELECT id FROM ldap_entries "
+                       "WHERE oc_map_id=%lu"
+                       "AND keyval=?) and url=?",
+                       oc_map->bom_id );
+               at_map->bam_delete_proc = ch_strdup( tmp );
+       }
+
        at_map->bam_param_order = 0;
        at_map->bam_expect_return = 0;
        at_map->bam_next = NULL;
@@ -206,15 +341,165 @@ backsql_add_sysmaps( backsql_oc_map_rec *oc_map )
        return 1;
 }
 
+struct backsql_attr_schema_info {
+       backsql_info    *bas_si;
+       SQLHDBC         bas_dbh;
+       SQLHSTMT        bas_sth;
+       unsigned long   *bas_oc_id;
+       int             bas_rc;
+};
+
+static int
+backsql_oc_get_attr_mapping( void *v_oc, void *v_bas )
+{
+       RETCODE                         rc;
+       BACKSQL_ROW_NTS                 at_row;
+       backsql_oc_map_rec              *oc_map = (backsql_oc_map_rec *)v_oc;
+       backsql_at_map_rec              *at_map;
+       struct backsql_attr_schema_info *bas = (struct backsql_attr_schema_info *)v_bas;
+
+       /* bas->bas_oc_id has been bound to bas->bas_sth */
+       *bas->bas_oc_id = oc_map->bom_id;
+
+       Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
+               "executing at_query\n"
+               "    \"%s\"\n"
+               "    for objectClass \"%s\"\n"
+               "    with param oc_id=\"%lu\"\n",
+               bas->bas_si->at_query,
+               BACKSQL_OC_NAME( oc_map ),
+               *bas->bas_oc_id );
+
+       rc = SQLExecute( bas->bas_sth );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
+                       "error executing at_query\n"
+                       "    \"%s\"\n"
+                       "    for objectClass \"%s\"\n"
+                       "    with param oc_id=\"%lu\"\n",
+                       bas->bas_si->at_query,
+                       BACKSQL_OC_NAME( oc_map ),
+                       *bas->bas_oc_id );
+               backsql_PrintErrors( SQL_NULL_HENV, bas->bas_dbh, bas->bas_sth, rc );
+               bas->bas_rc = LDAP_OTHER;
+               return BACKSQL_AVL_STOP;
+       }
+
+       backsql_BindRowAsStrings( bas->bas_sth, &at_row );
+       for ( ; rc = SQLFetch( bas->bas_sth ), BACKSQL_SUCCESS( rc ); ) {
+               const char      *text = NULL;
+               struct berval   bv;
+               struct berbuf   bb = BB_NULL;
+
+               Debug( LDAP_DEBUG_TRACE, 
+                       "attributeType:\n"
+                       "\tname=\"%s\"\n"
+                       "\tsel_expr=\"%s\"\n"
+                       "\tfrom=\"%s\"\n",
+                       at_row.cols[ 0 ], at_row.cols[ 1 ],
+                       at_row.cols[ 2 ] );
+               Debug( LDAP_DEBUG_TRACE, 
+                       "\tjoin_where=\"%s\"\n"
+                       "\tadd_proc=\"%s\"\n"
+                       "\tdelete_proc=\"%s\"\n",
+                       at_row.cols[ 3 ], at_row.cols[ 4 ],
+                       at_row.cols[ 5 ]);
+               /* TimesTen */
+               Debug( LDAP_DEBUG_TRACE, "\tsel_expr_u=\"%s\"\n",
+                               at_row.cols[ 8 ], 0, 0 );
+               at_map = (backsql_at_map_rec *)ch_calloc( 1,
+                               sizeof( backsql_at_map_rec ) );
+               rc = slap_str2ad( at_row.cols[ 0 ], 
+                               &at_map->bam_ad, &text );
+               if ( rc != LDAP_SUCCESS ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
+                               "attribute \"%s\" for objectClass \"%s\" "
+                               "is not defined in schema: %s\n", 
+                               at_row.cols[ 0 ],
+                               BACKSQL_OC_NAME( oc_map ), text );
+                       bas->bas_rc = LDAP_CONSTRAINT_VIOLATION;
+                       return BACKSQL_AVL_STOP;
+               }
+
+               ber_str2bv( at_row.cols[ 1 ], 0, 1, &at_map->bam_sel_expr );
+               if ( at_row.value_len[ 8 ] < 0 ) {
+                       BER_BVZERO( &at_map->bam_sel_expr_u );
+
+               } else {
+                       ber_str2bv( at_row.cols[ 8 ], 0, 1, 
+                                       &at_map->bam_sel_expr_u );
+               }
+
+               ber_str2bv( at_row.cols[ 2 ], 0, 0, &bv );
+               backsql_merge_from_clause( &bb, &bv );
+               at_map->bam_from_tbls = bb.bb_val;
+               if ( at_row.value_len[ 3 ] < 0 ) {
+                       BER_BVZERO( &at_map->bam_join_where );
+
+               } else {
+                       ber_str2bv( at_row.cols[ 3 ], 0, 1, 
+                                       &at_map->bam_join_where );
+               }
+               at_map->bam_add_proc = NULL;
+               if ( at_row.value_len[ 4 ] > 0 ) {
+                       at_map->bam_add_proc = ch_strdup( at_row.cols[4] );
+               }
+               at_map->bam_delete_proc = NULL;
+               if ( at_row.value_len[ 5 ] > 0 ) {
+                       at_map->bam_delete_proc = ch_strdup( at_row.cols[ 5 ] );
+               }
+               at_map->bam_param_order = strtol( at_row.cols[ 6 ], 
+                               NULL, 0 );
+               at_map->bam_expect_return = strtol( at_row.cols[ 7 ],
+                               NULL, 0 );
+               backsql_make_attr_query( oc_map, at_map );
+               Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
+                       "preconstructed query \"%s\"\n",
+                       at_map->bam_query, 0, 0 );
+               at_map->bam_next = NULL;
+               if ( avl_insert( &oc_map->bom_attrs, at_map, backsql_cmp_attr, backsql_dup_attr ) == BACKSQL_DUPLICATE ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_attr_mapping(): "
+                                       "duplicate attribute \"%s\" "
+                                       "in objectClass \"%s\" map\n",
+                                       at_map->bam_ad->ad_cname.bv_val,
+                                       oc_map->bom_oc->soc_cname.bv_val, 0 );
+               }
+
+               if ( !BER_BVISNULL( &bas->bas_si->upper_func ) &&
+                               BER_BVISNULL( &at_map->bam_sel_expr_u ) )
+               {
+                       struct berbuf   bb = BB_NULL;
+
+                       backsql_strfcat( &bb, "bcbc",
+                                       &bas->bas_si->upper_func,
+                                       '(' /* ) */ ,
+                                       &at_map->bam_sel_expr,
+                                       /* ( */ ')' );
+                       at_map->bam_sel_expr_u = bb.bb_val;
+               }
+       }
+       backsql_FreeRow( &at_row );
+       SQLFreeStmt( bas->bas_sth, SQL_CLOSE );
+
+       Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(\"%s\"): "
+               "autoadding 'objectClass' and 'ref' mappings\n",
+               BACKSQL_OC_NAME( oc_map ), 0, 0 );
+
+       (void)backsql_add_sysmaps( oc_map );
+
+       return BACKSQL_AVL_CONTINUE;
+}
+
+
 int
 backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
 {
-       SQLHSTMT                oc_sth, at_sth;
-       RETCODE                 rc;
-       BACKSQL_ROW_NTS         oc_row, at_row;
-       unsigned long           oc_id;
-       backsql_oc_map_rec      *oc_map;
-       backsql_at_map_rec      *at_map;
+       SQLHSTMT                        sth;
+       RETCODE                         rc;
+       BACKSQL_ROW_NTS                 oc_row;
+       unsigned long                   oc_id;
+       backsql_oc_map_rec              *oc_map;
+       struct backsql_attr_schema_info bas;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_load_schema_map()\n", 0, 0, 0 );
 
@@ -222,7 +507,7 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
         * TimesTen : See if the ldap_entries.dn_ru field exists in the schema
         */
        if ( !BACKSQL_DONTCHECK_LDAPINFO_DN_RU( si ) ) {
-               rc = backsql_Prepare( dbh, &oc_sth, 
+               rc = backsql_Prepare( dbh, &sth, 
                                backsql_check_dn_ru_query, 0 );
                if ( rc == SQL_SUCCESS ) {
                        /* Yes, the field exists */
@@ -234,49 +519,32 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                        si->bsql_flags &= ~BSQLF_HAS_LDAPINFO_DN_RU;
                }
 
-               SQLFreeStmt( oc_sth, SQL_DROP );
+               SQLFreeStmt( sth, SQL_DROP );
        }
 
+       Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): oc_query \"%s\"\n", 
+                       si->oc_query, 0, 0 );
 
-       rc = backsql_Prepare( dbh, &oc_sth, si->oc_query, 0 );
+       rc = backsql_Prepare( dbh, &sth, si->oc_query, 0 );
        if ( rc != SQL_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
                        "error preparing oc_query: \"%s\"\n", 
                        si->oc_query, 0, 0 );
-               backsql_PrintErrors( si->db_env, dbh, oc_sth, rc );
-               return LDAP_OTHER;
-       }
-       Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): at_query \"%s\"\n", 
-                       si->at_query, 0, 0 );
-
-       rc = backsql_Prepare( dbh, &at_sth, si->at_query, 0 );
-       if ( rc != SQL_SUCCESS ) {
-               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
-                       "error preparing at_query: \"%s\"\n", 
-                       si->at_query, 0, 0 );
-               backsql_PrintErrors( si->db_env, dbh, at_sth, rc );
+               backsql_PrintErrors( si->db_env, dbh, sth, rc );
                return LDAP_OTHER;
        }
 
-       rc = backsql_BindParamID( at_sth, 1, &oc_id );
-       if ( rc != SQL_SUCCESS ) {
-               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
-                       "error binding param for at_query: \n", 0, 0, 0 );
-               backsql_PrintErrors( si->db_env, dbh, at_sth, rc );
-               return LDAP_OTHER;
-       }
-
-       rc = SQLExecute( oc_sth );
+       rc = SQLExecute( sth );
        if ( rc != SQL_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
                        "error executing oc_query: \n", 0, 0, 0 );
-               backsql_PrintErrors( si->db_env, dbh, oc_sth, rc );
+               backsql_PrintErrors( si->db_env, dbh, sth, rc );
                return LDAP_OTHER;
        }
 
-       backsql_BindRowAsStrings( oc_sth, &oc_row );
-       rc = SQLFetch( oc_sth );
-       for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( oc_sth ) ) {
+       backsql_BindRowAsStrings( sth, &oc_row );
+       rc = SQLFetch( sth );
+       for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
                int     colnum;
 
                oc_map = (backsql_oc_map_rec *)ch_calloc( 1,
@@ -347,119 +615,48 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                        "add=%d, del=%d; attributes:\n",
                        BACKSQL_IS_ADD( oc_map->bom_expect_return ), 
                        BACKSQL_IS_DEL( oc_map->bom_expect_return ), 0 );
+       }
 
-               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
-                       "autoadding 'objectClass' and 'ref' mappings\n",
-                       0, 0, 0 );
-               backsql_add_sysmaps( oc_map );
-               rc = SQLExecute( at_sth );
-               if ( rc != SQL_SUCCESS ) {
-                       Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
-                               "error executing at_query: \n", 0, 0, 0 );
-                       backsql_PrintErrors( SQL_NULL_HENV, dbh, at_sth, rc );
-                       return LDAP_OTHER;
-               }
+       backsql_FreeRow( &oc_row );
+       SQLFreeStmt( sth, SQL_DROP );
 
-               backsql_BindRowAsStrings( at_sth, &at_row );
-               rc = SQLFetch( at_sth );
-               for ( ; BACKSQL_SUCCESS(rc); rc = SQLFetch( at_sth ) ) {
-                       const char      *text = NULL;
-                       struct berval   bv;
-                       struct berbuf   bb = BB_NULL;
+       /* prepare for attribute fetching */
+       Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): at_query \"%s\"\n", 
+                       si->at_query, 0, 0 );
 
-                       Debug( LDAP_DEBUG_TRACE, 
-                               "attributeType:\n"
-                               "\tname=\"%s\"\n"
-                               "\tsel_expr=\"%s\"\n"
-                               "\tfrom=\"%s\"\n",
-                               at_row.cols[ 0 ], at_row.cols[ 1 ],
-                               at_row.cols[ 2 ] );
-                       Debug( LDAP_DEBUG_TRACE, 
-                               "\tjoin_where=\"%s\"\n"
-                               "\tadd_proc=\"%s\"\n"
-                               "\tdelete_proc=\"%s\"\n",
-                               at_row.cols[ 3 ], at_row.cols[ 4 ],
-                               at_row.cols[ 5 ]);
-                       /* TimesTen */
-                       Debug( LDAP_DEBUG_TRACE, "\tsel_expr_u=\"%s\"\n",
-                                       at_row.cols[ 8 ], 0, 0 );
-                       at_map = (backsql_at_map_rec *)ch_calloc( 1,
-                                       sizeof( backsql_at_map_rec ) );
-                       rc = slap_str2ad( at_row.cols[ 0 ], 
-                                       &at_map->bam_ad, &text );
-                       if ( rc != LDAP_SUCCESS ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
-                                       "attribute \"%s\" for objectClass \"%s\" "
-                                       "is not defined in schema: %s\n", 
-                                       at_row.cols[ 0 ],
-                                       BACKSQL_OC_NAME( oc_map ), text );
-                               return LDAP_CONSTRAINT_VIOLATION;
-                       }
+       rc = backsql_Prepare( dbh, &sth, si->at_query, 0 );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
+                       "error preparing at_query: \"%s\"\n", 
+                       si->at_query, 0, 0 );
+               backsql_PrintErrors( si->db_env, dbh, sth, rc );
+               return LDAP_OTHER;
+       }
 
-                       ber_str2bv( at_row.cols[ 1 ], 0, 1, &at_map->bam_sel_expr );
-                       if ( at_row.value_len[ 8 ] < 0 ) {
-                               at_map->bam_sel_expr_u.bv_val = NULL;
-                               at_map->bam_sel_expr_u.bv_len = 0;
-                       } else {
-                               ber_str2bv( at_row.cols[ 8 ], 0, 1, 
-                                               &at_map->bam_sel_expr_u );
-                       }
+       rc = backsql_BindParamID( sth, 1, &oc_id );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
+                       "error binding param \"oc_id\" for at_query\n", 0, 0, 0 );
+               backsql_PrintErrors( si->db_env, dbh, sth, rc );
+               return LDAP_OTHER;
+       }
 
-                       ber_str2bv( at_row.cols[ 2 ], 0, 0, &bv );
-                       backsql_merge_from_clause( &bb, &bv );
-                       at_map->bam_from_tbls = bb.bb_val;
-                       if ( at_row.value_len[ 3 ] < 0 ) {
-                               at_map->bam_join_where.bv_val = NULL;
-                               at_map->bam_join_where.bv_len = 0;
-                       } else {
-                               ber_str2bv( at_row.cols[ 3 ], 0, 1, 
-                                               &at_map->bam_join_where );
-                       }
-                       at_map->bam_add_proc = NULL;
-                       if ( at_row.value_len[ 4 ] > 0 ) {
-                               at_map->bam_add_proc = ch_strdup( at_row.cols[4] );
-                       }
-                       at_map->bam_delete_proc = NULL;
-                       if ( at_row.value_len[ 5 ] > 0 ) {
-                               at_map->bam_delete_proc = ch_strdup( at_row.cols[ 5 ] );
-                       }
-                       at_map->bam_param_order = strtol( at_row.cols[ 6 ], 
-                                       NULL, 0 );
-                       at_map->bam_expect_return = strtol( at_row.cols[ 7 ],
-                                       NULL, 0 );
-                       backsql_make_attr_query( oc_map, at_map );
-                       Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
-                               "preconstructed query \"%s\"\n",
-                               at_map->bam_query, 0, 0 );
-                       at_map->bam_next = NULL;
-                       if ( avl_insert( &oc_map->bom_attrs, at_map, backsql_cmp_attr, backsql_dup_attr ) == BACKSQL_DUPLICATE ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_load_schema_map(): "
-                                               "duplicate attribute \"%s\" "
-                                               "in objectClass \"%s\" map\n",
-                                               at_map->bam_ad->ad_cname.bv_val,
-                                               oc_map->bom_oc->soc_cname.bv_val, 0 );
-                       }
+       bas.bas_si = si;
+       bas.bas_dbh = dbh;
+       bas.bas_sth = sth;
+       bas.bas_oc_id = &oc_id;
+       bas.bas_rc = LDAP_SUCCESS;
 
-                       if ( si->upper_func.bv_val && at_map->bam_sel_expr_u.bv_val == NULL ) {
-                               struct berbuf   bb = BB_NULL;
+       (void)avl_apply( si->oc_by_oc, backsql_oc_get_attr_mapping,
+                       &bas, BACKSQL_AVL_STOP, AVL_INORDER );
+
+       SQLFreeStmt( sth, SQL_DROP );
 
-                               backsql_strfcat( &bb, "bcbc",
-                                               &si->upper_func,
-                                               '(' /* ) */ ,
-                                               &at_map->bam_sel_expr,
-                                               /* ( */ ')' );
-                               at_map->bam_sel_expr_u = bb.bb_val;
-                       }
-               }
-               backsql_FreeRow( &at_row );
-               SQLFreeStmt( at_sth, SQL_CLOSE );
-       }
-       backsql_FreeRow( &oc_row );
-       SQLFreeStmt( at_sth, SQL_DROP );
-       SQLFreeStmt( oc_sth, SQL_DROP );
        si->bsql_flags |= BSQLF_SCHEMA_LOADED;
+
        Debug( LDAP_DEBUG_TRACE, "<==backsql_load_schema_map()\n", 0, 0, 0 );
-       return LDAP_SUCCESS;
+
+       return bas.bas_rc;
 }
 
 backsql_oc_map_rec *
@@ -667,10 +864,10 @@ backsql_free_attr( void *v_at )
        Debug( LDAP_DEBUG_TRACE, "==>free_attr(): \"%s\"\n", 
                        at->bam_ad->ad_cname.bv_val, 0, 0 );
        ch_free( at->bam_sel_expr.bv_val );
-       if ( at->bam_from_tbls.bv_val != NULL ) {
+       if ( !BER_BVISNULL( &at->bam_from_tbls ) ) {
                ch_free( at->bam_from_tbls.bv_val );
        }
-       if ( at->bam_join_where.bv_val != NULL ) {
+       if ( !BER_BVISNULL( &at->bam_join_where ) ) {
                ch_free( at->bam_join_where.bv_val );
        }
        if ( at->bam_add_proc != NULL ) {
@@ -684,7 +881,7 @@ backsql_free_attr( void *v_at )
        }
 
        /* TimesTen */
-       if ( at->bam_sel_expr_u.bv_val ) {
+       if ( !BER_BVISNULL( &at->bam_sel_expr_u ) ) {
                ch_free( at->bam_sel_expr_u.bv_val );
        }
 
index c4a74dedb00d934908b5d81dcb1d3d4441b87c6a..31fac986cac4fceefacb1ca72736eabe4dd95324 100644 (file)
 #include <stdio.h>
 #include <sys/types.h>
 #include "ac/string.h"
+#include "ac/ctype.h"
 
 #include "slap.h"
 #include "lber_pvt.h"
 #include "ldap_pvt.h"
 #include "proto-sql.h"
 
-#define BACKSQL_STOP           0
-#define BACKSQL_CONTINUE       1
-
 static int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
 static int backsql_process_filter_eq( backsql_srch_info *bsi, 
                backsql_at_map_rec *at,
@@ -63,7 +61,7 @@ backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
                return 1;
        }
 
-       for ( ; bsi->bsi_attrs[ n_attrs ].an_name.bv_val; n_attrs++ ) {
+       for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) {
                an = &bsi->bsi_attrs[ n_attrs ];
                
                Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
@@ -89,8 +87,7 @@ backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
 
        an[ n_attrs ].an_name = ad->ad_cname;
        an[ n_attrs ].an_desc = ad;
-       an[ n_attrs + 1 ].an_name.bv_val = NULL;
-       an[ n_attrs + 1 ].an_name.bv_len = 0;
+       BER_BVZERO( &an[ n_attrs + 1 ].an_name );
 
        bsi->bsi_attrs = an;
        
@@ -130,12 +127,13 @@ backsql_init_search(
                bsi->bsi_attrs = NULL;
 
        } else {
+               int     is_oc = 0;
+
                bsi->bsi_attrs = (AttributeName *)ch_calloc( 1, 
                                sizeof( AttributeName ) );
-               bsi->bsi_attrs[ 0 ].an_name.bv_val = NULL;
-               bsi->bsi_attrs[ 0 ].an_name.bv_len = 0;
+               BER_BVZERO( &bsi->bsi_attrs[ 0 ].an_name );
                
-               for ( p = attrs; p->an_name.bv_val; p++ ) {
+               for ( p = attrs; !BER_BVISNULL( &p->an_name ); p++ ) {
                        /*
                         * ignore "1.1"; handle "+"
                         */
@@ -145,27 +143,35 @@ backsql_init_search(
 
                        } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
                                continue;
+
+                       } else if ( p->an_desc == slap_schema.si_ad_objectClass ) {
+                               is_oc = 1;
                        }
 
                        backsql_attrlist_add( bsi, p->an_desc );
                }
+
+               if ( is_oc == 0 ) {
+                       /* add objectClass if not present,
+                        * because it is required to understand
+                        * if an entry is a referral, an alias 
+                        * or so... */
+                       backsql_attrlist_add( bsi, slap_schema.si_ad_objectClass );
+               }
        }
 
        bsi->bsi_abandon = 0;
        bsi->bsi_id_list = NULL;
+       bsi->bsi_id_listtail = &bsi->bsi_id_list;
        bsi->bsi_n_candidates = 0;
        bsi->bsi_stoptime = stoptime;
-       bsi->bsi_sel.bb_val.bv_val = NULL;
-       bsi->bsi_sel.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_sel.bb_val );
        bsi->bsi_sel.bb_len = 0;
-       bsi->bsi_from.bb_val.bv_val = NULL;
-       bsi->bsi_from.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_from.bb_val );
        bsi->bsi_from.bb_len = 0;
-       bsi->bsi_join_where.bb_val.bv_val = NULL;
-       bsi->bsi_join_where.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_join_where.bb_val );
        bsi->bsi_join_where.bb_len = 0;
-       bsi->bsi_flt_where.bb_val.bv_val = NULL;
-       bsi->bsi_flt_where.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_flt_where.bb_val );
        bsi->bsi_flt_where.bb_len = 0;
        bsi->bsi_filter_oc = NULL;
 
@@ -201,13 +207,13 @@ backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
                switch ( op ) {
                case LDAP_FILTER_AND:
                        backsql_strfcat( &bsi->bsi_flt_where, "l",
-                                       (ber_len_t)sizeof( " AND " ) - 1
+                                       (ber_len_t)STRLENOF( " AND " )
                                                " AND " );
                        break;
 
                case LDAP_FILTER_OR:
                        backsql_strfcat( &bsi->bsi_flt_where, "l",
-                                       (ber_len_t)sizeof( " OR " ) - 1,
+                                       (ber_len_t)STRLENOF( " OR " ),
                                                " OR " );
                        break;
                }
@@ -254,7 +260,7 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
                 * val LIKE '%1%2%3%4%'
                 */
 
-               bv.bv_len = 0;
+               BER_BVZERO( &bv );
                if ( f->f_sub_initial.bv_val ) {
                        bv.bv_len += f->f_sub_initial.bv_len;
                }
@@ -270,7 +276,7 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
                bv.bv_val = ch_malloc( bv.bv_len + 1 );
 
                s = 0;
-               if ( f->f_sub_initial.bv_val ) {
+               if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
                        bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ];
                        for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) {
                                bv.bv_val[ s + 2 * i - 1 ] = '%';
@@ -281,7 +287,7 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
                }
 
                if ( f->f_sub_any != NULL ) {
-                       for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) {
+                       for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
                                bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ];
                                for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) {
                                        bv.bv_val[ s + 2 * i - 1 ] = '%';
@@ -292,7 +298,7 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
                        }
                }
 
-               if ( f->f_sub_final.bv_val ) {
+               if ( !BER_BVISNULL( &f->f_sub_final ) ) {
                        bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ];
                        for ( i = 1; i < f->f_sub_final.bv_len; i++ ) {
                                bv.bv_val[ s + 2 * i - 1 ] = '%';
@@ -332,16 +338,16 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
                backsql_strfcat( &bsi->bsi_flt_where, 
                                "bl",
                                &at->bam_sel_expr_u,
-                               (ber_len_t)sizeof( " LIKE '" ) - 1,
+                               (ber_len_t)STRLENOF( " LIKE '" ),
                                        " LIKE '" );
 
        } else {
                backsql_strfcat( &bsi->bsi_flt_where, "bl",
                                &at->bam_sel_expr,
-                               (ber_len_t)sizeof( " LIKE '" ) - 1, " LIKE '" );
+                               (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
        }
  
-       if ( f->f_sub_initial.bv_val != NULL ) {
+       if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
                ber_len_t       start;
 
 #ifdef BACKSQL_TRACE
@@ -362,7 +368,7 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
        backsql_strfcat( &bsi->bsi_flt_where, "c", '%' );
 
        if ( f->f_sub_any != NULL ) {
-               for ( i = 0; f->f_sub_any[ i ].bv_val != NULL; i++ ) {
+               for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) {
                        ber_len_t       start;
 
 #ifdef BACKSQL_TRACE
@@ -386,7 +392,7 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
                }
        }
 
-       if ( f->f_sub_final.bv_val != NULL ) {
+       if ( !BER_BVISNULL( &f->f_sub_final ) ) {
                ber_len_t       start;
 
 #ifdef BACKSQL_TRACE
@@ -405,11 +411,55 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
        }
 
        backsql_strfcat( &bsi->bsi_flt_where, "l", 
-                       (ber_len_t)sizeof( /* (' */ "')" ) - 1, /* ( */ "')" );
+                       (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" );
  
        return 1;
 }
 
+static int
+backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls )
+{
+       if ( BER_BVISNULL( from_tbls ) ) {
+               return LDAP_SUCCESS;
+       }
+
+       if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) {
+               char    *start, *end, *tmp;
+
+               tmp = ch_strdup( from_tbls->bv_val );
+
+               for ( start = tmp, end = strchr( start, ',' ); start; ) {
+                       if ( end ) {
+                               end[0] = '\0';
+                       }
+
+                       if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL )
+                       {
+                               backsql_strfcat( &bsi->bsi_from, "cs", ',', start );
+                       }
+
+                       if ( end ) {
+                               /* in case there are spaces after the comma... */
+                               for ( start = &end[1]; isspace( start[0] ); start++ );
+                               if ( start[0] ) {
+                                       end = strchr( start, ',' );
+                               } else {
+                                       start = NULL;
+                               }
+                       } else {
+                               start = NULL;
+                       }
+               }
+
+               ch_free( tmp );
+
+       } else {
+               backsql_strfcat( &bsi->bsi_from, "b", from_tbls );
+       }
+
+       return LDAP_SUCCESS;
+}
+
 static int
 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
 {
@@ -442,7 +492,7 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
 
        case LDAP_FILTER_NOT:
                backsql_strfcat( &bsi->bsi_flt_where, "l",
-                               (ber_len_t)sizeof( "NOT (" /* ) */ ) - 1,
+                               (ber_len_t)STRLENOF( "NOT (" /* ) */ ),
                                        "NOT (" /* ) */ );
                rc = backsql_process_filter( bsi, f->f_not );
                backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' );
@@ -465,7 +515,7 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                         * like '%attributeName=value%'"
                         */
                        backsql_strfcat( &bsi->bsi_flt_where, "l",
-                                       (ber_len_t)sizeof( "1=1" ) - 1, "1=1" );
+                                       (ber_len_t)STRLENOF( "1=1" ), "1=1" );
                        bsi->bsi_status = LDAP_SUCCESS;
                        rc = 1;
                        goto done;
@@ -519,19 +569,32 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                         * - a search for "top" will return everything
                         */
                        if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
-                               goto filter_oc_success;
+                               static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" );
+
+                               backsql_merge_from_tbls( bsi, &ldap_entry_objclasses );
+
+                               backsql_strfcat( &bsi->bsi_flt_where, "lbl",
+                                               (ber_len_t)STRLENOF( "1=1 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
+                                                       "1=1 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
+                                               &bsi->bsi_oc->bom_oc->soc_cname,
+                                               (ber_len_t)STRLENOF( /* (' */ "')" ),
+                                                       /* (' */ "')" );
+                               bsi->bsi_status = LDAP_SUCCESS;
+                               rc = 1;
+                               goto done;
                        }
 
                        break;
                }
 
                case LDAP_FILTER_PRESENT:
-filter_oc_success:;
                        backsql_strfcat( &bsi->bsi_flt_where, "l",
-                                       (ber_len_t)sizeof( "1=1" ) - 1, "1=1" );
+                                       (ber_len_t)STRLENOF( "1=1" ), "1=1" );
                        bsi->bsi_status = LDAP_SUCCESS;
                        rc = 1;
                        goto done;
+
+                       /* FIXME: LDAP_FILTER_EXT? */
                        
                default:
                        Debug( LDAP_DEBUG_TRACE,
@@ -560,7 +623,7 @@ filter_oc_success:;
                 * candidate.
                 */
                backsql_strfcat( &bsi->bsi_flt_where, "l",
-                               (ber_len_t)sizeof( "1=1" ) - 1, "1=1" );
+                               (ber_len_t)STRLENOF( "1=1" ), "1=1" );
                if ( ad == slap_schema.si_ad_hasSubordinates ) {
                        /*
                         * instruct candidate selection algorithm
@@ -593,7 +656,7 @@ filter_oc_success:;
                /* search anyway; other parts of the filter
                 * may succeeed */
                backsql_strfcat( &bsi->bsi_flt_where, "l",
-                               (ber_len_t)sizeof( "1=1" ) - 1, "1=1" );
+                               (ber_len_t)STRLENOF( "1=1" ), "1=1" );
                bsi->bsi_status = LDAP_SUCCESS;
                rc = 1;
                goto done;
@@ -616,7 +679,7 @@ next:;
        /* if more definitions of the same attr, apply */
        if ( vat[i]->bam_next ) {
                backsql_strfcat( &bsi->bsi_flt_where, "l",
-                       sizeof( " OR " ) - 1, " OR " );
+                       STRLENOF( " OR " ), " OR " );
                vat[i] = vat[i]->bam_next;
                goto next;
        }
@@ -625,7 +688,7 @@ next:;
        i++;
        if ( vat[i] ) {
                backsql_strfcat( &bsi->bsi_flt_where, "l",
-                       sizeof( " OR " ) - 1, " OR " );
+                       STRLENOF( " OR " ), " OR " );
                goto next;
        }
 
@@ -664,14 +727,14 @@ backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at,
                backsql_strfcat( &bsi->bsi_flt_where, "cbl",
                                '(', /* ) */
                                &at->bam_sel_expr_u, 
-                               (ber_len_t)sizeof( "='" ) - 1,
+                               (ber_len_t)STRLENOF( "='" ),
                                        "='" );
 
                start = bsi->bsi_flt_where.bb_val.bv_len;
 
                backsql_strfcat( &bsi->bsi_flt_where, "bl",
                                filter_value, 
-                               (ber_len_t)sizeof( /* (' */ "')" ) - 1,
+                               (ber_len_t)STRLENOF( /* (' */ "')" ),
                                        /* (' */ "')" );
 
                ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
@@ -680,9 +743,9 @@ backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at,
                backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
                                '(', /* ) */
                                &at->bam_sel_expr,
-                               (ber_len_t)sizeof( "='" ) - 1, "='",
+                               (ber_len_t)STRLENOF( "='" ), "='",
                                filter_value,
-                               (ber_len_t)sizeof( /* (' */ "')" ) - 1,
+                               (ber_len_t)STRLENOF( /* (' */ "')" ),
                                        /* (' */ "')" );
        }
 
@@ -705,14 +768,14 @@ backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at,
                backsql_strfcat( &bsi->bsi_flt_where, "cbl",
                                '(', /* ) */
                                &at->bam_sel_expr_u, 
-                               (ber_len_t)sizeof( " LIKE '%" ) - 1,
+                               (ber_len_t)STRLENOF( " LIKE '%" ),
                                        " LIKE '%" );
 
                start = bsi->bsi_flt_where.bb_val.bv_len;
 
                backsql_strfcat( &bsi->bsi_flt_where, "bl",
                                filter_value, 
-                               (ber_len_t)sizeof( /* (' */ "%')" ) - 1,
+                               (ber_len_t)STRLENOF( /* (' */ "%')" ),
                                        /* (' */ "%')" );
 
                ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
@@ -721,10 +784,10 @@ backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at,
                backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
                                '(', /* ) */
                                &at->bam_sel_expr,
-                               (ber_len_t)sizeof( " LIKE '%" ) - 1,
+                               (ber_len_t)STRLENOF( " LIKE '%" ),
                                        " LIKE '%",
                                filter_value,
-                               (ber_len_t)sizeof( /* (' */ "%')" ) - 1,
+                               (ber_len_t)STRLENOF( /* (' */ "%')" ),
                                        /* (' */ "%')" );
        }
 
@@ -743,18 +806,20 @@ backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_r
        Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n",
                at->bam_ad->ad_cname.bv_val, 0, 0 );
 
-       backsql_merge_from_clause( &bsi->bsi_from, &at->bam_from_tbls );
-
        /*
         * need to add this attribute to list of attrs to load,
         * so that we can do test_filter() later
         */
        backsql_attrlist_add( bsi, at->bam_ad );
 
-       if ( at->bam_join_where.bv_val != NULL 
-                       && strstr( bsi->bsi_join_where.bb_val.bv_val, at->bam_join_where.bv_val ) == NULL ) {
+       backsql_merge_from_tbls( bsi, &at->bam_from_tbls );
+
+       if ( !BER_BVISNULL( &at->bam_join_where )
+                       && strstr( bsi->bsi_join_where.bb_val.bv_val,
+                               at->bam_join_where.bv_val ) == NULL )
+       {
                backsql_strfcat( &bsi->bsi_join_where, "lb",
-                               (ber_len_t)sizeof( " AND " ) - 1, " AND ",
+                               (ber_len_t)STRLENOF( " AND " ), " AND ",
                                &at->bam_join_where );
        }
 
@@ -811,6 +876,23 @@ equality_match:;
                        break;
                }
 
+               /* NOTE: this is required by objectClass inheritance 
+                * and auxiliary objectClass use in filters for slightly
+                * more efficient candidate selection. */
+               /* FIXME: a bit too many specializations to deal with
+                * very specific cases... */
+               if ( at->bam_ad == slap_schema.si_ad_objectClass
+                               || at->bam_ad == slap_schema.si_ad_structuralObjectClass )
+               {
+                       backsql_strfcat( &bsi->bsi_flt_where, "lbl",
+                                       (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
+                                               "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
+                                       filter_value,
+                                       (ber_len_t)STRLENOF( /* (' */ "')" ),
+                                               /* (' */ "')" );
+                       break;
+               }
+
                /*
                 * maybe we should check type of at->sel_expr here somehow,
                 * to know whether upper_func is applicable, but for now
@@ -851,7 +933,7 @@ equality_match:;
 
                        backsql_strfcat( &bsi->bsi_flt_where, "bl",
                                        filter_value, 
-                                       (ber_len_t)sizeof( /* (' */ "')" ) - 1,
+                                       (ber_len_t)STRLENOF( /* (' */ "')" ),
                                                /* (' */ "')" );
 
                        ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
@@ -863,17 +945,17 @@ equality_match:;
                                        &ordering,
                                        '\'',
                                        &f->f_av_value,
-                                       (ber_len_t)sizeof( /* (' */ "')" ) - 1,
+                                       (ber_len_t)STRLENOF( /* (' */ "')" ),
                                                /* ( */ "')" );
                }
                break;
 
        case LDAP_FILTER_PRESENT:
                backsql_strfcat( &bsi->bsi_flt_where, "lbl",
-                               (ber_len_t)sizeof( "NOT (" /* ) */) - 1,
+                               (ber_len_t)STRLENOF( "NOT (" /* ) */),
                                        "NOT (", /* ) */
                                &at->bam_sel_expr, 
-                               (ber_len_t)sizeof( /* ( */ " IS NULL)" ) - 1,
+                               (ber_len_t)STRLENOF( /* ( */ " IS NULL)" ),
                                        /* ( */ " IS NULL)" );
                break;
 
@@ -897,7 +979,7 @@ equality_match:;
                /* unhandled filter type; should not happen */
                assert( 0 );
                backsql_strfcat( &bsi->bsi_flt_where, "l",
-                               (ber_len_t)sizeof( "1=1" ) - 1, "1=1" );
+                               (ber_len_t)STRLENOF( "1=1" ), "1=1" );
                break;
 
        }
@@ -915,38 +997,34 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
        int             rc;
 
        assert( query );
-       query->bv_val = NULL;
-       query->bv_len = 0;
+       BER_BVZERO( query );
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n", 0, 0, 0 );
-       bsi->bsi_sel.bb_val.bv_val = NULL;
-       bsi->bsi_sel.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_sel.bb_val );
+       BER_BVZERO( &bsi->bsi_sel.bb_val );
        bsi->bsi_sel.bb_len = 0;
-       bsi->bsi_from.bb_val.bv_val = NULL;
-       bsi->bsi_from.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_from.bb_val );
        bsi->bsi_from.bb_len = 0;
-       bsi->bsi_join_where.bb_val.bv_val = NULL;
-       bsi->bsi_join_where.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_join_where.bb_val );
        bsi->bsi_join_where.bb_len = 0;
-       bsi->bsi_flt_where.bb_val.bv_val = NULL;
-       bsi->bsi_flt_where.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_flt_where.bb_val );
        bsi->bsi_flt_where.bb_len = 0;
 
        backsql_strfcat( &bsi->bsi_sel, "lbcbc",
-                       (ber_len_t)sizeof( "SELECT DISTINCT ldap_entries.id," ) - 1,
+                       (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ),
                                "SELECT DISTINCT ldap_entries.id,", 
                        &bsi->bsi_oc->bom_keytbl, 
                        '.', 
                        &bsi->bsi_oc->bom_keycol, 
                        ',' );
 
-       if ( bi->strcast_func.bv_val ) {
+       if ( !BER_BVISNULL( &bi->strcast_func ) ) {
                backsql_strfcat( &bsi->bsi_sel, "blbl",
                                &bi->strcast_func, 
-                               (ber_len_t)sizeof( "('" /* ') */ ) - 1,
+                               (ber_len_t)STRLENOF( "('" /* ') */ ),
                                        "('" /* ') */ ,
                                &bsi->bsi_oc->bom_oc->soc_cname,
-                               (ber_len_t)sizeof( /* (' */ "')" ) - 1,
+                               (ber_len_t)STRLENOF( /* (' */ "')" ),
                                        /* (' */ "')" );
        } else {
                backsql_strfcat( &bsi->bsi_sel, "cbc",
@@ -954,21 +1032,33 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
                                &bsi->bsi_oc->bom_oc->soc_cname,
                                '\'' );
        }
+#ifdef BACKSQL_ALIASING_QUOTE
+       backsql_strfcat( &bsi->bsi_sel, "lclcl",
+                       (ber_len_t)STRLENOF( " " BACKSQL_ALIASING ),
+                               " " BACKSQL_ALIASING,
+                       BACKSQL_ALIASING_QUOTE,
+                       (ber_len_t)STRLENOF( "objectClass" ),
+                               "objectClass",
+                       BACKSQL_ALIASING_QUOTE,
+                       (ber_len_t)STRLENOF( ",ldap_entries.dn " BACKSQL_ALIASING "dn" ),
+                               ",ldap_entries.dn " BACKSQL_ALIASING "dn" );
+#else /* ! BACKSQL_ALIASING_QUOTE */
        backsql_strfcat( &bsi->bsi_sel, "l",
-                       (ber_len_t)sizeof( " AS objectClass,ldap_entries.dn AS dn" ) - 1,
-                       " AS objectClass,ldap_entries.dn AS dn" );
+                       (ber_len_t)STRLENOF( " " BACKSQL_ALIASING "objectClass,ldap_entries.dn " BACKSQL_ALIASING "dn" ),
+                               " " BACKSQL_ALIASING "objectClass,ldap_entries.dn " BACKSQL_ALIASING "dn" );
+#endif /* ! BACKSQL_ALIASING_QUOTE */
 
        backsql_strfcat( &bsi->bsi_from, "lb",
-                       (ber_len_t)sizeof( " FROM ldap_entries," ) - 1,
+                       (ber_len_t)STRLENOF( " FROM ldap_entries," ),
                                " FROM ldap_entries,",
                        &bsi->bsi_oc->bom_keytbl );
 
        backsql_strfcat( &bsi->bsi_join_where, "lbcbl",
-                       (ber_len_t)sizeof( " WHERE " ) - 1, " WHERE ",
+                       (ber_len_t)STRLENOF( " WHERE " ), " WHERE ",
                        &bsi->bsi_oc->bom_keytbl,
                        '.',
                        &bsi->bsi_oc->bom_keycol,
-                       (ber_len_t)sizeof( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ) - 1,
+                       (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ),
                                "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
 
        switch ( bsi->bsi_scope ) {
@@ -976,11 +1066,11 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
                if ( BACKSQL_CANUPPERCASE( bi ) ) {
                        backsql_strfcat( &bsi->bsi_join_where, "bl",
                                        &bi->upper_func,
-                                       (ber_len_t)sizeof( "(ldap_entries.dn)=?" ) - 1,
+                                       (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ),
                                                "(ldap_entries.dn)=?" );
                } else {
                        backsql_strfcat( &bsi->bsi_join_where, "l",
-                                       (ber_len_t)sizeof( "ldap_entries.dn=?" ) - 1,
+                                       (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
                                                "ldap_entries.dn=?" );
                }
                break;
@@ -989,18 +1079,18 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
                if ( BACKSQL_CANUPPERCASE( bi ) ) {
                        backsql_strfcat( &bsi->bsi_join_where, "bl",
                                        &bi->upper_func,
-                                       (ber_len_t)sizeof( "(ldap_entries.dn) LIKE ?" ) - 1,
+                                       (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
                                                "(ldap_entries.dn) LIKE ?" );
                } else {
                        backsql_strfcat( &bsi->bsi_join_where, "l",
-                                       (ber_len_t)sizeof( "ldap_entries.dn LIKE ?" ) - 1,
+                                       (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
                                                "ldap_entries.dn LIKE ?" );
                }
                break;
                
        case LDAP_SCOPE_ONELEVEL:
                backsql_strfcat( &bsi->bsi_join_where, "l",
-                               (ber_len_t)sizeof( "ldap_entries.parent=?" ) - 1,
+                               (ber_len_t)STRLENOF( "ldap_entries.parent=?" ),
                                        "ldap_entries.parent=?" );
                break;
 
@@ -1008,11 +1098,11 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
                if ( BACKSQL_CANUPPERCASE( bi ) ) {
                        backsql_strfcat( &bsi->bsi_join_where, "bl",
                                        &bi->upper_func,
-                                       (ber_len_t)sizeof( "(ldap_entries.dn) LIKE ?" ) - 1,
+                                       (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
                                                "(ldap_entries.dn) LIKE ?"  );
                } else {
                        backsql_strfcat( &bsi->bsi_join_where, "l",
-                                       (ber_len_t)sizeof( "ldap_entries.dn LIKE ?" ) - 1,
+                                       (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
                                                "ldap_entries.dn LIKE ?" );
                }
 
@@ -1030,7 +1120,7 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
                                &bsi->bsi_sel.bb_val,
                                &bsi->bsi_from.bb_val, 
                                &bsi->bsi_join_where.bb_val,
-                               (ber_len_t)sizeof( " AND " ) - 1, " AND ",
+                               (ber_len_t)STRLENOF( " AND " ), " AND ",
                                &bsi->bsi_flt_where.bb_val );
 
                *query = bb.bb_val;
@@ -1041,20 +1131,20 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
                 * anything.  No need to issue the query
                 */
                free( query->bv_val );
-               query->bv_val = NULL;
+               BER_BVZERO( query );
        }
  
        free( bsi->bsi_sel.bb_val.bv_val );
-       bsi->bsi_sel.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_sel.bb_val );
        bsi->bsi_sel.bb_len = 0;
        free( bsi->bsi_from.bb_val.bv_val );
-       bsi->bsi_from.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_from.bb_val );
        bsi->bsi_from.bb_len = 0;
        free( bsi->bsi_join_where.bb_val.bv_val );
-       bsi->bsi_join_where.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_join_where.bb_val );
        bsi->bsi_join_where.bb_len = 0;
        free( bsi->bsi_flt_where.bb_val.bv_val );
-       bsi->bsi_flt_where.bb_val.bv_len = 0;
+       BER_BVZERO( &bsi->bsi_flt_where.bb_val );
        bsi->bsi_flt_where.bb_len = 0;
        
        Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n",
@@ -1097,7 +1187,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                /* should never get here */
                assert( 0 );
                bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED;
-               return BACKSQL_STOP;
+               return BACKSQL_AVL_STOP;
        }
        
        bsi->bsi_oc = oc;
@@ -1118,21 +1208,21 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                default:
                        bsi->bsi_status = LDAP_SUCCESS;
                        /* try next */
-                       return BACKSQL_CONTINUE;
+                       return BACKSQL_AVL_CONTINUE;
 
                case LDAP_ADMINLIMIT_EXCEEDED:
                case LDAP_OTHER:
                        /* don't try any more */
-                       return BACKSQL_STOP;
+                       return BACKSQL_AVL_STOP;
                }
        }
 
-       if ( query.bv_val == NULL ) {
+       if ( BER_BVISNULL( &query ) ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
                        "could not construct query for objectclass \"%s\"\n",
                        oc->bom_oc->soc_cname.bv_val, 0, 0 );
                bsi->bsi_status = LDAP_SUCCESS;
-               return BACKSQL_CONTINUE;
+               return BACKSQL_AVL_CONTINUE;
        }
 
        Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n", 
@@ -1140,12 +1230,13 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
 
        rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 );
        free( query.bv_val );
+       BER_BVZERO( &query );
        if ( rc != SQL_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
                        "error preparing query\n", 0, 0, 0 );
                backsql_PrintErrors( bi->db_env, bsi->bsi_dbh, sth, rc );
                bsi->bsi_status = LDAP_OTHER;
-               return BACKSQL_CONTINUE;
+               return BACKSQL_AVL_CONTINUE;
        }
        
        Debug( LDAP_DEBUG_TRACE, "id: '%ld'\n", bsi->bsi_oc->bom_id, 0, 0 );
@@ -1154,7 +1245,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
                        "error binding objectclass id parameter\n", 0, 0, 0 );
                bsi->bsi_status = LDAP_OTHER;
-               return BACKSQL_CONTINUE;
+               return BACKSQL_AVL_CONTINUE;
        }
 
        switch ( bsi->bsi_scope ) {
@@ -1166,7 +1257,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                 */
                if ( bsi->bsi_base_dn->bv_len > BACKSQL_MAX_DN_LEN ) {
                        bsi->bsi_status = LDAP_OTHER;
-                       return BACKSQL_CONTINUE;
+                       return BACKSQL_AVL_CONTINUE;
                }
 
                AC_MEMCPY( temp_base_dn, bsi->bsi_base_dn->bv_val,
@@ -1189,7 +1280,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                        backsql_PrintErrors( bi->db_env, bsi->bsi_dbh, 
                                        sth, rc );
                        bsi->bsi_status = LDAP_OTHER;
-                       return BACKSQL_CONTINUE;
+                       return BACKSQL_AVL_CONTINUE;
                }
                break;
 
@@ -1200,7 +1291,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                 */
                if ( bsi->bsi_base_dn->bv_len > BACKSQL_MAX_DN_LEN ) {
                        bsi->bsi_status = LDAP_OTHER;
-                       return BACKSQL_CONTINUE;
+                       return BACKSQL_AVL_CONTINUE;
                }
 
                /* 
@@ -1249,7 +1340,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                        backsql_PrintErrors( bi->db_env, bsi->bsi_dbh, 
                                        sth, rc );
                        bsi->bsi_status = LDAP_OTHER;
-                       return BACKSQL_CONTINUE;
+                       return BACKSQL_AVL_CONTINUE;
                }
                break;
        }
@@ -1263,7 +1354,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                                res == LDAP_NO_SUCH_OBJECT ? ": no such entry"
                                : "", 0, 0 );
                        bsi->bsi_status = res;
-                       return BACKSQL_CONTINUE;
+                       return BACKSQL_AVL_CONTINUE;
                }
 
 #ifdef BACKSQL_ARBITRARY_KEY
@@ -1283,7 +1374,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                        Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
                                "error binding base id parameter\n", 0, 0, 0 );
                        bsi->bsi_status = LDAP_OTHER;
-                       return BACKSQL_CONTINUE;
+                       return BACKSQL_AVL_CONTINUE;
                }
                break;
        }
@@ -1295,7 +1386,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                backsql_PrintErrors( bi->db_env, bsi->bsi_dbh, sth, rc );
                SQLFreeStmt( sth, SQL_DROP );
                bsi->bsi_status = LDAP_OTHER;
-               return BACKSQL_CONTINUE;
+               return BACKSQL_AVL_CONTINUE;
        }
 
        backsql_BindRowAsStrings( sth, &row );
@@ -1327,9 +1418,10 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                        c_id->eid_dn = dn;
                }
 
-               c_id->eid_next = bsi->bsi_id_list;
-               bsi->bsi_id_list = c_id;
-               bsi->bsi_n_candidates--;
+               /* append at end of list ... */
+               c_id->eid_next = NULL;
+               *bsi->bsi_id_listtail = c_id;
+               bsi->bsi_id_listtail = &c_id->eid_next;
 
 #ifdef BACKSQL_ARBITRARY_KEY
                Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
@@ -1342,6 +1434,8 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
                        c_id->eid_id, c_id->eid_keyval, row.cols[ 3 ] );
 #endif /* ! BACKSQL_ARBITRARY_KEY */
 
+               /* count candidates, for unchecked limit */
+               bsi->bsi_n_candidates--;
                if ( bsi->bsi_n_candidates == -1 ) {
                        break;
                }
@@ -1352,7 +1446,7 @@ backsql_oc_get_candidates( void *v_oc, void *v_bsi )
        Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n",
                        n_candidates - bsi->bsi_n_candidates, 0, 0 );
 
-       return ( bsi->bsi_n_candidates == -1 ? BACKSQL_STOP : BACKSQL_CONTINUE );
+       return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE );
 }
 
 int
@@ -1361,7 +1455,7 @@ backsql_search( Operation *op, SlapReply *rs )
        backsql_info            *bi = (backsql_info *)op->o_bd->be_private;
        SQLHDBC                 dbh;
        int                     sres;
-       Entry                   *entry, *res;
+       Entry                   user_entry = { 0 };
        int                     manageDSAit;
        time_t                  stoptime = 0;
        backsql_srch_info       srch_info;
@@ -1383,7 +1477,7 @@ backsql_search( Operation *op, SlapReply *rs )
 
        if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
-                       "search base length (%ld) exceeds max length (%ld)\n", 
+                       "search base length (%ld) exceeds max length (%d)\n", 
                        op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN, 0 );
                /*
                 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
@@ -1436,7 +1530,7 @@ backsql_search( Operation *op, SlapReply *rs )
                ( op->ors_limit->lms_s_unchecked == -1 ? -2 :
                ( op->ors_limit->lms_s_unchecked ) ) );
        avl_apply( bi->oc_by_oc, backsql_oc_get_candidates,
-                       &srch_info, BACKSQL_STOP, AVL_INORDER );
+                       &srch_info, BACKSQL_AVL_STOP, AVL_INORDER );
        if ( op->ors_limit != NULL      /* isroot == TRUE */
                        && op->ors_limit->lms_s_unchecked != -1
                        && srch_info.bsi_n_candidates == -1 )
@@ -1451,8 +1545,11 @@ backsql_search( Operation *op, SlapReply *rs )
         * mentioned in attrs and filter), test it against full filter 
         * and then send to client
         */
-       for ( eid = srch_info.bsi_id_list; eid != NULL; 
-                       eid = backsql_free_entryID( eid, 1 ) ) {
+       for ( eid = srch_info.bsi_id_list;
+                       eid != NULL; 
+                       eid = backsql_free_entryID( eid, 1 ) )
+       {
+               int             rc;
                Attribute       *hasSubordinate = NULL,
                                *a = NULL;
 
@@ -1485,24 +1582,73 @@ backsql_search( Operation *op, SlapReply *rs )
                        eid->eid_id, eid->eid_oc_id, eid->eid_keyval );
 #endif /* ! BACKSQL_ARBITRARY_KEY */
 
-               entry = (Entry *)ch_calloc( sizeof( Entry ), 1 );
-               res = backsql_id2entry( &srch_info, entry, eid );
-               if ( res == NULL ) {
+               srch_info.bsi_e = &user_entry;
+               rc = backsql_id2entry( &srch_info, eid );
+               if ( rc != LDAP_SUCCESS ) {
                        Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
-                               "error in backsql_id2entry() "
-                               "- skipping entry\n", 0, 0, 0 );
+                               "error %d in backsql_id2entry() "
+                               "- skipping\n", rc, 0, 0 );
                        continue;
                }
 
+               /* check scope */
+               switch ( op->ors_scope ) {
+               case LDAP_SCOPE_BASE:
+               case BACKSQL_SCOPE_BASE_LIKE:
+                       if ( !bvmatch( &user_entry.e_nname, &op->o_req_ndn ) ) {
+                               goto next_entry;
+                       }
+                       break;
+
+               case LDAP_SCOPE_ONE:
+               {
+                       struct berval   rdn = user_entry.e_nname;
+                       rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
+                       if ( !dnIsOneLevelRDN( &rdn ) ) {
+                               goto next_entry;
+                       }
+                       /* fall thru */
+               }
+
+               case LDAP_SCOPE_SUBTREE:
+                       if ( !dnIsSuffix( &user_entry.e_nname, &op->o_req_ndn ) ) {
+                               goto next_entry;
+                       }
+                       break;
+               }
+
                if ( !manageDSAit &&
                                op->ors_scope != LDAP_SCOPE_BASE &&
                                op->ors_scope != BACKSQL_SCOPE_BASE_LIKE &&
-                               is_entry_referral( entry ) ) {
+                               is_entry_referral( &user_entry ) )
+               {
                        BerVarray refs;
                        struct berval matched_dn;
 
-                       ber_dupbv( &matched_dn, &entry->e_name );
-                       refs = get_entry_referrals( op, entry );
+                       ber_dupbv( &matched_dn, &user_entry.e_name );
+                       refs = get_entry_referrals( op, &user_entry );
+                       if ( !refs ) {
+                               backsql_srch_info       srch_info2 = { 0 };
+                               Entry                   user_entry2 = { 0 };
+
+                               /* retry with the full entry... */
+                               backsql_init_search( &srch_info2,
+                                               &user_entry.e_name,
+                                               LDAP_SCOPE_BASE, 
+                                               -1, -1, -1, NULL,
+                                               dbh, op, rs, NULL );
+                               srch_info2.bsi_e = &user_entry2;
+                               rc = backsql_id2entry( &srch_info2, eid );
+                               if ( rc == LDAP_SUCCESS ) {
+                                       if ( is_entry_referral( &user_entry2 ) )
+                                       {
+                                               refs = get_entry_referrals( op,
+                                                               &user_entry2 );
+                                       } /* else: FIXME: inconsistency! */
+                                       entry_clean( &user_entry2 );
+                               }
+                       }
+
                        if ( refs ) {
                                rs->sr_ref = referral_rewrite( refs,
                                                &matched_dn, &op->o_req_dn,
@@ -1523,7 +1669,7 @@ backsql_search( Operation *op, SlapReply *rs )
                        ber_memfree( matched_dn.bv_val );
                        rs->sr_matched = NULL;
 
-                       continue;
+                       goto next_entry;
                }
 
                /*
@@ -1532,16 +1678,14 @@ backsql_search( Operation *op, SlapReply *rs )
                 * filter_has_subordinates()
                 */
                if ( srch_info.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
-                       int             rc;
-
-                       rc = backsql_has_children( bi, dbh, &entry->e_nname );
+                       rc = backsql_has_children( bi, dbh, &user_entry.e_nname );
 
-                       switch( rc ) {
+                       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; 
+                                       for ( a = user_entry.e_attrs; 
                                                        a && a->a_next; 
                                                        a = a->a_next );
 
@@ -1556,15 +1700,11 @@ backsql_search( Operation *op, SlapReply *rs )
                                        "has_children failed( %d)\n", 
                                        rc, 0, 0 );
                                rc = 1;
-                               break;
-                       }
-
-                       if ( rc ) {
-                               continue;
+                               goto next_entry;
                        }
                }
 
-               if ( test_filter( op, entry, op->ors_filter )
+               if ( test_filter( op, &user_entry, op->ors_filter )
                                == LDAP_COMPARE_TRUE ) {
                        if ( hasSubordinate && !( srch_info.bsi_flags & BSQL_SF_ALL_OPER ) 
                                        && !ad_inlist( slap_schema.si_ad_hasSubordinates, op->ors_attrs ) ) {
@@ -1573,38 +1713,31 @@ backsql_search( Operation *op, SlapReply *rs )
                                hasSubordinate = NULL;
                        }
 
-#if 0  /* noop is masked SLAP_CTRL_UPDATE */
-                       if ( op->o_noop ) {
-                               sres = 0;
-                       } else
-#endif
-                       {
-                               rs->sr_attrs = op->ors_attrs;
-                               rs->sr_entry = entry;
-                               rs->sr_flags = REP_ENTRY_MODIFIABLE;
-                               sres = send_search_entry( op, rs );
-                               rs->sr_entry = NULL;
-                               rs->sr_attrs = NULL;
-                       }
+                       rs->sr_attrs = op->ors_attrs;
+                       rs->sr_entry = &user_entry;
+                       rs->sr_flags = REP_ENTRY_MODIFIABLE;
+                       sres = send_search_entry( op, rs );
+                       rs->sr_entry = NULL;
+                       rs->sr_attrs = NULL;
 
                        switch ( sres ) {
                        case 0:
                                break;
 
-                       case -1:
-                               Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
-                                       "connection lost\n", 0, 0, 0 );
-                               goto end_of_search;
-
                        default:
                                /*
                                 * FIXME: send_search_entry failed;
                                 * better stop
                                 */
-                               break;
+                       case -1:
+                               Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
+                                       "connection lost\n", 0, 0, 0 );
+                               goto end_of_search;
                        }
                }
-               entry_free( entry );
+
+next_entry:;
+               entry_clean( &user_entry );
 
                if ( op->ors_slimit != SLAP_NO_LIMIT
                                && rs->sr_nentries >= op->ors_slimit )
@@ -1616,11 +1749,14 @@ backsql_search( Operation *op, SlapReply *rs )
        }
 
 end_of_search:;
+       /* in case we got here accidentally */
+       entry_clean( &user_entry );
 
        if ( rs->sr_nentries > 0 ) {
                rs->sr_ref = rs->sr_v2ref;
                rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
                        : LDAP_REFERRAL;
+
        } else {
                rs->sr_err = srch_info.bsi_status;
        }
index 86b46893163929f3c865a7ce598cf4e51f0a3b33..ff0fa3d94117c9c2d13462fed4eb1305045f46db 100644 (file)
@@ -32,8 +32,8 @@
 
 #define MAX_ATTR_LEN 16384
 
-typedef struct backsql_conn {
-       int             ldap_cid;
+typedef struct backsql_db_conn {
+       unsigned long   ldap_cid;
        SQLHDBC         dbh;
 } backsql_db_conn;
 
@@ -145,6 +145,7 @@ backsql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row )
 #endif /* BACKSQL_TRACE */
                
                backsql_PrintErrors( SQL_NULL_HENV, SQL_NULL_HDBC, sth, rc );
+
        } else {
 #ifdef BACKSQL_TRACE
                Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: "
@@ -270,6 +271,7 @@ int
 backsql_init_db_env( backsql_info *si )
 {
        RETCODE         rc;
+       int             ret = SQL_SUCCESS;
        
        Debug( LDAP_DEBUG_TRACE, "==>backsql_init_db_env()\n", 0, 0, 0 );
        rc = SQLAllocEnv( &si->db_env );
@@ -278,9 +280,10 @@ backsql_init_db_env( backsql_info *si )
                                0, 0, 0 );
                backsql_PrintErrors( SQL_NULL_HENV, SQL_NULL_HDBC,
                                SQL_NULL_HENV, rc );
+               ret = SQL_ERROR;
        }
-       Debug( LDAP_DEBUG_TRACE, "<==backsql_init_db_env()\n", 0, 0, 0 );
-       return SQL_SUCCESS;
+       Debug( LDAP_DEBUG_TRACE, "<==backsql_init_db_env()=%d\n", ret, 0, 0 );
+       return ret;
 }
 
 int
@@ -303,7 +306,7 @@ backsql_free_db_env( backsql_info *si )
 }
 
 static int
-backsql_open_db_conn( backsql_info *si, int ldap_cid, backsql_db_conn **pdbc )
+backsql_open_db_conn( backsql_info *si, unsigned long ldap_cid, backsql_db_conn **pdbc )
 {
        /* TimesTen */
        char                    DBMSName[ 32 ];
@@ -325,8 +328,10 @@ backsql_open_db_conn( backsql_info *si, int ldap_cid, backsql_db_conn **pdbc )
                return LDAP_UNAVAILABLE;
        }
 
-       rc = SQLConnect( dbc->dbh, si->dbname, SQL_NTS, si->dbuser, 
-                       SQL_NTS, si->dbpasswd, SQL_NTS );
+       rc = SQLConnect( dbc->dbh,
+                       (SQLCHAR*)si->dbname, SQL_NTS,
+                       (SQLCHAR*)si->dbuser, SQL_NTS,
+                       (SQLCHAR*)si->dbpasswd, SQL_NTS );
        if ( rc != SQL_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn: "
                        "SQLConnect() to database \"%s\" as user \"%s\" "
@@ -389,7 +394,8 @@ int
 backsql_free_db_conn( Operation *op )
 {
        backsql_info            *si = (backsql_info *)op->o_bd->be_private;
-       backsql_db_conn         tmp, *conn;
+       backsql_db_conn         tmp = { 0 },
+                               *conn;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_free_db_conn()\n", 0, 0, 0 );
        tmp.ldap_cid = op->o_connid;
@@ -414,8 +420,8 @@ int
 backsql_get_db_conn( Operation *op, SQLHDBC *dbh )
 {
        backsql_info            *si = (backsql_info *)op->o_bd->be_private;
-       backsql_db_conn         *dbc;
-       backsql_db_conn         tmp;
+       backsql_db_conn         *dbc,
+                               tmp = { 0 };
        int                     rc = LDAP_SUCCESS;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_get_db_conn()\n", 0, 0, 0 );
index 1bb975f434718a813527d06cf8ab905674e66845..16084ef4ef414d0fd768e8094d50859edc5e5590 100644 (file)
@@ -52,6 +52,10 @@ char backsql_def_delentry_query[] = "DELETE FROM ldap_entries WHERE id=?";
 char backsql_def_insentry_query[] = 
        "INSERT INTO ldap_entries (dn,oc_map_id,parent,keyval) "
        "VALUES (?,?,?,?)";
+char backsql_def_delobjclasses_query[] = "DELETE FROM ldap_entry_objclasses "
+       "WHERE entry_id=?";
+char backsql_def_delreferrals_query[] = "DELETE FROM ldap_referrals "
+       "WHERE entry_id=?";
 char backsql_def_subtree_cond[] = "ldap_entries.dn LIKE CONCAT('%',?)";
 char backsql_def_upper_subtree_cond[] = "(ldap_entries.dn) LIKE CONCAT('%',?)";
 char backsql_id_query[] = "SELECT id,keyval,oc_map_id FROM ldap_entries WHERE ";
@@ -59,7 +63,7 @@ char backsql_id_query[] = "SELECT id,keyval,oc_map_id FROM ldap_entries WHERE ";
 char backsql_def_concat_func[] = "CONCAT(?,?)";
 
 /* TimesTen */
-char backsql_check_dn_ru_query[] = "SELECT dn_ru from ldap_entries";
+char backsql_check_dn_ru_query[] = "SELECT dn_ru FROM ldap_entries";
 
 struct berbuf *
 backsql_strcat( struct berbuf *dest, ... )
@@ -110,7 +114,8 @@ backsql_strcat( struct berbuf *dest, ... )
 
 #ifdef BACKSQL_TRACE
                        Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
-                               "new buflen=%d, dest=%p\n", dest->bb_len, dest, 0 );
+                               "new buflen=%d, dest=%p\n",
+                               dest->bb_len, dest, 0 );
 #endif /* BACKSQL_TRACE */
                }
                AC_MEMCPY( dest->bb_val.bv_val + cdlen, cstr, cslen + 1 );
@@ -120,7 +125,7 @@ backsql_strcat( struct berbuf *dest, ... )
 
 #ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "<==backsql_strcat() (dest=\"%s\")\n", 
-                       dest, 0, 0 );
+                       dest->bb_val.bv_val, 0, 0 );
 #endif /* BACKSQL_TRACE */
 
        dest->bb_val.bv_len = cdlen;
@@ -172,7 +177,7 @@ backsql_strfcat( struct berbuf *dest, const char *fmt, ... )
                        cslen = va_arg( strs, ber_len_t );
                        cstr = va_arg( strs, char * );
                        break;
-                       
+
                /* string */
                case 's':
                        cstr = va_arg( strs, char * );
@@ -231,7 +236,7 @@ backsql_strfcat( struct berbuf *dest, const char *fmt, ... )
 
 #ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "<==backsql_strfcat() (dest=\"%s\")\n", 
-                       dest, 0, 0 );
+                       dest->bb_val.bv_val, 0, 0 );
 #endif /* BACKSQL_TRACE */
 
        dest->bb_val.bv_len = cdlen;
@@ -313,18 +318,18 @@ backsql_get_table_spec( char **p )
        s = q;
 
        BACKSQL_NEXT_WORD;
-       if ( !strcasecmp( s, "as" ) ) {
+       if ( strcasecmp( s, "AS" ) == 0 ) {
                s = q;
                BACKSQL_NEXT_WORD;
        }
 
-#if 0
-       backsql_strcat( &res, " AS ", s, NULL );
-       /* oracle doesn't understand AS :( and other RDBMSes don't need it */
-#endif
-
-       /* table alias */
-       backsql_strfcat( &res, "cs", ' ', s );
+       /* oracle doesn't understand "AS" :( and other RDBMSes don't need it */
+#ifdef BACKSQL_ALIASING_QUOTE
+       backsql_strfcat( &res, "scsc", " " BACKSQL_ALIASING,
+                       BACKSQL_ALIASING_QUOTE, s, BACKSQL_ALIASING_QUOTE );
+#else /* ! BACKSQL_ALIASING */
+       backsql_strcat( &res, " " BACKSQL_ALIASING, s, NULL );
+#endif /* ! BACKSQL_ALIASING */
 
        return res.bb_val.bv_val;
 }
@@ -340,7 +345,8 @@ backsql_merge_from_clause(
 #ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_merge_from_clause(): "
                "dest_from=\"%s\",src_from=\"%s\"\n",
-               dest_from ? dest_from->bb_val.bv_val : "<NULL>", src_from, 0 );
+               dest_from ? dest_from->bb_val.bv_val : "<NULL>",
+               src_from->bv_val, 0 );
 #endif /* BACKSQL_TRACE */
 
        srcc = ch_strdup( src_from->bv_val );