From: Pierangelo Masarati Date: Mon, 19 Jan 2004 22:13:15 +0000 (+0000) Subject: make file names more slapd-ish; add attribute inheritance to search attributes; preco... X-Git-Tag: OPENLDAP_REL_ENG_2_1_MP~6 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=eeb9a078239fad9ea8e974ead98ed28eb19a7d92;p=openldap make file names more slapd-ish; add attribute inheritance to search attributes; precompile uppercased search --- diff --git a/servers/slapd/back-sql/Makefile.in b/servers/slapd/back-sql/Makefile.in index e67192ec49..7037bdea3b 100644 --- a/servers/slapd/back-sql/Makefile.in +++ b/servers/slapd/back-sql/Makefile.in @@ -13,10 +13,12 @@ ## top-level directory of the distribution or, alternatively, at ## . -SRCS = init.c config.c search.c bind.c other.c \ - entry-id.c schema-map.c sql-wrap.c modify.c util.c -OBJS = init.lo config.lo search.lo bind.lo other.lo \ - entry-id.lo schema-map.lo sql-wrap.lo modify.lo util.lo +SRCS = init.c config.c search.c bind.c compare.c operational.c \ + entry-id.c schema-map.c sql-wrap.c modify.c util.c \ + add.c delete.c modrdn.c +OBJS = init.lo config.lo search.lo bind.lo compare.lo operational.lo \ + entry-id.lo schema-map.lo sql-wrap.lo modify.lo util.lo \ + add.lo delete.lo modrdn.lo LDAP_INCDIR= ../../../include LDAP_LIBDIR= ../../../libraries diff --git a/servers/slapd/back-sql/add.c b/servers/slapd/back-sql/add.c new file mode 100644 index 0000000000..1ce39b93b3 --- /dev/null +++ b/servers/slapd/back-sql/add.c @@ -0,0 +1,970 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1999-2004 The OpenLDAP Foundation. + * Portions Copyright 1999 Dmitry Kovalev. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Dmitry Kovalev for inclusion + * by OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_SQL + +#include +#include +#include "ac/string.h" + +#include "slap.h" +#include "ldap_pvt.h" +#include "proto-sql.h" + +/* + * Skip: + * - the first occurrence of objectClass, which is used + * to determine how to build 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 ) \ + ) + +int +backsql_modify_internal( + Operation *op, + SlapReply *rs, + SQLHDBC dbh, + backsql_oc_map_rec *oc, + backsql_entryID *e_id, + Modifications *modlist ) +{ + backsql_info *bi = (backsql_info*)op->o_bd->be_private; + RETCODE rc; + SQLHSTMT sth; + Modifications *ml; + + Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): " + "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 ) { + 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; + ad = c_mod->sm_desc; + + Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " + "modifying attribute \"%s\" according to " + "mappings for objectClass \"%s\"\n", + ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 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_internal(): " + "attribute \"%s\" is not registered " + "in objectClass \"%s\"\n", + ad->ad_cname.bv_val, oc, 0 ); + + if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted " + "within namingContext"; + goto done; + } + + continue; + } + + switch( c_mod->sm_op ) { + case LDAP_MOD_REPLACE: { + SQLHSTMT asth; + BACKSQL_ROW_NTS row; + + Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " + "replacing values for attribute \"%s\"\n", + at->bam_ad->ad_cname.bv_val, 0, 0 ); + + if ( at->bam_add_proc == NULL ) { + Debug( LDAP_DEBUG_TRACE, + " backsql_modify_internal(): " + "add procedure is not defined " + "for attribute \"%s\" " + "- unable to perform replacements\n", + at->bam_ad->ad_cname.bv_val, 0, 0 ); + + if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted " + "within namingContext"; + goto done; + } + + break; + } + + if ( at->bam_delete_proc == NULL ) { + if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { + Debug( LDAP_DEBUG_TRACE, + " backsql_modify_internal(): " + "delete procedure is not defined " + "for attribute \"%s\"\n", + at->bam_ad->ad_cname.bv_val, 0, 0 ); + + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted " + "within namingContext"; + goto done; + } + + Debug( LDAP_DEBUG_TRACE, + " backsql_modify_internal(): " + "delete procedure is not defined " + "for attribute \"%s\" " + "- adding only\n", + at->bam_ad->ad_cname.bv_val, 0, 0 ); + + goto add_only; + } + +del_all: + rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 ); + if ( rc != SQL_SUCCESS ) { + 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 ) ) { + rs->sr_err = LDAP_OTHER; + rs->sr_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_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 ) ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + + break; + } + + rc = SQLExecute( asth ); + if ( !BACKSQL_SUCCESS( rc ) ) { + 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 ) ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + + break; + } + + backsql_BindRowAsStrings( asth, &row ); + rc = SQLFetch( asth ); + for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) { + for ( i = 0; i < row.ncols; i++ ) { + if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { + pno = 1; + SQLBindParameter(sth, 1, + SQL_PARAM_OUTPUT, + SQL_C_ULONG, + SQL_INTEGER, + 0, 0, &prc, 0, 0 ); + } else { + pno = 0; + } + po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; + SQLBindParameter( sth, pno + 1 + po, + SQL_PARAM_INPUT, + SQL_C_ULONG, SQL_INTEGER, + 0, 0, &e_id->keyval, 0, 0 ); + + /* + * check for syntax needed here + * maybe need binary bind? + */ + SQLBindParameter(sth, pno + 2 - po, + SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, + 0, 0, row.cols[ i ], + strlen( row.cols[ i ] ), 0 ); + + Debug( LDAP_DEBUG_TRACE, + " backsql_modify_internal(): " + "executing \"%s\"\n", + at->bam_delete_proc, 0, 0 ); + rc = SQLExecDirect( sth, + at->bam_delete_proc, SQL_NTS ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + " 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 ) ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + } +#ifdef BACKSQL_REALLOC_STMT + SQLFreeStmt( sth, SQL_DROP ); + SQLAllocStmt( dbh, &sth ); +#endif /* BACKSQL_REALLOC_STMT */ + } + } + backsql_FreeRow( &row ); + SQLFreeStmt( asth, SQL_DROP ); + } + + /* + * PASSTHROUGH - to add new attributes -- do NOT add break + */ + case LDAP_MOD_ADD: + case SLAP_MOD_SOFTADD: +add_only:; + if ( at->bam_add_proc == NULL ) { + Debug( LDAP_DEBUG_TRACE, + " backsql_modify_internal(): " + "add procedure is not defined " + "for attribute \"%s\"\n", + at->bam_ad->ad_cname.bv_val, 0, 0 ); + + if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted " + "within namingContext"; + goto done; + } + + break; + } + + Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " + "adding new values for attribute \"%s\"\n", + at->bam_ad->ad_cname.bv_val, 0, 0 ); + for ( i = 0, at_val = c_mod->sm_bvalues; + at_val->bv_val != NULL; + i++, at_val++ ) { + if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) { + pno = 1; + SQLBindParameter( sth, 1, + SQL_PARAM_OUTPUT, + SQL_C_ULONG, SQL_INTEGER, + 0, 0, &prc, 0, 0); + } else { + pno = 0; + } + po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0; + SQLBindParameter( sth, pno + 1 + po, + SQL_PARAM_INPUT, + SQL_C_ULONG, SQL_INTEGER, + 0, 0, &e_id->keyval, 0, 0 ); + + /* + * check for syntax needed here + * maybe need binary bind? + */ + SQLBindParameter( sth, pno + 2 - po, + SQL_PARAM_INPUT, + SQL_C_CHAR, SQL_CHAR, + 0, 0, at_val->bv_val, + at_val->bv_len, 0 ); + + Debug( LDAP_DEBUG_TRACE, + " backsql_modify_internal(): " + "executing \"%s\"\n", + at->bam_add_proc, 0, 0 ); + rc = SQLExecDirect( sth, at->bam_add_proc, + SQL_NTS ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + " 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 ) ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + } +#ifdef BACKSQL_REALLOC_STMT + SQLFreeStmt( sth, SQL_DROP ); + SQLAllocStmt( dbh, &sth ); +#endif /* BACKSQL_REALLOC_STMT */ + } + break; + + case LDAP_MOD_DELETE: + if ( at->bam_delete_proc == NULL ) { + Debug( LDAP_DEBUG_TRACE, + " backsql_modify_internal(): " + "delete procedure is not defined " + "for attribute \"%s\"\n", + at->bam_ad->ad_cname.bv_val, 0, 0 ); + + if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted " + "within namingContext"; + goto done; + } + + break; + } + + if ( c_mod->sm_bvalues == NULL ) { + Debug( LDAP_DEBUG_TRACE, + " backsql_modify_internal(): " + "no values given to delete " + "for attribute \"%s\" " + "-- deleting all values\n", + at->bam_ad->ad_cname.bv_val, 0, 0 ); + goto del_all; + } + + Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): " + "deleting values for attribute \"%s\"\n", + at->bam_ad->ad_cname.bv_val, 0, 0 ); + + for ( i = 0, at_val = c_mod->sm_bvalues; + at_val->bv_val != NULL; + i++, at_val++ ) { + if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { + pno = 1; + SQLBindParameter( sth, 1, + SQL_PARAM_OUTPUT, + SQL_C_ULONG, SQL_INTEGER, + 0, 0, &prc, 0, 0 ); + } else { + pno = 0; + } + po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; + SQLBindParameter( sth, pno + 1 + po, + SQL_PARAM_INPUT, + SQL_C_ULONG, SQL_INTEGER, + 0, 0, &e_id->keyval, 0, 0 ); + + /* + * check for syntax needed here + * maybe need binary bind? + */ + SQLBindParameter( sth, pno + 2 - po, + SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, + 0, 0, at_val->bv_val, + at_val->bv_len, 0 ); + + Debug( LDAP_DEBUG_TRACE, + " backsql_modify_internal(): " + "executing \"%s\"\n", + at->bam_delete_proc, 0, 0 ); + rc = SQLExecDirect( sth, at->bam_delete_proc, + SQL_NTS ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, + " 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 ) ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + } +#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 */ + } + +done:; + +#ifndef BACKSQL_REALLOC_STMT + SQLFreeStmt( sth, SQL_DROP ); +#endif /* BACKSQL_REALLOC_STMT */ + + Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%d%s\n", + rs->sr_err, rs->sr_text ? ": " : "", + rs->sr_text ? rs->sr_text : "" ); + + /* + * FIXME: should fail in case one change fails? + */ + return rs->sr_err; +} + +int +backsql_add( Operation *op, SlapReply *rs ) +{ + backsql_info *bi = (backsql_info*)op->o_bd->be_private; + SQLHDBC dbh; + SQLHSTMT sth; + unsigned long new_keyval = 0; + long i; + RETCODE rc; + backsql_oc_map_rec *oc = NULL; + backsql_at_map_rec *at_rec = NULL; + backsql_entryID e_id, parent_id; + Entry p; + Attribute *at; + struct berval *at_val; + struct berval pdn; + /* first parameter #, parameter order */ + SQLUSMALLINT pno, po; + /* procedure return code */ + int prc; + + Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry \"%s\"\n", + op->oq_add.rs_e->e_name.bv_val, 0, 0 ); + + /* check schema */ + if ( global_schemacheck ) { + char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; + + rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e, + NULL, + &rs->sr_text, textbuf, sizeof( textbuf ) ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "entry failed schema check -- aborting\n", + 0, 0, 0 ); + goto done; + } + } + + /* search structural objectClass */ + for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) { + if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) { + break; + } + } + + /* there must exist */ + assert( at != NULL ); + + /* I guess we should play with sub/supertypes to find a suitable oc */ + oc = backsql_name2oc( bi, &at->a_vals[0] ); + + if ( oc == NULL ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "cannot determine objectclass of entry -- aborting\n", + 0, 0, 0 ); + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted within namingContext"; + goto done; + } + + if ( oc->bom_create_proc == NULL ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "create procedure is not defined for this objectclass " + "- aborting\n", 0, 0, 0 ); + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted within namingContext"; + goto done; + + } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) + && oc->bom_create_keyval == NULL ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "create procedure needs select procedure, " + "but none is defined - aborting\n", 0, 0, 0 ); + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted within namingContext"; + goto done; + } + + rs->sr_err = backsql_get_db_conn( op, &dbh ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "could not get connection handle - exiting\n", + 0, 0, 0 ); + rs->sr_text = ( rs->sr_err == LDAP_OTHER ) + ? "SQL-backend error" : NULL; + goto done; + } + + /* + * Check if entry exists + */ + rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->oq_add.rs_e->e_name ); + if ( rs->sr_err == LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "entry \"%s\" exists\n", + op->oq_add.rs_e->e_name.bv_val, 0, 0 ); + rs->sr_err = LDAP_ALREADY_EXISTS; + goto done; + } + + /* + * Check if parent exists + */ + dnParent( &op->oq_add.rs_e->e_name, &pdn ); + rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "could not lookup parent entry for new record \"%s\"\n", + pdn.bv_val, 0, 0 ); + + if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) { + goto done; + } + + /* + * Look for matched + */ + while ( 1 ) { + struct berval dn; + char *matched = NULL; + + dn = pdn; + dnParent( &dn, &pdn ); + + /* + * Empty DN ("") defaults to LDAP_SUCCESS + */ + rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn ); + switch ( rs->sr_err ) { + 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: + rs->sr_err = LDAP_NO_SUCH_OBJECT; + rs->sr_matched = matched; + goto done; + } + } + } + + /* + * 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 + */ + + p.e_attrs = NULL; + p.e_name = pdn; + dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname ); + if ( !access_allowed( op, &p, slap_schema.si_ad_children, + NULL, ACL_WRITE, NULL ) ) { + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto done; + } + + rc = SQLAllocStmt( dbh, &sth ); + if ( rc != SQL_SUCCESS ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + + if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) { + SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, + SQL_INTEGER, 0, 0, &new_keyval, 0, 0 ); + } + + Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\"\n", + oc->bom_create_proc, 0, 0 ); + rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "create_proc execution failed\n", 0, 0, 0 ); + backsql_PrintErrors( bi->db_env, dbh, sth, rc); + SQLFreeStmt( sth, SQL_DROP ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + if ( op->o_noop ) { + SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK ); + } + + if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) { + SWORD ncols; + SQLINTEGER value_len; + + 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 ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } +#endif /* BACKSQL_REALLOC_STMT */ + + rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS ); + if ( rc != SQL_SUCCESS ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + } + + /* + * 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 ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + + } else if ( ncols != 1 ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "create_proc result is bogus (ncols=%d)\n", + ncols, 0, 0 ); + backsql_PrintErrors( bi->db_env, dbh, sth, rc); + SQLFreeStmt( sth, SQL_DROP ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + +#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 ), + &value_len ); + + rc = SQLFetch( sth ); + + if ( value_len <= 0 ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "create_proc result is empty?\n", + 0, 0, 0 ); + backsql_PrintErrors( bi->db_env, dbh, sth, rc); + SQLFreeStmt( sth, SQL_DROP ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + } + +#ifndef BACKSQL_REALLOC_STMT + SQLFreeStmt( sth, SQL_RESET_PARAMS ); +#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 ); + + for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) { + SQLUSMALLINT currpos; + + 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; + } + + 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, + BACKSQL_OC_NAME( oc ), 0 ); + + if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted " + "within namingContext"; + goto done; + } + + continue; + } + + if ( at_rec->bam_add_proc == NULL ) { + Debug( LDAP_DEBUG_TRACE, " 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 ) ) { + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted " + "within namingContext"; + goto done; + } + + continue; + } + +#ifdef BACKSQL_REALLOC_STMT + rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 ); + if ( rc != SQL_SUCCESS ) { + + if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + + continue; + } +#endif /* BACKSQL_REALLOC_STMT */ + + if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) { + pno = 1; + SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, + SQL_C_ULONG, SQL_INTEGER, + 0, 0, &prc, 0, 0 ); + } else { + pno = 0; + } + + po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0; + currpos = pno + 1 + po; + SQLBindParameter( sth, currpos, + SQL_PARAM_INPUT, SQL_C_ULONG, + SQL_INTEGER, 0, 0, &new_keyval, 0, 0 ); + currpos = pno + 2 - po; + + 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 ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) { + continue; + } + } + + /* + * check for syntax needed here + * maybe need binary bind? + */ + + 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->bam_add_proc, new_keyval, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "executing \"%s\" for val[%d], id=%ld\n", + at_rec->bam_add_proc, i, new_keyval ); +#endif +#ifndef BACKSQL_REALLOC_STMT + rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS ); +#else /* BACKSQL_REALLOC_STMT */ + rc = SQLExecute( sth ); +#endif /* BACKSQL_REALLOC_STMT */ + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " 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 ) ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + } + } +#ifndef BACKSQL_REALLOC_STMT + SQLFreeStmt( sth, SQL_RESET_PARAMS ); +#else /* BACKSQL_REALLOC_STMT */ + SQLFreeStmt( sth, SQL_DROP ); +#endif /* BACKSQL_REALLOC_STMT */ + } + +#ifdef BACKSQL_REALLOC_STMT + rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 ); + if ( rc != SQL_SUCCESS ) { + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } +#endif /* BACKSQL_REALLOC_STMT */ + + backsql_BindParamStr( sth, 1, op->oq_add.rs_e->e_name.bv_val, + BACKSQL_MAX_DN_LEN ); + SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, + 0, 0, &oc->bom_id, 0, 0 ); + SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, + 0, 0, &parent_id.id, 0, 0 ); + SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, + 0, 0, &new_keyval, 0, 0 ); + + Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\" for dn \"%s\"\n", + bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 ); + Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, parent_id=%ld, " + "keyval=%ld\n", oc->bom_id, parent_id.id, new_keyval ); +#ifndef BACKSQL_REALLOC_STMT + rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS ); +#else /* BACKSQL_REALLOC_STMT */ + rc = SQLExecute( sth ); +#endif /* BACKSQL_REALLOC_STMT */ + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_add(): " + "could not insert ldap_entries record\n", 0, 0, 0 ); + backsql_PrintErrors( bi->db_env, dbh, sth, rc ); + + /* + * execute delete_proc to delete data added !!! + */ + SQLFreeStmt( sth, SQL_DROP ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + + SQLFreeStmt( sth, SQL_DROP ); + + /* + * Commit only if all operations succeed + */ + SQLTransact( SQL_NULL_HENV, dbh, + op->o_noop ? SQL_ROLLBACK : SQL_COMMIT ); + + /* + * FIXME: NOOP does not work for add -- it works for all + * the other operations, and I don't get the reason :( + * + * hint: there might be some autocommit in Postgres + * so that when the unique id of the key table is + * automatically increased, there's no rollback. + * We might implement a "rollback" procedure consisting + * in deleting that row. + */ + +done:; + send_ldap_result( op, rs ); + + Debug( LDAP_DEBUG_TRACE, "<==backsql_add(): %d%s%s\n", + rs->sr_err, + rs->sr_text ? ": " : "", + rs->sr_text ? rs->sr_text : "" ); + + return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 ); +} + +#endif /* SLAPD_SQL */ + diff --git a/servers/slapd/back-sql/back-sql.h b/servers/slapd/back-sql/back-sql.h index 77dc5e700f..0241eeb170 100644 --- a/servers/slapd/back-sql/back-sql.h +++ b/servers/slapd/back-sql/back-sql.h @@ -78,8 +78,14 @@ #include "sql-types.h" /* - * Better use the standard length of 8192 (as of servers/slapd/dn.c) ? + * PostgreSQL 7.0 doesn't work without :( */ +#define BACKSQL_REALLOC_STMT + +/* + * Better use the standard length of 8192 (as of slap.h)? + */ +/* #define BACKSQL_MAX_DN_LEN SLAP_LDAPDN_MAXLEN */ #define BACKSQL_MAX_DN_LEN 255 /* @@ -87,6 +93,147 @@ */ #undef BACKSQL_TRACE +/* + * Entry ID structure + */ +typedef struct backsql_entryID { + unsigned long id; + unsigned long keyval; + unsigned long oc_id; + struct berval dn; + struct backsql_entryID *next; +} backsql_entryID; + +/* + * "structural" objectClass mapping structure + */ +typedef struct backsql_oc_map_rec { + /* + * Structure of corresponding LDAP objectClass definition + */ + ObjectClass *bom_oc; +#define BACKSQL_OC_NAME(ocmap) ((ocmap)->bom_oc->soc_cname.bv_val) + + struct berval bom_keytbl; + struct berval bom_keycol; + /* expected to return keyval of newly created entry */ + char *bom_create_proc; + /* in case create_proc does not return the keyval of the newly + * created row */ + char *bom_create_keyval; + /* supposed to expect keyval as parameter and delete + * all the attributes as well */ + char *bom_delete_proc; + /* flags whether delete_proc is a function (whether back-sql + * should bind first parameter as output for return code) */ + int bom_expect_return; + unsigned long bom_id; + Avlnode *bom_attrs; +} backsql_oc_map_rec; + +/* + * attributeType mapping structure + */ +typedef struct backsql_at_map_rec { + /* Description of corresponding LDAP attribute type */ + AttributeDescription *bam_ad; + /* ObjectClass if bam_ad is objectClass */ + ObjectClass *bam_oc; + + struct berval bam_from_tbls; + struct berval bam_join_where; + struct berval bam_sel_expr; + + /* TimesTen, or, if a uppercase function is defined, + * an uppercased version of bam_sel_expr */ + struct berval bam_sel_expr_u; + + /* supposed to expect 2 binded values: entry keyval + * and attr. value to add, like "add_name(?,?,?)" */ + char *bam_add_proc; + /* supposed to expect 2 binded values: entry keyval + * and attr. value to delete */ + char *bam_delete_proc; + /* for optimization purposes attribute load query + * is preconstructed from parts on schemamap load time */ + char *bam_query; + /* following flags are bitmasks (first bit used for add_proc, + * second - for delete_proc) */ + /* order of parameters for procedures above; + * 1 means "data then keyval", 0 means "keyval then data" */ + int bam_param_order; + /* flags whether one or more of procedures is a function + * (whether back-sql should bind first parameter as output + * for return code) */ + int bam_expect_return; + + /* next mapping for attribute */ + struct backsql_at_map_rec *bam_next; +} backsql_at_map_rec; + +#define BACKSQL_AT_MAP_REC_INIT { NULL, NULL, BER_BVC(""), BER_BVC(""), BER_BVNULL, BER_BVNULL, NULL, NULL, NULL, 0, 0, NULL } + +/* define to uppercase filters only if the matching rule requires it + * (currently broken) */ +/* #define BACKSQL_UPPERCASE_FILTER */ + +#define BACKSQL_AT_CANUPPERCASE(at) ((at)->bam_sel_expr_u.bv_val) + +/* defines to support bitmasks above */ +#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)) + +#define BACKSQL_CONCAT +/* + * berbuf structure: a berval with a buffer size associated + */ +typedef struct berbuf { + struct berval bb_val; + ber_len_t bb_len; +} BerBuffer; + +#define BB_NULL { { 0, NULL }, 0 } + +typedef struct backsql_srch_info { + Operation *bsi_op; + + int bsi_flags; +#define BSQL_SF_ALL_OPER 0x0001 +#define BSQL_SF_FILTER_HASSUBORDINATE 0x0002 + + struct berval *bsi_base_dn; + int bsi_scope; + Filter *bsi_filter; + int bsi_slimit, + bsi_tlimit; + time_t bsi_stoptime; + + backsql_entryID *bsi_id_list, + *bsi_c_eid; + int bsi_n_candidates; + int bsi_abandon; + int bsi_status; + + backsql_oc_map_rec *bsi_oc; + struct berbuf bsi_sel, + bsi_from, + bsi_join_where, + bsi_flt_where; + ObjectClass *bsi_filter_oc; + SQLHDBC bsi_dbh; + AttributeName *bsi_attrs; + + Entry *bsi_e; +} backsql_srch_info; + +/* + * Backend private data structure + */ typedef struct { char *dbhost; int dbport; @@ -150,3 +297,5 @@ typedef struct { #endif /* __BACKSQL_H__ */ + + diff --git a/servers/slapd/back-sql/bind.c b/servers/slapd/back-sql/bind.c index ed73fea3e3..82da5b9be2 100644 --- a/servers/slapd/back-sql/bind.c +++ b/servers/slapd/back-sql/bind.c @@ -24,11 +24,9 @@ #include #include + #include "slap.h" -#include "back-sql.h" -#include "sql-wrap.h" -#include "util.h" -#include "entry-id.h" +#include "proto-sql.h" int backsql_bind( Operation *op, SlapReply *rs ) diff --git a/servers/slapd/back-sql/compare.c b/servers/slapd/back-sql/compare.c new file mode 100644 index 0000000000..43ebc9c7b9 --- /dev/null +++ b/servers/slapd/back-sql/compare.c @@ -0,0 +1,175 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1999-2004 The OpenLDAP Foundation. + * Portions Copyright 1999 Dmitry Kovalev. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Dmitry Kovalev for inclusion + * by OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_SQL + +#include +#include + +#include "slap.h" +#include "proto-sql.h" + +int +backsql_compare( Operation *op, SlapReply *rs ) +{ + backsql_info *bi = (backsql_info*)op->o_bd->be_private; + backsql_entryID user_id; + SQLHDBC dbh; + Entry *e = NULL, user_entry; + Attribute *a = NULL, *a_op = NULL; + backsql_srch_info bsi; + int rc; + AttributeName anlist[2]; + + user_entry.e_name.bv_val = NULL; + user_entry.e_name.bv_len = 0; + user_entry.e_nname.bv_val = NULL; + user_entry.e_nname.bv_len = 0; + user_entry.e_attrs = NULL; + + Debug( LDAP_DEBUG_TRACE, "==>backsql_compare()\n", 0, 0, 0 ); + + rs->sr_err = backsql_get_db_conn( op, &dbh ); + if (!dbh) { + Debug( LDAP_DEBUG_TRACE, "backsql_compare(): " + "could not get connection handle - exiting\n", + 0, 0, 0 ); + + rs->sr_text = ( rs->sr_err == LDAP_OTHER ) + ? "SQL-backend error" : NULL; + goto return_results; + } + + rc = backsql_dn2id( bi, &user_id, dbh, &op->o_req_ndn ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_compare(): " + "could not retrieve compare dn id - no such entry\n", + 0, 0, 0 ); + rs->sr_err = LDAP_NO_SUCH_OBJECT; + goto return_results; + } + + anlist[0].an_name = op->oq_compare.rs_ava->aa_desc->ad_cname; + anlist[0].an_desc = op->oq_compare.rs_ava->aa_desc; + anlist[1].an_name.bv_val = NULL; + + /* + * Try to get attr as dynamic operational + */ + if ( is_at_operational( op->oq_compare.rs_ava->aa_desc->ad_type ) ) { + AttributeName *an_old; + Entry *e_old; + + user_entry.e_attrs = NULL; + user_entry.e_name = op->o_req_dn; + user_entry.e_nname = op->o_req_ndn; + + an_old = rs->sr_attrs; + e_old = rs->sr_entry; + + rs->sr_attrs = anlist; + rs->sr_entry = &user_entry; + rs->sr_err = backsql_operational( op, rs, 0, &a_op ); + rs->sr_attrs = an_old; + rs->sr_entry = e_old; + + if ( rs->sr_err != LDAP_SUCCESS ) { + goto return_results; + } + + } + + /* + * attr was dynamic operational + */ + if ( a_op != NULL ) { + user_entry.e_attrs = a_op; + e = &user_entry; + + } else { + backsql_init_search( &bsi, &op->o_req_ndn, LDAP_SCOPE_BASE, + -1, -1, -1, NULL, dbh, op, anlist ); + e = backsql_id2entry( &bsi, &user_entry, &user_id ); + if ( e == NULL ) { + Debug( LDAP_DEBUG_TRACE, "backsql_compare(): " + "error in backsql_id2entry() " + "- compare failed\n", 0, 0, 0 ); + rs->sr_err = LDAP_OTHER; + goto return_results; + } + } + + if ( ! access_allowed( op, e, op->oq_compare.rs_ava->aa_desc, + &op->oq_compare.rs_ava->aa_value, + ACL_COMPARE, NULL ) ) { + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto return_results; + } + + rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; + for ( a = attrs_find( e->e_attrs, op->oq_compare.rs_ava->aa_desc ); + a != NULL; + a = attrs_find( a->a_next, op->oq_compare.rs_ava->aa_desc )) + { + rs->sr_err = LDAP_COMPARE_FALSE; + if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | + SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, + a->a_nvals, + &op->oq_compare.rs_ava->aa_value, + op->o_tmpmemctx ) == 0 ) + { + rs->sr_err = LDAP_COMPARE_TRUE; + break; + } + } + +return_results:; + send_ldap_result( op, rs ); + + if ( e != NULL ) { + if ( e->e_name.bv_val != NULL ) { + free( e->e_name.bv_val ); + } + + if ( e->e_nname.bv_val != NULL ) { + free( e->e_nname.bv_val ); + } + + if ( e->e_attrs != NULL ) { + attrs_free( e->e_attrs ); + } + } + + Debug(LDAP_DEBUG_TRACE,"<==backsql_compare()\n",0,0,0); + switch ( rs->sr_err ) { + case LDAP_COMPARE_TRUE: + case LDAP_COMPARE_FALSE: + return 0; + + default: + return 1; + } +} + +#endif /* SLAPD_SQL */ + diff --git a/servers/slapd/back-sql/config.c b/servers/slapd/back-sql/config.c index d88a57396d..10f934a321 100644 --- a/servers/slapd/back-sql/config.c +++ b/servers/slapd/back-sql/config.c @@ -25,10 +25,9 @@ #include #include "ac/string.h" #include + #include "slap.h" -#include "back-sql.h" -#include "sql-wrap.h" -#include "util.h" +#include "proto-sql.h" int backsql_db_config( diff --git a/servers/slapd/back-sql/delete.c b/servers/slapd/back-sql/delete.c new file mode 100644 index 0000000000..4db3f1db15 --- /dev/null +++ b/servers/slapd/back-sql/delete.c @@ -0,0 +1,187 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1999-2004 The OpenLDAP Foundation. + * Portions Copyright 1999 Dmitry Kovalev. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Dmitry Kovalev for inclusion + * by OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_SQL + +#include +#include +#include "ac/string.h" + +#include "slap.h" +#include "ldap_pvt.h" +#include "proto-sql.h" + +int +backsql_delete( Operation *op, SlapReply *rs ) +{ + backsql_info *bi = (backsql_info*)op->o_bd->be_private; + SQLHDBC dbh; + SQLHSTMT sth; + RETCODE rc; + backsql_oc_map_rec *oc = NULL; + backsql_entryID e_id; + Entry e; + /* first parameter no */ + SQLUSMALLINT pno; + + Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry \"%s\"\n", + op->o_req_ndn.bv_val, 0, 0 ); + + dnParent( &op->o_req_dn, &e.e_name ); + dnParent( &op->o_req_ndn, &e.e_nname ); + e.e_attrs = NULL; + + /* check parent for "children" acl */ + if ( !access_allowed( 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 ); + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto done; + + } + + rs->sr_err = backsql_get_db_conn( op, &dbh ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "could not get connection handle - exiting\n", + 0, 0, 0 ); + rs->sr_text = ( rs->sr_err == LDAP_OTHER ) + ? "SQL-backend error" : NULL; + goto done; + } + + rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "could not lookup entry id\n", 0, 0, 0 ); + goto done; + } + + rs->sr_err = backsql_has_children( bi, dbh, &op->o_req_ndn ); + switch ( rs->sr_err ) { + case LDAP_COMPARE_TRUE: + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "entry \"%s\" has children\n", + op->o_req_dn.bv_val, 0, 0 ); + rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; + rs->sr_text = "subtree delete not supported"; + goto done; + + case LDAP_COMPARE_FALSE: + break; + + default: + goto done; + } + + 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 ); + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted within namingContext"; + goto done; + } + + if ( oc->bom_delete_proc == NULL ) { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "delete procedure is not defined " + "for this objectclass - aborting\n", 0, 0, 0 ); + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "operation not permitted within namingContext"; + goto done; + } + + SQLAllocStmt( dbh, &sth ); + if ( BACKSQL_IS_DEL( oc->bom_expect_return ) ) { + pno = 1; + SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, + SQL_INTEGER, 0, 0, &rc, 0, 0 ); + } else { + pno = 0; + } + + SQLBindParameter( sth, pno + 1, SQL_PARAM_INPUT, + SQL_C_ULONG, SQL_INTEGER, 0, 0, &e_id.keyval, 0, 0 ); + + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): executing \"%s\"\n", + oc->bom_delete_proc, 0, 0 ); + rc = SQLExecDirect( sth, oc->bom_delete_proc, SQL_NTS ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "delete_proc execution failed\n", 0, 0, 0 ); + backsql_PrintErrors( bi->db_env, dbh, sth, rc ); + SQLFreeStmt( sth, SQL_DROP ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } +#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 ); + rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_delete(): " + "failed to delete record from ldap_entries\n", + 0, 0, 0 ); + backsql_PrintErrors( bi->db_env, dbh, sth, rc ); + SQLFreeStmt( sth, SQL_DROP ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + goto done; + } + + 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, + op->o_noop ? SQL_ROLLBACK : SQL_COMMIT ); + + rs->sr_err = LDAP_SUCCESS; + +done:; + send_ldap_result( op, rs ); + + Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 ); + + return ( ( rs->sr_err == LDAP_SUCCESS ) ? op->o_noop : 1 ); +} + +#endif /* SLAPD_SQL */ + diff --git a/servers/slapd/back-sql/entry-id.c b/servers/slapd/back-sql/entry-id.c index 19f3cdac77..e1cf863cd1 100644 --- a/servers/slapd/back-sql/entry-id.c +++ b/servers/slapd/back-sql/entry-id.c @@ -25,14 +25,11 @@ #include #include #include "ac/string.h" + #include "lber_pvt.h" #include "ldap_pvt.h" #include "slap.h" -#include "back-sql.h" -#include "sql-wrap.h" -#include "schema-map.h" -#include "entry-id.h" -#include "util.h" +#include "proto-sql.h" backsql_entryID * backsql_free_entryID( backsql_entryID *id, int freeit ) @@ -367,7 +364,6 @@ Entry * 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; @@ -391,23 +387,29 @@ backsql_id2entry( backsql_srch_info *bsi, Entry *e, backsql_entryID *eid ) Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " "custom attribute list\n", 0, 0, 0 ); for ( i = 0; bsi->bsi_attrs[ i ].an_name.bv_val; i++ ) { - AttributeName *attr = &bsi->bsi_attrs[ i ]; + backsql_at_map_rec **vat; + AttributeName *attr = &bsi->bsi_attrs[ i ]; + int j; if ( attr->an_desc == ad_oc ) { continue; } - at = backsql_ad2at( bsi->bsi_oc, attr->an_desc ); - if ( at != NULL ) { - backsql_get_attr_vals( at, bsi ); - - } else { + rc = backsql_supad2at( bsi->bsi_oc, attr->an_desc, &vat ); + if ( rc != 0 ) { Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " - "attribute '%s' is not defined " - "for objectlass '%s'\n", - attr->an_name.bv_val, - BACKSQL_OC_NAME( bsi->bsi_oc ), 0 ); + "attribute '%s' is not defined " + "for objectlass '%s'\n", + attr->an_name.bv_val, + BACKSQL_OC_NAME( bsi->bsi_oc ), 0 ); + continue; } + + for ( j = 0; vat[j]; j++ ) { + backsql_get_attr_vals( vat[j], bsi ); + } + + ch_free( vat ); } } else { diff --git a/servers/slapd/back-sql/entry-id.h b/servers/slapd/back-sql/entry-id.h deleted file mode 100644 index bdab2249c8..0000000000 --- a/servers/slapd/back-sql/entry-id.h +++ /dev/null @@ -1,44 +0,0 @@ -/* $OpenLDAP$ */ -/* This work is part of OpenLDAP Software . - * - * Copyright 1999-2004 The OpenLDAP Foundation. - * Portions Copyright 1999 Dmitry Kovalev. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted only as authorized by the OpenLDAP - * Public License. - * - * A copy of this license is available in the file LICENSE in the - * top-level directory of the distribution or, alternatively, at - * . - */ -/* ACKNOWLEDGEMENTS: - * This work was initially developed by Dmitry Kovalev for inclusion - * by OpenLDAP Software. - */ - -#ifndef __BACKSQL_ENTRYID_H__ -#define __BACKSQL_ENTRYID_H__ - -typedef struct backsql_entryID { - unsigned long id; - unsigned long keyval; - unsigned long oc_id; - struct berval dn; - struct backsql_entryID *next; -} backsql_entryID; - -int backsql_dn2id( backsql_info *bi, backsql_entryID *id, - SQLHDBC dbh, struct berval *dn ); - -int backsql_count_children( backsql_info *bi, SQLHDBC dbh, - struct berval *dn, unsigned long *nchildren ); -int backsql_has_children( backsql_info *bi, SQLHDBC dbh, struct berval *dn ); - - -/* returns next */ -backsql_entryID *backsql_free_entryID( backsql_entryID *id, int freeit ); - -#endif /* __BACKSQL_ENTRYID_H__ */ - diff --git a/servers/slapd/back-sql/init.c b/servers/slapd/back-sql/init.c index 840ef0989a..8de4c64208 100644 --- a/servers/slapd/back-sql/init.c +++ b/servers/slapd/back-sql/init.c @@ -24,12 +24,10 @@ #include #include + #include "slap.h" #include "ldap_pvt.h" -#include "back-sql.h" -#include "sql-wrap.h" -#include "schema-map.h" -#include "util.h" +#include "proto-sql.h" #ifdef SLAPD_SQL_DYNAMIC diff --git a/servers/slapd/back-sql/modify.c b/servers/slapd/back-sql/modify.c index 3901a7b907..c36db54f4c 100644 --- a/servers/slapd/back-sql/modify.c +++ b/servers/slapd/back-sql/modify.c @@ -25,445 +25,10 @@ #include #include #include "ac/string.h" + #include "slap.h" #include "ldap_pvt.h" -#include "back-sql.h" -#include "sql-wrap.h" -#include "schema-map.h" -#include "entry-id.h" -#include "util.h" - -/* - * PostgreSQL 7.0 doesn't work without :( - */ -#define BACKSQL_REALLOC_STMT - -/* - * Skip: - * - the first occurrence of objectClass, which is used - * to determine how to build 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( - Operation *op, - SlapReply *rs, - SQLHDBC dbh, - backsql_oc_map_rec *oc, - backsql_entryID *e_id, - Modifications *modlist ) -{ - backsql_info *bi = (backsql_info*)op->o_bd->be_private; - RETCODE rc; - SQLHSTMT sth; - Modifications *ml; - - Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): " - "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 ) { - 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; - ad = c_mod->sm_desc; - - 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_internal(): " - "attribute provided is not registered " - "in objectClass '%s'\n", - ad->ad_cname.bv_val, 0, 0 ); - - if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted " - "within namingContext"; - goto done; - } - - continue; - } - - switch( c_mod->sm_op ) { - case LDAP_MOD_REPLACE: { - SQLHSTMT asth; - BACKSQL_ROW_NTS row; - - Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): " - "replacing values for attribute '%s'\n", - at->bam_ad->ad_cname.bv_val, 0, 0 ); - - if ( at->bam_add_proc == NULL ) { - Debug( LDAP_DEBUG_TRACE, - "backsql_modify_internal(): " - "add procedure is not defined " - "for attribute '%s' " - "- unable to perform replacements\n", - at->bam_ad->ad_cname.bv_val, 0, 0 ); - - if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted " - "within namingContext"; - goto done; - } - - break; - } - - if ( at->bam_delete_proc == NULL ) { - Debug( LDAP_DEBUG_TRACE, - "backsql_modify_internal(): " - "delete procedure is not defined " - "for attribute '%s' " - "- adding only\n", - at->bam_ad->ad_cname.bv_val, 0, 0 ); - - if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted " - "within namingContext"; - goto done; - } - - goto add_only; - } - -del_all: - rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 ); - if ( rc != SQL_SUCCESS ) { - 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 ) ) { - rs->sr_err = LDAP_OTHER; - rs->sr_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_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 ) ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - goto done; - } - - break; - } - - rc = SQLExecute( asth ); - if ( !BACKSQL_SUCCESS( rc ) ) { - 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 ) ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - goto done; - } - - break; - } - - backsql_BindRowAsStrings( asth, &row ); - rc = SQLFetch( asth ); - for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( asth ) ) { - for ( i = 0; i < row.ncols; i++ ) { - if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { - pno = 1; - SQLBindParameter(sth, 1, - SQL_PARAM_OUTPUT, - SQL_C_ULONG, - SQL_INTEGER, - 0, 0, &prc, 0, 0 ); - } else { - pno = 0; - } - po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; - SQLBindParameter( sth, pno + 1 + po, - SQL_PARAM_INPUT, - SQL_C_ULONG, SQL_INTEGER, - 0, 0, &e_id->keyval, 0, 0 ); - - /* - * check for syntax needed here - * maybe need binary bind? - */ - SQLBindParameter(sth, pno + 2 - po, - SQL_PARAM_INPUT, - SQL_C_CHAR, SQL_CHAR, - 0, 0, row.cols[ i ], - strlen( row.cols[ i ] ), 0 ); - - Debug( LDAP_DEBUG_TRACE, - "backsql_modify_internal(): " - "executing '%s'\n", - at->bam_delete_proc, 0, 0 ); - rc = SQLExecDirect( sth, - at->bam_delete_proc, SQL_NTS ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - "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 ) ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - goto done; - } - } -#ifdef BACKSQL_REALLOC_STMT - SQLFreeStmt( sth, SQL_DROP ); - SQLAllocStmt( dbh, &sth ); -#endif /* BACKSQL_REALLOC_STMT */ - } - } - backsql_FreeRow( &row ); - SQLFreeStmt( asth, SQL_DROP ); - } - - /* - * PASSTHROUGH - to add new attributes -- do NOT add break - */ - case LDAP_MOD_ADD: - case SLAP_MOD_SOFTADD: -add_only:; - if ( at->bam_add_proc == NULL ) { - Debug( LDAP_DEBUG_TRACE, - "backsql_modify_internal(): " - "add procedure is not defined " - "for attribute '%s'\n", - at->bam_ad->ad_cname.bv_val, 0, 0 ); - - if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted " - "within namingContext"; - goto done; - } - - break; - } - - Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): " - "adding new values for attribute '%s'\n", - at->bam_ad->ad_cname.bv_val, 0, 0 ); - for ( i = 0, at_val = c_mod->sm_bvalues; - at_val->bv_val != NULL; - i++, at_val++ ) { - if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) { - pno = 1; - SQLBindParameter( sth, 1, - SQL_PARAM_OUTPUT, - SQL_C_ULONG, SQL_INTEGER, - 0, 0, &prc, 0, 0); - } else { - pno = 0; - } - po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0; - SQLBindParameter( sth, pno + 1 + po, - SQL_PARAM_INPUT, - SQL_C_ULONG, SQL_INTEGER, - 0, 0, &e_id->keyval, 0, 0 ); - - /* - * check for syntax needed here - * maybe need binary bind? - */ - SQLBindParameter( sth, pno + 2 - po, - SQL_PARAM_INPUT, - SQL_C_CHAR, SQL_CHAR, - 0, 0, at_val->bv_val, - at_val->bv_len, 0 ); - - Debug( LDAP_DEBUG_TRACE, - "backsql_modify_internal(): " - "executing '%s'\n", - at->bam_add_proc, 0, 0 ); - rc = SQLExecDirect( sth, at->bam_add_proc, - SQL_NTS ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - "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 ) ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - goto done; - } - } -#ifdef BACKSQL_REALLOC_STMT - SQLFreeStmt( sth, SQL_DROP ); - SQLAllocStmt( dbh, &sth ); -#endif /* BACKSQL_REALLOC_STMT */ - } - break; - - case LDAP_MOD_DELETE: - if ( at->bam_delete_proc == NULL ) { - Debug( LDAP_DEBUG_TRACE, - "backsql_modify_internal(): " - "delete procedure is not defined " - "for attribute '%s'\n", - at->bam_ad->ad_cname.bv_val, 0, 0 ); - - if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted " - "within namingContext"; - goto done; - } - - break; - } - - if ( c_mod->sm_bvalues == NULL ) { - Debug( LDAP_DEBUG_TRACE, - "backsql_modify_internal(): " - "no values given to delete " - "for attribute '%s' " - "-- deleting all values\n", - at->bam_ad->ad_cname.bv_val, 0, 0 ); - goto del_all; - } - - Debug( LDAP_DEBUG_TRACE, "backsql_modify_internal(): " - "deleting values for attribute '%s'\n", - at->bam_ad->ad_cname.bv_val, 0, 0 ); - - for ( i = 0, at_val = c_mod->sm_bvalues; - at_val->bv_val != NULL; - i++, at_val++ ) { - if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) { - pno = 1; - SQLBindParameter( sth, 1, - SQL_PARAM_OUTPUT, - SQL_C_ULONG, SQL_INTEGER, - 0, 0, &prc, 0, 0 ); - } else { - pno = 0; - } - po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0; - SQLBindParameter( sth, pno + 1 + po, - SQL_PARAM_INPUT, - SQL_C_ULONG, SQL_INTEGER, - 0, 0, &e_id->keyval, 0, 0 ); - - /* - * check for syntax needed here - * maybe need binary bind? - */ - SQLBindParameter( sth, pno + 2 - po, - SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, - 0, 0, at_val->bv_val, - at_val->bv_len, 0 ); - - Debug( LDAP_DEBUG_TRACE, - "backsql_modify_internal(): " - "executing '%s'\n", - at->bam_delete_proc, 0, 0 ); - rc = SQLExecDirect( sth, at->bam_delete_proc, - SQL_NTS ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, - "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 ) ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - goto done; - } - } -#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 */ - } - -done:; - -#ifndef BACKSQL_REALLOC_STMT - SQLFreeStmt( sth, SQL_DROP ); -#endif /* BACKSQL_REALLOC_STMT */ - - /* - * FIXME: should fail in case one change fails? - */ - return rs->sr_err; -} +#include "proto-sql.h" int backsql_modify( Operation *op, SlapReply *rs ) @@ -479,12 +44,12 @@ backsql_modify( Operation *op, SlapReply *rs ) * (missing mapping, SQL write fails or so) the entire operation * should be rolled-back */ - Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): changing entry '%s'\n", + Debug( LDAP_DEBUG_TRACE, "==>backsql_modify(): modifying entry \"%s\"\n", op->o_req_ndn.bv_val, 0, 0 ); rs->sr_err = backsql_get_db_conn( op, &dbh ); if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modify(): " + Debug( LDAP_DEBUG_TRACE, " backsql_modify(): " "could not get connection handle - exiting\n", 0, 0, 0 ); /* @@ -499,7 +64,7 @@ backsql_modify( Operation *op, SlapReply *rs ) rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn ); if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modify(): " + Debug( LDAP_DEBUG_TRACE, " backsql_modify(): " "could not lookup entry id\n", 0, 0, 0 ); rs->sr_text = ( rs->sr_err == LDAP_OTHER ) ? "SQL-backend error" : NULL; @@ -507,13 +72,13 @@ backsql_modify( Operation *op, SlapReply *rs ) return 1; } - Debug( LDAP_DEBUG_TRACE, "backsql_modify(): " - "modifying entry '%s' (id=%ld)\n", + 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(): " + Debug( LDAP_DEBUG_TRACE, " backsql_modify(): " "cannot determine objectclass of entry -- aborting\n", 0, 0, 0 ); /* @@ -554,1001 +119,5 @@ backsql_modify( Operation *op, SlapReply *rs ) return op->o_noop; } -int -backsql_modrdn( Operation *op, SlapReply *rs ) -{ - backsql_info *bi = (backsql_info*)op->o_bd->be_private; - SQLHDBC dbh; - SQLHSTMT sth; - RETCODE rc; - backsql_entryID e_id, pe_id, new_pid; - backsql_oc_map_rec *oc = NULL; - struct berval p_dn, p_ndn, - *new_pdn = NULL, *new_npdn = NULL, - new_dn, new_ndn; - LDAPRDN new_rdn = NULL; - LDAPRDN old_rdn = NULL; - Entry e; - Modifications *mod; - struct berval *newSuperior = op->oq_modrdn.rs_newSup; - - Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry '%s', " - "newrdn='%s', newSuperior='%s'\n", - op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val, - newSuperior ? newSuperior->bv_val : "(NULL)" ); - rs->sr_err = backsql_get_db_conn( op, &dbh ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "could not get connection handle - exiting\n", - 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - send_ldap_result( op, rs ); - return 1; - } - - rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "could not lookup entry id\n", 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - send_ldap_result( op, rs ); - return 1; - } - - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): entry id is %ld\n", - e_id.id, 0, 0 ); - - if ( backsql_has_children( bi, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "entry \"%s\" has children\n", - op->o_req_dn.bv_val, 0, 0 ); - rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; - rs->sr_text = "subtree rename not supported"; - send_ldap_result( op, rs ); - return 1; - } - - dnParent( &op->o_req_dn, &p_dn ); - dnParent( &op->o_req_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 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "not allowed within namingContext"; - send_ldap_result( op, rs ); - 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( op, &e, slap_schema.si_ad_children, - NULL, ACL_WRITE, NULL ) ) { - Debug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 ); - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - goto modrdn_return; - } - - if ( newSuperior ) { - /* - * namingContext "" is not supported - */ - if ( newSuperior->bv_len == 0 ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "newSuperior is \"\" - aborting\n", 0, 0, 0 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "not allowed within namingContext"; - send_ldap_result( op, rs ); - goto modrdn_return; - } - - new_pdn = newSuperior; - new_npdn = op->oq_modrdn.rs_nnewSup; - - e.e_name = *new_pdn; - e.e_nname = *new_npdn; - - /* - * Check for children access to new parent - */ - if ( !access_allowed( op, &e, slap_schema.si_ad_children, - NULL, ACL_WRITE, NULL ) ) { - Debug( LDAP_DEBUG_TRACE, "no access to new parent\n", - 0, 0, 0 ); - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - goto modrdn_return; - } - - } else { - new_pdn = &p_dn; - new_npdn = &p_ndn; - } - - if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "newSuperior is equal to old parent - ignored\n", - 0, 0, 0 ); - newSuperior = NULL; - } - - if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "newSuperior is equal to entry being moved " - "- aborting\n", 0, 0, 0 ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "newSuperior is equal to old DN"; - send_ldap_result( op, rs ); - goto modrdn_return; - } - - build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn, NULL ); - rs->sr_err = dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, - op->o_tmpmemctx ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "new dn is invalid ('%s') - aborting\n", - new_dn.bv_val, 0, 0 ); - rs->sr_text = "unable to build new DN"; - send_ldap_result( op, rs ); - goto modrdn_return; - } - - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): new entry dn is '%s'\n", - new_dn.bv_val, 0, 0 ); - - rs->sr_err = backsql_dn2id( bi, &pe_id, dbh, &p_ndn ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "could not lookup old parent entry id\n", 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - send_ldap_result( op, rs ); - goto modrdn_return; - } - - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "old parent entry id is %ld\n", pe_id.id, 0, 0 ); - - rs->sr_err = backsql_dn2id( bi, &new_pid, dbh, new_npdn ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "could not lookup new parent entry id\n", 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - send_ldap_result( op, rs ); - goto modrdn_return; - } - - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "new parent entry id is %ld\n", new_pid.id, 0, 0 ); - - - 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 ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "failed to delete record from ldap_entries\n", - 0, 0, 0 ); - backsql_PrintErrors( bi->db_env, dbh, sth, rc ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - goto modrdn_return; - } - - SQLFreeStmt( sth, SQL_RESET_PARAMS ); - - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "executing insentry_query\n", 0, 0, 0 ); - backsql_BindParamStr( sth, 1, new_dn.bv_val, BACKSQL_MAX_DN_LEN ); - SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, - 0, 0, &e_id.oc_id, 0, 0 ); - SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, - 0, 0, &new_pid.id, 0, 0 ); - SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, - 0, 0, &e_id.keyval, 0, 0 ); - rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_modrdn(): " - "could not insert ldap_entries record\n", 0, 0, 0 ); - backsql_PrintErrors( bi->db_env, dbh, sth, rc ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - goto modrdn_return; - } - - /* - * Get attribute type and attribute value of our new rdn, - * we will need to add that to our new entry - */ - if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn, - (char **)&rs->sr_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 - rs->sr_err = LDAP_INVALID_DN_SYNTAX; - goto modrdn_return; - } - -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "backsql_modrdn: new_rdn_type=\"%s\", " - "new_rdn_val=\"%s\"\n", - new_rdn[ 0 ]->la_attr.bv_val, - new_rdn[ 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 ]->la_attr.bv_val, - new_rdn[ 0 ]->la_value.bv_val, 0 ); -#endif - - if ( op->oq_modrdn.rs_deleteoldrdn ) { - if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn, - (char **)&rs->sr_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 - rs->sr_err = LDAP_OTHER; - goto modrdn_return; - } - } - - e.e_name = new_dn; - e.e_nname = new_ndn; - rs->sr_err = slap_modrdn2mods( op, rs, &e, old_rdn, new_rdn, &mod ); - if ( rs->sr_err != LDAP_SUCCESS ) { - goto modrdn_return; - } - - if ( !acl_check_modlist( op, &e, mod )) { - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - goto modrdn_return; - } - - oc = backsql_id2oc( bi, e_id.oc_id ); - rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod ); - - if ( rs->sr_err == LDAP_SUCCESS ) { - - /* - * Commit only if all operations succeed - */ - SQLTransact( SQL_NULL_HENV, dbh, - op->o_noop ? SQL_ROLLBACK : SQL_COMMIT ); - } - -modrdn_return: - SQLFreeStmt( sth, SQL_DROP ); - - if ( new_dn.bv_val ) { - ch_free( new_dn.bv_val ); - } - - if ( new_ndn.bv_val ) { - 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( op, rs ); - - Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 ); - return op->o_noop; -} - -int -backsql_add( Operation *op, SlapReply *rs ) -{ - backsql_info *bi = (backsql_info*)op->o_bd->be_private; - SQLHDBC dbh; - SQLHSTMT sth; - unsigned long new_keyval = 0; - long i; - RETCODE rc; - backsql_oc_map_rec *oc = NULL; - backsql_at_map_rec *at_rec = NULL; - backsql_entryID e_id, parent_id; - Entry p; - Attribute *at; - struct berval *at_val; - struct berval pdn; - /* first parameter #, parameter order */ - SQLUSMALLINT pno, po; - /* procedure return code */ - int prc; - - Debug( LDAP_DEBUG_TRACE, "==>backsql_add(): adding entry '%s'\n", - op->oq_add.rs_e->e_name.bv_val, 0, 0 ); - - /* check schema */ - if ( global_schemacheck ) { - char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' }; - - rs->sr_err = entry_schema_check( op->o_bd, op->oq_add.rs_e, - NULL, - &rs->sr_text, textbuf, sizeof( textbuf ) ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "entry failed schema check -- aborting\n", - 0, 0, 0 ); - send_ldap_result( op, rs ); - return 1; - } - } - - /* search structural objectClass */ - for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) { - if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) { - break; - } - } - - /* there must exist */ - assert( at != NULL ); - - /* I guess we should play with sub/supertypes to find a suitable oc */ - oc = backsql_name2oc( bi, &at->a_vals[0] ); - - if ( oc == NULL ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "cannot determine objectclass of entry -- aborting\n", - 0, 0, 0 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted within namingContext"; - send_ldap_result( op, rs ); - return 1; - } - - if ( oc->bom_create_proc == NULL ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "create procedure is not defined for this objectclass " - "- aborting\n", 0, 0, 0 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted within namingContext"; - send_ldap_result( op, rs ); - return 1; - - } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) - && oc->bom_create_keyval == NULL ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "create procedure needs select procedure, " - "but none is defined - aborting\n", 0, 0, 0 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted within namingContext"; - send_ldap_result( op, rs ); - return 1; - } - - rs->sr_err = backsql_get_db_conn( op, &dbh ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "could not get connection handle - exiting\n", - 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL, - send_ldap_result( op, rs ); - return 1; - } - - /* - * Check if entry exists - */ - rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->oq_add.rs_e->e_name ); - if ( rs->sr_err == LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "entry '%s' exists\n", - op->oq_add.rs_e->e_name.bv_val, 0, 0 ); - rs->sr_err = LDAP_ALREADY_EXISTS; - send_ldap_result( op, rs ); - return 1; - } - - /* - * Check if parent exists - */ - dnParent( &op->oq_add.rs_e->e_name, &pdn ); - rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "could not lookup parent entry for new record '%s'\n", - pdn.bv_val, 0, 0 ); - - if ( rs->sr_err != LDAP_NO_SUCH_OBJECT ) { - send_ldap_result( op, rs ); - return 1; - } - - /* - * Look for matched - */ - while ( 1 ) { - struct berval dn; - char *matched = NULL; - - dn = pdn; - dnParent( &dn, &pdn ); - - /* - * Empty DN ("") defaults to LDAP_SUCCESS - */ - rs->sr_err = backsql_dn2id( bi, &parent_id, dbh, &pdn ); - switch ( rs->sr_err ) { - 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: - rs->sr_err = LDAP_NO_SUCH_OBJECT; - rs->sr_matched = matched; - send_ldap_result( op, rs ); - 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 - */ - - p.e_attrs = NULL; - p.e_name = pdn; - dnParent( &op->oq_add.rs_e->e_nname, &p.e_nname ); - if ( !access_allowed( op, &p, slap_schema.si_ad_children, - NULL, ACL_WRITE, NULL ) ) { - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - send_ldap_result( op, rs ); - return 1; - } - - rc = SQLAllocStmt( dbh, &sth ); - if ( rc != SQL_SUCCESS ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } - - if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) { - SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, - SQL_INTEGER, 0, 0, &new_keyval, 0, 0 ); - } - - Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s'\n", - oc->bom_create_proc, 0, 0 ); - rc = SQLExecDirect( sth, oc->bom_create_proc, SQL_NTS ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "create_proc execution failed\n", 0, 0, 0 ); - backsql_PrintErrors( bi->db_env, dbh, sth, rc); - SQLFreeStmt( sth, SQL_DROP ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } - if ( op->o_noop ) { - SQLTransact( SQL_NULL_HENV, dbh, SQL_ROLLBACK ); - } - - if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) { - SWORD ncols; - SQLINTEGER value_len; - - 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 ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } -#endif /* BACKSQL_REALLOC_STMT */ - - rc = SQLExecDirect( sth, oc->bom_create_keyval, SQL_NTS ); - if ( rc != SQL_SUCCESS ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } - } - - /* - * 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 ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - - } else if ( ncols != 1 ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "create_proc result is bogus (ncols=%d)\n", - ncols, 0, 0 ); - backsql_PrintErrors( bi->db_env, dbh, sth, rc); - SQLFreeStmt( sth, SQL_DROP ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - 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 ), - &value_len ); - - rc = SQLFetch( sth ); - - if ( value_len <= 0 ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "create_proc result is empty?\n", - 0, 0, 0 ); - backsql_PrintErrors( bi->db_env, dbh, sth, rc); - SQLFreeStmt( sth, SQL_DROP ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } - } - -#ifndef BACKSQL_REALLOC_STMT - SQLFreeStmt( sth, SQL_RESET_PARAMS ); -#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 ); - - for ( at = op->oq_add.rs_e->e_attrs; at != NULL; at = at->a_next ) { - SQLUSMALLINT currpos; - - 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; - } - - 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, - BACKSQL_OC_NAME( oc ), 0 ); - - if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted " - "within namingContext"; - send_ldap_result( op, rs ); - return 1; - } - - continue; - } - - if ( at_rec->bam_add_proc == NULL ) { - Debug( LDAP_DEBUG_TRACE, "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 ) ) { - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted " - "within namingContext"; - send_ldap_result( op, rs ); - return 1; - } - - continue; - } - -#ifdef BACKSQL_REALLOC_STMT - rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 ); - if ( rc != SQL_SUCCESS ) { - - if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } - - continue; - } -#endif /* BACKSQL_REALLOC_STMT */ - - if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) { - pno = 1; - SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, - SQL_C_ULONG, SQL_INTEGER, - 0, 0, &prc, 0, 0 ); - } else { - pno = 0; - } - - po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0; - currpos = pno + 1 + po; - SQLBindParameter( sth, currpos, - SQL_PARAM_INPUT, SQL_C_ULONG, - SQL_INTEGER, 0, 0, &new_keyval, 0, 0 ); - currpos = pno + 2 - po; - - 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 ( bvmatch( at_val, &oc->bom_oc->soc_cname ) ) { - continue; - } - } - - /* - * check for syntax needed here - * maybe need binary bind? - */ - - 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->bam_add_proc, new_keyval, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "executing '%s' with val='%s', id=%ld\n", - at_rec->bam_add_proc, at_val->bv_val, new_keyval ); -#endif -#ifndef BACKSQL_REALLOC_STMT - rc = SQLExecDirect( sth, at_rec->bam_add_proc, SQL_NTS ); -#else /* BACKSQL_REALLOC_STMT */ - rc = SQLExecute( sth ); -#endif /* BACKSQL_REALLOC_STMT */ - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "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 ) ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } - } - } -#ifndef BACKSQL_REALLOC_STMT - SQLFreeStmt( sth, SQL_RESET_PARAMS ); -#else /* BACKSQL_REALLOC_STMT */ - SQLFreeStmt( sth, SQL_DROP ); -#endif /* BACKSQL_REALLOC_STMT */ - } - -#ifdef BACKSQL_REALLOC_STMT - rc = backsql_Prepare( dbh, &sth, bi->insentry_query, 0 ); - if ( rc != SQL_SUCCESS ) { - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } -#endif /* BACKSQL_REALLOC_STMT */ - - backsql_BindParamStr( sth, 1, op->oq_add.rs_e->e_name.bv_val, - BACKSQL_MAX_DN_LEN ); - SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, - 0, 0, &oc->bom_id, 0, 0 ); - SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, - 0, 0, &parent_id.id, 0, 0 ); - SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, - 0, 0, &new_keyval, 0, 0 ); - - Debug( LDAP_DEBUG_TRACE, "backsql_add(): executing '%s' for dn '%s'\n", - bi->insentry_query, op->oq_add.rs_e->e_name.bv_val, 0 ); - Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, parent_id=%ld, " - "keyval=%ld\n", oc->bom_id, parent_id.id, new_keyval ); -#ifndef BACKSQL_REALLOC_STMT - rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS ); -#else /* BACKSQL_REALLOC_STMT */ - rc = SQLExecute( sth ); -#endif /* BACKSQL_REALLOC_STMT */ - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_add(): " - "could not insert ldap_entries record\n", 0, 0, 0 ); - backsql_PrintErrors( bi->db_env, dbh, sth, rc ); - - /* - * execute delete_proc to delete data added !!! - */ - SQLFreeStmt( sth, SQL_DROP ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } - - SQLFreeStmt( sth, SQL_DROP ); - - /* - * Commit only if all operations succeed - */ - SQLTransact( SQL_NULL_HENV, dbh, - op->o_noop ? SQL_ROLLBACK : SQL_COMMIT ); - - /* - * FIXME: NOOP does not work for add -- it works for all - * the other operations, and I don't get the reason :( - */ - - send_ldap_result( op, rs ); - - return op->o_noop; -} - -int -backsql_delete( Operation *op, SlapReply *rs ) -{ - backsql_info *bi = (backsql_info*)op->o_bd->be_private; - SQLHDBC dbh; - SQLHSTMT sth; - RETCODE rc; - backsql_oc_map_rec *oc = NULL; - backsql_entryID e_id; - Entry e; - /* first parameter no */ - SQLUSMALLINT pno; - - Debug( LDAP_DEBUG_TRACE, "==>backsql_delete(): deleting entry '%s'\n", - op->o_req_ndn.bv_val, 0, 0 ); - - dnParent( &op->o_req_dn, &e.e_name ); - dnParent( &op->o_req_ndn, &e.e_nname ); - e.e_attrs = NULL; - - /* check parent for "children" acl */ - if ( !access_allowed( 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 ); - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - send_ldap_result( op, rs ); - return 1; - - } - - rs->sr_err = backsql_get_db_conn( op, &dbh ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " - "could not get connection handle - exiting\n", - 0, 0, 0 ); - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL, - send_ldap_result( op, rs ); - return 1; - } - - rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn ); - if ( rs->sr_err != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " - "could not lookup entry id\n", 0, 0, 0 ); - send_ldap_result( op, rs ); - return 1; - } - - rs->sr_err = backsql_has_children( bi, dbh, &op->o_req_ndn ); - switch ( rs->sr_err ) { - case LDAP_COMPARE_TRUE: - Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " - "entry \"%s\" has children\n", - op->o_req_dn.bv_val, 0, 0 ); - rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; - rs->sr_text = "subtree delete not supported"; - send_ldap_result( op, rs ); - return 1; - - case LDAP_COMPARE_FALSE: - break; - - default: - send_ldap_result( op, rs ); - 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 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted within namingContext"; - send_ldap_result( op, rs ); - return 1; - } - - if ( oc->bom_delete_proc == NULL ) { - Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " - "delete procedure is not defined " - "for this objectclass - aborting\n", 0, 0, 0 ); - rs->sr_err = LDAP_UNWILLING_TO_PERFORM; - rs->sr_text = "operation not permitted within namingContext"; - send_ldap_result( op, rs ); - return 1; - } - - SQLAllocStmt( dbh, &sth ); - if ( BACKSQL_IS_DEL( oc->bom_expect_return ) ) { - pno = 1; - SQLBindParameter( sth, 1, SQL_PARAM_OUTPUT, SQL_C_ULONG, - SQL_INTEGER, 0, 0, &rc, 0, 0 ); - } else { - pno = 0; - } - - SQLBindParameter( sth, pno + 1, SQL_PARAM_INPUT, - SQL_C_ULONG, SQL_INTEGER, 0, 0, &e_id.keyval, 0, 0 ); - - Debug( LDAP_DEBUG_TRACE, "backsql_delete(): executing '%s'\n", - oc->bom_delete_proc, 0, 0 ); - rc = SQLExecDirect( sth, oc->bom_delete_proc, SQL_NTS ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " - "delete_proc execution failed\n", 0, 0, 0 ); - backsql_PrintErrors( bi->db_env, dbh, sth, rc ); - SQLFreeStmt( sth, SQL_DROP ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - 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 ); - rc = SQLExecDirect( sth, bi->delentry_query, SQL_NTS ); - if ( rc != SQL_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_delete(): " - "failed to delete record from ldap_entries\n", - 0, 0, 0 ); - backsql_PrintErrors( bi->db_env, dbh, sth, rc ); - SQLFreeStmt( sth, SQL_DROP ); - rs->sr_err = LDAP_OTHER; - rs->sr_text = "SQL-backend error"; - send_ldap_result( op, rs ); - return 1; - } - - 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, - op->o_noop ? SQL_ROLLBACK : SQL_COMMIT ); - - rs->sr_err = LDAP_SUCCESS; - send_ldap_result( op, rs ); - Debug( LDAP_DEBUG_TRACE, "<==backsql_delete()\n", 0, 0, 0 ); - - return op->o_noop; -} - #endif /* SLAPD_SQL */ diff --git a/servers/slapd/back-sql/modrdn.c b/servers/slapd/back-sql/modrdn.c new file mode 100644 index 0000000000..8dcc1cc6fc --- /dev/null +++ b/servers/slapd/back-sql/modrdn.c @@ -0,0 +1,364 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1999-2004 The OpenLDAP Foundation. + * Portions Copyright 1999 Dmitry Kovalev. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Dmitry Kovalev for inclusion + * by OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_SQL + +#include +#include +#include "ac/string.h" + +#include "slap.h" +#include "ldap_pvt.h" +#include "proto-sql.h" + +int +backsql_modrdn( Operation *op, SlapReply *rs ) +{ + backsql_info *bi = (backsql_info*)op->o_bd->be_private; + SQLHDBC dbh; + SQLHSTMT sth; + RETCODE rc; + backsql_entryID e_id, pe_id, new_pid; + backsql_oc_map_rec *oc = NULL; + struct berval p_dn, p_ndn, + *new_pdn = NULL, *new_npdn = NULL, + new_dn, new_ndn; + LDAPRDN new_rdn = NULL; + LDAPRDN old_rdn = NULL; + Entry e; + Modifications *mod; + struct berval *newSuperior = op->oq_modrdn.rs_newSup; + + Debug( LDAP_DEBUG_TRACE, "==>backsql_modrdn() renaming entry \"%s\", " + "newrdn=\"%s\", newSuperior=\"%s\"\n", + op->o_req_dn.bv_val, op->oq_modrdn.rs_newrdn.bv_val, + newSuperior ? newSuperior->bv_val : "(NULL)" ); + rs->sr_err = backsql_get_db_conn( op, &dbh ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "could not get connection handle - exiting\n", + 0, 0, 0 ); + rs->sr_text = ( rs->sr_err == LDAP_OTHER ) + ? "SQL-backend error" : NULL; + send_ldap_result( op, rs ); + return 1; + } + + rs->sr_err = backsql_dn2id( bi, &e_id, dbh, &op->o_req_ndn ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "could not lookup entry id\n", 0, 0, 0 ); + rs->sr_text = ( rs->sr_err == LDAP_OTHER ) + ? "SQL-backend error" : NULL; + send_ldap_result( op, rs ); + return 1; + } + + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): entry id=%ld\n", + e_id.id, 0, 0 ); + + if ( backsql_has_children( bi, dbh, &op->o_req_ndn ) == LDAP_COMPARE_TRUE ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "entry \"%s\" has children\n", + op->o_req_dn.bv_val, 0, 0 ); + rs->sr_err = LDAP_NOT_ALLOWED_ON_NONLEAF; + rs->sr_text = "subtree rename not supported"; + send_ldap_result( op, rs ); + return 1; + } + + dnParent( &op->o_req_dn, &p_dn ); + dnParent( &op->o_req_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 ); + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "not allowed within namingContext"; + send_ldap_result( op, rs ); + 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( op, &e, slap_schema.si_ad_children, + NULL, ACL_WRITE, NULL ) ) { + Debug( LDAP_DEBUG_TRACE, " no access to parent\n", 0, 0, 0 ); + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto modrdn_return; + } + + if ( newSuperior ) { + /* + * namingContext "" is not supported + */ + if ( newSuperior->bv_len == 0 ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "newSuperior is \"\" - aborting\n", 0, 0, 0 ); + rs->sr_err = LDAP_UNWILLING_TO_PERFORM; + rs->sr_text = "not allowed within namingContext"; + send_ldap_result( op, rs ); + goto modrdn_return; + } + + new_pdn = newSuperior; + new_npdn = op->oq_modrdn.rs_nnewSup; + + e.e_name = *new_pdn; + e.e_nname = *new_npdn; + + /* + * Check for children access to new parent + */ + if ( !access_allowed( op, &e, slap_schema.si_ad_children, + NULL, ACL_WRITE, NULL ) ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "no access to new parent \"%s\"\n", + new_pdn->bv_val, 0, 0 ); + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto modrdn_return; + } + + } else { + new_pdn = &p_dn; + new_npdn = &p_ndn; + } + + if ( newSuperior && dn_match( &p_ndn, new_npdn ) ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "newSuperior is equal to old parent - ignored\n", + 0, 0, 0 ); + newSuperior = NULL; + } + + if ( newSuperior && dn_match( &op->o_req_ndn, new_npdn ) ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "newSuperior is equal to entry being moved " + "- aborting\n", 0, 0, 0 ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "newSuperior is equal to old DN"; + send_ldap_result( op, rs ); + goto modrdn_return; + } + + build_new_dn( &new_dn, new_pdn, &op->oq_modrdn.rs_newrdn, NULL ); + rs->sr_err = dnNormalize( 0, NULL, NULL, &new_dn, &new_ndn, + op->o_tmpmemctx ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "new dn is invalid (\"%s\") - aborting\n", + new_dn.bv_val, 0, 0 ); + rs->sr_text = "unable to build new DN"; + send_ldap_result( op, rs ); + goto modrdn_return; + } + + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): new entry dn is \"%s\"\n", + new_dn.bv_val, 0, 0 ); + + rs->sr_err = backsql_dn2id( bi, &pe_id, dbh, &p_ndn ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "could not lookup old parent entry id\n", 0, 0, 0 ); + rs->sr_text = ( rs->sr_err == LDAP_OTHER ) + ? "SQL-backend error" : NULL; + send_ldap_result( op, rs ); + goto modrdn_return; + } + + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "old parent entry id is %ld\n", pe_id.id, 0, 0 ); + + rs->sr_err = backsql_dn2id( bi, &new_pid, dbh, new_npdn ); + if ( rs->sr_err != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "could not lookup new parent entry id\n", 0, 0, 0 ); + rs->sr_text = ( rs->sr_err == LDAP_OTHER ) + ? "SQL-backend error" : NULL; + send_ldap_result( op, rs ); + goto modrdn_return; + } + + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "new parent entry id=%ld\n", new_pid.id, 0, 0 ); + + + 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 ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "failed to delete record from ldap_entries\n", + 0, 0, 0 ); + backsql_PrintErrors( bi->db_env, dbh, sth, rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + send_ldap_result( op, rs ); + goto modrdn_return; + } + + SQLFreeStmt( sth, SQL_RESET_PARAMS ); + + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "executing insentry_query\n", 0, 0, 0 ); + backsql_BindParamStr( sth, 1, new_dn.bv_val, BACKSQL_MAX_DN_LEN ); + SQLBindParameter( sth, 2, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, + 0, 0, &e_id.oc_id, 0, 0 ); + SQLBindParameter( sth, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, + 0, 0, &new_pid.id, 0, 0 ); + SQLBindParameter( sth, 4, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, + 0, 0, &e_id.keyval, 0, 0 ); + rc = SQLExecDirect( sth, bi->insentry_query, SQL_NTS ); + if ( rc != SQL_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, " backsql_modrdn(): " + "could not insert ldap_entries record\n", 0, 0, 0 ); + backsql_PrintErrors( bi->db_env, dbh, sth, rc ); + rs->sr_err = LDAP_OTHER; + rs->sr_text = "SQL-backend error"; + send_ldap_result( op, rs ); + goto modrdn_return; + } + + /* + * Get attribute type and attribute value of our new rdn, + * we will need to add that to our new entry + */ + if ( ldap_bv2rdn( &op->oq_modrdn.rs_newrdn, &new_rdn, + (char **)&rs->sr_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 + rs->sr_err = LDAP_INVALID_DN_SYNTAX; + goto modrdn_return; + } + +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + " backsql_modrdn: new_rdn_type=\"%s\", " + "new_rdn_val=\"%s\"\n", + new_rdn[ 0 ]->la_attr.bv_val, + new_rdn[ 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 ]->la_attr.bv_val, + new_rdn[ 0 ]->la_value.bv_val, 0 ); +#endif + + if ( op->oq_modrdn.rs_deleteoldrdn ) { + if ( ldap_bv2rdn( &op->o_req_dn, &old_rdn, + (char **)&rs->sr_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 + rs->sr_err = LDAP_OTHER; + goto modrdn_return; + } + } + + e.e_name = new_dn; + e.e_nname = new_ndn; + rs->sr_err = slap_modrdn2mods( op, rs, &e, old_rdn, new_rdn, &mod ); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto modrdn_return; + } + + if ( !acl_check_modlist( op, &e, mod )) { + rs->sr_err = LDAP_INSUFFICIENT_ACCESS; + goto modrdn_return; + } + + oc = backsql_id2oc( bi, e_id.oc_id ); + rs->sr_err = backsql_modify_internal( op, rs, dbh, oc, &e_id, mod ); + + if ( rs->sr_err == LDAP_SUCCESS ) { + + /* + * Commit only if all operations succeed + */ + SQLTransact( SQL_NULL_HENV, dbh, + op->o_noop ? SQL_ROLLBACK : SQL_COMMIT ); + } + +modrdn_return: + SQLFreeStmt( sth, SQL_DROP ); + + if ( new_dn.bv_val ) { + ch_free( new_dn.bv_val ); + } + + if ( new_ndn.bv_val ) { + 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( op, rs ); + + Debug( LDAP_DEBUG_TRACE, "<==backsql_modrdn()\n", 0, 0, 0 ); + return op->o_noop; +} + +#endif /* SLAPD_SQL */ + diff --git a/servers/slapd/back-sql/operational.c b/servers/slapd/back-sql/operational.c new file mode 100644 index 0000000000..f495d051d8 --- /dev/null +++ b/servers/slapd/back-sql/operational.c @@ -0,0 +1,89 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1999-2004 The OpenLDAP Foundation. + * Portions Copyright 1999 Dmitry Kovalev. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Dmitry Kovalev for inclusion + * by OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_SQL + +#include +#include + +#include "slap.h" +#include "proto-sql.h" + +/* + * sets the supported operational attributes (if required) + */ + +int +backsql_operational( + Operation *op, + SlapReply *rs, + int opattrs, + Attribute **a ) +{ + + backsql_info *bi = (backsql_info*)op->o_bd->be_private; + SQLHDBC dbh = SQL_NULL_HDBC; + Attribute **aa = a; + int rc = 0; + + Debug( LDAP_DEBUG_TRACE, "==>backsql_operational(): entry '%s'\n", + rs->sr_entry->e_nname.bv_val, 0, 0 ); + + + if ( ( opattrs || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) + && attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL ) { + + rc = backsql_get_db_conn( op, &dbh ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_TRACE, "backsql_operational(): " + "could not get connection handle - exiting\n", + 0, 0, 0 ); + return 1; + } + + rc = backsql_has_children( bi, dbh, &rs->sr_entry->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; + } + } + + Debug( LDAP_DEBUG_TRACE, "<==backsql_operational()\n", 0, 0, 0); + + return rc; +} + +#endif /* SLAPD_SQL */ + diff --git a/servers/slapd/back-sql/other.c b/servers/slapd/back-sql/other.c deleted file mode 100644 index 6c9dd6e188..0000000000 --- a/servers/slapd/back-sql/other.c +++ /dev/null @@ -1,234 +0,0 @@ -/* $OpenLDAP$ */ -/* This work is part of OpenLDAP Software . - * - * Copyright 1999-2004 The OpenLDAP Foundation. - * Portions Copyright 1999 Dmitry Kovalev. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted only as authorized by the OpenLDAP - * Public License. - * - * A copy of this license is available in the file LICENSE in the - * top-level directory of the distribution or, alternatively, at - * . - */ -/* ACKNOWLEDGEMENTS: - * This work was initially developed by Dmitry Kovalev for inclusion - * by OpenLDAP Software. - */ - -#include "portable.h" - -#ifdef SLAPD_SQL - -#include -#include -#include "slap.h" -#include "back-sql.h" -#include "sql-wrap.h" -#include "entry-id.h" -#include "util.h" - -int -backsql_compare( Operation *op, SlapReply *rs ) -{ - backsql_info *bi = (backsql_info*)op->o_bd->be_private; - backsql_entryID user_id; - SQLHDBC dbh; - Entry *e = NULL, user_entry; - Attribute *a = NULL, *a_op = NULL; - backsql_srch_info bsi; - int rc; - AttributeName anlist[2]; - - user_entry.e_name.bv_val = NULL; - user_entry.e_name.bv_len = 0; - user_entry.e_nname.bv_val = NULL; - user_entry.e_nname.bv_len = 0; - user_entry.e_attrs = NULL; - - Debug( LDAP_DEBUG_TRACE, "==>backsql_compare()\n", 0, 0, 0 ); - - rs->sr_err = backsql_get_db_conn( op, &dbh ); - if (!dbh) { - Debug( LDAP_DEBUG_TRACE, "backsql_compare(): " - "could not get connection handle - exiting\n", - 0, 0, 0 ); - - rs->sr_text = ( rs->sr_err == LDAP_OTHER ) - ? "SQL-backend error" : NULL; - goto return_results; - } - - rc = backsql_dn2id( bi, &user_id, dbh, &op->o_req_ndn ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_compare(): " - "could not retrieve compare dn id - no such entry\n", - 0, 0, 0 ); - rs->sr_err = LDAP_NO_SUCH_OBJECT; - goto return_results; - } - - anlist[0].an_name = op->oq_compare.rs_ava->aa_desc->ad_cname; - anlist[0].an_desc = op->oq_compare.rs_ava->aa_desc; - anlist[1].an_name.bv_val = NULL; - - /* - * Try to get attr as dynamic operational - */ - if ( is_at_operational( op->oq_compare.rs_ava->aa_desc->ad_type ) ) { - AttributeName *an_old; - Entry *e_old; - - user_entry.e_attrs = NULL; - user_entry.e_name = op->o_req_dn; - user_entry.e_nname = op->o_req_ndn; - - an_old = rs->sr_attrs; - e_old = rs->sr_entry; - - rs->sr_attrs = anlist; - rs->sr_entry = &user_entry; - rs->sr_err = backsql_operational( op, rs, 0, &a_op ); - rs->sr_attrs = an_old; - rs->sr_entry = e_old; - - if ( rs->sr_err != LDAP_SUCCESS ) { - goto return_results; - } - - } - - /* - * attr was dynamic operational - */ - if ( a_op != NULL ) { - user_entry.e_attrs = a_op; - e = &user_entry; - - } else { - backsql_init_search( &bsi, &op->o_req_ndn, LDAP_SCOPE_BASE, - -1, -1, -1, NULL, dbh, op, anlist ); - e = backsql_id2entry( &bsi, &user_entry, &user_id ); - if ( e == NULL ) { - Debug( LDAP_DEBUG_TRACE, "backsql_compare(): " - "error in backsql_id2entry() " - "- compare failed\n", 0, 0, 0 ); - rs->sr_err = LDAP_OTHER; - goto return_results; - } - } - - if ( ! access_allowed( op, e, op->oq_compare.rs_ava->aa_desc, - &op->oq_compare.rs_ava->aa_value, - ACL_COMPARE, NULL ) ) { - rs->sr_err = LDAP_INSUFFICIENT_ACCESS; - goto return_results; - } - - rs->sr_err = LDAP_NO_SUCH_ATTRIBUTE; - for ( a = attrs_find( e->e_attrs, op->oq_compare.rs_ava->aa_desc ); - a != NULL; - a = attrs_find( a->a_next, op->oq_compare.rs_ava->aa_desc )) - { - rs->sr_err = LDAP_COMPARE_FALSE; - if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, - SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | - SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, - a->a_nvals, - &op->oq_compare.rs_ava->aa_value, - op->o_tmpmemctx ) == 0 ) - { - rs->sr_err = LDAP_COMPARE_TRUE; - break; - } - } - -return_results:; - send_ldap_result( op, rs ); - - if ( e != NULL ) { - if ( e->e_name.bv_val != NULL ) { - free( e->e_name.bv_val ); - } - - if ( e->e_nname.bv_val != NULL ) { - free( e->e_nname.bv_val ); - } - - if ( e->e_attrs != NULL ) { - attrs_free( e->e_attrs ); - } - } - - Debug(LDAP_DEBUG_TRACE,"<==backsql_compare()\n",0,0,0); - switch ( rs->sr_err ) { - case LDAP_COMPARE_TRUE: - case LDAP_COMPARE_FALSE: - return 0; - - default: - return 1; - } -} - -/* - * sets the supported operational attributes (if required) - */ - -int -backsql_operational( - Operation *op, - SlapReply *rs, - int opattrs, - Attribute **a ) -{ - - backsql_info *bi = (backsql_info*)op->o_bd->be_private; - SQLHDBC dbh = SQL_NULL_HDBC; - Attribute **aa = a; - int rc = 0; - - Debug( LDAP_DEBUG_TRACE, "==>backsql_operational(): entry '%s'\n", - rs->sr_entry->e_nname.bv_val, 0, 0 ); - - - if ( ( opattrs || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) - && attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL ) { - - rc = backsql_get_db_conn( op, &dbh ); - if ( rc != LDAP_SUCCESS ) { - Debug( LDAP_DEBUG_TRACE, "backsql_operational(): " - "could not get connection handle - exiting\n", - 0, 0, 0 ); - return 1; - } - - rc = backsql_has_children( bi, dbh, &rs->sr_entry->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; - } - } - - Debug( LDAP_DEBUG_TRACE, "<==backsql_operational()\n", 0, 0, 0); - - return rc; -} - -#endif /* SLAPD_SQL */ - diff --git a/servers/slapd/back-sql/proto-sql.h b/servers/slapd/back-sql/proto-sql.h new file mode 100644 index 0000000000..19b7518887 --- /dev/null +++ b/servers/slapd/back-sql/proto-sql.h @@ -0,0 +1,207 @@ +/* This work is part of OpenLDAP Software . + * + * Copyright 1999-2004 The OpenLDAP Foundation. + * Portions Copyright 1999 Dmitry Kovalev. + * Portions Copyright 2002 Pierangelo Mararati. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Dmitry Kovalev for inclusion + * by OpenLDAP Software. Additional significant contributors include + * Pierangelo Mararati + */ + +/* + * 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) + * - added noop control + * - added values return filter control + * - hasSubordinate can be used in search filters (with limitations) + * - eliminated oc->name; use oc->oc->soc_cname instead + * + * 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 PROTO_SQL_H +#define PROTO_SQL_H + +#include "back-sql.h" +#include "sql-types.h" + +/* + * add.c + */ +int backsql_modify_internal( + Operation *op, + SlapReply *rs, + SQLHDBC dbh, + backsql_oc_map_rec *oc, + backsql_entryID *e_id, + Modifications *modlist ); + +/* + * entry-id.c + */ + +/* stores in *id the ID in table ldap_entries corresponding to DN, if any */ +int backsql_dn2id( backsql_info *bi, backsql_entryID *id, + SQLHDBC dbh, struct berval *dn ); + +/* stores in *nchildren the count of children for an entry */ +int backsql_count_children( backsql_info *bi, SQLHDBC dbh, + struct berval *dn, unsigned long *nchildren ); + +/* returns LDAP_COMPARE_TRUE/LDAP_COMPARE_FALSE if the entry corresponding + * to DN has/has not children */ +int backsql_has_children( backsql_info *bi, SQLHDBC dbh, struct berval *dn ); + +/* frees *id and returns next in list */ +backsql_entryID *backsql_free_entryID( backsql_entryID *id, int freeit ); + +/* turns an ID into an entry */ +Entry *backsql_id2entry( backsql_srch_info *bsi, Entry *e, + backsql_entryID *id ); + +/* + * schema-map.c + */ + +int backsql_load_schema_map( backsql_info *si, SQLHDBC dbh ); + +backsql_oc_map_rec *backsql_oc2oc( backsql_info *si, ObjectClass *oc ); + +backsql_oc_map_rec *backsql_id2oc( backsql_info *si, unsigned long id ); + +backsql_oc_map_rec * backsql_name2oc( backsql_info *si, + struct berval *oc_name ); + +backsql_at_map_rec *backsql_ad2at( backsql_oc_map_rec *objclass, + AttributeDescription *ad ); + +int backsql_supad2at( backsql_oc_map_rec *objclass, + AttributeDescription *supad, backsql_at_map_rec ***pret ); + +int backsql_destroy_schema_map( backsql_info *si ); + +/* + * search.c + */ + +void backsql_init_search( backsql_srch_info *bsi, + struct berval *nbase, int scope, int slimit, int tlimit, + time_t stoptime, Filter *filter, SQLHDBC dbh, + Operation *op, AttributeName *attrs ); + +/* + * sql-wrap.h + */ + +RETCODE backsql_Prepare( SQLHDBC dbh, SQLHSTMT *sth, char* query, int timeout ); + +#define backsql_BindParamStr( sth, par_ind, str, maxlen ) \ + SQLBindParameter( (sth), (SQLUSMALLINT)(par_ind), \ + SQL_PARAM_INPUT, \ + SQL_C_CHAR, SQL_VARCHAR, \ + (SQLUINTEGER)(maxlen), 0, (SQLPOINTER)(str), \ + (SQLUINTEGER)(maxlen), NULL ) + +#define backsql_BindParamID( sth, par_ind, id ) \ + SQLBindParameter( (sth), (SQLUSMALLINT)(par_ind), \ + SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, \ + 0, 0, (SQLPOINTER)(id), 0, (SQLINTEGER*)NULL ) + +RETCODE backsql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row ); + +RETCODE backsql_FreeRow( BACKSQL_ROW_NTS *row ); + +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 ); + +int backsql_get_db_conn( Operation *op, SQLHDBC *dbh ); + +int backsql_free_db_conn( Operation *op ); + +/* + * util.c + */ + +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_def_concat_func[]; +extern char + backsql_check_dn_ru_query[]; + +struct berbuf * backsql_strcat( struct berbuf *dest, ... ); +struct berbuf * backsql_strfcat( struct berbuf *dest, const char *fmt, ... ); + +int backsql_entry_addattr( Entry *e, struct berval *at_name, + struct berval *at_val, void *memctx ); + +int backsql_merge_from_clause( struct berbuf *dest_from, + 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 /* PROTO_SQL_H */ diff --git a/servers/slapd/back-sql/schema-map.c b/servers/slapd/back-sql/schema-map.c index 3f75bb84ad..12598772f3 100644 --- a/servers/slapd/back-sql/schema-map.c +++ b/servers/slapd/back-sql/schema-map.c @@ -25,13 +25,11 @@ #include #include #include "ac/string.h" + #include "slap.h" #include "lber_pvt.h" #include "ldap_pvt.h" -#include "back-sql.h" -#include "sql-wrap.h" -#include "schema-map.h" -#include "util.h" +#include "proto-sql.h" #define BACKSQL_DUPLICATE (-1) @@ -439,6 +437,17 @@ backsql_load_schema_map( backsql_info *si, SQLHDBC dbh ) at_map->bam_ad->ad_cname.bv_val, oc_map->bom_oc->soc_cname.bv_val, 0 ); } + + if ( si->upper_func.bv_val && at_map->bam_sel_expr_u.bv_val == NULL ) { + struct berbuf bb = BB_NULL; + + backsql_strfcat( &bb, "bcbc", + &si->upper_func, + '(' /* ) */ , + &at_map->bam_sel_expr, + /* ( */ ')' ); + at_map->bam_sel_expr_u = bb.bb_val; + } } backsql_FreeRow( &at_row ); SQLFreeStmt( at_sth, SQL_CLOSE ); diff --git a/servers/slapd/back-sql/schema-map.h b/servers/slapd/back-sql/schema-map.h index cf7d388a3a..71145785da 100644 --- a/servers/slapd/back-sql/schema-map.h +++ b/servers/slapd/back-sql/schema-map.h @@ -54,6 +54,11 @@ typedef struct backsql_at_map_rec { struct berval bam_from_tbls; struct berval bam_join_where; struct berval bam_sel_expr; + + /* TimesTen, or, if a uppercase function is defined, + * an uppercased version of bam_sel_expr */ + struct berval bam_sel_expr_u; + /* supposed to expect 2 binded values: entry keyval * and attr. value to add, like "add_name(?,?,?)" */ char *bam_add_proc; @@ -72,14 +77,17 @@ typedef struct backsql_at_map_rec { * (whether back-sql should bind first parameter as output * for return code) */ int bam_expect_return; - /* TimesTen */ - struct berval bam_sel_expr_u; /* next mapping for attribute */ struct backsql_at_map_rec *bam_next; } backsql_at_map_rec; -#define BACKSQL_AT_MAP_REC_INIT { NULL, NULL, BER_BVC(""), BER_BVC(""), BER_BVNULL, NULL, NULL, NULL, 0, 0, BER_BVNULL, NULL } +#define BACKSQL_AT_MAP_REC_INIT { NULL, NULL, BER_BVC(""), BER_BVC(""), BER_BVNULL, BER_BVNULL, NULL, NULL, NULL, 0, 0, NULL } + +/* define to uppercase filters only if the matching rule requires it + * (currently broken) */ +/* #define BACKSQL_UPPERCASE_FILTER */ +#define BACKSQL_AT_CANUPPERCASE(at) ((at)->bam_sel_expr_u.bv_val) /* defines to support bitmasks above */ #define BACKSQL_ADD 0x1 diff --git a/servers/slapd/back-sql/search.c b/servers/slapd/back-sql/search.c index fc89418bf7..d036ea2ea0 100644 --- a/servers/slapd/back-sql/search.c +++ b/servers/slapd/back-sql/search.c @@ -25,14 +25,11 @@ #include #include #include "ac/string.h" + #include "slap.h" #include "lber_pvt.h" #include "ldap_pvt.h" -#include "back-sql.h" -#include "sql-wrap.h" -#include "schema-map.h" -#include "entry-id.h" -#include "util.h" +#include "proto-sql.h" #define BACKSQL_STOP 0 #define BACKSQL_CONTINUE 1 @@ -218,18 +215,21 @@ static int backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at ) { - int i; +#ifdef BACKSQL_UPPERCASE_FILTER backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; +#endif /* BACKSQL_UPPERCASE_FILTER */ + int i; int casefold = 0; if ( !f ) { return 0; } -#if 0 /* always uppercase strings by now */ + /* always uppercase strings by now */ +#ifdef BACKSQL_UPPERCASE_FILTER if ( SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr, bi->bi_caseIgnoreMatch ) ) -#endif +#endif /* BACKSQL_UPPERCASE_FILTER */ { casefold = 1; } @@ -246,26 +246,17 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, Debug( LDAP_DEBUG_TRACE, "expr: '%s%s%s'\n", at->bam_sel_expr.bv_val, at->bam_sel_expr_u.bv_val ? "' '" : "", at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" ); - if ( casefold && bi->upper_func.bv_val ) { + if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { /* - * If a pre-upper-cased version of the column exists, use it + * If a pre-upper-cased version of the column + * or a precompiled upper function exists, use it */ - if ( at->bam_sel_expr_u.bv_val ) { - backsql_strfcat( &bsi->bsi_flt_where, - "bl", - &at->bam_sel_expr_u, - (ber_len_t)sizeof( " LIKE '" ) - 1, - " LIKE '" ); - } else { - backsql_strfcat( &bsi->bsi_flt_where, - "bcbcl", - &bi->upper_func, - '(', - &at->bam_sel_expr, - ')', - (ber_len_t)sizeof( " LIKE '" ) - 1, - " LIKE '" ); - } + backsql_strfcat( &bsi->bsi_flt_where, + "bl", + &at->bam_sel_expr_u, + (ber_len_t)sizeof( " LIKE '" ) - 1, + " LIKE '" ); + } else { backsql_strfcat( &bsi->bsi_flt_where, "bl", &at->bam_sel_expr, @@ -273,12 +264,12 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, } if ( f->f_sub_initial.bv_val != NULL ) { - size_t start; + ber_len_t start; start = bsi->bsi_flt_where.bb_val.bv_len; backsql_strfcat( &bsi->bsi_flt_where, "b", &f->f_sub_initial ); - if ( casefold && bi->upper_func.bv_val ) { + if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); } } @@ -287,7 +278,7 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, if ( f->f_sub_any != NULL ) { for ( i = 0; f->f_sub_any[ i ].bv_val != NULL; i++ ) { - size_t start; + ber_len_t start; #ifdef BACKSQL_TRACE Debug( LDAP_DEBUG_TRACE, @@ -301,7 +292,7 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, "bc", &f->f_sub_any[ i ], '%' ); - if ( casefold && bi->upper_func.bv_val ) { + if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { /* * Note: toupper('%') = '%' */ @@ -310,12 +301,12 @@ backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f, } if ( f->f_sub_final.bv_val != NULL ) { - size_t start; + ber_len_t start; start = bsi->bsi_flt_where.bb_val.bv_len; backsql_strfcat( &bsi->bsi_flt_where, "b", &f->f_sub_final ); - if ( casefold && bi->upper_func.bv_val ) { + if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] ); } } @@ -372,6 +363,21 @@ backsql_process_filter( backsql_srch_info *bsi, Filter *f ) case LDAP_FILTER_EXT: ad = f->f_mra->ma_desc; + if ( f->f_mr_dnattrs ) { + /* + * if dn attrs filtering is requested, better return + * success and let test_filter() deal with candidate + * selection; otherwise we'd need to set conditions + * on the contents of the DN, e.g. "SELECT ... FROM + * ldap_entries AS attributeName WHERE attributeName.dn + * like '%attributeName=value%'" + */ + backsql_strfcat( &bsi->bsi_flt_where, "l", + (ber_len_t)sizeof( "1=1" ) - 1, "1=1" ); + bsi->bsi_status = LDAP_SUCCESS; + rc = 1; + goto done; + } break; default: @@ -553,7 +559,6 @@ done:; static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at ) { - backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; int casefold = 0; struct berval *filter_value = NULL; MatchingRule *matching_rule = NULL; @@ -591,10 +596,11 @@ backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_r matching_rule = f->f_mr_rule; equality_match:; -#if 0 /* always uppercase strings by now */ + /* always uppercase strings by now */ +#ifdef BACKSQL_UPPERCASE_FILTER if ( SLAP_MR_ASSOCIATED( matching_rule, bi->bi_caseIgnoreMatch ) ) -#endif +#endif /* BACKSQL_UPPERCASE_FILTER */ { casefold = 1; } @@ -605,24 +611,14 @@ equality_match:; * upper_func stuff is made for Oracle, where UPPER is * safely applicable to NUMBER etc. */ - if ( casefold && bi->upper_func.bv_val ) { - size_t start; - - if ( at->bam_sel_expr_u.bv_val ) { - backsql_strfcat( &bsi->bsi_flt_where, "cbl", - '(', /* ) */ - &at->bam_sel_expr_u, - (ber_len_t)sizeof( "='" ) - 1, - "='" ); - } else { - backsql_strfcat( &bsi->bsi_flt_where, "cbcbl", - '(' /* ) */ , - &bi->upper_func, - '(' /* ) */ , - &at->bam_sel_expr, - (ber_len_t)sizeof( /* ( */ ")='" ) - 1, - /* ( */ ")='" ); - } + if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { + ber_len_t start; + + backsql_strfcat( &bsi->bsi_flt_where, "cbl", + '(', /* ) */ + &at->bam_sel_expr_u, + (ber_len_t)sizeof( "='" ) - 1, + "='" ); start = bsi->bsi_flt_where.bb_val.bv_len; @@ -650,10 +646,11 @@ equality_match:; /* fall thru to next case */ case LDAP_FILTER_LE: -#if 0 /* always uppercase strings by now */ + /* always uppercase strings by now */ +#ifdef BACKSQL_UPPERCASE_FILTER if ( SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering, bi->bi_caseIgnoreMatch ) ) -#endif +#endif /* BACKSQL_UPPERCASE_FILTER */ { casefold = 1; } @@ -661,25 +658,14 @@ equality_match:; /* * FIXME: should we uppercase the operands? */ - if ( casefold && bi->upper_func.bv_val ) { - size_t start; - - if ( at->bam_sel_expr_u.bv_val ) { - backsql_strfcat( &bsi->bsi_flt_where, "cbbc", - '(', /* ) */ - &at->bam_sel_expr_u, - &ordering, - '\'' ); - } else { - backsql_strfcat( &bsi->bsi_flt_where, "cbcbcbc", - '(' /* ) */ , - &bi->upper_func, - '(' /* ) */ , - &at->bam_sel_expr, - /* ( */ ')', - &ordering, - '\'' ); - } + if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { + ber_len_t start; + + backsql_strfcat( &bsi->bsi_flt_where, "cbbc", + '(', /* ) */ + &at->bam_sel_expr_u, + &ordering, + '\'' ); start = bsi->bsi_flt_where.bb_val.bv_len; @@ -724,24 +710,14 @@ equality_match:; * upper_func stuff is made for Oracle, where UPPER is * safely applicable to NUMBER etc. */ - if ( bi->upper_func.bv_val ) { - size_t start; - - if ( at->bam_sel_expr_u.bv_val ) { - backsql_strfcat( &bsi->bsi_flt_where, "cbl", - '(', /* ) */ - &at->bam_sel_expr_u, - (ber_len_t)sizeof( " LIKE '%" ) - 1, - " LIKE '%" ); - } else { - backsql_strfcat( &bsi->bsi_flt_where, "cbcbl", - '(' /* ) */ , - &bi->upper_func, - '(' /* ) */ , - &at->bam_sel_expr, - (ber_len_t)sizeof( /* ( */ ") LIKE '%" ) - 1, - /* ( */ ") LIKE '%" ); - } + if ( at->bam_sel_expr_u.bv_val ) { + ber_len_t start; + + backsql_strfcat( &bsi->bsi_flt_where, "cbl", + '(', /* ) */ + &at->bam_sel_expr_u, + (ber_len_t)sizeof( " LIKE '%" ) - 1, + " LIKE '%" ); start = bsi->bsi_flt_where.bb_val.bv_len; diff --git a/servers/slapd/back-sql/sql-wrap.c b/servers/slapd/back-sql/sql-wrap.c index 07ec0e5b77..e86477c1ba 100644 --- a/servers/slapd/back-sql/sql-wrap.c +++ b/servers/slapd/back-sql/sql-wrap.c @@ -25,12 +25,10 @@ #include #include "ac/string.h" #include + #include "slap.h" #include "ldap_pvt.h" -#include "back-sql.h" -#include "sql-types.h" -#include "sql-wrap.h" -#include "schema-map.h" +#include "proto-sql.h" #define MAX_ATTR_LEN 16384 diff --git a/servers/slapd/back-sql/sql-wrap.h b/servers/slapd/back-sql/sql-wrap.h deleted file mode 100644 index 1a57bc5739..0000000000 --- a/servers/slapd/back-sql/sql-wrap.h +++ /dev/null @@ -1,50 +0,0 @@ -/* $OpenLDAP$ */ -/* This work is part of OpenLDAP Software . - * - * Copyright 1999-2004 The OpenLDAP Foundation. - * Portions Copyright 1999 Dmitry Kovalev. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted only as authorized by the OpenLDAP - * Public License. - * - * A copy of this license is available in the file LICENSE in the - * top-level directory of the distribution or, alternatively, at - * . - */ -/* ACKNOWLEDGEMENTS: - * This work was initially developed by Dmitry Kovalev for inclusion - * by OpenLDAP Software. - */ -#ifndef __BACKSQL_SQL_WRAP_H__ -#define __BACKSQL_SQL_WRAP_H__ - -#include "back-sql.h" -#include "sql-types.h" - -RETCODE backsql_Prepare( SQLHDBC dbh, SQLHSTMT *sth, char* query, int timeout ); - -#define backsql_BindParamStr( sth, par_ind, str, maxlen ) \ - SQLBindParameter( (sth), (SQLUSMALLINT)(par_ind), \ - SQL_PARAM_INPUT, \ - SQL_C_CHAR, SQL_VARCHAR, \ - (SQLUINTEGER)(maxlen), 0, (SQLPOINTER)(str), \ - (SQLUINTEGER)(maxlen), NULL ) - -#define backsql_BindParamID( sth, par_ind, id ) \ - SQLBindParameter( (sth), (SQLUSMALLINT)(par_ind), \ - SQL_PARAM_INPUT, SQL_C_ULONG, SQL_INTEGER, \ - 0, 0, (SQLPOINTER)(id), 0, (SQLINTEGER*)NULL ) - -RETCODE backsql_BindRowAsStrings( SQLHSTMT sth, BACKSQL_ROW_NTS *row ); -RETCODE backsql_FreeRow( BACKSQL_ROW_NTS *row ); -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 ); -int backsql_get_db_conn( Operation *op, SQLHDBC *dbh ); -int backsql_free_db_conn( Operation *op ); - -#endif /* __BACKSQL_SQL_WRAP_H__ */ - diff --git a/servers/slapd/back-sql/util.c b/servers/slapd/back-sql/util.c index 02bd21d639..a138989c59 100644 --- a/servers/slapd/back-sql/util.c +++ b/servers/slapd/back-sql/util.c @@ -27,12 +27,11 @@ #include "ac/string.h" #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" +#include "proto-sql.h" #define BACKSQL_MAX(a,b) ((a)>(b)?(a):(b)) #define BACKSQL_MIN(a,b) ((a)<(b)?(a):(b)) @@ -282,7 +281,7 @@ backsql_entry_addattr( return 1; } -char * +static char * backsql_get_table_spec( char **p ) { char *s, *q; diff --git a/servers/slapd/back-sql/util.h b/servers/slapd/back-sql/util.h deleted file mode 100644 index 5282c1ae43..0000000000 --- a/servers/slapd/back-sql/util.h +++ /dev/null @@ -1,103 +0,0 @@ -/* $OpenLDAP$ */ -/* This work is part of OpenLDAP Software . - * - * Copyright 1999-2004 The OpenLDAP Foundation. - * Portions Copyright 1999 Dmitry Kovalev. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted only as authorized by the OpenLDAP - * Public License. - * - * A copy of this license is available in the file LICENSE in the - * top-level directory of the distribution or, alternatively, at - * . - */ -/* ACKNOWLEDGEMENTS: - * This work was initially developed by Dmitry Kovalev for inclusion - * by OpenLDAP Software. - */ - -#ifndef __BACKSQL_UTIL_H__ -#define __BACKSQL_UTIL_H__ - - -#include "entry-id.h" -#include "schema-map.h" - -#define BACKSQL_CONCAT - -typedef struct berbuf { - struct berval bb_val; - ber_len_t bb_len; -} BerBuffer; -#define BB_NULL { { 0, NULL }, 0 } - -struct berbuf * backsql_strcat( struct berbuf *dest, ... ); -struct berbuf * backsql_strfcat( struct berbuf *dest, const char *fmt, ... ); - -int backsql_entry_addattr( Entry *e, struct berval *at_name, - struct berval *at_val, void *memctx ); - -typedef struct backsql_srch_info { - Operation *bsi_op; - - int bsi_flags; -#define BSQL_SF_ALL_OPER 0x0001 -#define BSQL_SF_FILTER_HASSUBORDINATE 0x0002 - - struct berval *bsi_base_dn; - int bsi_scope; - Filter *bsi_filter; - int bsi_slimit, - bsi_tlimit; - time_t bsi_stoptime; - - backsql_entryID *bsi_id_list, - *bsi_c_eid; - int bsi_n_candidates; - int bsi_abandon; - int bsi_status; - - backsql_oc_map_rec *bsi_oc; - struct berbuf bsi_sel, - bsi_from, - bsi_join_where, - bsi_flt_where; - ObjectClass *bsi_filter_oc; - SQLHDBC bsi_dbh; - AttributeName *bsi_attrs; - - Entry *bsi_e; -} backsql_srch_info; - -void backsql_init_search( backsql_srch_info *bsi, - struct berval *nbase, int scope, int slimit, int tlimit, - time_t stoptime, Filter *filter, SQLHDBC dbh, - Operation *op, AttributeName *attrs ); -Entry *backsql_id2entry( backsql_srch_info *bsi, Entry *e, - backsql_entryID *id ); - -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_def_concat_func[]; -extern char - backsql_check_dn_ru_query[]; - -int backsql_merge_from_clause( struct berbuf *dest_from, - 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__ */ -