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