]> git.sur5r.net Git - openldap/commitdiff
CHANGES:
authorPierangelo Masarati <ando@openldap.org>
Fri, 16 Aug 2002 16:45:24 +0000 (16:45 +0000)
committerPierangelo Masarati <ando@openldap.org>
Fri, 16 Aug 2002 16:45:24 +0000 (16:45 +0000)
- now all write operations appear to work correctly with PostgeSQL 7.0
- all write operations have been made transactional (atomic writes to
  entries are committed separately only in case of complete^1 success
  while all other operations are rolled-back by default)
- more cleanup and handling of exceptional conditions

TODO:
- deen to check with different databases and more up to date versions
  of both unixODBC and PostgreSQL.

^1: attribute add/modify/delete operations silently succeed if the
    appropriate add/delete proc does not exist for each attribute;
    this may be correct to hide undesired/unimplemented correspondence
    between LDAP and SQL databases; however, a more appropriate
    LDAP behavior would be a failure with LDAP_UNAVAILABLE if a
    single write operation cannot be executed for such reason

18 files changed:
servers/slapd/back-sql/back-sql.h
servers/slapd/back-sql/bind.c
servers/slapd/back-sql/entry-id.c
servers/slapd/back-sql/init.c
servers/slapd/back-sql/modify.c
servers/slapd/back-sql/other.c
servers/slapd/back-sql/rdbms_depend/pgsql/backsql_create.sql
servers/slapd/back-sql/rdbms_depend/pgsql/testdb_create.sql
servers/slapd/back-sql/rdbms_depend/pgsql/testdb_data.sql
servers/slapd/back-sql/rdbms_depend/pgsql/testdb_metadata.sql
servers/slapd/back-sql/schema-map.c
servers/slapd/back-sql/schema-map.h
servers/slapd/back-sql/search.c
servers/slapd/back-sql/sql-types.h
servers/slapd/back-sql/sql-wrap.c
servers/slapd/back-sql/sql-wrap.h
servers/slapd/back-sql/util.c
servers/slapd/back-sql/util.h

index 02614e3ff2a3412e5ac5fb8bafdfc329f12ad34f..bd349175a4726f4972044bf4aabfcea4090bdd3d 100644 (file)
@@ -35,7 +35,7 @@ typedef struct {
        char            *upper_func;
        char            *strcast_func;
        Avlnode         *db_conns;
-       Avlnode         *oc_by_name;
+       Avlnode         *oc_by_oc;
        Avlnode         *oc_by_id;
        int             schema_loaded;
        ldap_pvt_thread_mutex_t         dbconn_mutex;
index 9c112c19605c81742e46e868af662a90d26ac2b7..30c060f5c483ae022a9829ff82d685292272f2b7 100644 (file)
@@ -37,6 +37,7 @@ backsql_bind(
        Entry                   *e, user_entry;
        Attribute               *a;
        backsql_srch_info       bsi;
+       int                     rc;
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_bind()\n", 0, 0, 0 );
 
@@ -59,13 +60,14 @@ backsql_bind(
        /*
         * method = LDAP_AUTH_SIMPLE
         */
-       dbh = backsql_get_db_conn( be, conn );
+       rc = backsql_get_db_conn( be, conn, &dbh );
        if (!dbh) {
                Debug( LDAP_DEBUG_TRACE, "backsql_bind(): "
                        "could not get connection handle - exiting\n",
                        0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                               "SQL-backend error", NULL, NULL );
+               send_ldap_result( conn, op, rc, "",
+                               rc == LDAP_OTHER ? "SQL-backend error" : "", 
+                               NULL, NULL );
                return 1;
        }
 
index eab33bbc140462d3fe4b2635781479331353603f..552d23946e09706e28cff8d02d2cfc48b029e6e8 100644 (file)
@@ -182,7 +182,7 @@ backsql_get_attr_vals( backsql_at_map_rec *at, backsql_srch_info *bsi )
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
                "oc='%s' attr='%s' keyval=%ld\n",
-               bsi->oc->name, at->name, bsi->c_eid->keyval );
+               bsi->oc->name.bv_val, at->name.bv_val, bsi->c_eid->keyval );
 
        rc = backsql_Prepare( bsi->dbh, &sth, at->query, 0 );
        if ( rc != SQL_SUCCESS ) {
@@ -215,26 +215,28 @@ backsql_get_attr_vals( backsql_at_map_rec *at, backsql_srch_info *bsi )
        for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
                for ( i = 0; i < row.ncols; i++ ) {
                        if ( row.is_null[ i ] > 0 ) {
-                                       backsql_entry_addattr( bsi->e, 
-                                               row.col_names[ i ],
-                                               row.cols[ i ],
+                               struct berval   bv;
+
+                               bv.bv_val = row.cols[ i ];
 #if 0
-                                               row.col_prec[ i ]
+                               bv.bv_len = row.col_prec[ i ];
 #else
-                                               /*
-                                                * FIXME: what if a binary 
-                                                * is fetched?
-                                                */
-                                               strlen( row.cols[ i ] )
+                               /*
+                                * FIXME: what if a binary 
+                                * is fetched?
+                                */
+                               bv.bv_len = strlen( row.cols[ i ] );
 #endif
-                                               );
+                                       backsql_entry_addattr( bsi->e, 
+                                               &row.col_names[ i ], &bv );
+
 #if 0
                                Debug( LDAP_DEBUG_TRACE, "prec=%d\n",
                                        (int)row.col_prec[ i ], 0, 0 );
                        } else {
                                Debug( LDAP_DEBUG_TRACE, "NULL value "
                                        "in this row for attribute '%s'\n",
-                                       row.col_names[ i ], 0, 0 );
+                                       row.col_names[ i ].bv_val, 0, 0 );
 #endif
                        }
                }
@@ -250,7 +252,7 @@ backsql_get_attr_vals( backsql_at_map_rec *at, backsql_srch_info *bsi )
 Entry *
 backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
 {
-       char                    **c_at_name;
+       int                     i;
        backsql_at_map_rec      *at;
        int                     rc;
 
@@ -261,7 +263,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                return NULL;
        }
 
-       bsi->oc = backsql_oc_with_id( bsi->bi, eid->oc_id );
+       bsi->oc = backsql_id2oc( bsi->bi, eid->oc_id );
        bsi->e = e;
        bsi->c_eid = eid;
        e->e_attrs = NULL;
@@ -274,24 +276,31 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
        if ( bsi->attrs != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
                        "custom attribute list\n", 0, 0, 0 );
-               for ( c_at_name = bsi->attrs; *c_at_name != NULL; c_at_name++ ) {
-                       if ( !strcasecmp( *c_at_name, "objectclass" ) 
-                                       || !strcasecmp( *c_at_name, "0.10" ) ) {
+               for ( i = 0; bsi->attrs[ i ].an_name.bv_val; i++ ) {
+                       AttributeName *attr = &bsi->attrs[ i ];
+
+                       if ( attr->an_desc == slap_schema.si_ad_objectClass
+#if 0  /* FIXME: what is 0.10 ? */
+                                       || !BACKSQL_NCMP( &attr->an_name, &bv_n_0_10 ) 
+#endif
+                                       ) {
 #if 0
-                               backsql_entry_addattr( bsi->e, "objectclass",
-                                               bsi->oc->name,
-                                               strlen( bsi->oc->name ) );
+                               backsql_entry_addattr( bsi->e, 
+                                               &bv_n_objectclass,
+                                               &bsi->oc->name );
 #endif
                                continue;
                        }
-                       at = backsql_at_with_name( bsi->oc, *c_at_name );
+
+                       at = backsql_ad2at( bsi->oc, attr->an_desc );
                        if ( at != NULL ) {
                                backsql_get_attr_vals( at, bsi );
                        } else {
                                Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
                                        "attribute '%s' is not defined "
                                        "for objectlass '%s'\n",
-                                       *c_at_name, bsi->oc->name, 0 );
+                                       attr->an_name.bv_val, 
+                                       bsi->oc->name.bv_val, 0 );
                        }
                }
        } else {
@@ -301,8 +310,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                                bsi, 0, AVL_INORDER );
        }
 
-       backsql_entry_addattr( bsi->e, "objectclass", bsi->oc->name,
-                       strlen( bsi->oc->name ) );
+       backsql_entry_addattr( bsi->e, &bv_n_objectclass, &bsi->oc->name );
 
        Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 );
 
index ab38e378466b7a4ff66b3ec976b5ed109a26751b..79d8dec530d590a7e78b5331f2e2671fd4c58e68 100644 (file)
@@ -14,6 +14,7 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include "slap.h"
+#include "ldap_pvt.h"
 #include "back-sql.h"
 #include "sql-wrap.h"
 #include "schema-map.h"
@@ -238,8 +239,7 @@ backsql_db_open(
        }
        
        tmp.c_connid =- 1;
-       dbh = backsql_get_db_conn( bd, &tmp );
-       if ( !dbh ) {
+       if ( backsql_get_db_conn( bd, &tmp, &dbh ) != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "connection failed, exiting\n", 0, 0, 0 );
                return 1;
index f1bc54869b8cb7b613bf01a8b604fa1962267529..2757d33e4c4b660279d67a73c43bbd2fa7c1912e 100644 (file)
@@ -15,6 +15,7 @@
 #include <sys/types.h>
 #include <string.h>
 #include "slap.h"
+#include "ldap_pvt.h"
 #include "back-sql.h"
 #include "sql-wrap.h"
 #include "schema-map.h"
  */
 #define        BACKSQL_REALLOC_STMT
 
-int
-backsql_modify(
-       BackendDB       *be,
-       Connection      *conn,
-       Operation       *op,
-       struct berval   *dn,
-       struct berval   *ndn,
-       Modifications   *modlist )
+static int
+backsql_modify_internal(
+       backsql_info            *bi,
+       SQLHDBC                 dbh, 
+       backsql_oc_map_rec      *oc,
+       backsql_entryID         *e_id,
+       Modifications           *modlist )
 {
-       backsql_info            *bi = (backsql_info*)be->be_private;
-       SQLHDBC                 dbh;
-       SQLHSTMT                sth;
-       RETCODE                 rc;
-       backsql_oc_map_rec      *oc = NULL;
-       backsql_entryID         e_id;
-       int                     res;
-       Modification            *c_mod;
-       Modifications           *ml;
-       backsql_at_map_rec      *at = NULL;
-       struct berval           *at_val;
-       int                     i;
-       /* first parameter no, parameter order */
-       SQLUSMALLINT            pno, po;
-       /* procedure return code */
-       int                     prc;
-
-       Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): changing entry '%s'\n",
-               ndn->bv_val, 0, 0 );
-       dbh = backsql_get_db_conn( be, conn );
-       if ( !dbh ) {
-               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
-                       "could not get connection handle - exiting\n", 
-                       0, 0, 0 );
-               /*
-                * FIXME: we don't want to send back 
-                * excessively detailed messages
-                */
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                               "SQL-backend error", NULL, NULL );
-               return 1;
-       }
-
-       res = backsql_dn2id( bi, &e_id, dbh, ndn );
-       if ( res != LDAP_SUCCESS ) {
-               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
-                       "could not lookup entry id\n", 0, 0, 0 );
-               send_ldap_result( conn, op, res , "", NULL, NULL, NULL );
-               return 1;
-       }
+       RETCODE         rc;
+       SQLHSTMT        sth;
+       Modifications   *ml;
 
-       Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
-               "modifying entry '%s' (id=%ld)\n", 
-               e_id.dn.bv_val, e_id.id, 0 );
-
-       oc = backsql_oc_with_id( bi, e_id.oc_id );
-       if ( oc == NULL ) {
-               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
-                       "cannot determine objectclass of entry -- aborting\n",
-                       0, 0, 0 );
-               /*
-                * FIXME: we don't want to send back 
-                * excessively detailed messages
-                */
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                               "SQL-backend error", NULL, NULL );
-               return 1;
-       }
-
-       SQLAllocStmt( dbh, &sth );
        Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                "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 ) {
-               char *attrname;
+               AttributeDescription *ad;
+               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;
 
-               attrname = c_mod->sm_desc->ad_cname.bv_val;
+               ad = c_mod->sm_desc;
                Debug( LDAP_DEBUG_TRACE, "backsql_modify(): attribute '%s'\n",
-                               attrname, 0, 0 );
-               at = backsql_at_with_name( oc, attrname );
+                               ad->ad_cname.bv_val, 0, 0 );
+               at = backsql_ad2at( oc, ad );
                if ( at == NULL ) {
                        Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                                "attribute provided is not registered "
                                "in objectclass '%s'\n",
-                               attrname, 0, 0 );
+                               ad->ad_cname.bv_val, 0, 0 );
                        continue;
                }
   
@@ -121,14 +80,14 @@ backsql_modify(
                         
                        Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                                "replacing values for attribute '%s'\n",
-                               at->name, 0, 0 );
+                               at->name.bv_val, 0, 0 );
 
                        if ( at->add_proc == NULL ) {
                                Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                                        "add procedure is not defined "
                                        "for attribute '%s' "
                                        "- unable to perform replacements\n",
-                                       at->name, 0, 0 );
+                                       at->name.bv_val, 0, 0 );
                                break;
                        }
 
@@ -137,7 +96,7 @@ backsql_modify(
                                        "delete procedure is not defined "
                                        "for attribute '%s' "
                                        "- adding only\n",
-                                       at->name, 0, 0 );
+                                       at->name.bv_val, 0, 0 );
                                goto add_only;
                        }
                        
@@ -151,7 +110,7 @@ del_all:
                                break;
                        }
 
-                       rc = backsql_BindParamID( asth, 1, &e_id.keyval );
+                       rc = backsql_BindParamID( asth, 1, &e_id->keyval );
                        if ( rc != SQL_SUCCESS ) {
                                Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                                        "error binding key value parameter\n",
@@ -177,7 +136,7 @@ del_all:
                        rc = SQLFetch( asth );
                        for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) {
                                for ( i = 0; i < row.ncols; i++ ) {
-                                       if ( at->expect_return & BACKSQL_DEL ) {
+                                       if ( BACKSQL_IS_DEL( at->expect_return ) ) {
                                                pno = 1;
                                                SQLBindParameter(sth, 1,
                                                        SQL_PARAM_OUTPUT,
@@ -187,11 +146,11 @@ del_all:
                                        } else {
                                                pno = 0;
                                        }
-                                       po = ( at->param_order & BACKSQL_DEL ) > 0;
+                                       po = ( BACKSQL_IS_DEL( at->param_order ) ) > 0;
                                        SQLBindParameter( sth, pno + 1 + po,
                                                SQL_PARAM_INPUT,
                                                SQL_C_ULONG, SQL_INTEGER,
-                                               0, 0, &e_id.keyval, 0, 0 );
+                                               0, 0, &e_id->keyval, 0, 0 );
 
                                        /*
                                         * check for syntax needed here 
@@ -218,6 +177,10 @@ del_all:
                                                backsql_PrintErrors( bi->db_env,
                                                                dbh, sth, rc );
                                        }
+#ifdef BACKSQL_REALLOC_STMT
+                                       SQLFreeStmt( sth, SQL_DROP );
+                                       SQLAllocStmt( dbh, &sth );
+#endif /* BACKSQL_REALLOC_STMT */
                                }
                        }
                        backsql_FreeRow( &row );
@@ -228,12 +191,13 @@ del_all:
                 * PASSTHROUGH - to add new attributes -- do NOT add break
                 */
                case LDAP_MOD_ADD:
+               case SLAP_MOD_SOFTADD:
 add_only:;
                        if ( at->add_proc == NULL ) {
                                Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                                        "add procedure is not defined "
                                        "for attribute '%s'\n",
-                                       at->name, 0, 0 );
+                                       at->name.bv_val, 0, 0 );
                                break;
                        }
                        
@@ -241,17 +205,17 @@ add_only:;
                                Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                                        "no values given to add "
                                        "for attribute '%s'\n",
-                                       at->name, 0, 0 );
+                                       at->name.bv_val, 0, 0 );
                                break;
                        }
                        
                        Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                                "adding new values for attribute '%s'\n",
-                               at->name, 0, 0 );
-                       for ( i = 0, at_val = &c_mod->sm_bvalues[ 0 ];
+                               at->name.bv_val, 0, 0 );
+                       for ( i = 0, at_val = c_mod->sm_bvalues;
                                        at_val->bv_val != NULL; 
-                                       i++, at_val = &c_mod->sm_bvalues[ i ] ) {
-                               if ( at->expect_return & BACKSQL_ADD ) {
+                                       i++, at_val++ ) {
+                               if ( BACKSQL_IS_ADD( at->expect_return ) ) {
                                        pno = 1;
                                        SQLBindParameter( sth, 1,
                                                SQL_PARAM_OUTPUT,
@@ -260,11 +224,11 @@ add_only:;
                                } else {
                                        pno = 0;
                                }
-                               po = ( at->param_order & BACKSQL_ADD ) > 0;
+                               po = ( BACKSQL_IS_ADD( at->param_order ) ) > 0;
                                SQLBindParameter( sth, pno + 1 + po,
                                        SQL_PARAM_INPUT, 
                                        SQL_C_ULONG, SQL_INTEGER,
-                                       0, 0, &e_id.keyval, 0, 0 );
+                                       0, 0, &e_id->keyval, 0, 0 );
 
                                /*
                                 * check for syntax needed here
@@ -289,6 +253,10 @@ add_only:;
                                        backsql_PrintErrors( bi->db_env,
                                                        dbh, sth, rc );
                                }
+#ifdef BACKSQL_REALLOC_STMT
+                               SQLFreeStmt( sth, SQL_DROP );
+                               SQLAllocStmt( dbh, &sth );
+#endif /* BACKSQL_REALLOC_STMT */
                        }
                        break;
                        
@@ -297,7 +265,7 @@ add_only:;
                                Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                                        "delete procedure is not defined "
                                        "for attribute '%s'\n",
-                                       at->name, 0, 0 );
+                                       at->name.bv_val, 0, 0 );
                                break;
                        }
 
@@ -306,17 +274,17 @@ add_only:;
                                        "no values given to delete "
                                        "for attribute '%s' "
                                        "-- deleting all values\n",
-                                       at->name, 0, 0 );
+                                       at->name.bv_val, 0, 0 );
                                goto del_all;
                        }
 
                        Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
                                "deleting values for attribute '%s'\n",
-                               at->name, 0, 0 );
-                       for( i = 0, at_val = &c_mod->sm_bvalues[ 0 ];
+                               at->name.bv_val, 0, 0 );
+                       for ( i = 0, at_val = c_mod->sm_bvalues;
                                        at_val->bv_val != NULL;
-                                       i++, at_val = &c_mod->sm_bvalues[ i ] ) {
-                               if ( at->expect_return & BACKSQL_DEL ) {
+                                       i++, at_val++ ) {
+                               if ( BACKSQL_IS_DEL( at->expect_return ) ) {
                                        pno = 1;
                                        SQLBindParameter( sth, 1,
                                                SQL_PARAM_OUTPUT,
@@ -325,11 +293,11 @@ add_only:;
                                } else {
                                        pno = 0;
                                }
-                               po = ( at->param_order & BACKSQL_DEL ) > 0;
+                               po = ( BACKSQL_IS_DEL( at->param_order ) ) > 0;
                                SQLBindParameter( sth, pno + 1 + po,
                                        SQL_PARAM_INPUT, 
                                        SQL_C_ULONG, SQL_INTEGER,
-                                       0, 0, &e_id.keyval, 0, 0 );
+                                       0, 0, &e_id->keyval, 0, 0 );
 
                                /*
                                 * check for syntax needed here 
@@ -353,15 +321,114 @@ add_only:;
                                        backsql_PrintErrors( bi->db_env,
                                                        dbh, sth, rc );
                                }
+#ifdef BACKSQL_REALLOC_STMT
+                               SQLFreeStmt( sth, SQL_DROP );
+                               SQLAllocStmt( dbh, &sth );
+#endif /* BACKSQL_REALLOC_STMT */
                        }
                        break;
                }
-               
+#ifndef BACKSQL_REALLOC_STMT
                SQLFreeStmt( sth, SQL_RESET_PARAMS );
+#else /* BACKSQL_REALLOC_STMT */
+               SQLFreeStmt( sth, SQL_DROP );
+#endif /* BACKSQL_REALLOC_STMT */
        }
 
+#ifndef BACKSQL_REALLOC_STMT
        SQLFreeStmt( sth, SQL_DROP );
-       send_ldap_result( conn, op, LDAP_SUCCESS, "", NULL, NULL, NULL );
+#endif /* BACKSQL_REALLOC_STMT */
+
+       /*
+        * FIXME: should fail in case one change fails?
+        */
+       return LDAP_SUCCESS;
+}
+
+int
+backsql_modify(
+       BackendDB       *be,
+       Connection      *conn,
+       Operation       *op,
+       struct berval   *dn,
+       struct berval   *ndn,
+       Modifications   *modlist )
+{
+       backsql_info            *bi = (backsql_info*)be->be_private;
+       SQLHDBC                 dbh;
+       backsql_oc_map_rec      *oc = NULL;
+       backsql_entryID         e_id;
+       int                     res;
+
+       /*
+        * FIXME: in case part of the operation cannot be performed
+        * (missing mapping, SQL write fails or so) the entire operation
+        * should be rolled-back
+        */
+
+       Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): changing entry '%s'\n",
+               ndn->bv_val, 0, 0 );
+       res = backsql_get_db_conn( be, conn, &dbh );
+       if ( res != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                       "could not get connection handle - exiting\n", 
+                       0, 0, 0 );
+               /*
+                * FIXME: we don't want to send back 
+                * excessively detailed messages
+                */
+               send_ldap_result( conn, op, res, "", 
+                               res == LDAP_OTHER ?  "SQL-backend error" : "", 
+                               NULL, NULL );
+               return 1;
+       }
+
+       res = backsql_dn2id( bi, &e_id, dbh, ndn );
+       if ( res != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                       "could not lookup entry id\n", 0, 0, 0 );
+               send_ldap_result( conn, op, res , "", 
+                               res == LDAP_OTHER ? "SQL-backend error" : "",
+                               NULL, NULL );
+               return 1;
+       }
+
+       Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+               "modifying entry '%s' (id=%ld)\n", 
+               e_id.dn.bv_val, e_id.id, 0 );
+
+       oc = backsql_id2oc( bi, e_id.oc_id );
+       if ( oc == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                       "cannot determine objectclass of entry -- aborting\n",
+                       0, 0, 0 );
+               /*
+                * FIXME: should never occur, since the entry was built!!!
+                */
+
+               /*
+                * FIXME: we don't want to send back 
+                * excessively detailed messages
+                */
+               send_ldap_result( conn, op, LDAP_OTHER, "",
+                               "SQL-backend error", NULL, NULL );
+               return 1;
+       }
+
+       res = backsql_modify_internal( bi, dbh, oc, &e_id, modlist );
+       if ( res == LDAP_SUCCESS ) {
+               /*
+                * Commit only if all operations succeed
+                *
+                * FIXME: backsql_modify_internal() does not fail 
+                * if add/delete operations are not available, or
+                * if a multiple value add actually results in a replace, 
+                * or if a single operation on an attribute fails 
+                * for any reason
+                */
+               SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+       }
+       send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 );
 
        return 0;
@@ -385,21 +452,28 @@ backsql_modrdn(
        SQLHSTMT                sth;
        RETCODE                 rc;
        backsql_entryID         e_id, pe_id, new_pid;
+       backsql_oc_map_rec      *oc = NULL;
        int                     res;
        struct berval           p_dn, p_ndn,
                                *new_pdn = NULL, *new_npdn = NULL,
                                new_dn, new_ndn;
+       const char              *text = NULL;
+       LDAPRDN                 *new_rdn = NULL;
+       LDAPRDN                 *old_rdn = NULL;
+       Modifications           *mod;
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry '%s', "
                        "newrdn='%s', newSuperior='%s'\n",
-                       dn->bv_val, newrdn->bv_val, newSuperior->bv_val );
-       dbh = backsql_get_db_conn( be, conn );
-       if ( !dbh ) {
+                       dn->bv_val, newrdn->bv_val, 
+                       newSuperior ? newSuperior->bv_val : "(NULL)" );
+       res = backsql_get_db_conn( be, conn, &dbh );
+       if ( res != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
                        "could not get connection handle - exiting\n", 
                        0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                       "SQL-backend error", NULL, NULL );
+               send_ldap_result( conn, op, res, "",
+                               res == LDAP_OTHER ?  "SQL-backend error" : "",
+                               NULL, NULL );
                return 1;
        }
 
@@ -407,10 +481,16 @@ backsql_modrdn(
        if ( res != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
                        "could not lookup entry id\n", 0, 0, 0 );
-               send_ldap_result( conn, op, res , "", NULL, NULL, NULL );
+               send_ldap_result( conn, op, res, "",
+                               res == LDAP_OTHER ?  "SQL-backend error" : "",
+                               NULL, NULL );
                return 1;
        }
 
+       /*
+        * FIXME: check whether entry has children
+        */
+
        Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): entry id is %ld\n",
                e_id.id, 0, 0 );
 
@@ -418,22 +498,31 @@ backsql_modrdn(
        dnParent( ndn, &p_ndn );
 
        if ( newSuperior ) {
+               /*
+                * namingContext "" is not supported
+                */
+               if ( newSuperior->bv_len == 0 ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
+                               "newSuperior is \"\" - aborting\n", 0, 0, 0 );
+                       send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, 
+                                       "", "not allowed within namingContext", 
+                                       NULL, NULL );
+                       goto modrdn_return;
+               }
+
                new_pdn = newSuperior;
                new_npdn = nnewSuperior;
+
        } else {
                new_pdn = &p_dn;
                new_npdn = &p_ndn;
        }
 
-       SQLAllocStmt( dbh, &sth );
-
        if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
-                       "newSuperior is equal to old parent - aborting\n",
+                       "newSuperior is equal to old parent - ignored\n",
                        0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, "", 
-                               NULL, NULL, NULL );
-               goto modrdn_return;
+               newSuperior = NULL;
        }
 
        if ( newSuperior && dn_match( ndn, new_npdn ) ) {
@@ -462,7 +551,9 @@ backsql_modrdn(
        if ( res != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
                        "could not lookup old parent entry id\n", 0, 0, 0 );
-               send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
+               send_ldap_result( conn, op, res, "", 
+                               res == LDAP_OTHER ? "SQL-backend error" : "",
+                               NULL, NULL );
                goto modrdn_return;
        }
 
@@ -473,7 +564,9 @@ backsql_modrdn(
        if ( res != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
                        "could not lookup new parent entry id\n", 0, 0, 0 );
-               send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
+               send_ldap_result( conn, op, res, "",
+                               res == LDAP_OTHER ? "SQL-backend error" : "",
+                               NULL, NULL );
                goto modrdn_return;
        }
        
@@ -483,6 +576,7 @@ backsql_modrdn(
  
        Debug(  LDAP_DEBUG_TRACE, "backsql_modrdn(): "
                "executing delentry_query\n", 0, 0, 0 );
+       SQLAllocStmt( dbh, &sth );
        SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
                        0, 0, &e_id.id, 0, 0 );
        rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS );
@@ -517,11 +611,82 @@ backsql_modrdn(
                goto modrdn_return;
        }
 
-       /*
-        * FIXME: should process deleteoldrdn here...
+       /* Get attribute type and attribute value of our new rdn, we will
+        * need to add that to our new entry
         */
+       if ( ldap_bv2rdn( newrdn, &new_rdn, (char **)&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
+               Debug( LDAP_DEBUG_TRACE,
+                       "backsql_modrdn: can't figure out "
+                       "type(s)/values(s) of newrdn\n", 
+                       0, 0, 0 );
+#endif
+               rc = LDAP_INVALID_DN_SYNTAX;
+               goto modrdn_return;
+       }
 
-       send_ldap_result( conn, op, LDAP_SUCCESS, "", NULL, NULL, NULL );
+#ifdef NEW_LOGGING
+       LDAP_LOG ( OPERATION, RESULTS, 
+               "backsql_modrdn: new_rdn_type=\"%s\", "
+               "new_rdn_val=\"%s\"\n",
+               new_rdn[ 0 ][ 0 ]->la_attr.bv_val, 
+               new_rdn[ 0 ][ 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 ][ 0 ]->la_attr.bv_val,
+               new_rdn[ 0 ][ 0 ]->la_value.bv_val, 0 );
+#endif
+
+       if ( deleteoldrdn ) {
+               if ( ldap_bv2rdn( dn, &old_rdn, (char **)&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
+                       Debug( LDAP_DEBUG_TRACE,
+                               "backsql_modrdn: can't figure out "
+                               "the old_rdn type(s)/value(s)\n", 
+                               0, 0, 0 );
+#endif
+                       rc = LDAP_OTHER;
+                       goto modrdn_return;             
+               }
+       }
+
+       res = slap_modrdn2mods( NULL, NULL, NULL, NULL, old_rdn, new_rdn, 
+                       deleteoldrdn, &mod );
+       if ( res != LDAP_SUCCESS ) {
+               goto modrdn_return;
+       }
+
+       oc = backsql_id2oc( bi, e_id.oc_id );
+       res = backsql_modify_internal( bi, dbh, oc, &e_id, mod );
+
+       if ( res != LDAP_SUCCESS ) {
+               goto modrdn_return;
+       }
+
+       /*
+        * Commit only if all operations succeed
+        *
+        * FIXME: backsql_modify_internal() does not fail 
+        * if add/delete operations are not available, or
+        * if a multiple value add actually results in a replace, 
+        * or if a single operation on an attribute fails for any
+        * reason
+        */
+       SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
 
 modrdn_return:
        SQLFreeStmt( sth, SQL_DROP );
@@ -534,6 +699,23 @@ modrdn_return:
                ch_free( new_ndn.bv_val );
        }
        
+       /* LDAP v2 supporting correct attribute handling. */
+       if ( new_rdn != NULL ) {
+               ldap_rdnfree( new_rdn );
+       }
+       if ( old_rdn != NULL ) {
+               ldap_rdnfree( old_rdn );
+       }
+       if( mod != NULL ) {
+               Modifications *tmp;
+               for (; mod; mod=tmp ) {
+                       tmp = mod->sml_next;
+                       free( mod );
+               }
+       }
+
+       send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
+
        Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );
        return 0;
 }
@@ -553,7 +735,7 @@ backsql_add(
        RETCODE                 rc;
        backsql_oc_map_rec      *oc = NULL;
        backsql_at_map_rec      *at_rec = NULL;
-       backsql_entryID         parent_id;
+       backsql_entryID         e_id, parent_id;
        int                     res;
        Attribute               *at;
        struct berval           *at_val;
@@ -567,12 +749,12 @@ backsql_add(
                        e->e_dn, 0, 0 );
 
        for ( at = e->e_attrs; at != NULL; at = at->a_next ) {
-#if 0
-               Debug( LDAP_DEBUG_TRACE, "backsql_add(): scanning entry "
-                       "-- %s\n", at->a_type, 0, 0 );
-#endif
-               if ( !strcasecmp( at->a_desc->ad_cname.bv_val, "objectclass" ) ) {
-                       oc = backsql_oc_with_name( bi, at->a_vals[ 0 ].bv_val );
+               if ( at->a_desc == slap_schema.si_ad_objectClass ) {
+                       /*
+                        * FIXME: only the objectClass provided first
+                        * is considered when creating a new entry
+                        */
+                       oc = backsql_name2oc( bi, &at->a_vals[ 0 ] );
                        break;
                }
        }
@@ -581,8 +763,9 @@ backsql_add(
                Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
                        "cannot determine objectclass of entry -- aborting\n",
                        0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                               "SQL-backend error", NULL, NULL );
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
+                               "operation not permitted within namingContext",
+                               NULL, NULL );
                return 1;
        }
 
@@ -590,33 +773,107 @@ backsql_add(
                Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
                        "create procedure is not defined for this objectclass "
                        "- aborting\n", 0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                               "SQL-backend error", NULL, NULL );
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
+                               "operation not permitted within namingContext",
+                               NULL, NULL );
                return 1;
        }
 
-       dbh = backsql_get_db_conn( be, conn );
-       if ( !dbh ) {
+       prc = backsql_get_db_conn( be, conn, &dbh );
+       if ( prc != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
                        "could not get connection handle - exiting\n", 
                        0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                               "SQL-backend error", NULL, NULL );
+               send_ldap_result( conn, op, prc, "",
+                               prc == LDAP_OTHER ?  "SQL-backend error" : "",
+                               NULL, NULL );
                return 1;
        }
 
+       /*
+        * Check if entry exists
+        */
+       res = backsql_dn2id( bi, &e_id, dbh, &e->e_name );
+       if ( res == LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
+                       "entry '%s' exists\n",
+                       e->e_name.bv_val, 0, 0 );
+               send_ldap_result( conn, op, LDAP_ALREADY_EXISTS, "", 
+                               NULL, NULL, NULL );
+               return 1;
+       }
+
+       /*
+        * Check if parent exists
+        */
+       dnParent( &e->e_name, &pdn );
+       res = backsql_dn2id( bi, &parent_id, dbh, &pdn );
+       if ( res != LDAP_SUCCESS ) {
+               
+               /*
+                * NO SUCH OBJECT seems more appropriate
+                */
+               Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
+                       "could not lookup parent entry for new record '%s'\n",
+                       pdn.bv_val, 0, 0 );
+
+               if ( res != LDAP_NO_SUCH_OBJECT ) {
+                       send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
+                       return 1;
+               }
+
+               /*
+                * Look for matched
+                */
+               while ( 1 ) {
+                       struct berval   dn;
+                       char            *matched = "";
+
+                       dn = pdn;
+                       dnParent( &dn, &pdn );
+
+                       /*
+                        * Empty DN ("") defaults to LDAP_SUCCESS
+                        */
+                       res = backsql_dn2id( bi, &parent_id, dbh, &pdn );
+                       switch ( res ) {
+                       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:
+                               send_ldap_result( conn, op, res, matched, 
+                                               NULL, NULL, NULL );
+                               return 1;
+                       } 
+               }
+       }
+
+       /*
+        * 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
+        */
+
 #ifndef BACKSQL_REALLOC_STMT
-       SQLAllocStmt( dbh, &sth );
+       rc = SQLAllocStmt( dbh, &sth );
 #else /* BACKSQL_REALLOC_STMT */
        rc = backsql_Prepare( dbh, &sth, oc->create_proc, 0 );
+#endif /* BACKSQL_REALLOC_STMT */
        if ( rc != SQL_SUCCESS ) {
                send_ldap_result( conn, op, LDAP_OTHER, "",
                                "SQL-backend error", NULL, NULL );
                return 1;
        }
-#endif /* BACKSQL_REALLOC_STMT */
 
-       if ( oc->expect_return ) {
+       if ( BACKSQL_IS_ADD( oc->expect_return ) ) {
                SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, 
                                SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
        }
@@ -638,10 +895,76 @@ backsql_add(
                return 1;
        }
 
-       if ( !oc->expect_return ) {
+       if ( !BACKSQL_IS_ADD( oc->expect_return ) ) {
+               SWORD           ncols;
+               SQLINTEGER      is_null;
+
                /*
-                * FIXME: need query to know the id of the inserted entry
+                * the query to know the id of the inserted entry
+                * must be embedded in the create procedure
                 */
+               rc = SQLNumResultCols( sth, &ncols );
+               if ( rc != SQL_SUCCESS ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
+                               "create_proc result evaluation failed\n",
+                               0, 0, 0 );
+                       backsql_PrintErrors( bi->db_env, dbh, sth, rc);
+                       SQLFreeStmt( sth, SQL_DROP );
+                       send_ldap_result( conn, op, LDAP_OTHER, "",
+                                       "SQL-backend error", NULL, NULL );
+                       return 1;
+
+               } else if ( ncols != 1 ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
+                               "create_proc result is bogus\n",
+                               0, 0, 0 );
+                       backsql_PrintErrors( bi->db_env, dbh, sth, rc);
+                       SQLFreeStmt( sth, SQL_DROP );
+                       send_ldap_result( conn, op, LDAP_OTHER, "",
+                                       "SQL-backend error", NULL, NULL );
+                       return 1;
+               }
+
+#if 0
+               {
+                       SQLCHAR         colname[ 64 ];
+                       SQLSMALLINT     name_len, col_type, col_scale, col_null;
+                       UDWORD          col_prec;
+
+                       /*
+                        * FIXME: check whether col_type is compatible,
+                        * if it can be null and so on ...
+                        */
+                       rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 
+                                       &colname[ 0 ], 
+                                       (SQLUINTEGER)( sizeof( colname ) - 1 ),
+                                       &name_len, &col_type,
+                                       &col_prec, &col_scale, &col_null );
+               }
+#endif
+
+               rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
+                               (SQLPOINTER)&new_keyval, 
+                               (SQLINTEGER)sizeof( new_keyval ), 
+                               &is_null );
+
+               rc = SQLFetch( sth );
+
+#if 0
+               /*
+                * FIXME: what does is_null mean?
+                */
+               if ( is_null ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
+                               "create_proc result is null\n",
+                               0, 0, 0 );
+                       backsql_PrintErrors( bi->db_env, dbh, sth, rc);
+                       SQLFreeStmt( sth, SQL_DROP );
+                       send_ldap_result( conn, op, LDAP_OTHER, "",
+                                       "SQL-backend error", NULL, NULL );
+                       return 1;
+               }
+#endif
        }
 
 #ifndef BACKSQL_REALLOC_STMT
@@ -649,6 +972,7 @@ backsql_add(
 #else /* BACKSQL_REALLOC_STMT */
        SQLFreeStmt( sth, SQL_DROP );
 #endif /* BACKSQL_REALLOC_STMT */
+
        Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
                "create_proc returned keyval=%ld\n", new_keyval, 0, 0 );
 
@@ -659,14 +983,14 @@ backsql_add(
                        continue;
                }
 
-               at_rec = backsql_at_with_name( oc, 
-                               at->a_desc->ad_cname.bv_val ); 
+               at_rec = backsql_ad2at( oc, at->a_desc ); 
   
                if ( at_rec == NULL ) {
                        Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
                                "attribute '%s' is not registered "
                                "in objectclass '%s'\n",
-                               at->a_desc->ad_cname.bv_val, oc->name, 0 );
+                               at->a_desc->ad_cname.bv_val,
+                               oc->name.bv_val, 0 );
                        continue;
                }
                
@@ -685,7 +1009,7 @@ backsql_add(
                }
 #endif /* BACKSQL_REALLOC_STMT */
 
-               if ( at_rec->expect_return & BACKSQL_ADD ) {
+               if ( BACKSQL_IS_ADD( at_rec->expect_return ) ) {
                        pno = 1;
                        SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT,
                                        SQL_C_ULONG, SQL_INTEGER,
@@ -694,7 +1018,7 @@ backsql_add(
                        pno = 0;
                }
 
-               po = ( at_rec->param_order & BACKSQL_ADD ) > 0;
+               po = ( BACKSQL_IS_ADD( at_rec->param_order ) ) > 0;
                currpos = pno + 1 + po;
                SQLBindParameter( sth, currpos,
                                SQL_PARAM_INPUT, SQL_C_ULONG,
@@ -712,10 +1036,15 @@ backsql_add(
 
                        backsql_BindParamStr( sth, currpos,
                                        at_val->bv_val, at_val->bv_len + 1 );
-
+#ifdef SECURITY_PARANOID
+                       Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
+                               "executing '%s', id=%ld\n", 
+                               at_rec->add_proc, new_keyval, 0 );
+#else
                        Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
                                "executing '%s' with val='%s', id=%ld\n", 
                                at_rec->add_proc, at_val->bv_val, new_keyval );
+#endif
 #ifndef BACKSQL_REALLOC_STMT
                        rc = SQLExecDirect( sth, at_rec->add_proc, SQL_NTS );
 #else /* BACKSQL_REALLOC_STMT */
@@ -735,18 +1064,6 @@ backsql_add(
 #endif /* BACKSQL_REALLOC_STMT */
        }
 
-       dnParent( &e->e_name, &pdn );
-       res = backsql_dn2id( bi, &parent_id, dbh, &pdn );
-       if ( res != LDAP_SUCCESS ) {
-               /*
-                * NO SUCH OBJECT seems more appropriate
-                */
-               Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
-                       "could not lookup parent entry for new record '%s'\n",
-                       pdn.bv_val, 0, 0 );
-               send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
-               return 1;
-       }
 #ifdef BACKSQL_REALLOC_STMT
        rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 );
        if ( rc != SQL_SUCCESS ) {
@@ -787,6 +1104,18 @@ backsql_add(
        }
        
        SQLFreeStmt( sth, SQL_DROP );
+
+       /*
+        * Commit only if all operations succeed
+        *
+        * FIXME: backsql_add() does not fail if add operations 
+        * are not available for some attributes, or if
+        * a multiple value add actually results in a replace, 
+        * or if a single operation on an attribute fails 
+        * for any reason
+        */
+       SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+
        send_ldap_result( conn, op, LDAP_SUCCESS, "",
                        NULL, NULL, NULL );
        return 0;
@@ -812,13 +1141,14 @@ backsql_delete(
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry '%s'\n",
                        ndn->bv_val, 0, 0 );
-       dbh = backsql_get_db_conn( be, conn );
-       if ( !dbh ) {
+       res = backsql_get_db_conn( be, conn, &dbh );
+       if ( res != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
                        "could not get connection handle - exiting\n", 
                        0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                               "SQL-backend error", NULL, NULL );
+               send_ldap_result( conn, op, res, "", 
+                               res == LDAP_OTHER ? "SQL-backend error" : "",
+                               NULL, NULL );
                return 1;
        }
        
@@ -830,7 +1160,7 @@ backsql_delete(
                return 1;
        }
 
-       oc = backsql_oc_with_id( bi, e_id.oc_id );
+       oc = backsql_id2oc( bi, e_id.oc_id );
        if ( oc == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
                        "cannot determine objectclass of entry "
@@ -844,13 +1174,14 @@ backsql_delete(
                Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
                        "delete procedure is not defined "
                        "for this objectclass - aborting\n", 0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                               "SQL-backend error", NULL, NULL );
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
+                               "operation not supported for required DN", 
+                               NULL, NULL );
                return 1;
        }
 
        SQLAllocStmt( dbh, &sth );
-       if ( oc->expect_return ) {
+       if ( BACKSQL_IS_DEL( oc->expect_return ) ) {
                pno = 1;
                SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG,
                                SQL_INTEGER, 0, 0, &rc, 0, 0 );
@@ -860,10 +1191,6 @@ backsql_delete(
 
        SQLBindParameter( sth, pno + 1, SQL_PARAM_INPUT, 
                        SQL_C_ULONG, SQL_INTEGER, 0, 0, &e_id.keyval, 0, 0 );
-#if 0
-       SQLBindParameter( sth, 2, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER,
-                       0, 0, &retcode, 0, 0 );
-#endif
 
        Debug( LDAP_DEBUG_TRACE, "backsql_delete(): executing '%s'\n",
                        oc->delete_proc, 0, 0 );
@@ -877,7 +1204,12 @@ backsql_delete(
                                "SQL-backend error", NULL, NULL );
                return 1;
        }
+#ifndef BACKSQL_REALLOC_STMT
        SQLFreeStmt( sth, SQL_RESET_PARAMS );
+#else /* BACKSQL_REALLOC_STMT */
+       SQLFreeStmt( sth, SQL_DROP );
+       SQLAllocStmt( dbh, &sth );
+#endif /* BACKSQL_REALLOC_STMT */
 
        SQLBindParameter( sth, 1, SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER,
                        0, 0, &e_id.id, 0, 0 );
@@ -894,6 +1226,18 @@ backsql_delete(
        }
        
        SQLFreeStmt( sth, SQL_DROP );
+
+       /*
+        * Commit only if all operations succeed
+        *
+        * FIXME: backsql_add() does not fail if add operations 
+        * are not available for some attributes, or if
+        * a multiple value add actually results in a replace, 
+        * or if a single operation on an attribute fails 
+        * for any reason
+        */
+       SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
+
        send_ldap_result( conn, op, LDAP_SUCCESS, "", NULL, NULL, NULL );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 );
        return 0;
index 62dcbe81509a666c9437b6193058876e23bb3af9..57c16d546e0abe264ebd7864f68340c1f1ed0b04 100644 (file)
 #include "back-sql.h"
 #include "sql-wrap.h"
 
-int
-backsql_dummy( void )
-{
-       return 0;
-}
-
 int
 backsql_compare(
        BackendDB       *bd,
index 22f6acc84084424f0a28239bbf85b3717d009a0a..65aea733cb596f86d3bcc3e36024eef2b7a954fd 100644 (file)
@@ -1,7 +1,8 @@
 drop table ldap_oc_mappings;
+drop sequence ldap_oc_mappings_id_seq;
 create table ldap_oc_mappings
  (
-       id integer not null primary key,
+       id serial not null primary key,
        name varchar(64) not null,
        keytbl varchar(64) not null,
        keycol varchar(64) not null,
@@ -11,9 +12,10 @@ create table ldap_oc_mappings
 );
 
 drop table ldap_attr_mappings;
+drop sequence ldap_attr_mappings_id_seq;
 create table ldap_attr_mappings
  (
-       id integer not null primary key,
+       id serial not null primary key,
        oc_map_id integer not null references ldap_oc_mappings(id),
        name varchar(255) not null,
        sel_expr varchar(255) not null,
@@ -27,9 +29,10 @@ create table ldap_attr_mappings
 );
 
 drop table ldap_entries;
+drop sequence ldap_entries_id_seq;
 create table ldap_entries
  (
-       id integer not null primary key,
+       id serial not null primary key,
        dn varchar(255) not null,
        oc_map_id integer not null references ldap_oc_mappings(id),
        parent int NOT NULL,
@@ -52,9 +55,3 @@ create table ldap_entry_objclasses
        oc_name varchar(64)
  );
 
------ Apparently PostgreSQL 7.0 does not know concat(); however,
------ back-sql can be configured to use '||' for string concatenation.
------ Those who can't live without concat() can uncomment this:
--- drop function concat(text, text);
--- create function concat(text, text) returns text as 'select $1 || $2;' language 'sql';
-
index 904d51b02cd58bcbbe61972ef05d434577728de1..6a3c0f7f665530f3273b5585464b0152ede07e5b 100644 (file)
@@ -1,37 +1,38 @@
 drop table persons;
-CREATE TABLE persons (
-       id int NOT NULL,
-       name varchar(255) NOT NULL,
-       PRIMARY KEY ( id )
+drop sequence persons_id_seq;
+create table persons (
+       id serial not null primary key,
+       name varchar(255) not null,
+       surname varchar(255) not null
 );
 
 drop table institutes;
-CREATE TABLE institutes (
-       id int NOT NULL,
-       name varchar(255),
-       PRIMARY KEY ( id )
+drop sequence institutes_id_seq;
+create table institutes (
+       id serial not null primary key,
+       name varchar(255)
 );
 
 drop table documents;
-CREATE TABLE documents (
-       id int NOT NULL,
-       title varchar(255) NOT NULL,
-       abstract varchar(255),
-       PRIMARY KEY ( id )
+drop sequence documents_id_seq;
+create table documents (
+       id serial not null primary key,
+       title varchar(255) not null,
+       abstract varchar(255)
 );
 
 drop table authors_docs;
-CREATE TABLE authors_docs (
-       pers_id int NOT NULL,
-       doc_id int NOT NULL,
-       PRIMARY KEY ( pers_id, doc_id )
+create table authors_docs (
+       pers_id int not null,
+       doc_id int not null,
+       primary key ( pers_id, doc_id )
 );
 
 drop table phones;
-CREATE TABLE phones (
-       id int NOT NULL ,
-       phone varchar(255) NOT NULL ,
-       pers_id int NOT NULL,
-       PRIMARY KEY ( id )
+drop sequence phones_id_seq;
+create table phones (
+       id serial not null primary key,
+       phone varchar(255) not null ,
+       pers_id int not null
 );
 
index f141f414eb0881a0cc33802d3ae5c786e5c37f44..b20733da0e3553d1208c6713210835244c63d9f7 100644 (file)
@@ -1,8 +1,8 @@
 insert into institutes (id,name) values (1,'sql');
 
-insert into persons (id,name) values (1,'Mitya Kovalev');
-insert into persons (id,name) values (2,'Torvlobnor Puzdoy');
-insert into persons (id,name) values (3,'Akakiy Zinberstein');
+insert into persons (id,name,surname) values (1,'Mitya','Kovalev');
+insert into persons (id,name,surname) values (2,'Torvlobnor','Puzdoy');
+insert into persons (id,name,surname) values (3,'Akakiy','Zinberstein');
 
 insert into phones (id,phone,pers_id) values (1,'332-2334',1);
 insert into phones (id,phone,pers_id) values (2,'222-3234',1);
@@ -14,3 +14,4 @@ insert into documents (id,abstract,title) values (2,'abstract2','book2');
 insert into authors_docs (pers_id,doc_id) values (1,1);
 insert into authors_docs (pers_id,doc_id) values (1,2);
 insert into authors_docs (pers_id,doc_id) values (2,1);
+
index 11e9b632e52b5ea01575af174c31f64eb05ca23f..7100a26884c80504a91a6c2d6b7739c561eedcdc 100644 (file)
@@ -1,17 +1,18 @@
 --mappings 
 
-insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,delete_proc,expect_return) values (1,'inetOrgPerson','persons','id','select create_person()',NULL,0);
+insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,delete_proc,expect_return) values (1,'inetOrgPerson','persons','id','select create_person()','select delete_person(?)',0);
 
 insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,delete_proc,expect_return) values (2,'document','documents','id',NULL,NULL,0);
 
 insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,delete_proc,expect_return) values (3,'organization','institutes','id',NULL,NULL,0);
 
 
-insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (1,1,'cn','persons.name','persons',NULL,'update persons set name=? where id=?',NULL,3,0);
+insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (1,1,'cn','text(persons.name||'' ''||persons.surname)','persons',NULL,'select update_person_cn(?,?)',NULL,3,0);
 
-insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (2,1,'telephoneNumber','phones.phone','persons,phones','phones.pers_id=persons.id',NULL,NULL,3,0);
+insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (2,1,'telephoneNumber','phones.phone','persons,phones','phones.pers_id=persons.id','select add_phone(?,?)','select delete_phone(?,?)',3,0);
 
-insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (3,1,'sn','persons.name','persons',NULL,NULL,NULL,3,0);
+insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (3,1,'givenName','persons.name','persons',NULL,'update persons set name=? where id=?',NULL,3,0);
+insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (6,1,'sn','persons.surname','persons',NULL,'update persons set surname=? where id=?',NULL,3,0);
 
 insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (4,2,'description','documents.abstract','documents',NULL,NULL,NULL,3,0);
 
@@ -24,7 +25,7 @@ insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,
 
 insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (7,3,'o','institutes.name','institutes',NULL,NULL,NULL,3,0);
 
-insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (8,1,'documentDN','ldap_entries.dn','ldap_entries,documents,authors_docs,persons','ldap_entries.keyval=documents.id AND ldap_entries.oc_map_id=2 AND authors_docs.doc_id=documents.id AND authors_docs.pers_id=persons.id',NULL,NULL,3,0);
+insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (8,1,'documentIdentifier','ldap_entries.dn','ldap_entries,documents,authors_docs,persons','ldap_entries.keyval=documents.id AND ldap_entries.oc_map_id=2 AND authors_docs.doc_id=documents.id AND authors_docs.pers_id=persons.id',NULL,NULL,3,0);
 
 insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,add_proc,delete_proc,param_order,expect_return) values (9,2,'documentAuthor','ldap_entries.dn','ldap_entries,documents,authors_docs,persons','ldap_entries.keyval=persons.id AND ldap_entries.oc_map_id=1 AND authors_docs.doc_id=documents.id AND authors_docs.pers_id=persons.id',NULL,NULL,3,0);
        
@@ -52,7 +53,48 @@ insert into ldap_referrals (entry_id,url) values (4,'http://localhost');
 -- procedures
 
 create function create_person () returns int
-       as 'insert into persons (id,name) values ((select max(id)+1 from persons),'''');
-       select max(id) from persons'
-language 'sql';
+as '
+       select setval (''persons_id_seq'', (select max(id) from persons));
+       insert into persons (id,name,surname) 
+               values (nextval(''persons_id_seq''),'''','''');
+       select max(id) from persons
+' language 'sql';
+
+create function update_person_cn (varchar, int) returns int
+as '
+       update persons set name = (
+               select case 
+                       when position('' '' in $1) = 0 then $1 
+                       else substr($1, 1, position('' '' in $1) - 1)
+               end
+       ),surname = (
+               select case 
+                       when position('' '' in $1) = 0 then ''''
+                       else substr($1, position('' '' in $1) + 1) 
+               end
+       ) where id = $2;
+       select $2 as return
+' language 'sql';
+
+create function delete_person (int) returns int
+as '
+       delete from phones where pers_id = $1;
+       delete from authors_docs where pers_id = $1;
+       delete from persons where id = $1;
+       select $1 as return
+' language 'sql';
+
+create function add_phone (varchar, int) returns int
+as '
+       select setval (''phones_id_seq'', (select max(id) from phones));
+       insert into phones (id,phone,pers_id)
+               values (nextval(''phones_id_seq''),$1,$2);
+       select max(id) from phones
+' language 'sql';
+
+create function delete_phone (varchar, int) returns int
+as '
+       delete from phones where phone = $1 and pers_id = $2;
+       select $2 as result
+' language 'sql';
 
index 2598849c481ec4c01562101b016b7532a4f1411a..cf765adc93466d78f48f750c87b262e4d2500e00 100644 (file)
 #include <sys/types.h>
 #include <string.h>
 #include "slap.h"
+#include "ldap_pvt.h"
 #include "back-sql.h"
 #include "sql-wrap.h"
 #include "schema-map.h"
 #include "util.h"
 
-int backsql_dummy( void *, void * );
-
-int
+/*
+ * Deprecated
+ */
+#if 0
+static int
 backsql_cmp_oc_name( backsql_oc_map_rec *m1, backsql_oc_map_rec *m2 )
 {
-       return strcasecmp( m1->name, m2->name );
+       return BACKSQL_NCMP( &m1->name, &m2->name );
 }
+#endif
 
-int
+/*
+ * Uses the pointer to the ObjectClass structure
+ */
+static int
+backsql_cmp_oc( backsql_oc_map_rec *m1, backsql_oc_map_rec *m2 )
+{
+       return ( m1->oc < m2->oc ? -1 : ( m1->oc > m2->oc ? 1 : 0 ) );
+}
+
+static int
 backsql_cmp_oc_id( backsql_oc_map_rec *m1, backsql_oc_map_rec *m2 )
 {
-       if ( m1->id < m2->id ) {
-               return -1;
-       }
-       if ( m1->id > m2->id ) {
-               return 1;
-       }
-       return 0;
+       return ( m1->id < m2->id ? -1 : ( m1->id > m2->id ? 1 : 0 ) );
 }
 
-int
-backsql_cmp_attr( 
-       backsql_at_map_rec      *m1, 
-       backsql_at_map_rec      *m2 )
+/*
+ * Deprecated
+ */
+#if 0
+static int
+backsql_cmp_attr_name( backsql_at_map_rec *m1, backsql_at_map_rec *m2 )
 {
-       return strcasecmp( m1->name, m2->name );
+       return BACKSQL_NCMP( &m1->name, &m2->name );
 }
+#endif
 
-char *
+/*
+ * Uses the pointer to the AttributeDescription structure
+ */
+static int
+backsql_cmp_attr( backsql_at_map_rec *m1, backsql_at_map_rec *m2 )
+{
+       return ( m1->ad < m2->ad ? -1 : ( m1->ad > m2->ad ? 1 : 0 ) );
+}
+
+static int
 backsql_make_attr_query( 
        backsql_oc_map_rec      *oc_map,
        backsql_at_map_rec      *at_map )
@@ -57,7 +76,8 @@ backsql_make_attr_query(
        int             tmpslen = 0;
 
        backsql_strcat( &tmps, &tmpslen, "SELECT ", at_map->sel_expr, 
-                       " AS ", at_map->name, " FROM ", at_map->from_tbls,
+                       " AS ", at_map->name.bv_val, 
+                       " FROM ", at_map->from_tbls,
                        " WHERE ", oc_map->keytbl,".", oc_map->keycol,
                        "=?", NULL );
        if ( at_map->join_where != NULL ) {
@@ -67,10 +87,10 @@ backsql_make_attr_query(
 
        at_map->query = tmps.bv_val;
        
-       return at_map->query;
+       return 0;
 }
 
-int
+static int
 backsql_add_sysmaps( backsql_oc_map_rec *oc_map )
 {
        backsql_at_map_rec      *at_map;
@@ -82,11 +102,13 @@ backsql_add_sysmaps( backsql_oc_map_rec *oc_map )
 
        at_map = (backsql_at_map_rec *)ch_calloc(1, 
                        sizeof( backsql_at_map_rec ) );
-       at_map->name = ch_strdup( "objectClass" );
+       at_map->ad = slap_schema.si_ad_objectClass;
+       ber_dupbv( &at_map->name, &at_map->ad->ad_cname );
        at_map->sel_expr = ch_strdup( "ldap_entry_objclasses.oc_name" );
        at_map->from_tbls = ch_strdup( "ldap_entry_objclasses,ldap_entries" );
        len = strlen( at_map->from_tbls );
        backsql_merge_from_clause( &at_map->from_tbls, &len, oc_map->keytbl );
+
        len = 0;
        bv.bv_val = NULL;
        bv.bv_len = 0;
@@ -96,25 +118,24 @@ backsql_add_sysmaps( backsql_oc_map_rec *oc_map )
                        oc_map->keytbl, ".", oc_map->keycol,
                        " and ldap_entries.oc_map_id=", s, NULL );
        at_map->join_where = bv.bv_val;
+
        at_map->add_proc = NULL;
        at_map->delete_proc = NULL;
        at_map->param_order = 0;
        at_map->expect_return = 0;
        backsql_make_attr_query( oc_map, at_map );
        avl_insert( &oc_map->attrs, at_map, 
-                       (AVL_CMP)backsql_cmp_attr, backsql_dummy );
+                       (AVL_CMP)backsql_cmp_attr, NULL );
 
        at_map = (backsql_at_map_rec *)ch_calloc( 1, 
                        sizeof( backsql_at_map_rec ) );
-       at_map->name = ch_strdup( "ref" );
+       at_map->ad = slap_schema.si_ad_ref;
+       ber_dupbv( &at_map->name, &at_map->ad->ad_cname );
        at_map->sel_expr = ch_strdup( "ldap_referrals.url" );
        at_map->from_tbls = ch_strdup( "ldap_referrals,ldap_entries" );
        len = strlen( at_map->from_tbls );
        backsql_merge_from_clause( &at_map->from_tbls, &len,oc_map->keytbl );
 
-       /* FIXME: no free? */
-       at_map->join_where = NULL;
-
        len = 0;
        bv.bv_val = NULL;
        bv.bv_len = 0;
@@ -124,13 +145,14 @@ backsql_add_sysmaps( backsql_oc_map_rec *oc_map )
                        oc_map->keytbl, ".", oc_map->keycol,
                        " and ldap_entries.oc_map_id=", s, NULL );
        at_map->join_where = bv.bv_val;
+
        at_map->add_proc = NULL;
        at_map->delete_proc = NULL;
        at_map->param_order = 0;
        at_map->expect_return = 0;
        backsql_make_attr_query( oc_map, at_map );
        avl_insert( &oc_map->attrs, at_map, 
-                       (AVL_CMP)backsql_cmp_attr, backsql_dummy );
+                       (AVL_CMP)backsql_cmp_attr, NULL );
 
        return 1;
 }
@@ -173,7 +195,7 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                        "error preparing oc_query: '%s'\n", 
                        si->oc_query, 0, 0 );
                backsql_PrintErrors( si->db_env, dbh, oc_sth, rc );
-               return -1;
+               return LDAP_OTHER;
        }
        Debug( LDAP_DEBUG_TRACE, "load_schema_map(): at_query '%s'\n", 
                        si->at_query, 0, 0 );
@@ -184,7 +206,7 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                        "error preparing at_query: '%s'\n", 
                        si->at_query, 0, 0 );
                backsql_PrintErrors( si->db_env, dbh, at_sth, rc );
-               return -1;
+               return LDAP_OTHER;
        }
 
        rc = backsql_BindParamID( at_sth, 1, &oc_id );
@@ -192,7 +214,7 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                        "error binding param for at_query: \n", 0, 0, 0 );
                backsql_PrintErrors( si->db_env, dbh, at_sth, rc );
-               return -1;
+               return LDAP_OTHER;
        }
 
        rc = SQLExecute( oc_sth );
@@ -200,7 +222,7 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                        "error executing oc_query: \n", 0, 0, 0 );
                backsql_PrintErrors( si->db_env, dbh, oc_sth, rc );
-               return -1;
+               return LDAP_OTHER;
        }
 
        backsql_BindRowAsStrings( oc_sth, &oc_row );
@@ -208,8 +230,18 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
        for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( oc_sth ) ) {
                oc_map = (backsql_oc_map_rec *)ch_calloc( 1,
                                sizeof( backsql_oc_map_rec ) );
+
                oc_map->id = atoi( oc_row.cols[ 0 ] );
-               oc_map->name = ch_strdup( oc_row.cols[ 1 ] );
+
+               ber_str2bv( oc_row.cols[ 1 ], 0, 1, &oc_map->name );
+               oc_map->oc = oc_bvfind( &oc_map->name );
+               if ( oc_map->oc == NULL ) {
+                       Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
+                               "objectClass '%s' is not defined in schema\n", 
+                               oc_map->name.bv_val, 0, 0 );
+                       return LDAP_OTHER;      /* undefined objectClass ? */
+               }
+               
                oc_map->keytbl = ch_strdup( oc_row.cols[ 2 ] );
                oc_map->keycol = ch_strdup( oc_row.cols[ 3 ] );
                oc_map->create_proc = ( oc_row.is_null[ 4 ] < 0 ) ? NULL 
@@ -224,24 +256,26 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                 */
 
                oc_map->attrs = NULL;
-               avl_insert( &si->oc_by_name, oc_map,
-                               (AVL_CMP)backsql_cmp_oc_name, backsql_dummy );
+               avl_insert( &si->oc_by_oc, oc_map,
+                               (AVL_CMP)backsql_cmp_oc, NULL );
                avl_insert( &si->oc_by_id, oc_map,
-                               (AVL_CMP)backsql_cmp_oc_id, backsql_dummy );
+                               (AVL_CMP)backsql_cmp_oc_id, NULL );
                oc_id = oc_map->id;
                Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                        "objectClass '%s': keytbl='%s' keycol='%s'\n",
-                       oc_map->name, oc_map->keytbl, oc_map->keycol );
-               if ( oc_map->delete_proc ) {
-                       Debug( LDAP_DEBUG_TRACE, "delete_proc='%s'\n", 
-                               oc_map->delete_proc, 0, 0 );
-               }
+                       oc_map->name.bv_val, oc_map->keytbl, oc_map->keycol );
                if ( oc_map->create_proc ) {
                        Debug( LDAP_DEBUG_TRACE, "create_proc='%s'\n",
                                oc_map->create_proc, 0, 0 );
                }
-               Debug( LDAP_DEBUG_TRACE, "expect_return=%d; attributes:\n",
-                       oc_map->expect_return, 0, 0 );
+               if ( oc_map->delete_proc ) {
+                       Debug( LDAP_DEBUG_TRACE, "delete_proc='%s'\n", 
+                               oc_map->delete_proc, 0, 0 );
+               }
+               Debug( LDAP_DEBUG_TRACE, "expect_return: "
+                       "add=%s, del=%s; attributes:\n",
+                       BACKSQL_IS_ADD( oc_map->expect_return ), 
+                       BACKSQL_IS_DEL( oc_map->expect_return ), 0 );
 
                Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                        "autoadding 'objectClass' and 'ref' mappings\n",
@@ -252,12 +286,14 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                        Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                                "error executing at_query: \n", 0, 0, 0 );
                        backsql_PrintErrors( SQL_NULL_HENV, dbh, at_sth, rc );
-                       return -1;
+                       return LDAP_OTHER;
                }
 
                backsql_BindRowAsStrings( at_sth, &at_row );
                rc = SQLFetch( at_sth );
                for ( ; BACKSQL_SUCCESS(rc); rc = SQLFetch( at_sth ) ) {
+                       const char      *text = NULL;
+
                        Debug( LDAP_DEBUG_TRACE, "********'%s'\n",
                                at_row.cols[ 0 ], 0, 0 );
                        Debug( LDAP_DEBUG_TRACE, 
@@ -274,7 +310,17 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                                        at_row.cols[ 8 ], 0, 0 );
                        at_map = (backsql_at_map_rec *)ch_calloc( 1,
                                        sizeof( backsql_at_map_rec ) );
-                       at_map->name = ch_strdup( at_row.cols[ 0 ] );
+                       ber_str2bv( at_row.cols[ 0 ], 0, 1, &at_map->name );
+                       rc = slap_bv2ad( &at_map->name, &at_map->ad, &text );
+                       if ( rc != LDAP_SUCCESS ) {
+                               Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
+                                       "attribute '%s' for objectClass '%s' "
+                                       "is not defined in schema: %s\n", 
+                                       at_map->name.bv_val, 
+                                       oc_map->name.bv_val, text );
+                               return LDAP_CONSTRAINT_VIOLATION;
+                       }
+                               
                        at_map->sel_expr = ch_strdup( at_row.cols[ 1 ] );
                        at_map->sel_expr_u = ( at_row.is_null[ 8 ] < 0 ) ? NULL
                                : ch_strdup( at_row.cols[ 8 ] );
@@ -296,8 +342,7 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                                "preconstructed query '%s'\n",
                                at_map->query, 0, 0 );
                        avl_insert( &oc_map->attrs, at_map, 
-                                       (AVL_CMP)backsql_cmp_attr,
-                                       backsql_dummy );
+                                       (AVL_CMP)backsql_cmp_attr, NULL );
                }
                backsql_FreeRow( &at_row );
                SQLFreeStmt( at_sth, SQL_CLOSE );
@@ -307,11 +352,41 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
        SQLFreeStmt( oc_sth, SQL_DROP );
        si->schema_loaded = 1;
        Debug( LDAP_DEBUG_TRACE, "<==load_schema_map()\n", 0, 0, 0 );
-       return 1;
+       return LDAP_SUCCESS;
 }
 
 backsql_oc_map_rec *
-backsql_oc_with_name( backsql_info *si, char *objclass )
+backsql_oc2oc( backsql_info *si, ObjectClass *oc )
+{
+       backsql_oc_map_rec      tmp, *res;
+
+#if 0
+       Debug( LDAP_DEBUG_TRACE, "==>backsql_oc2oc(): "
+               "searching for objectclass with name='%s'\n",
+               objclass, 0, 0 );
+#endif
+
+       tmp.oc = oc;
+       res = (backsql_oc_map_rec *)avl_find( si->oc_by_oc, &tmp,
+                       (AVL_CMP)backsql_cmp_oc );
+#if 0
+       if ( res != NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
+                       "found name='%s', id=%d\n", res->name, res->id, 0 );
+       } else {
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
+                       "not found\n", 0, 0, 0 );
+       }
+#endif
+       return res;
+}
+
+/*
+ * Deprecated
+ */
+backsql_oc_map_rec *
+backsql_name2oc( backsql_info *si, struct berval *oc_name )
 {
        backsql_oc_map_rec      tmp, *res;
 
@@ -320,10 +395,14 @@ backsql_oc_with_name( backsql_info *si, char *objclass )
                "searching for objectclass with name='%s'\n",
                objclass, 0, 0 );
 #endif
-       
-       tmp.name = objclass;
-       res = (backsql_oc_map_rec *)avl_find( si->oc_by_name, &tmp,
-                       (AVL_CMP)backsql_cmp_oc_name );
+
+       tmp.oc = oc_bvfind( oc_name );
+       if ( tmp.oc == NULL ) {
+               return NULL;
+       }
+
+       res = (backsql_oc_map_rec *)avl_find( si->oc_by_oc, &tmp,
+                       (AVL_CMP)backsql_cmp_oc );
 #if 0
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
@@ -338,7 +417,7 @@ backsql_oc_with_name( backsql_info *si, char *objclass )
 }
 
 backsql_oc_map_rec *
-backsql_oc_with_id( backsql_info *si, unsigned long id )
+backsql_id2oc( backsql_info *si, unsigned long id )
 {
        backsql_oc_map_rec      tmp, *res;
  
@@ -365,26 +444,26 @@ backsql_oc_with_id( backsql_info *si, unsigned long id )
 }
 
 backsql_at_map_rec *
-backsql_at_with_name( backsql_oc_map_rec* objclass, char *attr )
+backsql_ad2at( backsql_oc_map_rec* objclass, AttributeDescription *ad )
 {
        backsql_at_map_rec      tmp, *res;
  
 #if 0
-       Debug( LDAP_DEBUG_TRACE, "==>at_with_name(): "
+       Debug( LDAP_DEBUG_TRACE, "==>backsql_ad2at(): "
                "searching for attribute '%s' for objectclass '%s'\n",
                attr, objclass->name, 0 );
 #endif
-       tmp.name = attr;
+       tmp.ad = ad;
        res = (backsql_at_map_rec *)avl_find( objclass->attrs, &tmp,
                        (AVL_CMP)backsql_cmp_attr );
 
 #if 0
        if ( res != NULL ) {
-               Debug( LDAP_DEBUG_TRACE, "<==at_with_name(): "
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
                        "found name='%s', sel_expr='%s'\n",
                        res->name, res->sel_expr, 0 );
        } else {
-               Debug( LDAP_DEBUG_TRACE, "<==at_with_name(): "
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
                        "not found\n", 0, 0, 0 );
        }
 #endif
@@ -392,11 +471,48 @@ backsql_at_with_name( backsql_oc_map_rec* objclass, char *attr )
        return res;
 }
 
-int
+/*
+ * Deprecated
+ */
+backsql_at_map_rec *
+backsql_name2at( backsql_oc_map_rec* objclass, struct berval *attr )
+{
+       backsql_at_map_rec      tmp, *res;
+       const char              *text = NULL;
+#if 0
+       Debug( LDAP_DEBUG_TRACE, "==>backsql_name2at(): "
+               "searching for attribute '%s' for objectclass '%s'\n",
+               attr, objclass->name, 0 );
+#endif
+
+       if ( slap_bv2ad( attr, &tmp.ad, &text ) != LDAP_SUCCESS ) {
+               return NULL;
+       }
+
+       res = (backsql_at_map_rec *)avl_find( objclass->attrs, &tmp,
+                       (AVL_CMP)backsql_cmp_attr );
+
+#if 0
+       if ( res != NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_name2at(): "
+                       "found name='%s', sel_expr='%s'\n",
+                       res->name, res->sel_expr, 0 );
+       } else {
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_name2at(): "
+                       "not found\n", 0, 0, 0 );
+       }
+#endif
+
+       return res;
+}
+
+static void
 backsql_free_attr( backsql_at_map_rec *at )
 {
-       Debug( LDAP_DEBUG_TRACE, "==>free_attr(): '%s'\n", at->name, 0, 0 );
-       ch_free( at->name );
+       Debug( LDAP_DEBUG_TRACE, "==>free_attr(): '%s'\n", 
+                       at->name.bv_val, 0, 0 );
+       ch_free( at->name.bv_val );
        ch_free( at->sel_expr );
        if ( at->from_tbls != NULL ) {
                ch_free( at->from_tbls );
@@ -413,24 +529,24 @@ backsql_free_attr( backsql_at_map_rec *at )
        if ( at->query ) {
                ch_free( at->query );
        }
-       ch_free( at );
 
        /* TimesTen */
        if ( at->sel_expr_u ) {
                ch_free( at->sel_expr_u );
        }
        
-       Debug( LDAP_DEBUG_TRACE, "<==free_attr()\n", 0, 0, 0 );
+       ch_free( at );
 
-       return 1;
+       Debug( LDAP_DEBUG_TRACE, "<==free_attr()\n", 0, 0, 0 );
 }
 
-int
+static void
 backsql_free_oc( backsql_oc_map_rec *oc )
 {
-       Debug( LDAP_DEBUG_TRACE, "==>free_oc(): '%s'\n", oc->name, 0, 0 );
+       Debug( LDAP_DEBUG_TRACE, "==>free_oc(): '%s'\n", 
+                       oc->name.bv_val, 0, 0 );
        avl_free( oc->attrs, (AVL_FREE)backsql_free_attr );
-       ch_free( oc->name );
+       ch_free( oc->name.bv_val );
        ch_free( oc->keytbl );
        ch_free( oc->keycol );
        if ( oc->create_proc != NULL ) {
@@ -442,15 +558,14 @@ backsql_free_oc( backsql_oc_map_rec *oc )
        ch_free( oc );
 
        Debug( LDAP_DEBUG_TRACE, "<==free_oc()\n", 0, 0, 0 );
-       return 1;
 }
 
 int
 backsql_destroy_schema_map( backsql_info *si )
 {
        Debug( LDAP_DEBUG_TRACE, "==>destroy_schema_map()\n", 0, 0, 0 );
+       avl_free( si->oc_by_oc, NULL );
        avl_free( si->oc_by_id, (AVL_FREE)backsql_free_oc );
-       avl_free( si->oc_by_name, (AVL_FREE)backsql_dummy );
        Debug( LDAP_DEBUG_TRACE, "<==destroy_schema_map()\n", 0, 0, 0 );
        return 0;
 }
index 7747f59b9442a692277179a4d93b72bffb11937d..27f07278ef8034c934306c4bc87158c558b4abbe 100644 (file)
@@ -12,7 +12,8 @@
 
 
 typedef struct {
-       char            *name;
+       struct berval   name;
+       ObjectClass     *oc;
        char            *keytbl;
        char            *keycol;
        /* expected to return keyval of newly created entry */
@@ -29,7 +30,8 @@ typedef struct {
 
 typedef struct {
        /* literal name of corresponding LDAP attribute type */
-       char            *name;
+       struct berval   name;
+       AttributeDescription    *ad;
        char            *from_tbls;
        char            *join_where;
        char            *sel_expr;
@@ -56,14 +58,24 @@ typedef struct {
 } backsql_at_map_rec;
 
 /* defines to support bitmasks above */
-#define BACKSQL_ADD    1
-#define BACKSQL_DEL    2
+#define BACKSQL_ADD    0x1
+#define BACKSQL_DEL    0x2
+
+#define BACKSQL_IS_ADD(x)      ( BACKSQL_ADD & (x) )
+#define BACKSQL_IS_DEL(x)      ( BACKSQL_DEL & (x) )
+
+#define BACKSQL_NCMP(v1,v2)    ber_bvcmp((v1),(v2))
 
 int backsql_load_schema_map( backsql_info *si, SQLHDBC dbh );
-backsql_oc_map_rec *backsql_oc_with_name( backsql_info *si, char *objclass );
-backsql_oc_map_rec *backsql_oc_with_id( backsql_info *si, unsigned long id );
-backsql_at_map_rec *backsql_at_with_name( backsql_oc_map_rec *objclass,
-               char *attr );
+/* Deprecated */
+backsql_oc_map_rec *backsql_name2oc( backsql_info *si, struct berval *oc_name );
+backsql_oc_map_rec *backsql_oc2oc( backsql_info *si, ObjectClass *oc );
+backsql_oc_map_rec *backsql_id2oc( backsql_info *si, unsigned long id );
+/* Deprecated */
+backsql_at_map_rec *backsql_name2at( backsql_oc_map_rec *objclass,
+               struct berval *at_name );
+backsql_at_map_rec *backsql_ad2at( backsql_oc_map_rec *objclass,
+               AttributeDescription *ad );
 int backsql_destroy_schema_map( backsql_info *si );
 
 #endif /* __BACKSQL_SCHEMA_MAP_H__ */
index dff51d5d28f03530a1597b03cbebefcb688496d0..b8f5e143b0cb368e1fb967405f28f4f15975e7b5 100644 (file)
 
 static struct berval AllUser = BER_BVC( LDAP_ALL_USER_ATTRIBUTES );
 static struct berval AllOper = BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES );
+static struct berval NoAttrs = BER_BVC( LDAP_NO_ATTRS );
+
 #if 0
 static struct berval NoAttrs = BER_BVC( LDAP_NO_ATTRS );
 #endif
 
 static int
-backsql_attrlist_add( backsql_srch_info *bsi, struct berval *at_name )
+backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
 {
-       int     n_attrs = 0;
-       char    **tmp;
+       int             n_attrs = 0;
+       AttributeName   *an = NULL;
 
        if ( bsi->attrs == NULL ) {
                return 1;
        }
 
-       for ( ; bsi->attrs[ n_attrs ]; n_attrs++ ) {
+       for ( ; bsi->attrs[ n_attrs ].an_name.bv_val; n_attrs++ ) {
+               an = &bsi->attrs[ n_attrs ];
+               
                Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
                        "attribute '%s' is in list\n", 
-                       bsi->attrs[ n_attrs ], 0, 0 );
+                       an->an_name.bv_val, 0, 0 );
                /*
                 * We can live with strcmp because the attribute 
                 * list has been normalized before calling be_search
                 */
-               if ( !strcmp( bsi->attrs[ n_attrs ], at_name->bv_val ) ) {
+               if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) {
                        return 1;
                }
        }
        
        Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
-               "adding '%s' to list\n", at_name->bv_val, 0, 0 );
-       tmp = (char **)ch_realloc( bsi->attrs, (n_attrs + 2)*sizeof( char * ) );
-       if ( tmp == NULL ) {
+               "adding '%s' to list\n", ad->ad_cname.bv_val, 0, 0 );
+
+       an = (AttributeName *)ch_realloc( bsi->attrs,
+                       sizeof( AttributeName ) * ( n_attrs + 2 ) );
+       if ( an == NULL ) {
                return -1;
        }
-       bsi->attrs = tmp;
-       bsi->attrs[ n_attrs ] = ch_strdup( at_name->bv_val );
-       bsi->attrs[ n_attrs + 1 ] = NULL;
+
+       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;
+
+       bsi->attrs = an;
+       
        return 1;
 }
 
@@ -103,17 +114,21 @@ backsql_init_search(
                bsi->attrs = NULL;
 
        } else {
-               bsi->attrs = (char **)ch_calloc( 1, sizeof( char * ) );
-               bsi->attrs[ 0 ] = NULL;
+               bsi->attrs = (AttributeName *)ch_calloc( 1, 
+                               sizeof( AttributeName ) );
+               bsi->attrs[ 0 ].an_name.bv_val = NULL;
+               bsi->attrs[ 0 ].an_name.bv_len = 0;
                
                for ( p = attrs; p->an_name.bv_val; p++ ) {
                        /*
                         * ignore "+"
                         */
-                       if ( strcmp( p->an_name.bv_val, AllOper.bv_val ) == 0 ) {
+                       if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 
+                                       || BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
                                continue;
                        }
-                       backsql_attrlist_add( bsi, &p->an_name );
+
+                       backsql_attrlist_add( bsi, p->an_desc );
                }
        }
 
@@ -192,7 +207,13 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f )
                return 0;
        }
 
-       at = backsql_at_with_name( bsi->oc, f->f_sub_desc->ad_cname.bv_val );
+       at = backsql_ad2at( bsi->oc, f->f_sub_desc );
+
+       /*
+        * When dealing with case-sensitive strings 
+        * we may omit normalization; however, normalized
+        * SQL filters are more liberal.
+        */
 
        backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, "(" /* ) */ , NULL );
 
@@ -273,8 +294,8 @@ int
 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
 {
        backsql_at_map_rec      *at;
-       backsql_at_map_rec      oc_attr 
-               = { "objectClass", "", "", NULL, NULL, NULL, NULL };
+       backsql_at_map_rec      oc_attr = { BER_BVC("objectClass"),
+               slap_schema.si_ad_objectClass, "", "", NULL, NULL, NULL, NULL };
        AttributeDescription    *ad = NULL;
        int                     done = 0, len = 0;
        /* TimesTen */
@@ -325,7 +346,7 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
        }
 
        if ( strcasecmp( ad->ad_cname.bv_val, "objectclass" ) ) {
-               at = backsql_at_with_name( bsi->oc, ad->ad_cname.bv_val );
+               at = backsql_ad2at( bsi->oc, ad );
 
        } else {
                struct berval   bv;
@@ -337,13 +358,14 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                 */
                bv.bv_val = at->sel_expr;
                bv.bv_len = at->sel_expr ? strlen( at->sel_expr ) : 0;
-               backsql_strcat( &bv, &len, "'", bsi->oc->name, "'", NULL );
+               backsql_strcat( &bv, &len, "'", bsi->oc->name.bv_val, 
+                               "'", NULL );
                at->sel_expr = bv.bv_val;
        }
        if ( at == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
                        "attribute '%s' is not defined for objectclass '%s'\n",
-                       ad->ad_cname.bv_val, bsi->oc->name, 0 );
+                       ad->ad_cname.bv_val, bsi->oc->name.bv_val, 0 );
                backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
                                " 1=0 ", NULL );
                goto impossible;
@@ -355,7 +377,7 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
         * need to add this attribute to list of attrs to load,
         * so that we could do test_filter() later
         */
-       backsql_attrlist_add( bsi, &ad->ad_cname );
+       backsql_attrlist_add( bsi, ad );
 
        if ( at->join_where != NULL && strstr( bsi->join_where.bv_val, at->join_where ) == NULL ) {
                backsql_strcat( &bsi->join_where, &bsi->jwhere_len, 
@@ -365,7 +387,8 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
 #if 0  
        if ( at != &oc_attr ) {
                backsql_strcat( &bsi->sel, &bsi->sel_len,
-                               ",", at->sel_expr, " AS ", at->name, NULL );
+                               ",", at->sel_expr, " AS ", 
+                               at->name.bv_val, NULL );
        }
 #endif
 
@@ -472,7 +495,7 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
        backsql_strcat( &bsi->sel, &bsi->sel_len,
                        "SELECT DISTINCT ldap_entries.id,", 
                        bsi->oc->keytbl, ".", bsi->oc->keycol,
-                       ",'", bsi->oc->name, "' AS objectClass",
+                       ",'", bsi->oc->name.bv_val, "' AS objectClass",
                        ",ldap_entries.dn AS dn", NULL );
 #endif
        backsql_strcat( &bsi->sel, &bsi->sel_len,
@@ -481,10 +504,10 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
        if ( bi->strcast_func ) {
                backsql_strcat( &bsi->sel, &bsi->sel_len,
                                bi->strcast_func, 
-                               "('", bsi->oc->name, "')", NULL );
+                               "('", bsi->oc->name.bv_val, "')", NULL );
        } else {
                backsql_strcat( &bsi->sel, &bsi->sel_len,
-                               "'", bsi->oc->name, "'", NULL );
+                               "'", bsi->oc->name.bv_val, "'", NULL );
        }
        backsql_strcat( &bsi->sel, &bsi->sel_len,
                        " AS objectClass,ldap_entries.dn AS dn", NULL );
@@ -577,7 +600,7 @@ backsql_oc_get_candidates( backsql_oc_map_rec *oc, backsql_srch_info *bsi )
        char                    temp_base_dn[ BACKSQL_MAX_DN_LEN + 1 ];
  
        Debug(  LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc='%s'\n",
-                       oc->name, 0, 0 );
+                       oc->name.bv_val, 0, 0 );
        bsi->oc = oc;
        if ( backsql_srch_query( bsi, &query ) ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
@@ -700,16 +723,21 @@ backsql_oc_get_candidates( backsql_oc_map_rec *oc, backsql_srch_info *bsi )
                e = (Entry *)ch_calloc( 1, sizeof( Entry ) ); 
                for ( i = 1; i < row.ncols; i++ ) {
                        if ( row.is_null[ i ] > 0 ) {
-                               backsql_entry_addattr( e, row.col_names[ i ],
-                                               row.cols[ i ], 
-                                               row.col_prec[ i ] );
+                               struct berval   bv;
+
+                               ber_str2bv( row.cols[ i ], 
+                                               row.col_prec[ i ], 0, &bv );
+
+                               backsql_entry_addattr( e, 
+                                               &row.col_names[ i ], &bv );
+
                                Debug( LDAP_DEBUG_TRACE, "prec=%d\n", 
                                                (int)row.col_prec[ i ], 0, 0 );
                        } else {
                                Debug( LDAP_DEBUG_TRACE, 
                                        "NULL value in this row "
                                        "for attribute '%s'\n", 
-                                       row.col_names[ i ], 0, 0 );
+                                       &row.col_names[ i ], 0, 0 );
                        }
                }
 #endif
@@ -770,14 +798,15 @@ backsql_search(
        Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, "
                "attributes to load: %s\n",
                deref, attrsonly, attrs == NULL ? "all" : "custom list" );
-       dbh = backsql_get_db_conn( be, conn );
 
-       if ( !dbh ) {
+       sres = backsql_get_db_conn( be, conn, &dbh );
+       if ( sres != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
                        "could not get connection handle - exiting\n", 
                        0, 0, 0 );
-               send_ldap_result( conn, op, LDAP_OTHER, "",
-                               "SQL-backend error", NULL, NULL );
+               send_ldap_result( conn, op, sres, "",
+                               sres == LDAP_OTHER ?  "SQL-backend error" : "",
+                               NULL, NULL );
                return 1;
        }
 
@@ -861,7 +890,7 @@ backsql_search(
         * of entries matching LDAP query filter and scope (or at least 
         * candidates), and get the IDs
         */
-       avl_apply( bi->oc_by_name, (AVL_APPLY)backsql_oc_get_candidates,
+       avl_apply( bi->oc_by_oc, (AVL_APPLY)backsql_oc_get_candidates,
                        &srch_info, 0, AVL_INORDER );
 
        if ( !isroot && limit->lms_s_unchecked != -1 ) {
@@ -951,7 +980,7 @@ done:;
        for ( eid = srch_info.id_list; eid != NULL; 
                        eid = backsql_free_entryID( eid, 1 ) );
 
-       charray_free( srch_info.attrs );
+       ch_free( srch_info.attrs );
 
        Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
        return 0;
index d20a363dad05af5418cfb8eb3b59c03abf50bd77..f3eee45ef400f333243336d4ab4319e094f2d9fd 100644 (file)
@@ -15,7 +15,7 @@
 
 typedef struct {
        SWORD           ncols;
-       char            **col_names;
+       BerVarray       col_names;
        UDWORD          *col_prec;
        char            **cols;
        SQLINTEGER      *is_null;
index c549c99b7b47c8034fb9128ce3d6f0b2edd4c1f6..f5c63d9026c7b58a6d46cf1091a4241fbf67b460 100644 (file)
@@ -14,8 +14,8 @@
 #include <stdio.h>
 #include "ac/string.h"
 #include <sys/types.h>
-#include "ldap_pvt.h"
 #include "slap.h"
+#include "ldap_pvt.h"
 #include "back-sql.h"
 #include "sql-types.h"
 #include "sql-wrap.h"
@@ -28,8 +28,6 @@ typedef struct backsql_conn {
        SQLHDBC         dbh;
 } backsql_db_conn;
 
-int backsql_dummy( void *, void * );
-
 void
 backsql_PrintErrors( SQLHENV henv, SQLHDBC hdbc, SQLHSTMT sth, int rc )
 {
@@ -70,14 +68,15 @@ backsql_Prepare( SQLHDBC dbh, SQLHSTMT *sth, char *query, int timeout )
        Debug( LDAP_DEBUG_TRACE, "==>_SQLPrepare()\n", 0, 0, 0 );
 #endif
 
-       SQLGetInfo( dbh, SQL_DRIVER_NAME, drv_name, 30, &len );
+       SQLGetInfo( dbh, SQL_DRIVER_NAME, drv_name, sizeof( drv_name ), &len );
 
 #if 0
        Debug( LDAP_DEBUG_TRACE, "_SQLPrepare(): driver name='%s'\n",
                        drv_name, 0, 0 );
 #endif
-       
-       if ( !strncmp( ldap_pvt_str2upper( drv_name ), "SQLSRV32.DLL", 30 ) ) {
+
+       ldap_pvt_str2upper( drv_name );
+       if ( !strncmp( drv_name, "SQLSRV32.DLL", sizeof( drv_name ) ) ) {
                /*
                 * stupid default result set in MS SQL Server
                 * does not support multiple active statements
@@ -91,7 +90,8 @@ backsql_Prepare( SQLHDBC dbh, SQLHSTMT *sth, char *query, int timeout )
                                SQL_CONCUR_ROWVER );
                if ( rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO ) {
                        Debug( LDAP_DEBUG_TRACE, "_SQLPrepare(): "
-                               "SQLSetStmtOption(SQL_CONCURRENCY,SQL_CONCUR_ROWVER) failed:\n", 
+                               "SQLSetStmtOption(SQL_CONCURRENCY,"
+                               "SQL_CONCUR_ROWVER) failed:\n", 
                                0, 0, 0 );
                        backsql_PrintErrors( SQL_NULL_HENV, dbh, *sth, rc );
                }
@@ -116,6 +116,9 @@ backsql_Prepare( SQLHDBC dbh, SQLHSTMT *sth, char *query, int timeout )
 }
 
 #if 0
+/*
+ * Turned into macros --- see sql-wrap.h
+ */
 RETCODE
 backsql_BindParamStr( SQLHSTMT sth, int par_ind, char *str, int maxlen )
 {
@@ -168,19 +171,20 @@ backsql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row )
                        "ncols=%d\n", (int)row->ncols, 0, 0 );
 #endif
 
-               row->col_names = (char **)ch_calloc( row->ncols, 
+               row->col_names = (BerVarray)ch_calloc( row->ncols + 1, 
+                               sizeof( struct berval ) );
+               row->cols = (char **)ch_calloc( row->ncols + 1, 
                                sizeof( char * ) );
-               row->cols = (char **)ch_calloc( row->ncols, sizeof( char * ) );
                row->col_prec = (UDWORD *)ch_calloc( row->ncols,
                                sizeof( UDWORD ) );
                row->is_null = (SQLINTEGER *)ch_calloc( row->ncols,
                                sizeof( SQLINTEGER ) );
                for ( i = 1; i <= row->ncols; i++ ) {
                        rc = SQLDescribeCol( sth, (SQLSMALLINT)i, &colname[ 0 ],
-                                       (SQLUINTEGER)sizeof( colname ) - 1,
+                                       (SQLUINTEGER)( sizeof( colname ) - 1 ),
                                        &name_len, &col_type,
                                        &col_prec, &col_scale, &col_null );
-                       row->col_names[ i - 1 ] = ch_strdup( colname );
+                       ber_str2bv( colname, 0, 1, &row->col_names[ i - 1 ] );
 #if 0
                        Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: "
                                "col_name=%s, col_prec[%d]=%d\n",
@@ -220,6 +224,10 @@ backsql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row )
                                                &row->is_null[ i - 1 ] );
                        }
                }
+
+               row->col_names[ i - 1 ].bv_val = NULL;
+               row->col_names[ i - 1 ].bv_len = 0;
+               row->cols[ i - 1 ] = NULL;
        }
 #if 0
        Debug( LDAP_DEBUG_TRACE, "<== backsql_BindRowAsStrings()\n", 0, 0, 0 );
@@ -231,28 +239,19 @@ backsql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row )
 RETCODE
 backsql_FreeRow( BACKSQL_ROW_NTS *row )
 {
-       int     i;
-
        if ( row->cols == NULL ) {
                return SQL_ERROR;
        }
 
-       for ( i = 0; i < row->ncols; i++ ) {
-               /*
-                * FIXME: we need to free the col_names as well, don't we?
-                */
-               free( row->cols[ i ] );
-       }
-
-       free( row->col_names );
+       ber_bvarray_free( row->col_names );
+       charray_free( row->cols );
        free( row->col_prec );
-       free( row->cols );
        free( row->is_null );
 
        return SQL_SUCCESS;
 }
 
-int
+static int
 backsql_cmp_connid( backsql_db_conn *c1, backsql_db_conn *c2 )
 {
        if ( c1->ldap_cid > c2->ldap_cid ) {
@@ -266,13 +265,19 @@ backsql_cmp_connid( backsql_db_conn *c1, backsql_db_conn *c2 )
        return 0;
 }
 
-int
+static int
 backsql_close_db_conn( backsql_db_conn *conn )
 {
        Debug( LDAP_DEBUG_TRACE, "==>backsql_close_db_conn()\n", 0, 0, 0 );
 
+       /*
+        * Default transact is SQL_ROLLBACK; commit is required only
+        * by write operations, and it is explicitly performed after
+        * each atomic operation succeeds.
+        */
+
        /* TimesTen */
-       SQLTransact( SQL_NULL_HENV, conn->dbh, SQL_COMMIT );
+       SQLTransact( SQL_NULL_HENV, conn->dbh, SQL_ROLLBACK );
        SQLDisconnect( conn->dbh );
        SQLFreeConnect( conn->dbh );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_close_db_conn()\n", 0, 0, 0 );
@@ -314,24 +319,27 @@ backsql_free_db_env( backsql_info *si )
        return SQL_SUCCESS;
 }
 
-backsql_db_conn *
-backsql_open_db_conn( backsql_info *si, int ldap_cid )
+static int
+backsql_open_db_conn( backsql_info *si, int ldap_cid, backsql_db_conn **pdbc )
 {
        /* TimesTen */
        char                    DBMSName[ 32 ];
        backsql_db_conn         *dbc;
        int                     rc;
+
+       assert( pdbc );
+       *pdbc = NULL;
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_open_db_conn()\n", 0, 0, 0 );
        dbc = (backsql_db_conn *)ch_calloc( 1, sizeof( backsql_db_conn ) );
        dbc->ldap_cid = ldap_cid;
        rc = SQLAllocConnect( si->db_env, &dbc->dbh );
-       if (!BACKSQL_SUCCESS( rc ) ) {
+       if ( !BACKSQL_SUCCESS( rc ) ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn: "
                        "SQLAllocConnect() failed:\n", 0, 0, 0 );
                backsql_PrintErrors( si->db_env, SQL_NULL_HDBC,
                                SQL_NULL_HENV, rc );
-               return NULL;
+               return LDAP_UNAVAILABLE;
        }
 
        rc = SQLConnect( dbc->dbh, si->dbname, SQL_NTS, si->dbuser, 
@@ -344,7 +352,7 @@ backsql_open_db_conn( backsql_info *si, int ldap_cid )
                        "succeeded with info" : "failed" );
                backsql_PrintErrors( si->db_env, dbc->dbh, SQL_NULL_HENV, rc );
                if ( rc != SQL_SUCCESS_WITH_INFO ) {
-                       return NULL;
+                       return LDAP_UNAVAILABLE;
                }
        }
 
@@ -379,12 +387,13 @@ backsql_open_db_conn( backsql_info *si, int ldap_cid )
        Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn(): "
                "connected, adding to tree\n", 0, 0, 0 );
        ldap_pvt_thread_mutex_lock( &si->dbconn_mutex );
-       avl_insert( &si->db_conns, dbc, (AVL_CMP)backsql_cmp_connid,
-                       backsql_dummy );
+       avl_insert( &si->db_conns, dbc, (AVL_CMP)backsql_cmp_connid, NULL );
        ldap_pvt_thread_mutex_unlock( &si->dbconn_mutex );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_open_db_conn()\n", 0, 0, 0 );
 
-       return dbc;
+       *pdbc = dbc;
+
+       return LDAP_SUCCESS;
 }
 
 int
@@ -413,15 +422,19 @@ backsql_free_db_conn( Backend *be, Connection *ldapc )
        return SQL_SUCCESS;
 }
 
-SQLHDBC
-backsql_get_db_conn( Backend *be, Connection *ldapc )
+int
+backsql_get_db_conn( Backend *be, Connection *ldapc, SQLHDBC *dbh )
 {
        backsql_info            *si = (backsql_info *)be->be_private;
        backsql_db_conn         *dbc;
        backsql_db_conn         tmp;
+       int                     rc = LDAP_SUCCESS;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_get_db_conn()\n", 0, 0, 0 );
 
+       assert( dbh );
+       *dbh = SQL_NULL_HDBC;
+
        tmp.ldap_cid = ldapc->c_connid;
 
        /*
@@ -431,25 +444,33 @@ backsql_get_db_conn( Backend *be, Connection *ldapc )
        dbc = (backsql_db_conn *)avl_find( si->db_conns, &tmp,
                        (AVL_CMP)backsql_cmp_connid );
        if ( !dbc ) {
-               dbc = backsql_open_db_conn( si, ldapc->c_connid );
-       }
-       if ( !dbc ) {
-               Debug( LDAP_DEBUG_TRACE, "backsql_get_db_conn(): "
-                       "could not get connection handle -- returning NULL\n",
-                       0, 0, 0 );
-               return SQL_NULL_HDBC;
+               rc = backsql_open_db_conn( si, ldapc->c_connid, &dbc );
+               if ( rc != LDAP_SUCCESS) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_get_db_conn(): "
+                               "could not get connection handle "
+                               "-- returning NULL\n", 0, 0, 0 );
+                       return rc;
+               }
        }
+
        ldap_pvt_thread_mutex_lock( &si->schema_mutex );
        if ( !si->schema_loaded ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_get_db_conn(): "
                        "first call -- reading schema map\n", 0, 0, 0 );
-               backsql_load_schema_map( si, dbc->dbh );
+               rc = backsql_load_schema_map( si, dbc->dbh );
+               if ( rc != LDAP_SUCCESS ) {
+                       backsql_free_db_conn( be, ldapc );
+                       return rc;
+               }
        }
        ldap_pvt_thread_mutex_unlock( &si->schema_mutex );
 
+       *dbh = dbc->dbh;
+
        Debug( LDAP_DEBUG_TRACE, "<==backsql_get_db_conn()\n", 0, 0, 0 );
-       return dbc->dbh;
+
+       return LDAP_SUCCESS;
 }
 
 #endif /* SLAPD_SQL */
+
index 00edc26b6ef472b4d366f1ae61a2d194139bf345..964a953d2d53a36ad1128b54da63d1ca895eb755 100644 (file)
@@ -33,7 +33,7 @@ void backsql_PrintErrors( SQLHENV henv, SQLHDBC hdbc, SQLHSTMT sth, int rc );
 
 int backsql_init_db_env( backsql_info *si );
 int backsql_free_db_env( backsql_info *si );
-SQLHDBC backsql_get_db_conn( Backend *be, Connection *ldapc );
+int backsql_get_db_conn( Backend *be, Connection *ldapc, SQLHDBC *dbh );
 int backsql_free_db_conn( Backend *be, Connection *ldapc );
 
 #endif /* __BACKSQL_SQL_WRAP_H__ */
index e7458b7296ad244e648cd4ae92cb053863e6d21b..48701c6aa4975d578e271886534e41a2e77c3be3 100644 (file)
@@ -17,6 +17,8 @@
 #include "ac/ctype.h"
 #include "ac/stdarg.h"
 #include "slap.h"
+#include "lber_pvt.h"
+#include "ldap_pvt.h"
 #include "back-sql.h"
 #include "schema-map.h"
 #include "util.h"
@@ -40,6 +42,13 @@ char backsql_id_query[] = "SELECT id,keyval,oc_map_id FROM ldap_entries WHERE ";
 /* TimesTen */
 char backsql_check_dn_ru_query[] = "SELECT dn_ru from ldap_entries";
 
+/*
+ * Frequently used constants
+ */
+struct berval 
+       bv_n_objectclass        = BER_BVC("objectclass"),
+       bv_n_0_10               = BER_BVC("0.10");
+
 struct berval *
 backsql_strcat( struct berval *dest, int *buflen, ... )
 {
@@ -108,9 +117,8 @@ backsql_strcat( struct berval *dest, int *buflen, ... )
 int
 backsql_entry_addattr(
        Entry           *e,
-       char            *at_name,
-       char            *at_val, 
-       unsigned int    at_val_len )
+       struct berval   *at_name,
+       struct berval   *at_val )
 {
        struct berval           add_val[ 2 ];
        AttributeDescription    *ad;
@@ -118,18 +126,18 @@ backsql_entry_addattr(
        const char              *text;
 
        Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): "
-               "at_name='%s', at_val='%s'\n", at_name, at_val, 0 );
-       add_val[ 0 ].bv_val = at_val;
-       add_val[ 0 ].bv_len = at_val_len;
+               "at_name='%s', at_val='%s'\n", 
+               at_name->bv_val, at_val->bv_val, 0 );
+       add_val[ 0 ] = *at_val;
        add_val[ 1 ].bv_val = NULL;
        add_val[ 1 ].bv_len = 0;
 
        ad = NULL;
-       rc = slap_str2ad( at_name, &ad, &text );
+       rc = slap_bv2ad( at_name, &ad, &text );
        if ( rc != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): "
                        "failed to find AttributeDescription for '%s'\n",
-                       at_name, 0, 0 );
+                       at_name->bv_val, 0, 0 );
                return 0;
        }
 
@@ -138,7 +146,7 @@ backsql_entry_addattr(
        if ( rc != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): "
                        "failed to merge value '%s' for attribute '%s'\n",
-                       at_val, at_name, 0 );
+                       at_val->bv_val, at_name->bv_val, 0 );
                return 0;
        }
        
index baa600af3283dd2bcfa1dfdc16ab645f1884ff93..adc5911caffb57adeed96b186b6ff694fe9d717b 100644 (file)
 
 #define BACKSQL_STR_GROW 64
 
+extern struct berval 
+       bv_n_objectclass,
+       bv_n_0_10;
+
 struct berval *backsql_strcat( struct berval *dest, int *buflen, ... );
 
-int backsql_entry_addattr( Entry *e, char *at_name, char *at_val,
-               unsigned int at_val_len );
+int backsql_entry_addattr( Entry *e, struct berval *at_name, 
+               struct berval *at_val );
 
 typedef struct __backsql_srch_info {
        struct berval           *base_dn;
@@ -42,7 +46,7 @@ typedef struct __backsql_srch_info {
        Backend                 *be;
        Connection              *conn;
        Operation               *op;
-       char                    **attrs;
+       AttributeName           *attrs;
        Entry                   *e;
        /* 1 if the db is TimesTen; 0 if it's not */
        int                     isTimesTen;