]> git.sur5r.net Git - openldap/commitdiff
Sync with HEAD
authorKurt Zeilenga <kurt@openldap.org>
Thu, 29 Aug 2002 03:51:02 +0000 (03:51 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Thu, 29 Aug 2002 03:51:02 +0000 (03:51 +0000)
20 files changed:
servers/slapd/back-sql/back-sql.h
servers/slapd/back-sql/config.c
servers/slapd/back-sql/entry-id.c
servers/slapd/back-sql/entry-id.h
servers/slapd/back-sql/external.h [new file with mode: 0644]
servers/slapd/back-sql/init.c
servers/slapd/back-sql/modify.c
servers/slapd/back-sql/other.c
servers/slapd/back-sql/rdbms_depend/ibmdb2/backsql_create.sql
servers/slapd/back-sql/rdbms_depend/ibmdb2/slapd.conf
servers/slapd/back-sql/rdbms_depend/ibmdb2/testdb_create.sql
servers/slapd/back-sql/rdbms_depend/ibmdb2/testdb_data.sql
servers/slapd/back-sql/rdbms_depend/ibmdb2/testdb_metadata.sql
servers/slapd/back-sql/rdbms_depend/pgsql/slapd.conf
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-wrap.c
servers/slapd/back-sql/util.c
servers/slapd/back-sql/util.h

index bd349175a4726f4972044bf4aabfcea4090bdd3d..a456351479103a1cf41e4786d451930daf1331e0 100644 (file)
@@ -1,6 +1,3 @@
-#ifndef __BACKSQL_H__
-#define __BACKSQL_H__
-
 /*
  *      Copyright 1999, Dmitry Kovalev <mit@openldap.org>, All rights reserved.
  *
@@ -9,6 +6,66 @@
  *      license is available at http://www.OpenLDAP.org/license.html or
  *      in file LICENSE in the top-level directory of the distribution.
  */
+/*
+ *      Copyright 2002, Pierangelo Masarati <ando@OpenLDAP.org>.
+ *      All rights reserved.
+ *
+ *      This is a modified version of back-sql; the same conditions
+ *      of the above reported Copyright statement, and sigificantly
+ *      the OpenLDAP Public License apply.  Credits go to Dmitry 
+ *      Kovalev for the initial development of the backend.
+ *
+ *      This copyright statement cannot be altered.
+ */
+/*
+ *      The following changes have been addressed:
+ *      
+ * Enhancements:
+ *   - re-styled code for better readability
+ *   - upgraded backend API to reflect recent changes
+ *   - LDAP schema is checked when loading SQL/LDAP mapping
+ *   - AttributeDescription/ObjectClass pointers used for more efficient
+ *     mapping lookup
+ *   - bervals used where string length is required often
+ *   - atomized write operations by committing at the end of each operation
+ *     and defaulting connection closure to rollback
+ *   - added LDAP access control to write operations
+ *   - fully implemented modrdn (with rdn attrs change, deleteoldrdn,
+ *     access check, parent/children check and more)
+ *   - added parent access control, children control to delete operation
+ *   - added structuralObjectClass operational attribute check and
+ *     value return on search
+ *   - added hasSubordinate operational attribute on demand
+ *   - search limits are appropriately enforced
+ *   - function backsql_strcat() has been made more efficient
+ *   - concat function has been made configurable by means of a pattern
+ *   - added config switches:
+ *       - fail_if_no_mapping  write operations fail if there is no mapping
+ *       - has_ldapinfo_dn_ru  overrides autodetect
+ *       - concat_pattern      a string containing two '?' is used
+ *                             (note that "?||?" should be more portable
+ *                             than builtin function "CONCAT(?,?)")
+ *       - strcast_func                cast of string constants in "SELECT DISTINCT
+ *                             statements (needed by PostgreSQL)
+ *       - upper_needs_cast    cast the argument of upper when required
+ *                             (basically when building dn substring queries)
+ * 
+ * Todo:
+ *   - add security checks for SQL statements that can be injected (?)
+ *   - re-test with previously supported RDBMs
+ *   - replace dn_ru and so with normalized dn (no need for upper() and so
+ *     in dn match)
+ *   - implement a backsql_normalize() function to replace the upper()
+ *     conversion routines
+ *   - note that subtree deletion, subtree renaming and so could be easily
+ *     implemented (rollback and consistency checks are available :)
+ *   - implement "lastmod" and other operational stuff (ldap_entries table ?)
+ *   - check how to allow multiple operations with one statement, to remove
+ *     BACKSQL_REALLOC_STMT from modify.c (a more recent unixODBC lib?)
+ */
+
+#ifndef __BACKSQL_H__
+#define __BACKSQL_H__
 
 #include "external.h"
 #include "sql-types.h"
  */
 #define BACKSQL_MAX_DN_LEN     255
 
+/*
+ * define to enable very extensive trace logging (debug only)
+ */
+#undef BACKSQL_TRACE
+
+
 typedef struct {
        char            *dbhost;
        int             dbport;
@@ -26,27 +89,51 @@ typedef struct {
        char            *dbname;
        /*
         * SQL condition for subtree searches differs in syntax:
-        * "LIKE CONCAT('%',?)" or "LIKE '%'+?" or smth else 
+        * "LIKE CONCAT('%',?)" or "LIKE '%'+?" or "LIKE '%'||?"
+        * or smth else 
         */
-       char            *subtree_cond;
-       char            *oc_query,*at_query;
+       struct berval   subtree_cond;
+       struct berval   children_cond;
+       char            *oc_query, *at_query;
        char            *insentry_query,*delentry_query;
        char            *id_query;
-       char            *upper_func;
-       char            *strcast_func;
+       char            *has_children_query;
+       struct berval   upper_func;
+       struct berval   upper_func_open;
+       struct berval   upper_func_close;
+       BerVarray       concat_func;
+
+       unsigned int    bsql_flags;
+#define        BSQLF_SCHEMA_LOADED             0x0001
+#define        BSQLF_UPPER_NEEDS_CAST          0x0002
+#define        BSQLF_CREATE_NEEDS_SELECT       0x0004
+#define        BSQLF_FAIL_IF_NO_MAPPING        0x0008
+#define BSQLF_HAS_LDAPINFO_DN_RU       0x0010
+#define BSQLF_DONTCHECK_LDAPINFO_DN_RU 0x0020
+#define BSQLF_USE_REVERSE_DN           0x0040
+
+#define        BACKSQL_SCHEMA_LOADED(si) \
+       ((si)->bsql_flags & BSQLF_SCHEMA_LOADED)
+#define BACKSQL_UPPER_NEEDS_CAST(si) \
+       ((si)->bsql_flags & BSQLF_UPPER_NEEDS_CAST)
+#define BACKSQL_CREATE_NEEDS_SELECT(si) \
+       ((si)->bsql_flags & BSQLF_CREATE_NEEDS_SELECT)
+#define BACKSQL_FAIL_IF_NO_MAPPING(si) \
+       ((si)->bsql_flags & BSQLF_FAIL_IF_NO_MAPPING)
+#define BACKSQL_HAS_LDAPINFO_DN_RU(si) \
+       ((si)->bsql_flags & BSQLF_HAS_LDAPINFO_DN_RU)
+#define BACKSQL_DONTCHECK_LDAPINFO_DN_RU(si) \
+       ((si)->bsql_flags & BSQLF_DONTCHECK_LDAPINFO_DN_RU)
+#define BACKSQL_USE_REVERSE_DN(si) \
+       ((si)->bsql_flags & BSQLF_USE_REVERSE_DN)
+       
+       struct berval   strcast_func;
        Avlnode         *db_conns;
        Avlnode         *oc_by_oc;
        Avlnode         *oc_by_id;
-       int             schema_loaded;
        ldap_pvt_thread_mutex_t         dbconn_mutex;
        ldap_pvt_thread_mutex_t         schema_mutex;
        SQLHENV         db_env;
-       int             isTimesTen;
-
-       /* 
-        * Does ldapinfo.dn_ru exist in schema?
-        */
-       int             has_ldapinfo_dn_ru;  
 } backsql_info;
 
 #define BACKSQL_SUCCESS( rc ) \
index 7403cc1d6e9e33be40fff8ad64e9908848309888..3472496ae66361e9b3407fa2f080acc2f69314c0 100644 (file)
@@ -17,6 +17,7 @@
 #include "slap.h"
 #include "back-sql.h"
 #include "sql-wrap.h"
+#include "util.h"
 
 int
 backsql_db_config(
@@ -35,7 +36,7 @@ backsql_db_config(
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE, 
                                "<==backsql_db_config (%s line %d): "
-                               "missing hostname in dbhost directive\n",
+                               "missing hostname in \"dbhost\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
@@ -48,7 +49,7 @@ backsql_db_config(
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE, 
                                "<==backsql_db_config (%s line %d): "
-                               "missing username in dbuser directive\n",
+                               "missing username in \"dbuser\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
@@ -60,7 +61,7 @@ backsql_db_config(
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE, 
                                "<==backsql_db_config (%s line %d): "
-                               "missing password in dbpasswd directive\n",
+                               "missing password in \"dbpasswd\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
@@ -72,33 +73,53 @@ backsql_db_config(
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE, 
                                "<==backsql_db_config (%s line %d): "
-                               "missing database name in dbname directive\n",
-                               fname, lineno, 0 );
+                               "missing database name in \"dbname\" "
+                               "directive\n", fname, lineno, 0 );
                        return 1;
                }
                si->dbname = ch_strdup( argv[ 1 ] );
                Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): dbname=%s\n",
                        si->dbname, 0, 0 );
 
+       } else if ( !strcasecmp( argv[ 0 ], "concat_pattern" ) ) {
+               if ( argc < 2 ) {
+                       Debug( LDAP_DEBUG_TRACE, 
+                               "<==backsql_db_config (%s line %d): "
+                               "missing pattern"
+                               "in \"concat_pattern\" directive\n",
+                               fname, lineno, 0 );
+                       return 1;
+               }
+               if ( backsql_split_pattern( argv[ 1 ], &si->concat_func, 2 ) ) {
+                       Debug( LDAP_DEBUG_TRACE, 
+                               "<==backsql_db_config (%s line %d): "
+                               "unable to parse pattern \"%s\"\n"
+                               "in \"concat_pattern\" directive\n",
+                               fname, lineno, argv[ 1 ] );
+                       return 1;
+               }
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
+                       "concat_pattern=\"%s\"\n", argv[ 1 ], 0, 0 );
+
        } else if ( !strcasecmp( argv[ 0 ], "subtree_cond" ) ) {
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE, 
                                "<==backsql_db_config (%s line %d): "
                                "missing SQL condition "
-                               "in subtree_cond directive\n",
+                               "in \"subtree_cond\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
-               si->subtree_cond = ch_strdup( argv[ 1 ] );
+               ber_str2bv( argv[ 1 ], 0, 1, &si->subtree_cond );
                Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
-                       "subtree_cond=%s\n", si->subtree_cond, 0, 0 );
+                       "subtree_cond=%s\n", si->subtree_cond.bv_val, 0, 0 );
 
        } else if ( !strcasecmp( argv[ 0 ], "oc_query" ) ) {
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE, 
                                "<==backsql_db_config (%s line %d): "
                                "missing SQL statement "
-                               "in oc_query directive\n",
+                               "in \"oc_query\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
@@ -111,7 +132,7 @@ backsql_db_config(
                        Debug( LDAP_DEBUG_TRACE,
                                "<==backsql_db_config (%s line %d): "
                                "missing SQL statement "
-                               "in at_query directive\n",
+                               "in \"at_query\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
@@ -124,7 +145,7 @@ backsql_db_config(
                        Debug( LDAP_DEBUG_TRACE, 
                                "<==backsql_db_config (%s line %d): "
                                "missing SQL statement "
-                               "in insentry_query directive\n",
+                               "in \"insentry_query\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
@@ -132,38 +153,97 @@ backsql_db_config(
                Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
                        "insentry_query=%s\n", si->insentry_query, 0, 0 );
 
+       } else if ( !strcasecmp( argv[ 0 ], "create_needs_select" ) ) {
+               if ( argc < 2 ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<==backsql_db_config (%s line %d): "
+                               "missing { yes | no }"
+                               "in \"create_needs_select\" directive\n",
+                               fname, lineno, 0 );
+                       return 1;
+               }
+
+               if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
+                       si->bsql_flags |= BSQLF_CREATE_NEEDS_SELECT;
+
+               } else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
+                       si->bsql_flags &= ~BSQLF_CREATE_NEEDS_SELECT;
+
+               } else {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<==backsql_db_config (%s line %d): "
+                               "\"create_needs_select\" directive arg "
+                               "must be \"yes\" or \"no\"\n",
+                               fname, lineno, 0 );
+                       return 1;
+
+               }
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
+                       "create_needs_select =%s\n", 
+                       BACKSQL_CREATE_NEEDS_SELECT( si ) ? "yes" : "no",
+                       0, 0 );
+
        } else if ( !strcasecmp( argv[ 0 ], "upper_func" ) ) {
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE,
                                "<==backsql_db_config (%s line %d): "
                                "missing function name "
-                               "in upper_func directive\n",
+                               "in \"upper_func\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
-               si->upper_func = ch_strdup( argv[ 1 ] );
+               ber_str2bv( argv[ 1 ], 0, 1, &si->upper_func );
                Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
-                       "upper_func=%s\n", si->upper_func, 0, 0 );
+                       "upper_func=%s\n", si->upper_func.bv_val, 0, 0 );
+
+       } else if ( !strcasecmp( argv[ 0 ], "upper_needs_cast" ) ) {
+               if ( argc < 2 ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<==backsql_db_config (%s line %d): "
+                               "missing { yes | no }"
+                               "in \"upper_needs_cast\" directive\n",
+                               fname, lineno, 0 );
+                       return 1;
+               }
+
+               if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
+                       si->bsql_flags |= BSQLF_UPPER_NEEDS_CAST;
+
+               } else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
+                       si->bsql_flags &= ~BSQLF_UPPER_NEEDS_CAST;
+
+               } else {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<==backsql_db_config (%s line %d): "
+                               "\"upper_needs_cast\" directive arg "
+                               "must be \"yes\" or \"no\"\n",
+                               fname, lineno, 0 );
+                       return 1;
+
+               }
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
+                       "upper_needs_cast =%s\n", 
+                       BACKSQL_UPPER_NEEDS_CAST( si ) ? "yes" : "no", 0, 0 );
 
        } else if ( !strcasecmp( argv[ 0 ], "strcast_func" ) ) {
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE,
                                "<==backsql_db_config (%s line %d): "
                                "missing function name "
-                               "in strcast_func directive\n",
+                               "in \"strcast_func\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
-               si->strcast_func = ch_strdup( argv[ 1 ] );
+               ber_str2bv( argv[ 1 ], 0, 1, &si->strcast_func );
                Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
-                       "strcast_func=%s\n", si->strcast_func, 0, 0 );
+                       "strcast_func=%s\n", si->strcast_func.bv_val, 0, 0 );
 
        } else if ( !strcasecmp( argv[ 0 ], "delentry_query" ) ) {
                if ( argc < 2 ) {
                        Debug( LDAP_DEBUG_TRACE,
                                "<==backsql_db_config (%s line %d): "
                                "missing SQL statement "
-                               "in delentry_query directive\n",
+                               "in \"delentry_query\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
@@ -176,19 +256,23 @@ backsql_db_config(
                        Debug( LDAP_DEBUG_TRACE,
                                "<==backsql_db_config (%s line %d): "
                                "missing { yes | no }"
-                               "in has_ldapinfo_dn_ru directive\n",
+                               "in \"has_ldapinfo_dn_ru\" directive\n",
                                fname, lineno, 0 );
                        return 1;
                }
 
                if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
-                       si->has_ldapinfo_dn_ru = 1;
+                       si->bsql_flags |= BSQLF_HAS_LDAPINFO_DN_RU;
+                       si->bsql_flags |= BSQLF_DONTCHECK_LDAPINFO_DN_RU;
+
                } else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
-                       si->has_ldapinfo_dn_ru = 0;
+                       si->bsql_flags &= ~BSQLF_HAS_LDAPINFO_DN_RU;
+                       si->bsql_flags |= BSQLF_DONTCHECK_LDAPINFO_DN_RU;
+
                } else {
                        Debug( LDAP_DEBUG_TRACE,
                                "<==backsql_db_config (%s line %d): "
-                               "has_ldapinfo_dn_ru directive arg "
+                               "\"has_ldapinfo_dn_ru\" directive arg "
                                "must be \"yes\" or \"no\"\n",
                                fname, lineno, 0 );
                        return 1;
@@ -196,11 +280,40 @@ backsql_db_config(
                }
                Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
                        "has_ldapinfo_dn_ru=%s\n", 
-                       si->has_ldapinfo_dn_ru == 0 ? "no" : "yes", 0, 0 );
+                       BACKSQL_HAS_LDAPINFO_DN_RU( si ) ? "yes" : "no", 0, 0 );
+
+       } else if ( !strcasecmp( argv[ 0 ], "fail_if_no_mapping") ) {
+               if ( argc < 2 ) {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<==backsql_db_config (%s line %d): "
+                               "missing { yes | no }"
+                               "in \"fail_if_no_mapping\" directive\n",
+                               fname, lineno, 0 );
+                       return 1;
+               }
+
+               if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
+                       si->bsql_flags |= BSQLF_FAIL_IF_NO_MAPPING;
+
+               } else if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
+                       si->bsql_flags &= ~BSQLF_FAIL_IF_NO_MAPPING;
+
+               } else {
+                       Debug( LDAP_DEBUG_TRACE,
+                               "<==backsql_db_config (%s line %d): "
+                               "\"fail_if_no_mapping\" directive arg "
+                               "must be \"yes\" or \"no\"\n",
+                               fname, lineno, 0 );
+                       return 1;
+
+               }
+               Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config(): "
+                       "fail_if_no_mapping=%s\n", 
+                       BACKSQL_FAIL_IF_NO_MAPPING( si ) ? "yes" : "no", 0, 0 );
 
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_db_config (%s line %d): "
-                       "unknown directive '%s' (ignored)\n",
+                       "unknown directive \"%s\" (ignored)\n",
                        fname, lineno, argv[ 0 ] );
        }
 
index 552d23946e09706e28cff8d02d2cfc48b029e6e8..90564463acf41fdccb85d7a275e12c162760725d 100644 (file)
@@ -42,11 +42,6 @@ backsql_free_entryID( backsql_entryID *id, int freeit )
        return next;
 }
 
-/*
- * FIXME: need to change API to pass backsql_entryID **id 
- * and return an error code, to distinguish LDAP_OTHER from
- * LDAP_NO_SUCH_OBJECT
- */
 int
 backsql_dn2id(
        backsql_info            *bi,
@@ -56,9 +51,6 @@ backsql_dn2id(
 {
        SQLHSTMT                sth; 
        BACKSQL_ROW_NTS         row;
-#if 0
-       SQLINTEGER              nrows = 0;
-#endif
        RETCODE                 rc;
        int                     res;
 
@@ -93,7 +85,7 @@ backsql_dn2id(
                return LDAP_OTHER;
        }
 
-       if ( bi->has_ldapinfo_dn_ru ) {
+       if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
                /*
                 * Prepare an upper cased, byte reversed version 
                 * that can be searched using indexes
@@ -109,7 +101,7 @@ backsql_dn2id(
                                upperdn, 0, 0 );
                toBind = upperdn;
        } else {
-               if ( bi->isTimesTen ) {
+               if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
                        AC_MEMCPY( upperdn, dn->bv_val, dn->bv_len + 1 );
                        ldap_pvt_str2upper( upperdn );
                        Debug( LDAP_DEBUG_TRACE,
@@ -126,7 +118,8 @@ backsql_dn2id(
        if ( rc != SQL_SUCCESS) {
                /* end TimesTen */ 
                Debug( LDAP_DEBUG_TRACE, "backsql_dn2id(): "
-                       "error binding dn=\"%s\" parameter:\n", toBind, 0, 0 );
+                       "error binding dn=\"%s\" parameter:\n", 
+                       toBind, 0, 0 );
                backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc );
                SQLFreeStmt( sth, SQL_DROP );
                return LDAP_OTHER;
@@ -145,9 +138,9 @@ backsql_dn2id(
        backsql_BindRowAsStrings( sth, &row );
        rc = SQLFetch( sth );
        if ( BACKSQL_SUCCESS( rc ) ) {
-               id->id = atoi( row.cols[ 0 ] );
-               id->keyval = atoi( row.cols[ 1 ] );
-               id->oc_id = atoi( row.cols[ 2 ] );
+               id->id = strtol( row.cols[ 0 ], NULL, 0 );
+               id->keyval = strtol( row.cols[ 1 ], NULL, 0 );
+               id->oc_id = strtol( row.cols[ 2 ], NULL, 0 );
                ber_dupbv( &id->dn, dn );
                id->next = NULL;
 
@@ -169,6 +162,86 @@ backsql_dn2id(
        return res;
 }
 
+int
+backsql_has_children(
+       backsql_info            *bi,
+       SQLHDBC                 dbh,
+       struct berval           *dn )
+{
+       SQLHSTMT                sth; 
+       BACKSQL_ROW_NTS         row;
+       RETCODE                 rc;
+       int                     res;
+
+       Debug( LDAP_DEBUG_TRACE, "==>backsql_has_children(): dn='%s'\n", 
+                       dn->bv_val, 0, 0 );
+
+       if ( dn->bv_len > BACKSQL_MAX_DN_LEN ) {
+               Debug( LDAP_DEBUG_TRACE, 
+                       "backsql_has_children(): DN \"%s\" (%ld bytes) "
+                       "exceeds max DN length (%d):\n",
+                       dn->bv_val, dn->bv_len, BACKSQL_MAX_DN_LEN );
+               return LDAP_OTHER;
+       }
+       
+       /* begin TimesTen */
+       Debug(LDAP_DEBUG_TRACE, "children id query '%s'\n", 
+                       bi->has_children_query, 0, 0);
+       assert( bi->has_children_query );
+       rc = backsql_Prepare( dbh, &sth, bi->has_children_query, 0 );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, 
+                       "backsql_has_children(): error preparing SQL:\n%s", 
+                       bi->has_children_query, 0, 0);
+               backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc );
+               SQLFreeStmt( sth, SQL_DROP );
+               return LDAP_OTHER;
+       }
+
+       rc = backsql_BindParamStr( sth, 1, dn->bv_val, BACKSQL_MAX_DN_LEN );
+       if ( rc != SQL_SUCCESS) {
+               /* end TimesTen */ 
+               Debug( LDAP_DEBUG_TRACE, "backsql_has_children(): "
+                       "error binding dn=\"%s\" parameter:\n", 
+                       dn->bv_val, 0, 0 );
+               backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc );
+               SQLFreeStmt( sth, SQL_DROP );
+               return LDAP_OTHER;
+       }
+
+       rc = SQLExecute( sth );
+       if ( rc != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_has_children(): "
+                       "error executing query (\"%s\", \"%s\"):\n", 
+                       bi->has_children_query, dn->bv_val, 0 );
+               backsql_PrintErrors( SQL_NULL_HENV, dbh, sth, rc );
+               SQLFreeStmt( sth, SQL_DROP );
+               return LDAP_OTHER;
+       }
+
+       backsql_BindRowAsStrings( sth, &row );
+       
+       rc = SQLFetch( sth );
+       if ( BACKSQL_SUCCESS( rc ) ) {
+               if ( strtol( row.cols[ 0 ], NULL, 0 ) > 0 ) {
+                       res = LDAP_COMPARE_TRUE;
+               } else {
+                       res = LDAP_COMPARE_FALSE;
+               }
+
+       } else {
+               res = LDAP_OTHER;
+       }
+       backsql_FreeRow( &row );
+
+       SQLFreeStmt( sth, SQL_DROP );
+
+       Debug( LDAP_DEBUG_TRACE, "<==backsql_has_children(): %s\n",
+                       res == LDAP_COMPARE_TRUE ? "yes" : "no", 0, 0 );
+
+       return res;
+}
+
 int
 backsql_get_attr_vals( backsql_at_map_rec *at, backsql_srch_info *bsi )
 {
@@ -182,7 +255,9 @@ 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.bv_val, at->name.bv_val, bsi->c_eid->keyval );
+               // bsi->oc->name.bv_val, at->name.bv_val, 
+               bsi->oc->oc->soc_names[0], at->ad->ad_cname.bv_val, 
+               bsi->c_eid->keyval );
 
        rc = backsql_Prepare( bsi->dbh, &sth, at->query, 0 );
        if ( rc != SQL_SUCCESS ) {
@@ -230,14 +305,14 @@ backsql_get_attr_vals( backsql_at_map_rec *at, backsql_srch_info *bsi )
                                        backsql_entry_addattr( bsi->e, 
                                                &row.col_names[ i ], &bv );
 
-#if 0
+#ifdef BACKSQL_TRACE
                                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 ].bv_val, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
                        }
                }
        }
@@ -255,6 +330,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
        int                     i;
        backsql_at_map_rec      *at;
        int                     rc;
+       AttributeDescription    *ad_oc = slap_schema.si_ad_objectClass;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 );
 
@@ -279,7 +355,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                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 ( attr->an_desc == ad_oc
 #if 0  /* FIXME: what is 0.10 ? */
                                        || !BACKSQL_NCMP( &attr->an_name, &bv_n_0_10 ) 
 #endif
@@ -303,6 +379,7 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                                        bsi->oc->name.bv_val, 0 );
                        }
                }
+
        } else {
                Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
                        "retrieving all attributes\n", 0, 0, 0 );
@@ -310,7 +387,35 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid )
                                bsi, 0, AVL_INORDER );
        }
 
-       backsql_entry_addattr( bsi->e, &bv_n_objectclass, &bsi->oc->name );
+       if ( attr_merge_one( bsi->e, ad_oc, &bsi->oc->name ) ) {
+               entry_free( e );
+               return NULL;
+       }
+
+       if ( global_schemacheck ) {
+               const char      *text = NULL;
+               char            textbuf[ 1024 ];
+               size_t          textlen = sizeof( textbuf );
+               struct berval   bv[ 2 ] = { bsi->oc->name, { 0, NULL } };
+               struct berval   soc;
+               AttributeDescription    *ad_soc
+                       = slap_schema.si_ad_structuralObjectClass;
+
+               int rc = structural_class( bv, &soc, NULL, 
+                               &text, textbuf, textlen );
+               if ( rc != LDAP_SUCCESS ) {
+                       entry_free( e );
+                       return NULL;
+               }
+
+               if ( bsi->attr_flags | BSQL_SF_ALL_OPER 
+                               || an_find( bsi->attrs, &AllOper ) ) {
+                       if ( attr_merge_one( bsi->e, ad_soc, &soc ) ) {
+                               entry_free( e );
+                               return NULL;
+                       }
+               }
+       }
 
        Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 );
 
index bc52fa8669f15035184f5214513e64e385a5178c..c29470b4e8ae8166528e8b3e2b90547542f46676 100644 (file)
@@ -21,6 +21,8 @@ typedef struct backsql_entryID {
 
 int backsql_dn2id( backsql_info *bi, backsql_entryID *id,
                SQLHDBC dbh, struct berval *dn );
+int backsql_has_children( backsql_info *bi, SQLHDBC dbh, struct berval *dn );
+
 /* returns next */
 backsql_entryID *backsql_free_entryID( backsql_entryID *id, int freeit );
 
diff --git a/servers/slapd/back-sql/external.h b/servers/slapd/back-sql/external.h
new file mode 100644 (file)
index 0000000..a45ac6f
--- /dev/null
@@ -0,0 +1,43 @@
+/* $OpenLDAP$ */
+#ifndef _SQL_EXTERNAL_H
+#define _SQL_EXTERNAL_H
+
+/*
+ *      Copyright 1999, Dmitry Kovalev <mit@openldap.org>, All rights reserved.
+ *
+ *      Redistribution and use in source and binary forms are permitted only
+ *      as authorized by the OpenLDAP Public License.  A copy of this
+ *      license is available at http://www.OpenLDAP.org/license.html or
+ *      in file LICENSE in the top-level directory of the distribution.
+ */
+
+
+LDAP_BEGIN_DECL
+
+extern BI_init sql_back_initialize;
+extern BI_destroy      backsql_destroy;
+
+extern BI_db_init      backsql_db_init;
+extern BI_db_open      backsql_db_open;
+extern BI_db_close     backsql_db_close;
+extern BI_db_destroy   backsql_db_destroy;
+
+extern BI_db_config    backsql_db_config;
+
+extern BI_op_bind      backsql_bind;
+extern BI_op_unbind    backsql_unbind;
+extern BI_op_search    backsql_search;
+extern BI_op_compare   backsql_compare;
+extern BI_op_modify    backsql_modify;
+extern BI_op_modrdn    backsql_modrdn;
+extern BI_op_add       backsql_add;
+extern BI_op_delete    backsql_delete;
+extern BI_op_abandon   backsql_abandon;
+
+extern BI_operational  backsql_operational;
+
+extern BI_connection_destroy   backsql_connection_destroy;
+
+LDAP_END_DECL
+
+#endif /* _SQL_EXTERNAL_H */
index 79d8dec530d590a7e78b5331f2e2671fd4c58e68..3d4e30242fbbda57de828d00eec374d8b2a62a57 100644 (file)
@@ -74,6 +74,7 @@ sql_back_initialize(
        bi->bi_acl_group = 0;
        bi->bi_acl_attribute = 0;
        bi->bi_chk_referrals = 0;
+       bi->bi_operational = backsql_operational;
  
        bi->bi_connection_init = 0;
        bi->bi_connection_destroy = backsql_connection_destroy;
@@ -100,10 +101,10 @@ backsql_db_init(
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_db_init()\n", 0, 0, 0 );
        si = (backsql_info *)ch_calloc( 1, sizeof( backsql_info ) );
+       memset( si, '\0', sizeof( backsql_info ) );
        ldap_pvt_thread_mutex_init( &si->dbconn_mutex );
        ldap_pvt_thread_mutex_init( &si->schema_mutex );
        backsql_init_db_env( si );
-       si->has_ldapinfo_dn_ru = -1;
 
        bd->be_private = si;
        Debug( LDAP_DEBUG_TRACE, "<==backsql_db_init()\n", 0, 0, 0 );
@@ -120,11 +121,11 @@ backsql_db_destroy(
        ldap_pvt_thread_mutex_lock( &si->dbconn_mutex );
        backsql_free_db_env( si );
        ldap_pvt_thread_mutex_unlock( &si->dbconn_mutex );
+       ldap_pvt_thread_mutex_destroy( &si->dbconn_mutex );
        ldap_pvt_thread_mutex_lock( &si->schema_mutex );
        backsql_destroy_schema_map( si );
        ldap_pvt_thread_mutex_unlock( &si->schema_mutex );
        ldap_pvt_thread_mutex_destroy( &si->schema_mutex );
-       ldap_pvt_thread_mutex_destroy( &si->dbconn_mutex );
        free( si->dbname );
        free( si->dbuser );
        if ( si->dbpasswd ) {
@@ -133,11 +134,13 @@ backsql_db_destroy(
        if ( si->dbhost ) {
                free( si->dbhost );
        }
-       if ( si->upper_func ) {
-               free( si->upper_func );
+       if ( si->upper_func.bv_val ) {
+               free( si->upper_func.bv_val );
+               free( si->upper_func_open.bv_val );
+               free( si->upper_func_close.bv_val );
        }
        
-       free( si->subtree_cond );
+       free( si->subtree_cond.bv_val );
        free( si->oc_query );
        free( si->at_query );
        free( si->insentry_query );
@@ -155,7 +158,7 @@ backsql_db_open(
        backsql_info    *si = (backsql_info*)bd->be_private;
        Connection      tmp;
        SQLHDBC         dbh;
-       int             idq_len;
+       ber_len_t       idq_len;
        struct berval   bv;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_db_open(): "
@@ -163,52 +166,194 @@ backsql_db_open(
        if ( si->dbname == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "datasource name not specified "
-                       "(use dbname directive in slapd.conf)\n", 0, 0, 0 );
+                       "(use \"dbname\" directive in slapd.conf)\n", 0, 0, 0 );
                return 1;
        }
+
+       if ( si->concat_func == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "concat func not specified (use \"concat_pattern\" "
+                       "directive in slapd.conf)\n", 0, 0, 0 );
+
+               if ( backsql_split_pattern( backsql_def_concat_func, 
+                               &si->concat_func, 2 ) ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                               "unable to parse pattern '%s'",
+                               backsql_def_concat_func, 0, 0 );
+                       return 1;
+               }
+       }
+
+       /*
+        * Prepare cast string as required
+        */
+       if ( si->upper_func.bv_val ) {
+               char buf[1024];
+
+               if ( BACKSQL_UPPER_NEEDS_CAST( si ) ) {
+                       snprintf( buf, sizeof( buf ), 
+                               "%s(cast (" /* ? as varchar(%d))) */ , 
+                               si->upper_func.bv_val );
+                       ber_str2bv( buf, 0, 1, &si->upper_func_open );
+
+                       snprintf( buf, sizeof( buf ),
+                               /* (cast(? */ " as varchar(%d)))",
+                               BACKSQL_MAX_DN_LEN );
+                       ber_str2bv( buf, 0, 1, &si->upper_func_close );
+
+               } else {
+                       snprintf( buf, sizeof( buf ), "%s(" /* ?) */ ,
+                                       si->upper_func.bv_val );
+                       ber_str2bv( buf, 0, 1, &si->upper_func_open );
+
+                       ber_str2bv( /* (? */ ")", 0, 1, &si->upper_func_close );
+               }
+       }
        
        if ( si->dbuser == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "user name not specified "
-                       "(use dbuser directive in slapd.conf)\n", 0, 0, 0 );
+                       "(use \"dbuser\" directive in slapd.conf)\n", 0, 0, 0 );
                return 1;
        }
        
-       if ( si->subtree_cond == NULL ) {
+       if ( si->subtree_cond.bv_val == NULL ) {
+               /*
+                * Prepare concat function for subtree search condition
+                */
+               struct berval   concat;
+               ber_len_t       len = 0;
+               struct berval   values[] = {
+                       { sizeof( "'%'" ) - 1,  "'%'" },
+                       { sizeof( "?" ) - 1,    "?" },
+                       { 0,                    NULL }
+               };
+
+               if ( backsql_prepare_pattern( si->concat_func, values, 
+                               &concat ) ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                               "unable to prepare CONCAT pattern", 0, 0, 0 );
+                       return 1;
+               }
+                       
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "subtree search SQL condition not specified "
-                       "(use subtree_cond directive in slapd.conf)\n", 
+                       "(use \"subtree_cond\" directive in slapd.conf)\n", 
+                       0, 0, 0);
+
+               si->subtree_cond.bv_val = NULL;
+               si->subtree_cond.bv_len = 0;
+
+               if ( si->upper_func.bv_val ) {
+
+                       /*
+                        * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%',?))
+                        */
+
+                       backsql_strfcat( &si->subtree_cond, &len, "blbbb",
+                                       &si->upper_func,
+                                       (ber_len_t)sizeof( "(ldap_entries.dn) LIKE " ) - 1,
+                                               "(ldap_entries.dn) LIKE ",
+                                       &si->upper_func_open,
+                                       &concat,
+                                       &si->upper_func_close );
+
+               } else {
+
+                       /*
+                        * ldap_entries.dn LIKE CONCAT('%',?)
+                        */
+
+                       backsql_strfcat( &si->subtree_cond, &len, "lb",
+                                       (ber_len_t)sizeof( "ldap_entries.dn LIKE " ) - 1,
+                                               "ldap_entries.dn LIKE ",
+                                       &concat );
+               }
+                       
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "setting '%s' as default\n",
+                       si->subtree_cond.bv_val, 0, 0 );
+       }
+
+       if ( si->children_cond.bv_val == NULL ) {
+               /*
+                * Prepare concat function for children search condition
+                */
+               struct berval   concat;
+               ber_len_t       len = 0;
+               struct berval   values[] = {
+                       { sizeof( "'%,'" ) - 1, "'%,'" },
+                       { sizeof( "?" ) - 1,    "?" },
+                       { 0,                    NULL }
+               };
+
+               if ( backsql_prepare_pattern( si->concat_func, values, 
+                               &concat ) ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                               "unable to prepare CONCAT pattern", 0, 0, 0 );
+                       return 1;
+               }
+                       
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "children search SQL condition not specified "
+                       "(use \"children_cond\" directive in slapd.conf)\n", 
                        0, 0, 0);
-               if ( si->upper_func ) {
-                       struct berval   bv = { 0, NULL };
-                       int             len = 0;
 
-                       backsql_strcat( &bv, &len, si->upper_func,
-                                       backsql_def_upper_subtree_cond, NULL );
-                       si->subtree_cond = bv.bv_val;
+               si->children_cond.bv_val = NULL;
+               si->children_cond.bv_len = 0;
+
+               if ( si->upper_func.bv_val ) {
+
+                       /*
+                        * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%,',?))
+                        */
+
+                       backsql_strfcat( &si->children_cond, &len, "blbbb",
+                                       &si->upper_func,
+                                       (ber_len_t)sizeof( "(ldap_entries.dn) LIKE " ) - 1,
+                                               "(ldap_entries.dn) LIKE ",
+                                       &si->upper_func_open,
+                                       &concat,
+                                       &si->upper_func_close );
+
                } else {
-                       si->subtree_cond = ch_strdup( backsql_def_subtree_cond );
+
+                       /*
+                        * ldap_entries.dn LIKE CONCAT('%,',?)
+                        */
+
+                       backsql_strfcat( &si->children_cond, &len, "lb",
+                                       (ber_len_t)sizeof( "ldap_entries.dn LIKE " ) - 1,
+                                               "ldap_entries.dn LIKE ",
+                                       &concat );
                }
                        
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "setting '%s' as default\n",
-                       si->subtree_cond, 0, 0 );
+                       si->children_cond.bv_val, 0, 0 );
        }
 
        if ( si->oc_query == NULL ) {
+               if ( BACKSQL_CREATE_NEEDS_SELECT( si ) ) {
+                       si->oc_query =
+                               ch_strdup( backsql_def_needs_select_oc_query );
+
+               } else {
+                       si->oc_query = ch_strdup( backsql_def_oc_query );
+               }
+
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "objectclass mapping SQL statement not specified "
-                       "(use oc_query directive in slapd.conf)\n", 0, 0, 0 );
+                       "(use \"oc_query\" directive in slapd.conf)\n", 
+                       0, 0, 0 );
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
-                       "setting '%s' by default\n", 
-                       backsql_def_oc_query, 0, 0 );
-               si->oc_query = ch_strdup( backsql_def_oc_query );
+                       "setting '%s' by default\n", si->oc_query, 0, 0 );
        }
        
        if ( si->at_query == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "attribute mapping SQL statement not specified "
-                       "(use at_query directive in slapd.conf)\n",
+                       "(use \"at_query\" directive in slapd.conf)\n",
                        0, 0, 0 );
                Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "setting '%s' by default\n",
@@ -219,7 +364,7 @@ backsql_db_open(
        if ( si->insentry_query == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "entry insertion SQL statement not specified "
-                       "(use insentry_query directive in slapd.conf)\n",
+                       "(use \"insentry_query\" directive in slapd.conf)\n",
                        0, 0, 0 );
                Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "setting '%s' by default\n",
@@ -230,14 +375,15 @@ backsql_db_open(
        if ( si->delentry_query == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "entry deletion SQL statement not specified "
-                       "(use delentry_query directive in slapd.conf)\n",
+                       "(use \"delentry_query\" directive in slapd.conf)\n",
                        0, 0, 0 );
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "setting '%s' by default\n",
                        backsql_def_delentry_query, 0, 0 );
                si->delentry_query = ch_strdup( backsql_def_delentry_query );
        }
-       
+
+
        tmp.c_connid =- 1;
        if ( backsql_get_db_conn( bd, &tmp, &dbh ) != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
@@ -245,36 +391,55 @@ backsql_db_open(
                return 1;
        }
 
+       /*
+        * Prepare ID selection query
+        */
        si->id_query = NULL;
        idq_len = 0;
 
        bv.bv_val = NULL;
        bv.bv_len = 0;
-       if ( si->upper_func == NULL ) {
+       if ( si->upper_func.bv_val == NULL ) {
                backsql_strcat( &bv, &idq_len, backsql_id_query, 
                                "dn=?", NULL );
        } else {
-               if ( si->has_ldapinfo_dn_ru ) {
+               if ( BACKSQL_HAS_LDAPINFO_DN_RU( si ) ) {
                        backsql_strcat( &bv, &idq_len, backsql_id_query,
                                        "dn_ru=?", NULL );
                } else {
-                       if ( si->isTimesTen ) {
-                               backsql_strcat( &bv, &idq_len, 
+                       if ( BACKSQL_USE_REVERSE_DN( si ) ) {
+                               backsql_strfcat( &bv, &idq_len, "sbl",
                                                backsql_id_query,
-                                               si->upper_func, "(dn)=?",
-                                               NULL );
+                                               &si->upper_func, 
+                                               (ber_len_t)sizeof( "(dn)=?" ) - 1, "(dn)=?" );
                        } else {
-                               backsql_strcat( &bv, &idq_len, 
+                               backsql_strfcat( &bv, &idq_len, "sblbcb",
                                                backsql_id_query,
-                                               si->upper_func, "(dn)=",
-                                               si->upper_func, "(?)", NULL );
+                                               &si->upper_func, 
+                                               (ber_len_t)sizeof( "(dn)=" ) - 1, "(dn)=",
+                                               &si->upper_func_open, 
+                                               '?', 
+                                               &si->upper_func_close );
                        }
                }
        }
        si->id_query = bv.bv_val;
+
+               /*
+        * Prepare children ID selection query
+        */
+       si->has_children_query = NULL;
+       idq_len = 0;
+
+       bv.bv_val = NULL;
+       bv.bv_len = 0;
+       backsql_strfcat( &bv, &idq_len, "sb", 
+                       "select count(*) from ldap_entries where ",
+                       &si->children_cond );
+       si->has_children_query = bv.bv_val;
  
        backsql_free_db_conn( bd, &tmp );
-       if ( !si->schema_loaded ) {
+       if ( !BACKSQL_SCHEMA_LOADED( si ) ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "test failed, schema map not loaded - exiting\n",
                        0, 0, 0 );
index 2757d33e4c4b660279d67a73c43bbd2fa7c1912e..6966c2c6fdb5bf136f361b0e63c3881631b8a67c 100644 (file)
 #include "util.h"
 
 /*
- * PostgreSQL doesn't work without :(
+ * PostgreSQL 7.0 doesn't work without :(
  */
 #define        BACKSQL_REALLOC_STMT
 
+/*
+ * Skip:
+ * - the first occurrence of objectClass, which is used
+ *   to determine how to bulid the SQL entry (FIXME ?!?)
+ * - operational attributes
+ *   empty attributes (FIXME ?!?)
+ */
+#define        backsql_attr_skip(ad,vals) \
+       ( \
+               ( (ad) == slap_schema.si_ad_objectClass \
+                               && (vals)[ 1 ].bv_val == NULL ) \
+               || is_at_operational( (ad)->ad_type ) \
+               || ( (vals)[ 0 ].bv_val == NULL ) \
+       )
+
 static int
 backsql_modify_internal(
        backsql_info            *bi,
        SQLHDBC                 dbh, 
        backsql_oc_map_rec      *oc,
        backsql_entryID         *e_id,
-       Modifications           *modlist )
+       Modifications           *modlist,
+       const char              **text )
 {
        RETCODE         rc;
        SQLHSTMT        sth;
        Modifications   *ml;
+       int             res = LDAP_SUCCESS;
 
-       Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+       Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
                "traversing modifications list\n", 0, 0, 0 );
+
+       *text = NULL;
+
 #ifndef BACKSQL_REALLOC_STMT
        SQLAllocStmt( dbh, &sth );
 #endif /* BACKSQL_REALLOC_STMT */
+
        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
-               AttributeDescription *ad;
+               AttributeDescription    *ad;
                backsql_at_map_rec      *at = NULL;
                struct berval           *at_val;
                Modification            *c_mod;
@@ -60,16 +81,30 @@ backsql_modify_internal(
 #endif /* BACKSQL_REALLOC_STMT */
 
                c_mod = &ml->sml_mod;
-
                ad = c_mod->sm_desc;
-               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): attribute '%s'\n",
-                               ad->ad_cname.bv_val, 0, 0 );
+
+               Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
+                       "modifying attribute '%s'\n",
+                       ad->ad_cname.bv_val, 0, 0 );
+
+               if ( backsql_attr_skip( ad, c_mod->sm_bvalues ) ) {
+                       continue;
+               }
+
                at = backsql_ad2at( oc, ad );
                if ( at == NULL ) {
-                       Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                       Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
                                "attribute provided is not registered "
-                               "in objectclass '%s'\n",
+                               "in objectClass '%s'\n",
                                ad->ad_cname.bv_val, 0, 0 );
+
+                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                               res = LDAP_UNWILLING_TO_PERFORM;
+                               *text = "operation not permitted "
+                                       "within namingContext";
+                               goto done;
+                       }
+
                        continue;
                }
   
@@ -77,58 +112,100 @@ backsql_modify_internal(
                case LDAP_MOD_REPLACE: {
                        SQLHSTMT asth;
                        BACKSQL_ROW_NTS row;
-                        
-                       Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                       
+                       Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
                                "replacing values for attribute '%s'\n",
-                               at->name.bv_val, 0, 0 );
+                               at->ad->ad_cname.bv_val, 0, 0 );
 
                        if ( at->add_proc == NULL ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "add procedure is not defined "
                                        "for attribute '%s' "
                                        "- unable to perform replacements\n",
-                                       at->name.bv_val, 0, 0 );
+                                       at->ad->ad_cname.bv_val, 0, 0 );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       res = LDAP_UNWILLING_TO_PERFORM;
+                                       *text = "operation not permitted "
+                                               "within namingContext";
+                                       goto done;
+                               }
+
                                break;
                        }
 
                        if ( at->delete_proc == NULL ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "delete procedure is not defined "
                                        "for attribute '%s' "
                                        "- adding only\n",
-                                       at->name.bv_val, 0, 0 );
+                                       at->ad->ad_cname.bv_val, 0, 0 );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       res = LDAP_UNWILLING_TO_PERFORM;
+                                       *text = "operation not permitted "
+                                               "within namingContext";
+                                       goto done;
+                               }
+
                                goto add_only;
                        }
                        
 del_all:
                        rc = backsql_Prepare( dbh, &asth, at->query, 0 );
                        if ( rc != SQL_SUCCESS ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "error preparing query\n", 0, 0, 0 );
                                backsql_PrintErrors( bi->db_env, dbh, 
                                                asth, rc );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       res = LDAP_OTHER;
+                                       *text = "SQL-backend error";
+                                       goto done;
+                               }
+
                                break;
                        }
 
                        rc = backsql_BindParamID( asth, 1, &e_id->keyval );
                        if ( rc != SQL_SUCCESS ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "error binding key value parameter\n",
                                        0, 0, 0 );
                                backsql_PrintErrors( bi->db_env, dbh, 
                                                asth, rc );
                                SQLFreeStmt( asth, SQL_DROP );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       res = LDAP_OTHER;
+                                       *text = "SQL-backend error";
+                                       goto done;
+                               }
+
                                break;
                        }
                        
                        rc = SQLExecute( asth );
                        if ( !BACKSQL_SUCCESS( rc ) ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "error executing attribute query\n",
                                        0, 0, 0 );
                                backsql_PrintErrors( bi->db_env, dbh, 
                                                asth, rc );
                                SQLFreeStmt( asth, SQL_DROP );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       res = LDAP_OTHER;
+                                       *text = "SQL-backend error";
+                                       goto done;
+                               }
+
                                break;
                        }
 
@@ -163,19 +240,25 @@ del_all:
                                                strlen( row.cols[ i ] ), 0 );
                         
                                        Debug( LDAP_DEBUG_TRACE, 
-                                               "backsql_modify(): "
+                                               "backsql_modify_internal(): "
                                                "executing '%s'\n",
                                                at->delete_proc, 0, 0 );
                                        rc = SQLExecDirect( sth,
                                                at->delete_proc, SQL_NTS );
                                        if ( rc != SQL_SUCCESS ) {
                                                Debug( LDAP_DEBUG_TRACE,
-                                                       "backsql_modify(): "
+                                                       "backsql_modify_internal(): "
                                                        "delete_proc "
                                                        "execution failed\n",
                                                        0, 0, 0 );
                                                backsql_PrintErrors( bi->db_env,
                                                                dbh, sth, rc );
+
+                                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                                       res = LDAP_OTHER;
+                                                       *text = "SQL-backend error";
+                                                       goto done;
+                                               }
                                        }
 #ifdef BACKSQL_REALLOC_STMT
                                        SQLFreeStmt( sth, SQL_DROP );
@@ -194,24 +277,25 @@ del_all:
                case SLAP_MOD_SOFTADD:
 add_only:;
                        if ( at->add_proc == NULL ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "add procedure is not defined "
                                        "for attribute '%s'\n",
-                                       at->name.bv_val, 0, 0 );
-                               break;
-                       }
-                       
-                       if ( c_mod->sm_bvalues == NULL ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
-                                       "no values given to add "
-                                       "for attribute '%s'\n",
-                                       at->name.bv_val, 0, 0 );
+                                       at->ad->ad_cname.bv_val, 0, 0 );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       res = LDAP_UNWILLING_TO_PERFORM;
+                                       *text = "operation not permitted "
+                                               "within namingContext";
+                                       goto done;
+                               }
+
                                break;
                        }
                        
-                       Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                       Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
                                "adding new values for attribute '%s'\n",
-                               at->name.bv_val, 0, 0 );
+                               at->ad->ad_cname.bv_val, 0, 0 );
                        for ( i = 0, at_val = c_mod->sm_bvalues;
                                        at_val->bv_val != NULL; 
                                        i++, at_val++ ) {
@@ -240,18 +324,25 @@ add_only:;
                                        0, 0, at_val->bv_val, 
                                        at_val->bv_len, 0 );
 
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "executing '%s'\n", 
                                        at->add_proc, 0, 0 );
                                rc = SQLExecDirect( sth, at->add_proc, 
                                                SQL_NTS );
                                if ( rc != SQL_SUCCESS ) {
                                        Debug( LDAP_DEBUG_TRACE,
-                                               "backsql_modify(): "
+                                               "backsql_modify_internal(): "
                                                "add_proc execution failed\n",
                                                0, 0, 0 );
                                        backsql_PrintErrors( bi->db_env,
                                                        dbh, sth, rc );
+
+                                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                               res = LDAP_OTHER;
+                                               *text = "SQL-backend error";
+                                               goto done;
+                                       }
                                }
 #ifdef BACKSQL_REALLOC_STMT
                                SQLFreeStmt( sth, SQL_DROP );
@@ -262,25 +353,36 @@ add_only:;
                        
                case LDAP_MOD_DELETE:
                        if ( at->delete_proc == NULL ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "delete procedure is not defined "
                                        "for attribute '%s'\n",
-                                       at->name.bv_val, 0, 0 );
+                                       at->ad->ad_cname.bv_val, 0, 0 );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       res = LDAP_UNWILLING_TO_PERFORM;
+                                       *text = "operation not permitted "
+                                               "within namingContext";
+                                       goto done;
+                               }
+
                                break;
                        }
 
                        if ( c_mod->sm_bvalues == NULL ) {
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "no values given to delete "
                                        "for attribute '%s' "
                                        "-- deleting all values\n",
-                                       at->name.bv_val, 0, 0 );
+                                       at->ad->ad_cname.bv_val, 0, 0 );
                                goto del_all;
                        }
 
-                       Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                       Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): "
                                "deleting values for attribute '%s'\n",
-                               at->name.bv_val, 0, 0 );
+                               at->ad->ad_cname.bv_val, 0, 0 );
+
                        for ( i = 0, at_val = c_mod->sm_bvalues;
                                        at_val->bv_val != NULL;
                                        i++, at_val++ ) {
@@ -308,18 +410,25 @@ add_only:;
                                        0, 0, at_val->bv_val, 
                                        at_val->bv_len, 0 );
 
-                               Debug( LDAP_DEBUG_TRACE, "backsql_modify(): "
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "backsql_modify_internal(): "
                                        "executing '%s'\n", 
                                        at->delete_proc, 0, 0 );
                                rc = SQLExecDirect( sth, at->delete_proc,
                                                SQL_NTS );
                                if ( rc != SQL_SUCCESS ) {
                                        Debug( LDAP_DEBUG_TRACE,
-                                               "backsql_modify(): "
+                                               "backsql_modify_internal(): "
                                                "delete_proc execution "
                                                "failed\n", 0, 0, 0 );
                                        backsql_PrintErrors( bi->db_env,
                                                        dbh, sth, rc );
+
+                                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                               res = LDAP_OTHER;
+                                               *text = "SQL-backend error";
+                                               goto done;
+                                       }
                                }
 #ifdef BACKSQL_REALLOC_STMT
                                SQLFreeStmt( sth, SQL_DROP );
@@ -335,6 +444,8 @@ add_only:;
 #endif /* BACKSQL_REALLOC_STMT */
        }
 
+done:;
+       
 #ifndef BACKSQL_REALLOC_STMT
        SQLFreeStmt( sth, SQL_DROP );
 #endif /* BACKSQL_REALLOC_STMT */
@@ -342,7 +453,7 @@ add_only:;
        /*
         * FIXME: should fail in case one change fails?
         */
-       return LDAP_SUCCESS;
+       return res;
 }
 
 int
@@ -358,7 +469,9 @@ backsql_modify(
        SQLHDBC                 dbh;
        backsql_oc_map_rec      *oc = NULL;
        backsql_entryID         e_id;
+       Entry                   e;
        int                     res;
+       const char              *text = NULL;
 
        /*
         * FIXME: in case part of the operation cannot be performed
@@ -415,7 +528,17 @@ backsql_modify(
                return 1;
        }
 
-       res = backsql_modify_internal( bi, dbh, oc, &e_id, modlist );
+       e.e_attrs = NULL;
+       e.e_name = *dn;
+       e.e_nname = *ndn;
+       if ( !acl_check_modlist( be, conn, op, &e, modlist )) {
+               res = LDAP_INSUFFICIENT_ACCESS;
+
+       } else {
+               res = backsql_modify_internal( bi, dbh, oc, &e_id, 
+                               modlist, &text );
+       }
+
        if ( res == LDAP_SUCCESS ) {
                /*
                 * Commit only if all operations succeed
@@ -428,7 +551,7 @@ backsql_modify(
                 */
                SQLTransact( SQL_NULL_HENV, dbh, SQL_COMMIT );
        }
-       send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
+       send_ldap_result( conn, op, res, "", text, NULL, NULL );
        Debug( LDAP_DEBUG_TRACE, "<==backsql_modify()\n", 0, 0, 0 );
 
        return 0;
@@ -460,6 +583,7 @@ backsql_modrdn(
        const char              *text = NULL;
        LDAPRDN                 *new_rdn = NULL;
        LDAPRDN                 *old_rdn = NULL;
+       Entry                   e;
        Modifications           *mod;
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry '%s', "
@@ -494,9 +618,43 @@ backsql_modrdn(
        Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): entry id is %ld\n",
                e_id.id, 0, 0 );
 
+       if ( backsql_has_children( bi, dbh, ndn ) == LDAP_COMPARE_TRUE ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
+                       "entry \"%s\" has children\n", dn->bv_val, 0, 0 );
+               send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
+                               NULL, "subtree delete not supported",
+                               NULL, NULL );
+               return 1;
+       }
+
        dnParent( dn, &p_dn );
        dnParent( ndn, &p_ndn );
 
+       /*
+        * namingContext "" is not supported
+        */
+       if ( p_dn.bv_len == 0 ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): "
+                       "parent is \"\" - aborting\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, 
+                               "", "not allowed within namingContext", 
+                               NULL, NULL );
+               goto modrdn_return;
+       }
+
+       /*
+        * Check for children access to parent
+        */
+       e.e_attrs = NULL;
+       e.e_name = p_dn;
+       e.e_nname = p_ndn;
+       if ( !access_allowed( be, conn, op, &e, slap_schema.si_ad_children, 
+                               NULL, ACL_WRITE, NULL ) ) {
+               Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 );
+               res = LDAP_INSUFFICIENT_ACCESS;
+               goto modrdn_return;
+       }
+
        if ( newSuperior ) {
                /*
                 * namingContext "" is not supported
@@ -513,6 +671,21 @@ backsql_modrdn(
                new_pdn = newSuperior;
                new_npdn = nnewSuperior;
 
+               e.e_name = *new_pdn;
+               e.e_nname = *new_npdn;
+
+               /*
+                * Check for children access to new parent
+                */
+               if ( !access_allowed( be, conn, op, &e, 
+                                       slap_schema.si_ad_children, 
+                                       NULL, ACL_WRITE, NULL ) ) {
+                       Debug( LDAP_DEBUG_TRACE, "no access to new parent\n", 
+                                       0, 0, 0 );
+                       res = LDAP_INSUFFICIENT_ACCESS;
+                       goto modrdn_return;
+               }
+
        } else {
                new_pdn = &p_dn;
                new_npdn = &p_ndn;
@@ -611,8 +784,9 @@ backsql_modrdn(
                goto modrdn_return;
        }
 
-       /* Get attribute type and attribute value of our new rdn, we will
-        * need to add that to our new entry
+       /*
+        * 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 ) ) {
@@ -664,29 +838,35 @@ backsql_modrdn(
                }
        }
 
-       res = slap_modrdn2mods( NULL, NULL, NULL, NULL, old_rdn, new_rdn, 
+       e.e_name = new_dn;
+       e.e_nname = new_ndn;
+       res = slap_modrdn2mods( be, conn, op, &e, 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 ) {
+       if ( !acl_check_modlist( be, conn, op, &e, mod )) {
+               res = LDAP_INSUFFICIENT_ACCESS;
                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 );
+       oc = backsql_id2oc( bi, e_id.oc_id );
+       res = backsql_modify_internal( bi, dbh, oc, &e_id, mod, &text );
+
+       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 );
+       }
 
 modrdn_return:
        SQLFreeStmt( sth, SQL_DROP );
@@ -714,7 +894,7 @@ modrdn_return:
                }
        }
 
-       send_ldap_result( conn, op, res, "", NULL, NULL, NULL );
+       send_ldap_result( conn, op, res, "", text, NULL, NULL );
 
        Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 );
        return 0;
@@ -736,26 +916,43 @@ backsql_add(
        backsql_oc_map_rec      *oc = NULL;
        backsql_at_map_rec      *at_rec = NULL;
        backsql_entryID         e_id, parent_id;
+       Entry                   p;
        int                     res;
        Attribute               *at;
        struct berval           *at_val;
        struct berval           pdn;
-       /* first parameter no, parameter order */
+       /* first parameter #, parameter order */
        SQLUSMALLINT            pno, po;
        /* procedure return code */
        int                     prc;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry '%s'\n",
-                       e->e_dn, 0, 0 );
+                       e->e_name.bv_val, 0, 0 );
 
        for ( at = e->e_attrs; at != NULL; at = at->a_next ) {
                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;
+                       if ( global_schemacheck ) {
+                               const char      *text = NULL;
+                               char            textbuf[ 1024 ];
+                               size_t          textlen = sizeof( textbuf );
+                               struct berval   soc;
+
+                               int rc = structural_class( at->a_vals, &soc, 
+                                               NULL, &text, textbuf, textlen );
+                               if ( rc != LDAP_SUCCESS ) {
+                                       break;
+                               }
+                               oc = backsql_name2oc( bi, &soc );
+
+                       } else {
+
+                               /*
+                                * FIXME: only the objectClass provided first
+                                * is considered when creating a new entry
+                                */
+                               oc = backsql_name2oc( bi, &at->a_vals[ 0 ] );
+                       }
+                       break;
                }
        }
 
@@ -777,6 +974,16 @@ backsql_add(
                                "operation not permitted within namingContext",
                                NULL, NULL );
                return 1;
+
+       } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
+                       && oc->create_keyval == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
+                       "create procedure needs select, but none is defined"
+                       "- aborting\n", 0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
+                               "operation not permitted within namingContext",
+                               NULL, NULL );
+               return 1;
        }
 
        prc = backsql_get_db_conn( be, conn, &dbh );
@@ -862,6 +1069,16 @@ backsql_add(
         * is expected to return the id as the first column of a select
         */
 
+       p.e_attrs = NULL;
+       p.e_name = pdn;
+       dnParent( &e->e_nname, &p.e_nname );
+       if ( !access_allowed( be, conn, op, &p, slap_schema.si_ad_children,
+                               NULL, ACL_WRITE, NULL ) ) {
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, 
+                               NULL, NULL, NULL, NULL );
+               return 1;
+       }
+
 #ifndef BACKSQL_REALLOC_STMT
        rc = SQLAllocStmt( dbh, &sth );
 #else /* BACKSQL_REALLOC_STMT */
@@ -899,6 +1116,27 @@ backsql_add(
                SWORD           ncols;
                SQLINTEGER      is_null;
 
+               if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
+#ifndef BACKSQL_REALLOC_STMT
+                       SQLFreeStmt( sth, SQL_RESET_PARAMS );
+#else /* BACKSQL_REALLOC_STMT */
+                       SQLFreeStmt( sth, SQL_DROP );
+                       rc = SQLAllocStmt( dbh, &sth );
+                       if ( rc != SQL_SUCCESS ) {
+                               send_ldap_result( conn, op, LDAP_OTHER, "",
+                                       "SQL-backend error", NULL, NULL );
+                               return 1;
+                       }
+#endif /* BACKSQL_REALLOC_STMT */
+
+                       rc = SQLExecDirect( sth, oc->create_keyval, SQL_NTS );
+                       if ( rc != SQL_SUCCESS ) {
+                               send_ldap_result( conn, op, LDAP_OTHER, "",
+                                       "SQL-backend error", NULL, NULL );
+                               return 1;
+                       }
+               }
+
                /*
                 * the query to know the id of the inserted entry
                 * must be embedded in the create procedure
@@ -916,8 +1154,8 @@ backsql_add(
 
                } else if ( ncols != 1 ) {
                        Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
-                               "create_proc result is bogus\n",
-                               0, 0, 0 );
+                               "create_proc result is bogus (ncols=%d)\n",
+                               ncols, 0, 0 );
                        backsql_PrintErrors( bi->db_env, dbh, sth, rc);
                        SQLFreeStmt( sth, SQL_DROP );
                        send_ldap_result( conn, op, LDAP_OTHER, "",
@@ -979,7 +1217,18 @@ backsql_add(
        for ( at = e->e_attrs; at != NULL; at = at->a_next ) {
                SQLUSMALLINT    currpos;
 
-               if ( at->a_vals[ 0 ].bv_val == NULL ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
+                       "adding attribute '%s'\n", 
+                       at->a_desc->ad_cname.bv_val, 0, 0 );
+
+               /*
+                * Skip:
+                * - the first occurrence of objectClass, which is used
+                *   to determine how to bulid the SQL entry (FIXME ?!?)
+                * - operational attributes
+                *   empty attributes (FIXME ?!?)
+                */
+               if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
                        continue;
                }
 
@@ -991,6 +1240,16 @@ backsql_add(
                                "in objectclass '%s'\n",
                                at->a_desc->ad_cname.bv_val,
                                oc->name.bv_val, 0 );
+
+                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                               send_ldap_result( conn, op, 
+                                               LDAP_UNWILLING_TO_PERFORM, "",
+                                               "operation not permitted "
+                                               "within namingContext",
+                                               NULL, NULL );
+                               return 1;
+                       }
+
                        continue;
                }
                
@@ -999,12 +1258,31 @@ backsql_add(
                                "add procedure is not defined "
                                "for attribute '%s'\n",
                                at->a_desc->ad_cname.bv_val, 0, 0 );
+
+                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                               send_ldap_result( conn, op, 
+                                               LDAP_UNWILLING_TO_PERFORM, "",
+                                               "operation not permitted "
+                                               "within namingContext",
+                                               NULL, NULL );
+                               return 1;
+                       }
+
                        continue;
                }
 
 #ifdef BACKSQL_REALLOC_STMT
                rc = backsql_Prepare( dbh, &sth, at_rec->add_proc, 0 );
                if ( rc != SQL_SUCCESS ) {
+
+                       if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                               send_ldap_result( conn, op, 
+                                               LDAP_OTHER, "",
+                                               "SQL-backend error",
+                                               NULL, NULL );
+                               return 1;
+                       }
+
                        continue;
                }
 #endif /* BACKSQL_REALLOC_STMT */
@@ -1025,10 +1303,20 @@ backsql_add(
                                SQL_INTEGER, 0, 0, &new_keyval, 0, 0 );
                currpos = pno + 2 - po;
 
-               for ( i = 0, at_val = &at->a_vals[ 0 ];
-                               at_val->bv_val != NULL;
+               for ( i = 0, at_val = &at->a_vals[ i ];
+                               at_val->bv_val != NULL;
                                i++, at_val = &at->a_vals[ i ] ) {
 
+                       /*
+                        * Do not deal with the objectClass that is used
+                        * to build the entry
+                        */
+                       if ( at->a_desc == slap_schema.si_ad_objectClass ) {
+                               if ( ber_bvcmp( at_val, &oc->name ) == 0 ) {
+                                       continue;
+                               }
+                       }
+
                        /*
                         * check for syntax needed here 
                         * maybe need binary bind?
@@ -1055,6 +1343,14 @@ backsql_add(
                                        "add_proc execution failed\n", 
                                        0, 0, 0 );
                                backsql_PrintErrors( bi->db_env, dbh, sth, rc );
+
+                               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
+                                       send_ldap_result( conn, op, 
+                                                       LDAP_OTHER, "",
+                                                       "SQL-backend error",
+                                                       NULL, NULL );
+                                       return 1;
+                               }
                        }
                }
 #ifndef BACKSQL_REALLOC_STMT
@@ -1072,6 +1368,7 @@ backsql_add(
                return 1;
        }
 #endif /* BACKSQL_REALLOC_STMT */
+       
        backsql_BindParamStr( sth, 1, e->e_name.bv_val, BACKSQL_MAX_DN_LEN );
        SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,
                        0, 0, &oc->id, 0, 0 );
@@ -1135,12 +1432,30 @@ backsql_delete(
        RETCODE                 rc;
        backsql_oc_map_rec      *oc = NULL;
        backsql_entryID         e_id;
+       Entry                   e;
        int                     res;
        /* first parameter no */
        SQLUSMALLINT            pno;
 
        Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry '%s'\n",
                        ndn->bv_val, 0, 0 );
+
+       dnParent( dn, &e.e_name );
+       dnParent( ndn, &e.e_nname );
+       e.e_attrs = NULL;
+
+       /* check parent for "children" acl */
+       if ( !access_allowed( be, conn, op, &e, slap_schema.si_ad_children, 
+                       NULL, ACL_WRITE, NULL ) ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
+                       "no write access to parent\n", 
+                       0, 0, 0 );
+               send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS, 
+                               "", NULL, NULL, NULL );
+               return 1;
+
+       }
+       
        res = backsql_get_db_conn( be, conn, &dbh );
        if ( res != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
@@ -1160,13 +1475,32 @@ backsql_delete(
                return 1;
        }
 
+       res = backsql_has_children( bi, dbh, ndn );
+       switch ( res ) {
+       case LDAP_COMPARE_TRUE:
+               Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
+                       "entry \"%s\" has children\n", dn->bv_val, 0, 0 );
+               send_ldap_result( conn, op, LDAP_NOT_ALLOWED_ON_NONLEAF,
+                               NULL, "subtree delete not supported",
+                               NULL, NULL );
+               return 1;
+
+       case LDAP_COMPARE_FALSE:
+               break;
+
+       default:
+               send_ldap_result( conn, op, res, NULL, NULL, NULL, NULL );
+               return 1;
+       }
+
        oc = backsql_id2oc( bi, e_id.oc_id );
        if ( oc == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_delete(): "
                        "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;
        }
 
@@ -1175,7 +1509,7 @@ backsql_delete(
                        "delete procedure is not defined "
                        "for this objectclass - aborting\n", 0, 0, 0 );
                send_ldap_result( conn, op, LDAP_UNWILLING_TO_PERFORM, "",
-                               "operation not supported for required DN", 
+                               "operation not permitted within namingContext",
                                NULL, NULL );
                return 1;
        }
index 57c16d546e0abe264ebd7864f68340c1f1ed0b04..1629a086e30b2b7f57619ec1f678cb83fc635935 100644 (file)
@@ -16,6 +16,7 @@
 #include "slap.h"
 #include "back-sql.h"
 #include "sql-wrap.h"
+#include "entry-id.h"
 
 int
 backsql_compare(
@@ -43,5 +44,70 @@ backsql_abandon(
        return 0;
 }
 
+
+/*
+ * sets the supported operational attributes (if required)
+ */
+
+int
+backsql_operational(
+       BackendDB       *be,
+       Connection      *conn, 
+       Operation       *op,
+       Entry           *e,
+       AttributeName   *attrs,
+       int             opattrs,
+       Attribute       **a )
+{
+
+       backsql_info            *bi = (backsql_info*)be->be_private;
+       SQLHDBC                 dbh = SQL_NULL_HDBC;
+       Attribute               **aa = a;
+       int                     rc;
+
+       Debug( LDAP_DEBUG_TRACE, "==>backsql_operational(): entry '%s'\n",
+                       e->e_nname.bv_val, 0, 0 );
+
+
+       if ( opattrs || ad_inlist( slap_schema.si_ad_hasSubordinates, attrs ) ) {
+               rc = backsql_get_db_conn( be, conn, &dbh );
+               if ( rc != LDAP_SUCCESS ) {
+                       goto no_connection;
+               }
+               
+               rc = backsql_has_children( bi, dbh, &e->e_nname );
+
+               switch( rc ) {
+               case LDAP_COMPARE_TRUE:
+               case LDAP_COMPARE_FALSE:
+                       *aa = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
+                       if ( *aa != NULL ) {
+                               aa = &(*aa)->a_next;
+                       }
+                       rc = 0;
+                       break;
+
+               default:
+                       Debug(LDAP_DEBUG_TRACE, 
+                               "backsql_operational(): "
+                               "has_children failed( %d)\n", 
+                               rc, 0, 0 );
+                       rc = 1;
+                       break;
+               }
+       }
+
+       return rc;
+
+no_connection:;
+       Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
+               "could not get connection handle - exiting\n", 
+               0, 0, 0 );
+       send_ldap_result( conn, op, rc, "", 
+                       rc == LDAP_OTHER ? "SQL-backend error" : "",
+                       NULL, NULL );
+       return 1;
+}
+
 #endif /* SLAPD_SQL */
 
index ca19bb1ed162d76bbb3a086be179107d24103adc..c82e75002e2cbc614a0b52b1d1a6519a8515e39e 100644 (file)
@@ -6,6 +6,7 @@ create table ldap_oc_mappings
        keytbl varchar(64) not null,
        keycol varchar(64) not null,
        create_proc varchar(255),
+       create_keyval varchar(255),
        delete_proc varchar(255),
        expect_return integer not null
 );
index 86661da25d96d8ee5edb94eb13acc6f49e53d0fe..556470cb53cc6c4c7185896aae5e4b5856c81565 100644 (file)
@@ -30,4 +30,7 @@ dbpasswd      ibmdb2
 subtree_cond   "upper(ldap_entries.dn) LIKE CONCAT('%',?)"
 insentry_query "insert into ldap_entries (id,dn,oc_map_id,parent,keyval) values ((select max(id)+1 from ldap_entries),?,?,?,?)"
 upper_func     "upper"
+upper_needs_cast       "yes"
+create_needs_select    "yes"
+has_ldapinfo_dn_ru     "no"
 
index a1da4a1d5b2a1e0b86524790ceb0f8861236b48d..137d91f32674d214600574d1ab800d4a04627cdc 100644 (file)
@@ -1,7 +1,8 @@
 drop table persons;
 CREATE TABLE persons (
        id int NOT NULL,
-       name varchar(255) NOT NULL
+       name varchar(255) NOT NULL,
+       surname varchar(255) NOT NULL
 );
 
 drop table institutes;
index f141f414eb0881a0cc33802d3ae5c786e5c37f44..623d81990d5c1ab38d0b2a7618c154087981eb67 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);
index c38036ba2014186e44dd34697acdf9ec0186e7b0..e538f19e7db03fec0d22202761891a343813102e 100644 (file)
@@ -1,24 +1,27 @@
 --mappings 
 
-insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,delete_proc,expect_return)
-values (1,'inetOrgPerson','persons','id','insert into persons (name) values ('''');\n select last_insert_id();',NULL,0);
+insert into ldap_oc_mappings (id,name,keytbl,keycol,create_proc,create_keyval,delete_proc,expect_return)
+values (1,'inetOrgPerson','persons','id','insert into persons (id,name,surname) values ((select max(id)+1 from persons),'''','''')','select max(id) from persons',NULL,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,create_keyval,delete_proc,expect_return)
+values (2,'document','documents','id',NULL,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_oc_mappings (id,name,keytbl,keycol,create_proc,create_keyval,delete_proc,expect_return)
+values (3,'organization','institutes','id',NULL,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,NULL,NULL,3,0);
+values (1,1,'cn','case when persons.name!='''' and persons.surname!='''' then persons.name||'' ''||persons.surname when persons.surname!='''' then persons.surname when persons.name!='''' then persons.name else '''' end','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 (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 (3,1,'sn','persons.name','persons',NULL,NULL,NULL,3,0);
+values (3,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 (6,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 (4,2,'description','documents.abstract','documents',NULL,NULL,NULL,3,0);
@@ -35,7 +38,7 @@ insert into ldap_attr_mappings (id,oc_map_id,name,sel_expr,from_tbls,join_where,
 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',
+values (8,1,'documentAuthor','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);
 
index 3a5dbb5ed8c33db6430bd1ba2b4423ab30af4212..aecc890597407c1941e14db58d88c6b27c739f39 100644 (file)
@@ -27,9 +27,9 @@ rootpw                secret
 dbname         PostgreSQL
 dbuser         postgres
 dbpasswd       postgres
-subtree_cond   "upper(ldap_entries.dn) LIKE '%'||?"
 insentry_query "insert into ldap_entries (id,dn,oc_map_id,parent,keyval) values ((select max(id)+1 from ldap_entries),?,?,?,?)"
 upper_func     "upper"
 strcast_func   "text"
+concat_pattern "?||?"
 has_ldapinfo_dn_ru     no
 
index cf765adc93466d78f48f750c87b262e4d2500e00..eaa63ab69228919cf43f04952db6cba74bc7e243 100644 (file)
@@ -73,16 +73,25 @@ backsql_make_attr_query(
        backsql_at_map_rec      *at_map )
 {
        struct berval   tmps = { 0, NULL };
-       int             tmpslen = 0;
-
-       backsql_strcat( &tmps, &tmpslen, "SELECT ", at_map->sel_expr, 
-                       " 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 ) {
-               backsql_strcat( &tmps, &tmpslen, " AND ", 
-                               at_map->join_where, NULL );
+       ber_len_t       tmpslen = 0;
+
+       backsql_strfcat( &tmps, &tmpslen, "lblblblbcbl", 
+                       (ber_len_t)sizeof( "SELECT " ) - 1, "SELECT ", 
+                       &at_map->sel_expr, 
+                       (ber_len_t)sizeof( " AS " ) - 1, " AS ", 
+                       &at_map->ad->ad_cname,
+                       (ber_len_t)sizeof( " FROM " ) - 1, " FROM ", 
+                       &at_map->from_tbls, 
+                       (ber_len_t)sizeof( " WHERE " ) - 1, " WHERE ", 
+                       &oc_map->keytbl,
+                       '.', 
+                       &oc_map->keycol,
+                       (ber_len_t)sizeof( "=?" ) - 1, "=?" );
+
+       if ( at_map->join_where.bv_val != NULL ) {
+               backsql_strfcat( &tmps, &tmpslen, "lb",
+                               (ber_len_t)sizeof( " AND ") - 1, " AND ", 
+                               &at_map->join_where );
        }
 
        at_map->query = tmps.bv_val;
@@ -94,30 +103,34 @@ static int
 backsql_add_sysmaps( backsql_oc_map_rec *oc_map )
 {
        backsql_at_map_rec      *at_map;
-       int                     len;
-       char                    s[ 30 ]; 
-       struct berval           bv;
+       char                    s[ 30 ];
+       ber_len_t               len, slen;
+       
 
        snprintf( s, sizeof( s ), "%ld", oc_map->id );
+       slen = strlen( s );
 
        at_map = (backsql_at_map_rec *)ch_calloc(1, 
                        sizeof( backsql_at_map_rec ) );
        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 );
+       ber_str2bv( "ldap_entry_objclasses.oc_name", 0, 1, &at_map->sel_expr );
+       ber_str2bv( "ldap_entry_objclasses,ldap_entries", 0, 1, 
+                       &at_map->from_tbls );
+       len = at_map->from_tbls.bv_len + 1;
+       backsql_merge_from_clause( &at_map->from_tbls, &len, &oc_map->keytbl );
 
        len = 0;
-       bv.bv_val = NULL;
-       bv.bv_len = 0;
-       backsql_strcat( &bv, &len,
-                       "ldap_entries.id=ldap_entry_objclasses.entry_id "
-                       "and ldap_entries.keyval=",
-                       oc_map->keytbl, ".", oc_map->keycol,
-                       " and ldap_entries.oc_map_id=", s, NULL );
-       at_map->join_where = bv.bv_val;
+       at_map->join_where.bv_val = NULL;
+       at_map->join_where.bv_len = 0;
+       backsql_strfcat( &at_map->join_where, &len, "lbcbll",
+                       (ber_len_t)sizeof( "ldap_entries.id=ldap_entry_objclasses.entry_id and ldap_entries.keyval=" ) - 1,
+                               "ldap_entries.id=ldap_entry_objclasses.entry_id and ldap_entries.keyval=",
+                       &oc_map->keytbl, 
+                       '.', 
+                       &oc_map->keycol,
+                       (ber_len_t)sizeof( " and ldap_entries.oc_map_id=" ) - 1, 
+                               " and ldap_entries.oc_map_id=", 
+                       slen, s );
 
        at_map->add_proc = NULL;
        at_map->delete_proc = NULL;
@@ -130,21 +143,23 @@ 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->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 );
+       ber_str2bv( "ldap_referrals.url", 0, 1, &at_map->sel_expr );
+       ber_str2bv( "ldap_referrals,ldap_entries", 0, 1, &at_map->from_tbls );
+       len = at_map->from_tbls.bv_len + 1;
+       backsql_merge_from_clause( &at_map->from_tbls, &len, &oc_map->keytbl );
 
        len = 0;
-       bv.bv_val = NULL;
-       bv.bv_len = 0;
-       backsql_strcat( &bv, &len,
-                       "ldap_entries.id=ldap_referrals.entry_id "
-                       "and ldap_entries.keyval=",
-                       oc_map->keytbl, ".", oc_map->keycol,
-                       " and ldap_entries.oc_map_id=", s, NULL );
-       at_map->join_where = bv.bv_val;
+       at_map->join_where.bv_val = NULL;
+       at_map->join_where.bv_len = 0;
+       backsql_strfcat( &at_map->join_where, &len, "lbcbll",
+                       (ber_len_t)sizeof( "ldap_entries.id=ldap_referrals.entry_id and ldap_entries.keyval=" ) - 1,
+                               "ldap_entries.id=ldap_referrals.entry_id and ldap_entries.keyval=",
+                       &oc_map->keytbl, 
+                       '.', 
+                       &oc_map->keycol,
+                       (ber_len_t)sizeof( " and ldap_entries.oc_map_id=" ) - 1, 
+                               " and ldap_entries.oc_map_id=", 
+                       slen, s );
 
        at_map->add_proc = NULL;
        at_map->delete_proc = NULL;
@@ -166,23 +181,23 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
        unsigned long           oc_id;
        backsql_oc_map_rec      *oc_map;
        backsql_at_map_rec      *at_map;
-       char                    *tmps;
-       int                     tmpslen;
 
        Debug( LDAP_DEBUG_TRACE, "==>load_schema_map()\n", 0, 0, 0 );
 
        /* 
         * TimesTen : See if the ldap_entries.dn_ru field exists in the schema
         */
-       if ( si->has_ldapinfo_dn_ru == -1 ) {
+       if ( !BACKSQL_DONTCHECK_LDAPINFO_DN_RU( si ) ) {
                rc = backsql_Prepare( dbh, &oc_sth, 
                                backsql_check_dn_ru_query, 0 );
                if ( rc == SQL_SUCCESS ) {
-                       si->has_ldapinfo_dn_ru = 1;  /* Yes, the field exists */
+                       /* Yes, the field exists */
+                       si->bsql_flags |= BSQLF_HAS_LDAPINFO_DN_RU;
                        Debug( LDAP_DEBUG_TRACE, "ldapinfo.dn_ru field exists "
                                "in the schema\n", 0, 0, 0 );
                } else {
-                       si->has_ldapinfo_dn_ru = 0;  /* No such field exists */
+                       /* No such field exists */
+                       si->bsql_flags &= ~BSQLF_HAS_LDAPINFO_DN_RU;
                }
 
                SQLFreeStmt( oc_sth, SQL_DROP );
@@ -228,10 +243,12 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
        backsql_BindRowAsStrings( oc_sth, &oc_row );
        rc = SQLFetch( oc_sth );
        for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( oc_sth ) ) {
+               int     colnum;
+
                oc_map = (backsql_oc_map_rec *)ch_calloc( 1,
                                sizeof( backsql_oc_map_rec ) );
 
-               oc_map->id = atoi( oc_row.cols[ 0 ] );
+               oc_map->id = strtol( oc_row.cols[ 0 ], NULL, 0 );
 
                ber_str2bv( oc_row.cols[ 1 ], 0, 1, &oc_map->name );
                oc_map->oc = oc_bvfind( &oc_map->name );
@@ -242,13 +259,21 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                        return LDAP_OTHER;      /* undefined objectClass ? */
                }
                
-               oc_map->keytbl = ch_strdup( oc_row.cols[ 2 ] );
-               oc_map->keycol = ch_strdup( oc_row.cols[ 3 ] );
+               ber_str2bv( oc_row.cols[ 2 ], 0, 1, &oc_map->keytbl );
+               ber_str2bv( oc_row.cols[ 3 ], 0, 1, &oc_map->keycol );
                oc_map->create_proc = ( oc_row.is_null[ 4 ] < 0 ) ? NULL 
                        : ch_strdup( oc_row.cols[ 4 ] );
-               oc_map->delete_proc = ( oc_row.is_null[ 5 ] < 0 ) ? NULL 
-                       : ch_strdup( oc_row.cols[ 5 ] );
-               oc_map->expect_return = atoi( oc_row.cols[ 6 ] );
+
+               colnum = 5;
+               if ( BACKSQL_CREATE_NEEDS_SELECT( si ) ) {
+                       colnum = 6;
+                       oc_map->create_keyval = ( oc_row.is_null[ 5 ] < 0 ) 
+                               ? NULL : ch_strdup( oc_row.cols[ 5 ] );
+               }
+               oc_map->delete_proc = ( oc_row.is_null[ colnum ] < 0 ) ? NULL 
+                       : ch_strdup( oc_row.cols[ colnum ] );
+               oc_map->expect_return = strtol( oc_row.cols[ colnum + 1 ], 
+                               NULL, 0 );
 
                /*
                 * FIXME: first attempt to check for offending
@@ -263,17 +288,22 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                oc_id = oc_map->id;
                Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                        "objectClass '%s': keytbl='%s' keycol='%s'\n",
-                       oc_map->name.bv_val, oc_map->keytbl, oc_map->keycol );
+                       oc_map->name.bv_val, 
+                       oc_map->keytbl.bv_val, oc_map->keycol.bv_val );
                if ( oc_map->create_proc ) {
                        Debug( LDAP_DEBUG_TRACE, "create_proc='%s'\n",
                                oc_map->create_proc, 0, 0 );
                }
+               if ( oc_map->create_keyval ) {
+                       Debug( LDAP_DEBUG_TRACE, "create_keyval='%s'\n",
+                               oc_map->create_keyval, 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",
+                       "add=%d, del=%d; attributes:\n",
                        BACKSQL_IS_ADD( oc_map->expect_return ), 
                        BACKSQL_IS_DEL( oc_map->expect_return ), 0 );
 
@@ -293,6 +323,8 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
                rc = SQLFetch( at_sth );
                for ( ; BACKSQL_SUCCESS(rc); rc = SQLFetch( at_sth ) ) {
                        const char      *text = NULL;
+                       struct berval   bv;
+                       ber_len_t       tmpslen;
 
                        Debug( LDAP_DEBUG_TRACE, "********'%s'\n",
                                at_row.cols[ 0 ], 0, 0 );
@@ -310,33 +342,44 @@ 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 ) );
-                       ber_str2bv( at_row.cols[ 0 ], 0, 1, &at_map->name );
-                       rc = slap_bv2ad( &at_map->name, &at_map->ad, &text );
+                       rc = slap_str2ad( at_row.cols[ 0 ], 
+                                       &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, 
+                                       at_map->ad->ad_cname.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 ] );
-                       tmps = NULL;
+                       ber_str2bv( at_row.cols[ 1 ], 0, 1, &at_map->sel_expr );
+                       if ( at_row.is_null[ 8 ] < 0 ) {
+                               at_map->sel_expr_u.bv_val = NULL;
+                               at_map->sel_expr_u.bv_len = 0;
+                       } else {
+                               ber_str2bv( at_row.cols[ 8 ], 0, 1, 
+                                               &at_map->sel_expr_u );
+                       }
                        tmpslen = 0;
-                       backsql_merge_from_clause( &tmps, &tmpslen,
-                                       at_row.cols[ 2 ] );
-                       at_map->from_tbls = tmps;
-                       at_map->join_where = ( at_row.is_null[ 3 ] < 0 ) ? NULL 
-                               : ch_strdup( at_row.cols[ 3 ] );
+                       ber_str2bv( at_row.cols[ 2 ], 0, 0, &bv );
+                       backsql_merge_from_clause( &at_map->from_tbls, 
+                                       &tmpslen, &bv );
+                       if ( at_row.is_null[ 3 ] < 0 ) {
+                               at_map->join_where.bv_val = NULL;
+                               at_map->join_where.bv_len = 0;
+                       } else {
+                               ber_str2bv( at_row.cols[ 3 ], 0, 1, 
+                                               &at_map->join_where );
+                       }
                        at_map->add_proc = ( at_row.is_null[ 4 ] < 0 ) ? NULL
                                : ch_strdup( at_row.cols[4] );
                        at_map->delete_proc = ( at_row.is_null[ 5 ] < 0 ) ? NULL
                                : ch_strdup( at_row.cols[ 5 ] );
-                       at_map->param_order = atoi( at_row.cols[ 6 ] );
-                       at_map->expect_return = atoi( at_row.cols[ 7 ] );
+                       at_map->param_order = strtol( at_row.cols[ 6 ], 
+                                       NULL, 0 );
+                       at_map->expect_return = strtol( at_row.cols[ 7 ],
+                                       NULL, 0 );
                        backsql_make_attr_query( oc_map, at_map );
                        Debug( LDAP_DEBUG_TRACE, "load_schema_map(): "
                                "preconstructed query '%s'\n",
@@ -350,7 +393,7 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh )
        backsql_FreeRow( &oc_row );
        SQLFreeStmt( at_sth, SQL_DROP );
        SQLFreeStmt( oc_sth, SQL_DROP );
-       si->schema_loaded = 1;
+       si->bsql_flags |= BSQLF_SCHEMA_LOADED;
        Debug( LDAP_DEBUG_TRACE, "<==load_schema_map()\n", 0, 0, 0 );
        return LDAP_SUCCESS;
 }
@@ -360,16 +403,16 @@ backsql_oc2oc( backsql_info *si, ObjectClass *oc )
 {
        backsql_oc_map_rec      tmp, *res;
 
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_oc2oc(): "
                "searching for objectclass with name='%s'\n",
                objclass, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
        tmp.oc = oc;
        res = (backsql_oc_map_rec *)avl_find( si->oc_by_oc, &tmp,
                        (AVL_CMP)backsql_cmp_oc );
-#if 0
+#ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
                        "found name='%s', id=%d\n", res->name, res->id, 0 );
@@ -377,7 +420,7 @@ backsql_oc2oc( backsql_info *si, ObjectClass *oc )
                Debug( LDAP_DEBUG_TRACE, "<==backsql_oc2oc(): "
                        "not found\n", 0, 0, 0 );
        }
-#endif
+#endif /* BACKSQL_TRACE */
  
        return res;
 }
@@ -390,11 +433,11 @@ backsql_name2oc( backsql_info *si, struct berval *oc_name )
 {
        backsql_oc_map_rec      tmp, *res;
 
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>oc_with_name(): "
                "searching for objectclass with name='%s'\n",
                objclass, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
        tmp.oc = oc_bvfind( oc_name );
        if ( tmp.oc == NULL ) {
@@ -403,7 +446,7 @@ backsql_name2oc( backsql_info *si, struct berval *oc_name )
 
        res = (backsql_oc_map_rec *)avl_find( si->oc_by_oc, &tmp,
                        (AVL_CMP)backsql_cmp_oc );
-#if 0
+#ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
                        "found name='%s', id=%d\n", res->name, res->id, 0 );
@@ -411,7 +454,7 @@ backsql_name2oc( backsql_info *si, struct berval *oc_name )
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
                        "not found\n", 0, 0, 0 );
        }
-#endif
+#endif /* BACKSQL_TRACE */
  
        return res;
 }
@@ -421,16 +464,16 @@ backsql_id2oc( backsql_info *si, unsigned long id )
 {
        backsql_oc_map_rec      tmp, *res;
  
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>oc_with_id(): "
                "searching for objectclass with id='%d'\n", id, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
        tmp.id = id;
        res = (backsql_oc_map_rec *)avl_find( si->oc_by_id, &tmp,
                        (AVL_CMP)backsql_cmp_oc_id );
 
-#if 0
+#ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
                        "found name='%s', id=%d\n", res->name, res->id, 0 );
@@ -438,7 +481,7 @@ backsql_id2oc( backsql_info *si, unsigned long id )
                Debug( LDAP_DEBUG_TRACE, "<==oc_with_name(): "
                        "not found\n", 0, 0, 0 );
        }
-#endif
+#endif /* BACKSQL_TRACE */
        
        return res;
 }
@@ -448,25 +491,26 @@ backsql_ad2at( backsql_oc_map_rec* objclass, AttributeDescription *ad )
 {
        backsql_at_map_rec      tmp, *res;
  
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_ad2at(): "
                "searching for attribute '%s' for objectclass '%s'\n",
                attr, objclass->name, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
+
        tmp.ad = ad;
        res = (backsql_at_map_rec *)avl_find( objclass->attrs, &tmp,
                        (AVL_CMP)backsql_cmp_attr );
 
-#if 0
+#ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
                        "found name='%s', sel_expr='%s'\n",
-                       res->name, res->sel_expr, 0 );
+                       res->name, res->sel_expr.bv_val, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_ad2at(): "
                        "not found\n", 0, 0, 0 );
        }
-#endif
+#endif /* BACKSQL_TRACE */
 
        return res;
 }
@@ -480,11 +524,11 @@ backsql_name2at( backsql_oc_map_rec* objclass, struct berval *attr )
        backsql_at_map_rec      tmp, *res;
        const char              *text = NULL;
  
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_name2at(): "
                "searching for attribute '%s' for objectclass '%s'\n",
                attr, objclass->name, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
        if ( slap_bv2ad( attr, &tmp.ad, &text ) != LDAP_SUCCESS ) {
                return NULL;
@@ -493,16 +537,16 @@ backsql_name2at( backsql_oc_map_rec* objclass, struct berval *attr )
        res = (backsql_at_map_rec *)avl_find( objclass->attrs, &tmp,
                        (AVL_CMP)backsql_cmp_attr );
 
-#if 0
+#ifdef BACKSQL_TRACE
        if ( res != NULL ) {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_name2at(): "
                        "found name='%s', sel_expr='%s'\n",
-                       res->name, res->sel_expr, 0 );
+                       res->name, res->sel_expr.bv_val, 0 );
        } else {
                Debug( LDAP_DEBUG_TRACE, "<==backsql_name2at(): "
                        "not found\n", 0, 0, 0 );
        }
-#endif
+#endif /* BACKSQL_TRACE */
 
        return res;
 }
@@ -511,14 +555,13 @@ static void
 backsql_free_attr( backsql_at_map_rec *at )
 {
        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 );
+                       at->ad->ad_cname.bv_val, 0, 0 );
+       ch_free( at->sel_expr.bv_val );
+       if ( at->from_tbls.bv_val != NULL ) {
+               ch_free( at->from_tbls.bv_val );
        }
-       if ( at->join_where != NULL ) {
-               ch_free( at->join_where );
+       if ( at->join_where.bv_val != NULL ) {
+               ch_free( at->join_where.bv_val );
        }
        if ( at->add_proc != NULL ) {
                ch_free( at->add_proc );
@@ -531,8 +574,8 @@ backsql_free_attr( backsql_at_map_rec *at )
        }
 
        /* TimesTen */
-       if ( at->sel_expr_u ) {
-               ch_free( at->sel_expr_u );
+       if ( at->sel_expr_u.bv_val ) {
+               ch_free( at->sel_expr_u.bv_val );
        }
        
        ch_free( at );
@@ -547,11 +590,14 @@ backsql_free_oc( backsql_oc_map_rec *oc )
                        oc->name.bv_val, 0, 0 );
        avl_free( oc->attrs, (AVL_FREE)backsql_free_attr );
        ch_free( oc->name.bv_val );
-       ch_free( oc->keytbl );
-       ch_free( oc->keycol );
+       ch_free( oc->keytbl.bv_val );
+       ch_free( oc->keycol.bv_val );
        if ( oc->create_proc != NULL ) {
                ch_free( oc->create_proc );
        }
+       if ( oc->create_keyval != NULL ) {
+               ch_free( oc->create_keyval );
+       }
        if ( oc->delete_proc != NULL ) {
                ch_free( oc->delete_proc );
        }
index 27f07278ef8034c934306c4bc87158c558b4abbe..7c7f0cf39efeba05a3e81fb77c01ed49784c0041 100644 (file)
  *      in file LICENSE in the top-level directory of the distribution.
  */
 
-
 typedef struct {
+       /*
+        * FIXME: we explicitly keep the objectClass name because
+        * the ObjectClass structure does not use bervals (yet?)
+        */
        struct berval   name;
+       /*
+        * Structure of corresponding LDAP objectClass definition
+        */
        ObjectClass     *oc;
-       char            *keytbl;
-       char            *keycol;
+       struct berval   keytbl;
+       struct berval   keycol;
        /* expected to return keyval of newly created entry */
        char            *create_proc;
+       /* in case create_proc does not return the keyval of the newly
+        * created row */
+       char            *create_keyval;
        /* supposed to expect keyval as parameter and delete 
         * all the attributes as well */
        char            *delete_proc;
@@ -29,12 +38,11 @@ typedef struct {
 } backsql_oc_map_rec;
 
 typedef struct {
-       /* literal name of corresponding LDAP attribute type */
-       struct berval   name;
+       /* Description of corresponding LDAP attribute type */
        AttributeDescription    *ad;
-       char            *from_tbls;
-       char            *join_where;
-       char            *sel_expr;
+       struct berval   from_tbls;
+       struct berval   join_where;
+       struct berval   sel_expr;
        /* supposed to expect 2 binded values: entry keyval 
         * and attr. value to add, like "add_name(?,?,?)" */
        char            *add_proc;
@@ -45,7 +53,7 @@ typedef struct {
         * is preconstructed from parts on schemamap load time */
        char            *query;
        /* following flags are bitmasks (first bit used for add_proc, 
-        * second - for modify, third - for delete_proc) */
+        * second - for delete_proc) */
        /* order of parameters for procedures above; 
         * 1 means "data then keyval", 0 means "keyval then data" */
        int             param_order;
@@ -54,7 +62,7 @@ typedef struct {
         * for return code) */
        int             expect_return;
        /* TimesTen */
-       char            *sel_expr_u;
+       struct berval   sel_expr_u;
 } backsql_at_map_rec;
 
 /* defines to support bitmasks above */
index b8f5e143b0cb368e1fb967405f28f4f15975e7b5..ffd1856fd8715168f192d75b725c450b36f10d0d 100644 (file)
 #include "entry-id.h"
 #include "util.h"
 
-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, AttributeDescription *ad )
 {
@@ -102,6 +94,7 @@ backsql_init_search(
        bsi->be = be;
        bsi->conn = conn;
        bsi->op = op;
+       bsi->attr_flags = 0;
 
        /*
         * FIXME: need to discover how to deal with 1.1 (NoAttrs)
@@ -123,8 +116,11 @@ backsql_init_search(
                        /*
                         * ignore "+"
                         */
-                       if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 
-                                       || BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
+                       if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) {
+                               continue;
+
+                       } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
+                               bsi->attr_flags |= BSQL_SF_ALL_OPER;
                                continue;
                        }
 
@@ -161,8 +157,8 @@ backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
        if ( !f ) {
                return 0;
        }
-       
-       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, "(", NULL );
+
+       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c", '(' /* ) */  );
 
        while ( 1 ) {
                res = backsql_process_filter( bsi, f );
@@ -181,18 +177,20 @@ backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
 
                switch ( op ) {
                case LDAP_FILTER_AND:
-                       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                                       " AND ", NULL );
+                       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
+                                       (ber_len_t)sizeof( " AND " ) - 1, 
+                                               " AND " );
                        break;
 
                case LDAP_FILTER_OR:
-                       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                                       " OR ", NULL );
+                       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
+                                       (ber_len_t)sizeof( " OR " ) - 1,
+                                               " OR " );
                        break;
                }
        }
 
-       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, /* ( */ ")", NULL );
+       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c", /* ( */ ')' );
 
        return 1;
 }
@@ -209,63 +207,75 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f )
 
        at = backsql_ad2at( bsi->oc, f->f_sub_desc );
 
+       assert( at );
+
        /*
         * 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 );
+       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c", '(' /* ) */  );
 
        /* TimesTen */
-       Debug( LDAP_DEBUG_TRACE, "expr: '%s' '%s'\n", at->sel_expr,
-               at->sel_expr_u ? at->sel_expr_u : "<NULL>", 0 );
-       if ( bsi->bi->upper_func ) {
+       Debug( LDAP_DEBUG_TRACE, "expr: '%s' '%s'\n", at->sel_expr.bv_val,
+               at->sel_expr_u.bv_val ? at->sel_expr_u.bv_val : "<NULL>", 0 );
+       if ( bsi->bi->upper_func.bv_val ) {
                /*
                 * If a pre-upper-cased version of the column exists, use it
                 */
-               if ( at->sel_expr_u ) {
-                       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len,
-                                       at->sel_expr_u, " LIKE '", NULL);
+               if ( at->sel_expr_u.bv_val ) {
+                       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, 
+                                       "bl",
+                                       &at->sel_expr_u,
+                                       (ber_len_t)sizeof( " LIKE '" ) - 1,
+                                               " LIKE '" );
                } else {
-                       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                                       bsi->bi->upper_func,
-                                       "(", at->sel_expr, ")", 
-                                       " LIKE '", NULL );
+                       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len,
+                                       "bcbcl",
+                                       &bsi->bi->upper_func,
+                                       '(',
+                                       &at->sel_expr,
+                                       ')', 
+                                       (ber_len_t)sizeof( " LIKE '" ) - 1,
+                                               " LIKE '" );
                }
        } else {
-               backsql_strcat( &bsi->flt_where, &bsi->fwhere_len,
-                               at->sel_expr, " LIKE '", NULL );
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "bl",
+                               &at->sel_expr,
+                               (ber_len_t)sizeof( " LIKE '" ) - 1, " LIKE '" );
        }
  
        if ( f->f_sub_initial.bv_val != NULL ) {
                size_t  start;
 
                start = bsi->flt_where.bv_len;
-               backsql_strcat( &bsi->flt_where, &bsi->fwhere_len,
-                               f->f_sub_initial.bv_val, NULL );
-               if ( bsi->bi->upper_func ) {
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "b",
+                               &f->f_sub_initial );
+               if ( bsi->bi->upper_func.bv_val ) {
                        ldap_pvt_str2upper( &bsi->flt_where.bv_val[ start ] );
                }
        }
 
-       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, "%", NULL );
+       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c", '%' );
 
        if ( f->f_sub_any != NULL ) {
                for ( i = 0; f->f_sub_any[ i ].bv_val != NULL; i++ ) {
                        size_t  start;
 
-#if 0
+#ifdef BACKSQL_TRACE
                        Debug( LDAP_DEBUG_TRACE, 
                                "==>backsql_process_sub_filter(): "
                                "sub_any='%s'\n", f->f_sub_any[ i ].bv_val,
                                0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
                        start = bsi->flt_where.bv_len;
-                       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                                       f->f_sub_any[ i ].bv_val, "%", NULL );
-                       if ( bsi->bi->upper_func) {
+                       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len,
+                                       "bc",
+                                       &f->f_sub_any[ i ],
+                                       '%' );
+                       if ( bsi->bi->upper_func.bv_val ) {
                                /*
                                 * Note: toupper('%') = '%'
                                 */
@@ -277,15 +287,16 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f )
                        size_t  start;
 
                        start = bsi->flt_where.bv_len;
-                       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len,
-                                       f->f_sub_final.bv_val, NULL);
-                       if ( bsi->bi->upper_func ) {
+                       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "b",
+                                       &f->f_sub_final );
+                       if ( bsi->bi->upper_func.bv_val ) {
                                ldap_pvt_str2upper( &bsi->flt_where.bv_val[ start ] );
                        }
                }
        }
 
-       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, /* ( */ "')", NULL );
+       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l", 
+                       (ber_len_t)sizeof( /* (' */ "')" ) - 1, /* ( */ "')" );
  
        return 1;
 }
@@ -294,10 +305,12 @@ int
 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
 {
        backsql_at_map_rec      *at;
-       backsql_at_map_rec      oc_attr = { BER_BVC("objectClass"),
-               slap_schema.si_ad_objectClass, "", "", NULL, NULL, NULL, NULL };
+       backsql_at_map_rec      oc_attr = {
+               slap_schema.si_ad_objectClass, BER_BVC(""), BER_BVC(""), 
+               { 0, NULL }, NULL, NULL, NULL };
        AttributeDescription    *ad = NULL;
-       int                     done = 0, len = 0;
+       int                     done = 0;
+       ber_len_t               len = 0;
        /* TimesTen */
        int                     rc = 0;
 
@@ -320,10 +333,12 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                break;
 
        case LDAP_FILTER_NOT:
-               backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                               "NOT (", NULL );
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
+                               (ber_len_t)sizeof( "NOT (" /* ) */ ) - 1,
+                                       "NOT (" /* ) */ );
                rc = backsql_process_filter( bsi, f->f_not );
-               backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, ")", NULL );
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c",
+                               /* ( */ ')' );
                done = 1;
                break;
 
@@ -345,50 +360,52 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                goto done;
        }
 
-       if ( strcasecmp( ad->ad_cname.bv_val, "objectclass" ) ) {
+       if ( ad != slap_schema.si_ad_objectClass ) {
                at = backsql_ad2at( bsi->oc, ad );
 
        } else {
-               struct berval   bv;
-               
                at = &oc_attr;
-
-               /*
-                * FIXME: use berval for at->sel_expr ?
-                */
-               bv.bv_val = at->sel_expr;
-               bv.bv_len = at->sel_expr ? strlen( at->sel_expr ) : 0;
-               backsql_strcat( &bv, &len, "'", bsi->oc->name.bv_val, 
-                               "'", NULL );
-               at->sel_expr = bv.bv_val;
+               backsql_strfcat( &at->sel_expr, &len, "cbc",
+                               '\'', 
+                               &bsi->oc->name, 
+                               '\'' );
        }
+
        if ( at == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
                        "attribute '%s' is not defined for objectclass '%s'\n",
                        ad->ad_cname.bv_val, bsi->oc->name.bv_val, 0 );
-               backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                               " 1=0 ", NULL );
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
+                               (ber_len_t)sizeof( " 1=0 " ) - 1, " 1=0 " );
                goto impossible;
        }
 
-       backsql_merge_from_clause( &bsi->from.bv_val, &bsi->from_len, 
-                       at->from_tbls );
+       backsql_merge_from_clause( &bsi->from, &bsi->from_len, 
+                       &at->from_tbls );
        /*
         * need to add this attribute to list of attrs to load,
         * so that we could do test_filter() later
         */
        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, 
-                               " AND ", at->join_where, NULL );
+       if ( at->join_where.bv_val != NULL 
+                       && strstr( bsi->join_where.bv_val, at->join_where.bv_val ) == NULL ) {
+               backsql_strfcat( &bsi->join_where, &bsi->jwhere_len, "lb",
+                               (ber_len_t)sizeof( " AND " ) - 1, " AND ",
+                               &at->join_where );
        }
 
-#if 0  
+#if 0
+       /*
+        * FIXME: this is not required any more; however, note that
+        * attribute name syntax might collide with SQL legal aliases
+        */
        if ( at != &oc_attr ) {
-               backsql_strcat( &bsi->sel, &bsi->sel_len,
-                               ",", at->sel_expr, " AS ", 
-                               at->name.bv_val, NULL );
+               backsql_strfcat( &bsi->sel, &bsi->sel_len, "cblb",
+                               ',',
+                               &at->sel_expr,
+                               (ber_len_t)sizeof( " AS " ) - 1, " AS ", 
+                               &at->name );
        }
 #endif
 
@@ -400,49 +417,72 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
                 * upper_func stuff is made for Oracle, where UPPER is
                 * safely applicable to NUMBER etc.
                 */
-               if ( bsi->bi->upper_func ) {
+               if ( bsi->bi->upper_func.bv_val ) {
                        size_t  start;
 
-                       if ( at->sel_expr_u ) {
-                               backsql_strcat( &bsi->flt_where,
-                                               &bsi->fwhere_len, "(",
-                                               at->sel_expr_u, "='", NULL );
+                       if ( at->sel_expr_u.bv_val ) {
+                               backsql_strfcat( &bsi->flt_where,
+                                               &bsi->fwhere_len, "cbl",
+                                               '(',
+                                               &at->sel_expr_u, 
+                                               (ber_len_t)sizeof( "='" ) - 1,
+                                                       "='" );
                        } else {
-                               backsql_strcat( &bsi->flt_where,
-                                               &bsi->fwhere_len, "(",
-                                               bsi->bi->upper_func, "(",
-                                               at->sel_expr, ")='", NULL );
+                               backsql_strfcat( &bsi->flt_where,
+                                               &bsi->fwhere_len, "cbcbl",
+                                               '(' /* ) */ ,
+                                               &bsi->bi->upper_func,
+                                               '(' /* ) */ ,
+                                               &at->sel_expr,
+                                               (ber_len_t)sizeof( /* ( */ ")='" ) - 1,
+                                                       /* ( */ ")='" );
                        }
 
                        start = bsi->flt_where.bv_len;
 
-                       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                                       f->f_av_value.bv_val, "')", NULL );
+                       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len,
+                                       "bl",
+                                       &f->f_av_value, 
+                                       (ber_len_t)sizeof( /* (' */ "')" ) - 1,
+                                               /* (' */ "')" );
 
                        ldap_pvt_str2upper( &bsi->flt_where.bv_val[ start ] );
 
                } else {
-                       backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                                       "(", at->sel_expr, "='",
-                                       f->f_av_value.bv_val, "')", NULL );
+                       backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len,
+                                       "cblbl",
+                                       '(',
+                                       &at->sel_expr,
+                                       (ber_len_t)sizeof( "='" ) - 1, "='",
+                                       &f->f_av_value,
+                                       (ber_len_t)sizeof( /* (' */ "')" ) - 1,
+                                               /* (' */ "')" );
                }
                break;
 
        case LDAP_FILTER_GE:
-               backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                               "(", at->sel_expr, ">=", 
-                               f->f_av_value.bv_val, ")", NULL );
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "cblbc",
+                               '(' /* ) */ ,
+                               &at->sel_expr,
+                               (ber_len_t)sizeof( ">=" ) - 1, ">=", 
+                               &f->f_av_value,
+                               /* ( */ ')' );
                break;
                
        case LDAP_FILTER_LE:
-               backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                               "(", at->sel_expr, "<=", 
-                               f->f_av_value.bv_val, ")", NULL );
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "cblbc",
+                               '(' /* ) */ ,
+                               &at->sel_expr,
+                               (ber_len_t)sizeof( "<=" ) - 1, "<=", 
+                               &f->f_av_value,
+                               /* ( */ ')' );
                break;
 
        case LDAP_FILTER_PRESENT:
-               backsql_strcat( &bsi->flt_where, &bsi->fwhere_len, 
-                               "NOT (", at->sel_expr, " IS NULL)", NULL );
+               backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "lbl",
+                               (ber_len_t)sizeof( "NOT (" ) - 1, "NOT (", 
+                               &at->sel_expr, 
+                               (ber_len_t)sizeof( " IS NULL)" ) - 1, " IS NULL)" );
                break;
 
        case LDAP_FILTER_SUBSTRINGS:
@@ -451,16 +491,16 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f )
        }
 
 done:
-       if ( oc_attr.sel_expr != NULL ) {
-               free( oc_attr.sel_expr );
+       if ( oc_attr.sel_expr.bv_val != NULL ) {
+               free( oc_attr.sel_expr.bv_val );
        }
        
        Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter()\n", 0, 0, 0 );
        return 1;
 
 impossible:
-       if ( oc_attr.sel_expr != NULL ) {
-               free( oc_attr.sel_expr );
+       if ( oc_attr.sel_expr.bv_val != NULL ) {
+               free( oc_attr.sel_expr.bv_val );
        }
        Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter() returns -1\n",
                        0, 0, 0 );
@@ -471,7 +511,7 @@ static int
 backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
 {
        backsql_info    *bi = (backsql_info *)bsi->be->be_private;
-       int             q_len = 0;
+       ber_len_t       q_len = 0;
        int             rc;
 
        assert( query );
@@ -491,55 +531,87 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
        bsi->flt_where.bv_val = NULL;
        bsi->flt_where.bv_len = 0;
        bsi->fwhere_len = 0;
+
 #if 0
+       /*
+        * FIXME: this query has been split in case a string cast function
+        * is defined; more sophisticated (pattern based) function should
+        * be used
+        */
        backsql_strcat( &bsi->sel, &bsi->sel_len,
                        "SELECT DISTINCT ldap_entries.id,", 
-                       bsi->oc->keytbl, ".", bsi->oc->keycol,
+                       bsi->oc->keytbl.bv_val, ".", bsi->oc->keycol.bv_val,
                        ",'", bsi->oc->name.bv_val, "' AS objectClass",
                        ",ldap_entries.dn AS dn", NULL );
 #endif
-       backsql_strcat( &bsi->sel, &bsi->sel_len,
-                       "SELECT DISTINCT ldap_entries.id,", 
-                       bsi->oc->keytbl, ".", bsi->oc->keycol, ",", NULL );
-       if ( bi->strcast_func ) {
-               backsql_strcat( &bsi->sel, &bsi->sel_len,
-                               bi->strcast_func, 
-                               "('", bsi->oc->name.bv_val, "')", NULL );
+
+       backsql_strfcat( &bsi->sel, &bsi->sel_len, "lbcbc",
+                       (ber_len_t)sizeof( "SELECT DISTINCT ldap_entries.id," ) - 1,
+                               "SELECT DISTINCT ldap_entries.id,", 
+                       &bsi->oc->keytbl, 
+                       '.', 
+                       &bsi->oc->keycol, 
+                       ',' );
+
+       if ( bi->strcast_func.bv_val ) {
+               backsql_strfcat( &bsi->sel, &bsi->sel_len, "blbl",
+                               &bi->strcast_func, 
+                               (ber_len_t)sizeof( "('" /* ') */ ) - 1,
+                                       "('" /* ') */ ,
+                               &bsi->oc->name,
+                               (ber_len_t)sizeof( /* (' */ "')" ) - 1,
+                                       /* (' */ "')" );
        } else {
-               backsql_strcat( &bsi->sel, &bsi->sel_len,
-                               "'", bsi->oc->name.bv_val, "'", NULL );
+               backsql_strfcat( &bsi->sel, &bsi->sel_len, "cbc",
+                               '\'',
+                               &bsi->oc->name,
+                               '\'' );
        }
-       backsql_strcat( &bsi->sel, &bsi->sel_len,
-                       " AS objectClass,ldap_entries.dn AS dn", NULL );
-
-       backsql_strcat( &bsi->from, &bsi->from_len,
-                       " FROM ldap_entries,", bsi->oc->keytbl, NULL );
-       backsql_strcat( &bsi->join_where, &bsi->jwhere_len,
-                       " WHERE ", bsi->oc->keytbl, ".", bsi->oc->keycol,
-                       "=ldap_entries.keyval AND ",
-                       "ldap_entries.oc_map_id=? AND ", NULL );
+       backsql_strfcat( &bsi->sel, &bsi->sel_len, "l",
+                       (ber_len_t)sizeof( " AS objectClass,ldap_entries.dn AS dn" ) - 1,
+                       " AS objectClass,ldap_entries.dn AS dn" );
+
+       backsql_strfcat( &bsi->from, &bsi->from_len, "lb",
+                       (ber_len_t)sizeof( " FROM ldap_entries," ) - 1,
+                               " FROM ldap_entries,",
+                       &bsi->oc->keytbl );
+
+       backsql_strfcat( &bsi->join_where, &bsi->jwhere_len, "lbcbl",
+                       (ber_len_t)sizeof( " WHERE " ) - 1, " WHERE ",
+                       &bsi->oc->keytbl,
+                       '.',
+                       &bsi->oc->keycol,
+                       (ber_len_t)sizeof( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ) - 1,
+                               "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
 
        switch ( bsi->scope ) {
        case LDAP_SCOPE_BASE:
-               if ( bsi->bi->upper_func ) {
-                       backsql_strcat( &bsi->join_where, &bsi->jwhere_len, 
-                                       bsi->bi->upper_func,
-                                       "(","ldap_entries.dn)=",
-                                       bsi->bi->upper_func, "(?)", NULL );
+               if ( bsi->bi->upper_func.bv_val ) {
+                       backsql_strfcat( &bsi->join_where, &bsi->jwhere_len, 
+                                       "blbcb",
+                                       &bsi->bi->upper_func,
+                                       (ber_len_t)sizeof( "(ldap_entries.dn)=" ) - 1,
+                                               "(ldap_entries.dn)=",
+                                       &bsi->bi->upper_func_open,
+                                       '?', 
+                                       &bsi->bi->upper_func_close );
                } else {
-                       backsql_strcat( &bsi->join_where, &bsi->jwhere_len, 
-                                       "ldap_entries.dn=?", NULL );
+                       backsql_strfcat( &bsi->join_where, &bsi->jwhere_len,
+                                       "l",
+                                       (ber_len_t)sizeof( "ldap_entries.dn=?" ) - 1,
+                                               "ldap_entries.dn=?" );
                }
                break;
                
        case LDAP_SCOPE_ONELEVEL:
-               backsql_strcat( &bsi->join_where, &bsi->jwhere_len, 
-                               "ldap_entries.parent=?", NULL );
+               backsql_strfcat( &bsi->join_where, &bsi->jwhere_len, "l",
+                               (ber_len_t)sizeof( "ldap_entries.parent=?" ) - 1,
+                                       "ldap_entries.parent=?" );
                break;
 
        case LDAP_SCOPE_SUBTREE:
-               backsql_strcat( &bsi->join_where, &bsi->jwhere_len,
-                               bsi->bi->subtree_cond, NULL );
+               backsql_strfcat( &bsi->join_where, &bsi->jwhere_len, "b",
+                               &bsi->bi->subtree_cond );
                break;
 
        default:
@@ -548,10 +620,12 @@ backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
 
        rc = backsql_process_filter( bsi, bsi->filter );
        if ( rc > 0 ) {
-               backsql_strcat( query, &q_len,
-                               bsi->sel.bv_val, bsi->from.bv_val, 
-                               bsi->join_where.bv_val,
-                               " AND ", bsi->flt_where.bv_val, NULL );
+               backsql_strfcat( query, &q_len, "bbblb",
+                               &bsi->sel,
+                               &bsi->from, 
+                               &bsi->join_where,
+                               (ber_len_t)sizeof( " AND " ) - 1, " AND ",
+                               &bsi->flt_where );
 
        } else if ( rc < 0 ) {
                /* 
@@ -590,17 +664,19 @@ backsql_oc_get_candidates( backsql_oc_map_rec *oc, backsql_srch_info *bsi )
        RETCODE                 rc;
        backsql_entryID         base_id, *c_id;
        int                     res;
-#if 0
-       Entry                   *e;
-#endif
        BACKSQL_ROW_NTS         row;
        int                     i;
        int                     j;
-       /* TimesTen */
-       char                    temp_base_dn[ BACKSQL_MAX_DN_LEN + 1 ];
  
        Debug(  LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc='%s'\n",
                        oc->name.bv_val, 0, 0 );
+
+       if ( bsi->n_candidates == -1 ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
+                       "unchecked limit has been overcome\n", 0, 0, 0 );
+               return 1;
+       }
+       
        bsi->oc = oc;
        if ( backsql_srch_query( bsi, &query ) ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
@@ -640,7 +716,21 @@ backsql_oc_get_candidates( backsql_oc_map_rec *oc, backsql_srch_info *bsi )
                }
                break;
 
-       case LDAP_SCOPE_SUBTREE:
+       case LDAP_SCOPE_SUBTREE: {
+
+               /* 
+                * + 1 because we need room for '%'; this makes a subtree
+                * search for a DN BACKSQL_MAX_DN_LEN long legal 
+                * if it returns that DN only
+                */
+               char            temp_base_dn[ BACKSQL_MAX_DN_LEN + 1 + 1 ];
+
+               /*
+                * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
+                * however this should be handled earlier
+                */
+               assert( bsi->base_dn->bv_len <= BACKSQL_MAX_DN_LEN );
+                       
                /* 
                 * Sets the parameters for the SQL built earlier
                 * NOTE that all the databases could actually use 
@@ -654,7 +744,7 @@ backsql_oc_get_candidates( backsql_oc_map_rec *oc, backsql_srch_info *bsi )
                 * If "dn" is being used, do a suffix search.
                 * If "dn_ru" is being used, do a prefix search.
                 */
-               if ( bsi->bi->has_ldapinfo_dn_ru ) {
+               if ( BACKSQL_HAS_LDAPINFO_DN_RU( bsi->bi ) ) {
                        temp_base_dn[ 0 ] = '\0';
                        for ( i = 0, j = bsi->base_dn->bv_len - 1;
                                        j >= 0; i++, j--) {
@@ -684,6 +774,7 @@ backsql_oc_get_candidates( backsql_oc_map_rec *oc, backsql_srch_info *bsi )
                        return 1;
                }
                break;
+       }
 
        case LDAP_SCOPE_ONELEVEL:
                res = backsql_dn2id( bsi->bi, &base_id, 
@@ -719,41 +810,23 @@ backsql_oc_get_candidates( backsql_oc_map_rec *oc, backsql_srch_info *bsi )
        backsql_BindRowAsStrings( sth, &row );
        rc = SQLFetch( sth );
        for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
-#if 0
-               e = (Entry *)ch_calloc( 1, sizeof( Entry ) ); 
-               for ( i = 1; i < row.ncols; i++ ) {
-                       if ( row.is_null[ i ] > 0 ) {
-                               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 );
-                       }
-               }
-#endif
-
                c_id = (backsql_entryID *)ch_calloc( 1, 
                                sizeof( backsql_entryID ) );
-               c_id->id = atoi( row.cols[ 0 ] );
-               c_id->keyval = atoi( row.cols[ 1 ] );
+               c_id->id = strtol( row.cols[ 0 ], NULL, 0 );
+               c_id->keyval = strtol( row.cols[ 1 ], NULL, 0 );
                c_id->oc_id = bsi->oc->id;
                ber_str2bv( row.cols[ 3 ], 0, 1, &c_id->dn );
                c_id->next = bsi->id_list;
                bsi->id_list = c_id;
-               bsi->n_candidates++;
+               bsi->n_candidates--;
+
                Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
                        "added entry id=%ld, keyval=%ld dn='%s'\n",
                        c_id->id, c_id->keyval, row.cols[ 3 ] );
+
+               if ( bsi->n_candidates == -1 ) {
+                       break;
+               }
        }
        backsql_FreeRow( &row );
        SQLFreeStmt( sth, SQL_DROP );
@@ -799,6 +872,20 @@ backsql_search(
                "attributes to load: %s\n",
                deref, attrsonly, attrs == NULL ? "all" : "custom list" );
 
+       if ( nbase->bv_len > BACKSQL_MAX_DN_LEN ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
+                       "search base length (%ld) exceeds max length (%ld)\n", 
+                       nbase->bv_len, BACKSQL_MAX_DN_LEN, 0 );
+               /*
+                * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
+                * since it is impossible that such a long DN exists
+                * in the backend
+                */
+               send_ldap_result( conn, op, LDAP_ADMINLIMIT_EXCEEDED, 
+                               "", NULL, NULL, NULL );
+               return 1;
+       }
+
        sres = backsql_get_db_conn( be, conn, &dbh );
        if ( sres != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
@@ -811,7 +898,7 @@ backsql_search(
        }
 
        /* TimesTen : Pass it along to the lower level routines */ 
-       srch_info.isTimesTen = bi->isTimesTen
+       srch_info.use_reverse_dn = BACKSQL_USE_REVERSE_DN( bi )
  
        /* if not root, get appropriate limits */
        if ( be_isroot( be, &op->o_ndn ) ) {
@@ -890,11 +977,12 @@ backsql_search(
         * of entries matching LDAP query filter and scope (or at least 
         * candidates), and get the IDs
         */
+       srch_info.n_candidates = ( isroot ? -2 : limit->lms_s_unchecked == -1 
+                       ? -2 : limit->lms_s_unchecked );
        avl_apply( bi->oc_by_oc, (AVL_APPLY)backsql_oc_get_candidates,
                        &srch_info, 0, AVL_INORDER );
-
        if ( !isroot && limit->lms_s_unchecked != -1 ) {
-               if ( srch_info.n_candidates > limit->lms_s_unchecked ) {
+               if ( srch_info.n_candidates == -1 ) {
                        send_search_result( conn, op,
                                        LDAP_ADMINLIMIT_EXCEEDED,
                                        NULL, NULL, NULL, NULL, 0 );
@@ -908,7 +996,8 @@ backsql_search(
         * mentioned in attrs and filter), test it against full filter 
         * and then send to client
         */
-       for ( eid = srch_info.id_list; eid != NULL; eid = eid->next ) {
+       for ( eid = srch_info.id_list; eid != NULL; 
+                       eid = backsql_free_entryID( eid, 1 ) ) {
 
                /* check for abandon */
                if ( op->o_abandon ) {
@@ -919,7 +1008,7 @@ backsql_search(
                if ( tlimit != -1 && slap_get_time() > stoptime ) {
                        send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED,
                                NULL, NULL, v2refs, NULL, nentries );
-                       break;
+                       goto end_of_search;
                }
 
                Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
@@ -950,23 +1039,35 @@ backsql_search(
                                == LDAP_COMPARE_TRUE ) {
                        sres = send_search_entry( be, conn, op, entry,
                                        attrs, attrsonly, NULL );
-                       if ( sres == -1 ) {
+                       switch ( sres ) {
+                       case 0:
+                               nentries++;
+                               break;
+
+                       case -1:
                                Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
                                        "connection lost\n", 0, 0, 0 );
+                               goto end_of_search;
+
+                       default:
+                               /*
+                                * FIXME: send_search_entry failed;
+                                * better stop
+                                */
                                break;
                        }
-                       nentries += !sres;                                      
                }
                entry_free( entry );
 
-               if ( slimit != -1 && nentries > slimit ) {
+               if ( slimit != -1 && nentries >= slimit ) {
                        send_search_result( conn, op, LDAP_SIZELIMIT_EXCEEDED,
                                NULL, NULL, v2refs, NULL, nentries );
-                       break;
+                       goto end_of_search;
                }
-     
        }
 
+end_of_search:;
+
        if ( nentries > 0 ) {
                send_search_result( conn, op,
                        v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
@@ -977,9 +1078,6 @@ backsql_search(
        }
        
 done:;
-       for ( eid = srch_info.id_list; eid != NULL; 
-                       eid = backsql_free_entryID( eid, 1 ) );
-
        ch_free( srch_info.attrs );
 
        Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
index f5c63d9026c7b58a6d46cf1091a4241fbf67b460..cde2d30ecb746fc60a95f508258f2ed5f67761ea 100644 (file)
@@ -64,16 +64,16 @@ backsql_Prepare( SQLHDBC dbh, SQLHSTMT *sth, char *query, int timeout )
                return rc;
        }
 
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>_SQLPrepare()\n", 0, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
        SQLGetInfo( dbh, SQL_DRIVER_NAME, drv_name, sizeof( drv_name ), &len );
 
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "_SQLPrepare(): driver name='%s'\n",
                        drv_name, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
        ldap_pvt_str2upper( drv_name );
        if ( !strncmp( drv_name, "SQLSRV32.DLL", sizeof( drv_name ) ) ) {
@@ -107,10 +107,10 @@ backsql_Prepare( SQLHDBC dbh, SQLHSTMT *sth, char *query, int timeout )
                }
        }
 
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "<==_SQLPrepare() calling SQLPrepare()\n",
                        0, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
        return SQLPrepare( *sth, query, SQL_NTS );
 }
@@ -153,23 +153,23 @@ backsql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row )
                return SQL_ERROR;
        }
 
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==> backsql_BindRowAsStrings()\n", 0, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
        
        rc = SQLNumResultCols( sth, &row->ncols );
        if ( rc != SQL_SUCCESS ) {
-#if 0
+#ifdef BACKSQL_TRACE
                Debug( LDAP_DEBUG_TRACE, "_SQLBindRowAsStrings(): "
                        "SQLNumResultCols() failed:\n", 0, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
                
                backsql_PrintErrors( SQL_NULL_HENV, SQL_NULL_HDBC, sth, rc );
        } else {
-#if 0
+#ifdef BACKSQL_TRACE
                Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: "
                        "ncols=%d\n", (int)row->ncols, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
                row->col_names = (BerVarray)ch_calloc( row->ncols + 1, 
                                sizeof( struct berval ) );
@@ -185,11 +185,11 @@ backsql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row )
                                        &name_len, &col_type,
                                        &col_prec, &col_scale, &col_null );
                        ber_str2bv( colname, 0, 1, &row->col_names[ i - 1 ] );
-#if 0
+#ifdef BACKSQL_TRACE
                        Debug( LDAP_DEBUG_TRACE, "backsql_BindRowAsStrings: "
                                "col_name=%s, col_prec[%d]=%d\n",
                                colname, (int)i, (int)col_prec );
-#endif
+#endif /* BACKSQL_TRACE */
                        if ( col_type == SQL_LONGVARCHAR 
                                        || col_type == SQL_LONGVARBINARY) {
 #if 0
@@ -229,9 +229,10 @@ backsql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row )
                row->col_names[ i - 1 ].bv_len = 0;
                row->cols[ i - 1 ] = NULL;
        }
-#if 0
+
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "<== backsql_BindRowAsStrings()\n", 0, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
        return rc;
 }
@@ -244,7 +245,7 @@ backsql_FreeRow( BACKSQL_ROW_NTS *row )
        }
 
        ber_bvarray_free( row->col_names );
-       charray_free( row->cols );
+       ldap_charray_free( row->cols );
        free( row->col_prec );
        free( row->is_null );
 
@@ -305,10 +306,11 @@ int
 backsql_free_db_env( backsql_info *si )
 {
        Debug( LDAP_DEBUG_TRACE, "==>backsql_free_db_env()\n", 0, 0, 0 );
-#if 0
+
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "free_db_env(): delete AVL tree here!!!\n",
                        0, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
 
        /*
         * stop, if frontend waits for all threads to shutdown 
@@ -366,7 +368,8 @@ backsql_open_db_conn( backsql_info *si, int ldap_cid, backsql_db_conn **pdbc )
         * See if this connection is to TimesTen.  If it is,
         * remember that fact for later use.
         */
-       si->isTimesTen = 0;     /* Assume until proven otherwise */
+       /* Assume until proven otherwise */
+       si->bsql_flags &= ~BSQLF_USE_REVERSE_DN;
        DBMSName[ 0 ] = '\0';
        rc = SQLGetInfo( dbc->dbh, SQL_DBMS_NAME, (PTR)&DBMSName,
                        sizeof( DBMSName ), NULL );
@@ -375,7 +378,7 @@ backsql_open_db_conn( backsql_info *si, int ldap_cid, backsql_db_conn **pdbc )
                                strcmp( DBMSName, "Front-Tier" ) == 0 ) {
                        Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn: "
                                "TimesTen database!\n", 0, 0, 0 );
-                       si->isTimesTen = 1;
+                       si->bsql_flags |= BSQLF_USE_REVERSE_DN;
                }
        } else {
                Debug( LDAP_DEBUG_TRACE, "backsql_open_db_conn: "
@@ -454,11 +457,12 @@ backsql_get_db_conn( Backend *be, Connection *ldapc, SQLHDBC *dbh )
        }
 
        ldap_pvt_thread_mutex_lock( &si->schema_mutex );
-       if ( !si->schema_loaded ) {
+       if ( !BACKSQL_SCHEMA_LOADED( si ) ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_get_db_conn(): "
                        "first call -- reading schema map\n", 0, 0, 0 );
                rc = backsql_load_schema_map( si, dbc->dbh );
                if ( rc != LDAP_SUCCESS ) {
+                       ldap_pvt_thread_mutex_unlock( &si->schema_mutex );
                        backsql_free_db_conn( be, ldapc );
                        return rc;
                }
index 48701c6aa4975d578e271886534e41a2e77c3be3..ffd10efc9516e7f813661025ee440e895a0aeb3f 100644 (file)
 #include "schema-map.h"
 #include "util.h"
 
+#define BACKSQL_MAX(a,b) ((a)>(b)?(a):(b))
+#define BACKSQL_MIN(a,b) ((a)<(b)?(a):(b))
+
+#define BACKSQL_STR_GROW 256
 
 char backsql_def_oc_query[] = 
        "SELECT id,name,keytbl,keycol,create_proc,delete_proc,expect_return "
        "FROM ldap_oc_mappings";
+char backsql_def_needs_select_oc_query[] = 
+       "SELECT id,name,keytbl,keycol,create_proc,create_keyval,delete_proc,"
+       "expect_return FROM ldap_oc_mappings";
 char backsql_def_at_query[] = 
        "SELECT name,sel_expr,from_tbls,join_where,add_proc,delete_proc,"
        "param_order,expect_return,sel_expr_u FROM ldap_attr_mappings "
@@ -38,34 +45,29 @@ char backsql_def_insentry_query[] =
 char backsql_def_subtree_cond[] = "ldap_entries.dn LIKE CONCAT('%',?)";
 char backsql_def_upper_subtree_cond[] = "(ldap_entries.dn) LIKE CONCAT('%',?)";
 char backsql_id_query[] = "SELECT id,keyval,oc_map_id FROM ldap_entries WHERE ";
+/* better ?||? or cast(?||? as varchar) */ 
+char backsql_def_concat_func[] = "CONCAT(?,?)";
 
 /* 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, ... )
+backsql_strcat( struct berval *dest, ber_len_t *buflen, ... )
 {
        va_list         strs;
-       int             cdlen, cslen, grow;
+       ber_len_t       cdlen, cslen, grow;
        char            *cstr;
 
        assert( dest );
        assert( dest->bv_val == NULL 
                        || dest->bv_len == strlen( dest->bv_val ) );
  
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_strcat()\n" );
-#endif
+#endif /* BACKSQL_TRACE */
 
        va_start( strs, buflen );
-       if ( dest->bv_val == NULL || *buflen <= 0 ) {
+       if ( dest->bv_val == NULL || *buflen == 0 ) {
                dest->bv_val = (char *)ch_calloc( BACKSQL_STR_GROW, 
                                sizeof( char ) );
                dest->bv_len = 0;
@@ -78,12 +80,13 @@ backsql_strcat( struct berval *dest, int *buflen, ... )
                if ( *buflen - cdlen <= cslen ) {
                        char    *tmp_dest;
 
-#if 0
+#ifdef BACKSQL_TRACE
                        Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
                                "buflen=%d, cdlen=%d, cslen=%d "
                                "-- reallocating dest\n",
                                *buflen, cdlen + 1, cslen );
-#endif
+#endif /* BACKSQL_TRACE */
+
                        tmp_dest = (char *)ch_realloc( dest->bv_val,
                                        ( *buflen ) + grow * sizeof( char ) );
                        if ( tmp_dest == NULL ) {
@@ -94,20 +97,131 @@ backsql_strcat( struct berval *dest, int *buflen, ... )
                        }
                        dest->bv_val = tmp_dest;
                        *buflen += grow;
-#if 0
+
+#ifdef BACKSQL_TRACE
                        Debug( LDAP_DEBUG_TRACE, "backsql_strcat(): "
                                "new buflen=%d, dest=%p\n", *buflen, dest, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
                }
                AC_MEMCPY( dest->bv_val + cdlen, cstr, cslen + 1 );
                cdlen += cslen;
        }
        va_end( strs );
 
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "<==backsql_strcat() (dest='%s')\n", 
                        dest, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
+
+       dest->bv_len = cdlen;
+
+       return dest;
+} 
+
+struct berval *
+backsql_strfcat( struct berval *dest, ber_len_t *buflen, const char *fmt, ... )
+{
+       va_list         strs;
+       ber_len_t       cdlen;
+
+       assert( dest );
+       assert( buflen );
+       assert( fmt );
+       assert( *buflen == 0 || *buflen > dest->bv_len );
+       assert( dest->bv_val == NULL 
+                       || dest->bv_len == strlen( dest->bv_val ) );
+#ifdef BACKSQL_TRACE
+       Debug( LDAP_DEBUG_TRACE, "==>backsql_strfcat()\n" );
+#endif /* BACKSQL_TRACE */
+
+       va_start( strs, fmt );
+       if ( dest->bv_val == NULL || *buflen == 0 ) {
+               dest->bv_val = (char *)ch_calloc( BACKSQL_STR_GROW, 
+                               sizeof( char ) );
+               dest->bv_len = 0;
+               *buflen = BACKSQL_STR_GROW;
+       }
+
+       cdlen = dest->bv_len;
+       for ( ; fmt[0]; fmt++ ) {
+               ber_len_t       cslen, grow;
+               char            *cstr, cc[ 2 ] = { '\0', '\0' };
+               struct berval   *cbv;
+
+               switch ( fmt[ 0 ] ) {
+
+               /* berval */
+               case 'b':
+                       cbv = va_arg( strs, struct berval * );
+                       cstr = cbv->bv_val;
+                       cslen = cbv->bv_len;
+                       break;
+
+               /* length + string */
+               case 'l':
+                       cslen = va_arg( strs, ber_len_t );
+                       cstr = va_arg( strs, char * );
+                       break;
+                       
+               /* string */
+               case 's':
+                       cstr = va_arg( strs, char * );
+                       cslen = strlen( cstr );
+                       break;
+
+               /* char */
+               case 'c':
+                       /* 
+                        * `char' is promoted to `int' when passed through `...'
+                        */
+                       cc[0] = va_arg( strs, int );
+                       cstr = cc;
+                       cslen = 1;
+                       break;
+
+               default:
+                       assert( 0 );
+               }
+
+               grow = BACKSQL_MAX( BACKSQL_STR_GROW, cslen );
+               if ( *buflen - cdlen <= cslen ) {
+                       char    *tmp_dest;
+
+#ifdef BACKSQL_TRACE
+                       Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
+                               "buflen=%d, cdlen=%d, cslen=%d "
+                               "-- reallocating dest\n",
+                               *buflen, cdlen + 1, cslen );
+#endif /* BACKSQL_TRACE */
+
+                       tmp_dest = (char *)ch_realloc( dest->bv_val,
+                                       ( *buflen ) + grow * sizeof( char ) );
+                       if ( tmp_dest == NULL ) {
+                               Debug( LDAP_DEBUG_ANY, "backsql_strfcat(): "
+                                       "could not reallocate string buffer.\n",
+                                       0, 0, 0 );
+                               return NULL;
+                       }
+                       dest->bv_val = tmp_dest;
+                       *buflen += grow * sizeof( char );
+
+#ifdef BACKSQL_TRACE
+                       Debug( LDAP_DEBUG_TRACE, "backsql_strfcat(): "
+                               "new buflen=%d, dest=%p\n", *buflen, dest, 0 );
+#endif /* BACKSQL_TRACE */
+               }
+
+               AC_MEMCPY( dest->bv_val + cdlen, cstr, cslen + 1 );
+               cdlen += cslen;
+       }
+
+       va_end( strs );
+
+#ifdef BACKSQL_TRACE
+       Debug( LDAP_DEBUG_TRACE, "<==backsql_strfcat() (dest='%s')\n", 
+                       dest, 0, 0 );
+#endif /* BACKSQL_TRACE */
 
        dest->bv_len = cdlen;
 
@@ -120,17 +234,15 @@ backsql_entry_addattr(
        struct berval   *at_name,
        struct berval   *at_val )
 {
-       struct berval           add_val[ 2 ];
        AttributeDescription    *ad;
        int                     rc;
        const char              *text;
 
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): "
                "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;
+#endif /* BACKSQL_TRACE */
 
        ad = NULL;
        rc = slap_bv2ad( at_name, &ad, &text );
@@ -141,7 +253,7 @@ backsql_entry_addattr(
                return 0;
        }
 
-       rc = attr_merge( e, ad, add_val );
+       rc = attr_merge_one( e, ad, at_val );
 
        if ( rc != 0 ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_entry_addattr(): "
@@ -149,8 +261,11 @@ backsql_entry_addattr(
                        at_val->bv_val, at_name->bv_val, 0 );
                return 0;
        }
-       
+
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "<==backsql_query_addattr()\n", 0, 0, 0 );
+#endif /* BACKSQL_TRACE */
+
        return 1;
 }
 
@@ -159,7 +274,10 @@ backsql_get_table_spec( char **p )
 {
        char            *s, *q;
        struct berval   res = { 0, NULL };
-       int             res_len = 0;
+       ber_len_t       res_len = 0;
+
+       assert( p );
+       assert( *p );
 
        s = *p;
        while ( **p && **p != ',' ) {
@@ -188,49 +306,57 @@ backsql_get_table_spec( char **p )
                s = q;
                BACKSQL_NEXT_WORD;
        }
+
 #if 0
        backsql_strcat( &res, &res_len, " AS ", s, NULL );
        /* oracle doesn't understand AS :( */
 #endif
+
        /* table alias */
-       backsql_strcat( &res, &res_len, " ", s, NULL);
+       backsql_strfcat( &res, &res_len, "cs", ' ', s );
+
        return res.bv_val;
 }
 
 int
-backsql_merge_from_clause( char **dest_from, int *dest_len, char *src_from )
+backsql_merge_from_clause( 
+       struct berval   *dest_from,
+       ber_len_t       *dest_len, 
+       struct berval   *src_from )
 {
        char            *s, *p, *srcc, *pos, e;
        struct berval   res = { 0 , NULL };
 
-#if 0
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "==>backsql_merge_from_clause(): "
                "dest_from='%s',src_from='%s'\n",
-               dest_from, src_from, 0 );
-#endif
-       srcc = ch_strdup( src_from );
+               dest_from ? dest_from->bv_val : "<NULL>", src_from, 0 );
+#endif /* BACKSQL_TRACE */
+
+       srcc = ch_strdup( src_from->bv_val );
        p = srcc;
 
-       if ( *dest_from != NULL ) {
-               res.bv_val = *dest_from;
-               res.bv_len = strlen( *dest_from );
+       if ( dest_from != NULL ) {
+               res = *dest_from;
        }
        
        while ( *p ) {
                s = backsql_get_table_spec( &p );
-#if 0
+
+#ifdef BACKSQL_TRACE
                Debug( LDAP_DEBUG_TRACE, "backsql_merge_from_clause(): "
                        "p='%s' s='%s'\n", p, s, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
+
                if ( res.bv_val == NULL ) {
                        backsql_strcat( &res, dest_len, s, NULL );
 
                } else {
                        pos = strstr( res.bv_val, s );
                        if ( pos == NULL ) {
-                               backsql_strcat( &res, dest_len, ",", s, NULL );
+                               backsql_strfcat( &res, dest_len, "cs", ',', s );
                        } else if ( ( e = pos[ strlen( s ) ] ) != '\0' && e != ',' ) {
-                               backsql_strcat( &res, dest_len, ",", s, NULL );
+                               backsql_strfcat( &res, dest_len, "cs", ',', s );
                        }
                }
                
@@ -238,14 +364,115 @@ backsql_merge_from_clause( char **dest_from, int *dest_len, char *src_from )
                        ch_free( s );
                }
        }
-#if 0
+
+#ifdef BACKSQL_TRACE
        Debug( LDAP_DEBUG_TRACE, "<==backsql_merge_from_clause()\n", 0, 0, 0 );
-#endif
+#endif /* BACKSQL_TRACE */
+
        free( srcc );
-       *dest_from = res.bv_val;
+       *dest_from = res;
 
        return 1;
 }
 
+/*
+ * splits a pattern in components separated by '?'
+ * (double ?? are turned into single ? and left in the string)
+ * expected contains the number of expected occurrences of '?'
+ * (a negative value means parse as many as possible)
+ */
+
+int
+backsql_split_pattern(
+       const char      *_pattern,
+       BerVarray       *split_pattern,
+       int             expected )
+{
+       char            *pattern, *start, *end;
+       struct berval   bv;
+       int             rc = 0;
+
+#define SPLIT_CHAR     '?'
+       
+       assert( _pattern );
+       assert( split_pattern );
+
+       pattern = ch_strdup( _pattern );
+
+       start = pattern;
+       end = strchr( start, SPLIT_CHAR );
+       for ( ; start; expected-- ) {
+               char            *real_end = end;
+               ber_len_t       real_len;
+               
+               if ( real_end == NULL ) {
+                       real_end = start + strlen( start );
+
+               } else if ( real_end[ 1 ] == SPLIT_CHAR ) {
+                       expected++;
+                       AC_MEMCPY( real_end, real_end + 1, strlen( real_end ) );
+                       end = strchr( real_end + 1, SPLIT_CHAR );
+                       continue;
+               }
+
+               real_len = real_end - start;
+               if ( real_len == 0 ) {
+                       ber_str2bv( "", 0, 1, &bv );
+               } else {
+                       ber_str2bv( start, real_len, 1, &bv );
+               }
+
+               ber_bvarray_add( split_pattern, &bv );
+
+               if ( expected == 0 ) {
+                       if ( end != NULL ) {
+                               rc = -1;
+                               goto done;
+                       }
+                       break;
+               }
+
+               if ( end != NULL ) {
+                       start = end + 1;
+                       end = strchr( start, SPLIT_CHAR );
+               }
+       }
+
+done:;
+
+       ch_free( pattern );
+
+       return rc;
+}
+
+int
+backsql_prepare_pattern(
+       BerVarray       split_pattern,
+       BerVarray       values,
+       struct berval   *res )
+{
+       ber_len_t       len = 0;
+       int             i;
+
+       res->bv_val = NULL;
+       res->bv_len = 0;
+
+       for ( i = 0; values[i].bv_val; i++ ) {
+               if ( split_pattern[i].bv_val == NULL ) {
+                       return -1;
+               }
+               backsql_strfcat( res, &len, "b", &split_pattern[ i ] );
+               backsql_strfcat( res, &len, "b", &values[ i ] );
+       }
+
+       if ( split_pattern[ i ].bv_val == NULL ) {
+               return -1;
+       }
+
+       backsql_strfcat( res, &len, "b", &split_pattern[ i ] );
+
+       return 0;
+}
+
 #endif /* SLAPD_SQL */
 
index adc5911caffb57adeed96b186b6ff694fe9d717b..a9f1042d03d0e34836d97358f4da73587041d284 100644 (file)
 #include "entry-id.h"
 #include "schema-map.h"
 
-#define BACKSQL_MAX(a,b) ((a)>(b)?(a):(b))
-#define BACKSQL_MIN(a,b) ((a)<(b)?(a):(b))
+#define BACKSQL_CONCAT
 
-#define BACKSQL_STR_GROW 64
-
-extern struct berval 
-       bv_n_objectclass,
-       bv_n_0_10;
-
-struct berval *backsql_strcat( struct berval *dest, int *buflen, ... );
+struct berval * backsql_strcat( struct berval *dest, ber_len_t *buflen, ... );
+struct berval * backsql_strfcat( struct berval *dest, ber_len_t *buflen,
+               const char *fmt, ... );
 
 int backsql_entry_addattr( Entry *e, struct berval *at_name, 
                struct berval *at_val );
 
-typedef struct __backsql_srch_info {
+typedef struct backsql_srch_info {
        struct berval           *base_dn;
        int                     scope;
        Filter                  *filter;
@@ -40,16 +35,18 @@ typedef struct __backsql_srch_info {
        backsql_info            *bi;
        backsql_oc_map_rec      *oc;
        struct berval           sel, from, join_where, flt_where;
-       int                     sel_len, from_len, jwhere_len, fwhere_len;
+       ber_len_t               sel_len, from_len, jwhere_len, fwhere_len;
        SQLHDBC                 dbh;
        int                     status;
        Backend                 *be;
        Connection              *conn;
        Operation               *op;
        AttributeName           *attrs;
+       int                     attr_flags;
+#define        BSQL_SF_ALL_OPER        0x0001
        Entry                   *e;
        /* 1 if the db is TimesTen; 0 if it's not */
-       int                     isTimesTen; 
+       int                     use_reverse_dn; 
 } backsql_srch_info;
 
 int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
@@ -63,18 +60,24 @@ Entry *backsql_id2entry( backsql_srch_info *bsi, Entry *e,
 
 extern char 
        backsql_def_oc_query[],
+       backsql_def_needs_select_oc_query[],
        backsql_def_at_query[],
        backsql_def_delentry_query[],
        backsql_def_insentry_query[],
        backsql_def_subtree_cond[],
        backsql_def_upper_subtree_cond[],
-       backsql_id_query[];
+       backsql_id_query[],
+       backsql_def_concat_func[];
 extern char 
        backsql_check_dn_ru_query[];
 
-int backsql_merge_from_clause( char **dest_from, int *dest_len, 
-               char *src_from );
+int backsql_merge_from_clause( struct berval *dest_from, ber_len_t *dest_len, 
+               struct berval *src_from );
 
+int backsql_split_pattern( const char *pattern, BerVarray *split_pattern,
+               int expected );
+int backsql_prepare_pattern( BerVarray split_pattern, BerVarray values,
+               struct berval *res );
 
 #endif /* __BACKSQL_UTIL_H__ */