]> git.sur5r.net Git - openldap/commitdiff
Final run of changes to back-sql; IBM db2 support has been tested.
authorPierangelo Masarati <ando@openldap.org>
Fri, 23 Aug 2002 08:54:08 +0000 (08:54 +0000)
committerPierangelo Masarati <ando@openldap.org>
Fri, 23 Aug 2002 08:54:08 +0000 (08:54 +0000)
Now related ITSes need be audited and possibly closed.

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 ?)

21 files changed:
doc/man/man5/slapd-sql.5
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
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 6e52f64acb018cdc59ee70f65a990f31ef3c6ea5..c0b55fc623fad76d06003582f4190e2095da9d11 100644 (file)
@@ -63,7 +63,9 @@ These three options are generally unneeded, because this information is already
 taken from the datasource.
 Use them if you need to override datasource settings.
 Also, several RDBMS' drivers tend to require explicit passing of user/password,
-even if those are given in datasource.
+even if those are given in datasource (Note:
+.B dbhost
+is currently ignored).
 .RE
 .TP
 .B subtree_cond <SQL expression>
@@ -92,18 +94,74 @@ adding and deleting entries to ldap_entries, etc.
 All these and subtree_cond should have the given default values.
 For the current value it is recommended to look at the sources,
 or in the log output when slapd starts with "-d 5" or greater.
+Note that the parameter number and order must not be changed.
 .TP
 .B upper_func <SQL function name>
 Specifies the name of a function that converts a given value to uppercase.
 This is used for CIS matching when the RDBMS is case sensitive.
 .TP
+.B upper_needs_cast { yes | no }
+Set this directive to 
+.B yes
+if 
+.B upper_func
+needs an explicit cast when applied to literal strings.  The form
+.B cast (<arg> as varchar(<max DN length>))
+is used, where
+.B <max DN length>
+is builtin.
+This is
+.B experimental 
+and may change in future releases.
+.TP
+.B concat_pattern <pattern>
+This statement defines the
+.B pattern 
+to be used to concatenate strings.  The
+.B pattern
+MUST contain two question marks, '?', that will be replaced 
+by the two strings that must be concatenated.  The default value is
+.BR "CONCAT(?,?)";
+a form that is known to be highly portable is 
+.BR "?||?",
+but an explicit cast may be required when operating on literal strings:
+.BR "cast(?||? as varchar(<length>))".
+On some RDBMSes the form
+.B "?+?"
+is known to work.
+Carefully check the documentation of your RDBMS or stay with the examples
+for supported ones.
+This is
+.B experimental 
+and may change in future releases.
+.TP
 .B strcast_func <SQL function name>
 Specifies the name of a function that converts a given value to a string
-for appropriate ordering.  This is used when selecting distinct data.
+for appropriate ordering.  This is used in "SELECT DISTINCT" statements
+for strongly typed RDBMSes with little implicit casting (like PostgreSQL),
+when a literal string is specified.
+This is
+.B experimental 
+and may change in future releases.
 .TP
 .B has_ldapinfo_dn_ru { yes | no }
-Explicitly inform the backend whether the SQL schema has dn_ru or not.
-Overrides automatic check (required by PostgreSQL).
+Explicitly inform the backend whether the SQL schema has dn_ru column
+(dn in reverse uppercased form) or not.
+Overrides automatic check (required by PostgreSQL/unixODBC).
+This is
+.B experimental 
+and may change in future releases.
+
+.TP
+.B fail_if_no_mapping { yes | no }
+When set to
+.B yes
+it forces write operations to fail if no appropriate mapping between LDAP
+attributes and SQL data is available.  The default behavior is to ignore
+those changes that cannot be mapped correctly.
+This is
+.B experimental 
+and may change in future releases.
 
 .SH METAINFORMATION USED
 .LP
@@ -217,7 +275,7 @@ Keytbl and keycol thus contain "persons" (name of the table), and "id"
   ldap_attr_mappings (some columns are not listed for clarity)
   -----------
   id=1
-  oc_id=1
+  oc_map_id=1
   name="cn"
   sel_expr="CONCAT(persons.first_name,' ',persons.last_name)"
   from_tbls="persons"
@@ -356,7 +414,7 @@ information on this matter - they are self-explanatory for those familiar
 with concept expressed above.
 .LP
 .SH common techniques (referrals, multiclassing etc.)
-First of all, lets remember that among other major differences to the
+First of all, let's remember that among other major differences to the
 complete LDAP data model, the concept above does not directly support
 such things as multiple objectclasses per entry, and referrals.
 Fortunately, they are easy to adopt in this scheme.
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 );
 
index f016dfabb2121a1f4bbd23767f29eee9751a5313..a45ac6f0022340fd2447b5cd65f2c42477b63355 100644 (file)
@@ -34,6 +34,8 @@ 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
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..bbc2374d0954eab1fc6645aa93823faedcacc48f 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;
 }
@@ -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__ */