Final run of changes to back-sql; IBM db2 support has been tested.

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 ?)
This commit is contained in:
Pierangelo Masarati 2002-08-23 08:54:08 +00:00
parent 7b4b4b34c4
commit f11c6b27e7
21 changed files with 1886 additions and 560 deletions

View 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.

View 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"
@ -18,6 +75,12 @@
*/
#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 ) \

View 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 ] );
}

View 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 );

View 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 );

View 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

View 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);
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->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 {
si->subtree_cond = ch_strdup( backsql_def_subtree_cond );
/*
* 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, 0, 0 );
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);
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 {
/*
* 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->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,7 +375,7 @@ 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",
@ -238,6 +383,7 @@ backsql_db_open(
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 );

View file

@ -23,29 +23,50 @@
#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;
}
@ -78,57 +113,99 @@ backsql_modify_internal(
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 );
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(): "
"no values given to add "
"for attribute '%s'\n",
at->name.bv_val, 0, 0 );
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;
}

View 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 */

View 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
);

View 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"

View 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;

View 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);

View 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);

View 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

View file

@ -73,16 +73,25 @@ backsql_make_attr_query(
backsql_at_map_rec *at_map )
{
struct berval tmps = { 0, NULL };
int tmpslen = 0;
ber_len_t 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 );
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;
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 );
}

View file

@ -10,14 +10,23 @@
* 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 */

View file

@ -23,14 +23,6 @@
#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;
}
@ -162,7 +158,7 @@ backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
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
/*
* 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 );
} else {
backsql_strcat( &bsi->sel, &bsi->sel_len,
"'", bsi->oc->name.bv_val, "'", NULL );
}
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, "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_strfcat( &bsi->sel, &bsi->sel_len, "cbc",
'\'',
&bsi->oc->name,
'\'' );
}
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 );

View 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;
}

View file

@ -23,10 +23,17 @@
#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(): "
@ -150,7 +262,10 @@ backsql_entry_addattr(
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 */

View file

@ -14,21 +14,16 @@
#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__ */