mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-21 03:10:25 +08:00
1540 lines
40 KiB
C
1540 lines
40 KiB
C
/* $OpenLDAP$ */
|
|
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
*
|
|
* Copyright 1999-2005 The OpenLDAP Foundation.
|
|
* Portions Copyright 1999 Dmitry Kovalev.
|
|
* Portions Copyright 2002 Pierangelo Masarati.
|
|
* Portions Copyright 2004 Mark Adamson.
|
|
* 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
|
|
* <http://www.OpenLDAP.org/license.html>.
|
|
*/
|
|
/* ACKNOWLEDGEMENTS:
|
|
* This work was initially developed by Dmitry Kovalev for inclusion
|
|
* by OpenLDAP Software. Additional significant contributors include
|
|
* Pierangelo Masarati and Mark Adamson.
|
|
|
|
*/
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include "ac/string.h"
|
|
|
|
#include "slap.h"
|
|
#include "proto-sql.h"
|
|
|
|
#ifdef BACKSQL_SYNCPROV
|
|
#include <lutil.h>
|
|
#endif /* BACKSQL_SYNCPROV */
|
|
|
|
/*
|
|
* Skip:
|
|
* - null values (e.g. delete modification)
|
|
* - single occurrence of objectClass, because it is already used
|
|
* to determine how to build the SQL entry
|
|
* - operational attributes
|
|
* - empty attributes
|
|
*/
|
|
#define backsql_opattr_skip(ad) \
|
|
(is_at_operational( (ad)->ad_type ) && (ad) != slap_schema.si_ad_ref )
|
|
#define backsql_attr_skip(ad, vals) \
|
|
( \
|
|
( (ad) == slap_schema.si_ad_objectClass \
|
|
&& (vals) && BER_BVISNULL( &((vals)[ 1 ]) ) ) \
|
|
|| backsql_opattr_skip( (ad) ) \
|
|
|| ( (vals) && BER_BVISNULL( &((vals)[ 0 ]) ) ) \
|
|
)
|
|
|
|
int
|
|
backsql_modify_delete_all_values(
|
|
Operation *op,
|
|
SlapReply *rs,
|
|
SQLHDBC dbh,
|
|
backsql_entryID *e_id,
|
|
backsql_at_map_rec *at )
|
|
{
|
|
backsql_info *bi = (backsql_info *)op->o_bd->be_private;
|
|
RETCODE rc;
|
|
SQLHSTMT asth = SQL_NULL_HSTMT;
|
|
BACKSQL_ROW_NTS row;
|
|
|
|
assert( at != NULL );
|
|
if ( at->bam_delete_proc == NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"missing attribute value delete procedure "
|
|
"for attr \"%s\"\n",
|
|
at->bam_ad->ad_cname.bv_val, 0, 0 );
|
|
if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
|
|
rs->sr_text = "SQL-backend error";
|
|
return rs->sr_err = LDAP_OTHER;
|
|
}
|
|
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"error preparing attribute value select query "
|
|
"\"%s\"\n",
|
|
at->bam_query, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
asth, rc );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
return rs->sr_err = LDAP_OTHER;
|
|
}
|
|
|
|
rc = backsql_BindParamID( asth, 1, SQL_PARAM_INPUT, &e_id->eid_keyval );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"error binding key value parameter "
|
|
"to attribute value select query\n",
|
|
0, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
asth, rc );
|
|
SQLFreeStmt( asth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
return rs->sr_err = LDAP_OTHER;
|
|
}
|
|
|
|
rc = SQLExecute( asth );
|
|
if ( !BACKSQL_SUCCESS( rc ) ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"error executing attribute value select query\n",
|
|
0, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
asth, rc );
|
|
SQLFreeStmt( asth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
return rs->sr_err = LDAP_OTHER;
|
|
}
|
|
|
|
backsql_BindRowAsStrings_x( asth, &row, op->o_tmpmemctx );
|
|
for ( rc = SQLFetch( asth );
|
|
BACKSQL_SUCCESS( rc );
|
|
rc = SQLFetch( asth ) )
|
|
{
|
|
int i;
|
|
/* first parameter no, parameter order */
|
|
SQLUSMALLINT pno = 0,
|
|
po = 0;
|
|
/* procedure return code */
|
|
int prc = LDAP_SUCCESS;
|
|
|
|
for ( i = 0; i < row.ncols; i++ ) {
|
|
SQLHSTMT sth = SQL_NULL_HSTMT;
|
|
ber_len_t col_len;
|
|
|
|
rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"error preparing attribute value "
|
|
"delete procedure "
|
|
"\"%s\"\n",
|
|
at->bam_delete_proc, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
|
|
if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
|
|
pno = 1;
|
|
rc = backsql_BindParamInt( sth, 1,
|
|
SQL_PARAM_OUTPUT, &prc );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"error binding output parameter for %s[%d]\n",
|
|
at->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
}
|
|
po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
|
|
rc = backsql_BindParamID( sth, pno + 1 + po,
|
|
SQL_PARAM_INPUT, &e_id->eid_keyval );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"error binding keyval parameter for %s[%d]\n",
|
|
at->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
#ifdef BACKSQL_ARBITRARY_KEY
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values() "
|
|
"arg(%d)=%s\n",
|
|
pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
|
|
#else /* ! BACKSQL_ARBITRARY_KEY */
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values() "
|
|
"arg(%d)=%lu\n",
|
|
pno + 1 + po, e_id->eid_keyval, 0 );
|
|
#endif /* ! BACKSQL_ARBITRARY_KEY */
|
|
|
|
/*
|
|
* check for syntax needed here
|
|
* maybe need binary bind?
|
|
*/
|
|
col_len = strlen( row.cols[ i ] );
|
|
rc = backsql_BindParamStr( sth, pno + 2 - po,
|
|
SQL_PARAM_INPUT, row.cols[ i ], col_len );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"error binding value parameter for %s[%d]\n",
|
|
at->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"arg(%d)=%s; executing \"%s\"\n",
|
|
pno + 2 - po, row.cols[ i ],
|
|
at->bam_delete_proc );
|
|
rc = SQLExecute( sth );
|
|
if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
|
|
} else {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_delete_all_values(): "
|
|
"delete_proc "
|
|
"execution failed (rc=%d, prc=%d)\n",
|
|
rc, prc, 0 );
|
|
if ( prc != LDAP_SUCCESS ) {
|
|
/* SQL procedure executed fine
|
|
* but returned an error */
|
|
rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
|
|
|
|
} else {
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
rs->sr_err = LDAP_OTHER;
|
|
}
|
|
rs->sr_text = op->o_req_dn.bv_val;
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
goto done;
|
|
}
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
}
|
|
}
|
|
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
|
|
done:;
|
|
backsql_FreeRow_x( &row, op->o_tmpmemctx );
|
|
SQLFreeStmt( asth, SQL_DROP );
|
|
|
|
return rs->sr_err;
|
|
}
|
|
|
|
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;
|
|
Modifications *ml;
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): "
|
|
"traversing modifications list\n", 0, 0, 0 );
|
|
|
|
for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
|
|
AttributeDescription *ad;
|
|
int sm_op;
|
|
static char *sm_ops[] = { "add", "delete", "replace", "increment", NULL };
|
|
|
|
BerVarray sm_values;
|
|
#if 0
|
|
/* NOTE: some day we'll have to pass
|
|
* the normalized values as well */
|
|
BerVarray sm_nvalues;
|
|
#endif
|
|
backsql_at_map_rec *at = NULL;
|
|
struct berval *at_val;
|
|
int i;
|
|
|
|
ad = ml->sml_mod.sm_desc;
|
|
sm_op = ( ml->sml_mod.sm_op & LDAP_MOD_OP );
|
|
sm_values = ml->sml_mod.sm_values;
|
|
#if 0
|
|
sm_nvalues = ml->sml_mod.sm_nvalues;
|
|
#endif
|
|
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
|
|
"modifying attribute \"%s\" (%s) according to "
|
|
"mappings for objectClass \"%s\"\n",
|
|
ad->ad_cname.bv_val, sm_ops[ sm_op ], BACKSQL_OC_NAME( oc ) );
|
|
|
|
if ( backsql_attr_skip( ad, sm_values ) ) {
|
|
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, 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;
|
|
}
|
|
|
|
switch ( sm_op ) {
|
|
case LDAP_MOD_REPLACE: {
|
|
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:
|
|
rs->sr_err = backsql_modify_delete_all_values( op, rs, dbh, e_id, at );
|
|
if ( rs->sr_err != LDAP_SUCCESS ) {
|
|
goto done;
|
|
}
|
|
|
|
/* LDAP_MOD_DELETE gets here if all values must be deleted */
|
|
if ( sm_op == LDAP_MOD_DELETE ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 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 );
|
|
|
|
/* can't add a NULL val array */
|
|
assert( sm_values != NULL );
|
|
|
|
for ( i = 0, at_val = sm_values;
|
|
!BER_BVISNULL( at_val );
|
|
i++, at_val++ )
|
|
{
|
|
SQLHSTMT sth = SQL_NULL_HSTMT;
|
|
/* first parameter position, parameter order */
|
|
SQLUSMALLINT pno = 0,
|
|
po;
|
|
/* procedure return code */
|
|
int prc = LDAP_SUCCESS;
|
|
|
|
rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"error preparing add query\n",
|
|
0, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
|
|
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
goto done;
|
|
}
|
|
|
|
if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
|
|
pno = 1;
|
|
rc = backsql_BindParamInt( sth, 1,
|
|
SQL_PARAM_OUTPUT, &prc );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"error binding output parameter for %s[%d]\n",
|
|
at->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
}
|
|
po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
|
|
rc = backsql_BindParamID( sth, pno + 1 + po,
|
|
SQL_PARAM_INPUT, &e_id->eid_keyval );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"error binding keyval parameter for %s[%d]\n",
|
|
at->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
#ifdef BACKSQL_ARBITRARY_KEY
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"arg(%d)=\"%s\"\n",
|
|
pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
|
|
#else /* ! BACKSQL_ARBITRARY_KEY */
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"arg(%d)=\"%lu\"\n",
|
|
pno + 1 + po, e_id->eid_keyval, 0 );
|
|
#endif /* ! BACKSQL_ARBITRARY_KEY */
|
|
|
|
/*
|
|
* check for syntax needed here
|
|
* maybe need binary bind?
|
|
*/
|
|
rc = backsql_BindParamBerVal( sth, pno + 2 - po,
|
|
SQL_PARAM_INPUT, at_val );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"error binding value parameter for %s[%d]\n",
|
|
at->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"arg(%d)=\"%s\"; executing \"%s\"\n",
|
|
pno + 2 - po, at_val->bv_val,
|
|
at->bam_add_proc );
|
|
|
|
rc = SQLExecute( sth );
|
|
if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
|
|
} else {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"add_proc execution failed "
|
|
"(rc=%d, prc=%d)\n",
|
|
rc, prc, 0 );
|
|
if ( prc != LDAP_SUCCESS ) {
|
|
/* SQL procedure executed fine
|
|
* but returned an error */
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
|
|
rs->sr_text = at->bam_ad->ad_cname.bv_val;
|
|
return rs->sr_err;
|
|
|
|
} else {
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) )
|
|
{
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
}
|
|
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 ( sm_values == 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 = sm_values;
|
|
!BER_BVISNULL( at_val );
|
|
i++, at_val++ )
|
|
{
|
|
SQLHSTMT sth = SQL_NULL_HSTMT;
|
|
/* first parameter position, parameter order */
|
|
SQLUSMALLINT pno = 0,
|
|
po;
|
|
/* procedure return code */
|
|
int prc = LDAP_SUCCESS;
|
|
|
|
rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"error preparing delete query\n",
|
|
0, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
|
|
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
goto done;
|
|
}
|
|
|
|
if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
|
|
pno = 1;
|
|
rc = backsql_BindParamInt( sth, 1,
|
|
SQL_PARAM_OUTPUT, &prc );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"error binding output parameter for %s[%d]\n",
|
|
at->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
}
|
|
po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
|
|
rc = backsql_BindParamID( sth, pno + 1 + po,
|
|
SQL_PARAM_INPUT, &e_id->eid_keyval );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"error binding keyval parameter for %s[%d]\n",
|
|
at->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
#ifdef BACKSQL_ARBITRARY_KEY
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"arg(%d)=\"%s\"\n",
|
|
pno + 1 + po, e_id->eid_keyval.bv_val, 0 );
|
|
#else /* ! BACKSQL_ARBITRARY_KEY */
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"arg(%d)=\"%lu\"\n",
|
|
pno + 1 + po, e_id->eid_keyval, 0 );
|
|
#endif /* ! BACKSQL_ARBITRARY_KEY */
|
|
|
|
/*
|
|
* check for syntax needed here
|
|
* maybe need binary bind?
|
|
*/
|
|
rc = backsql_BindParamBerVal( sth, pno + 2 - po,
|
|
SQL_PARAM_INPUT, at_val );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"error binding value parameter for %s[%d]\n",
|
|
at->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
goto done;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"executing \"%s\"\n",
|
|
at->bam_delete_proc, 0, 0 );
|
|
rc = SQLExecute( sth );
|
|
if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS )
|
|
{
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
|
|
} else {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_modify_internal(): "
|
|
"delete_proc execution "
|
|
"failed (rc=%d, prc=%d)\n",
|
|
rc, prc, 0 );
|
|
|
|
if ( prc != LDAP_SUCCESS ) {
|
|
/* SQL procedure executed fine
|
|
* but returned an error */
|
|
rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
|
|
rs->sr_text = at->bam_ad->ad_cname.bv_val;
|
|
goto done;
|
|
|
|
} else {
|
|
backsql_PrintErrors( bi->sql_db_env,
|
|
dbh, sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = at->bam_ad->ad_cname.bv_val;
|
|
goto done;
|
|
}
|
|
}
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
}
|
|
break;
|
|
|
|
case LDAP_MOD_INCREMENT:
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_modify_internal(): "
|
|
"increment not supported yet\n", 0, 0, 0 );
|
|
if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
goto done;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
done:;
|
|
Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%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;
|
|
}
|
|
|
|
static int
|
|
backsql_add_attr(
|
|
Operation *op,
|
|
SlapReply *rs,
|
|
SQLHDBC dbh,
|
|
backsql_oc_map_rec *oc,
|
|
Attribute *at,
|
|
unsigned long new_keyval )
|
|
{
|
|
backsql_info *bi = (backsql_info*)op->o_bd->be_private;
|
|
backsql_at_map_rec *at_rec = NULL;
|
|
struct berval *at_val;
|
|
unsigned long i;
|
|
RETCODE rc;
|
|
SQLUSMALLINT currpos;
|
|
SQLHSTMT sth = SQL_NULL_HSTMT;
|
|
|
|
at_rec = backsql_ad2at( oc, at->a_desc );
|
|
|
|
if ( at_rec == NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): "
|
|
"attribute \"%s\" is not registered "
|
|
"in objectclass \"%s\"\n",
|
|
op->ora_e->e_name.bv_val,
|
|
at->a_desc->ad_cname.bv_val,
|
|
BACKSQL_OC_NAME( oc ) );
|
|
|
|
if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
|
|
rs->sr_text = "operation not permitted "
|
|
"within namingContext";
|
|
return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
}
|
|
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
if ( at_rec->bam_add_proc == NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): "
|
|
"add procedure is not defined "
|
|
"for attribute \"%s\" "
|
|
"of structuralObjectClass \"%s\"\n",
|
|
op->ora_e->e_name.bv_val,
|
|
at->a_desc->ad_cname.bv_val,
|
|
BACKSQL_OC_NAME( oc ) );
|
|
|
|
if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
|
|
rs->sr_text = "operation not permitted "
|
|
"within namingContext";
|
|
return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
}
|
|
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
for ( i = 0, at_val = &at->a_vals[ i ];
|
|
!BER_BVISNULL( at_val );
|
|
i++, at_val = &at->a_vals[ i ] )
|
|
{
|
|
/* procedure return code */
|
|
int prc = LDAP_SUCCESS;
|
|
/* first parameter #, parameter order */
|
|
SQLUSMALLINT pno, po;
|
|
char logbuf[] = "val[18446744073709551615UL], id=18446744073709551615UL";
|
|
|
|
/*
|
|
* Do not deal with the objectClass that is used
|
|
* to build the entry
|
|
*/
|
|
if ( at->a_desc == slap_schema.si_ad_objectClass ) {
|
|
if ( dn_match( at_val, &oc->bom_oc->soc_cname ) )
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
rs->sr_text = "SQL-backend error";
|
|
return rs->sr_err = LDAP_OTHER;
|
|
}
|
|
|
|
if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
|
|
pno = 1;
|
|
rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_add_attr(): "
|
|
"error binding output parameter for %s[%lu]\n",
|
|
at_rec->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
return rs->sr_err = LDAP_OTHER;
|
|
}
|
|
|
|
} else {
|
|
pno = 0;
|
|
}
|
|
|
|
po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
|
|
currpos = pno + 1 + po;
|
|
rc = backsql_BindParamInt( sth, currpos,
|
|
SQL_PARAM_INPUT, &new_keyval );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_add_attr(): "
|
|
"error binding keyval parameter for %s[%lu]\n",
|
|
at_rec->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
return rs->sr_err = LDAP_OTHER;
|
|
}
|
|
|
|
currpos = pno + 2 - po;
|
|
|
|
/*
|
|
* check for syntax needed here
|
|
* maybe need binary bind?
|
|
*/
|
|
|
|
rc = backsql_BindParamBerVal( sth, currpos, SQL_PARAM_INPUT, at_val );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_add_attr(): "
|
|
"error binding value parameter for %s[%lu]\n",
|
|
at_rec->bam_ad->ad_cname.bv_val, i, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
return rs->sr_err = LDAP_OTHER;
|
|
}
|
|
|
|
#ifdef LDAP_DEBUG
|
|
snprintf( logbuf, sizeof( logbuf ), "val[%lu], id=%lu",
|
|
i, new_keyval );
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add_attr(\"%s\"): "
|
|
"executing \"%s\" %s\n",
|
|
op->ora_e->e_name.bv_val,
|
|
at_rec->bam_add_proc, logbuf );
|
|
#endif
|
|
rc = SQLExecute( sth );
|
|
if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
|
|
} else {
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
" backsql_add_attr(\"%s\"): "
|
|
"add_proc execution failed (rc=%d, prc=%d)\n",
|
|
op->ora_e->e_name.bv_val, rc, prc );
|
|
if ( prc != LDAP_SUCCESS ) {
|
|
/* SQL procedure executed fine
|
|
* but returned an error */
|
|
rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
|
|
rs->sr_text = op->ora_e->e_name.bv_val;
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
return rs->sr_err;
|
|
|
|
} else {
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = op->ora_e->e_name.bv_val;
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
return rs->sr_err;
|
|
}
|
|
}
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
}
|
|
|
|
return LDAP_SUCCESS;
|
|
}
|
|
|
|
int
|
|
backsql_add( Operation *op, SlapReply *rs )
|
|
{
|
|
backsql_info *bi = (backsql_info*)op->o_bd->be_private;
|
|
SQLHDBC dbh = SQL_NULL_HDBC;
|
|
SQLHSTMT sth = SQL_NULL_HSTMT;
|
|
unsigned long new_keyval = 0;
|
|
RETCODE rc;
|
|
backsql_oc_map_rec *oc = NULL;
|
|
backsql_srch_info bsi = { 0 };
|
|
Entry p = { 0 }, *e = NULL;
|
|
Attribute *at,
|
|
*at_objectClass = NULL;
|
|
struct berval scname = BER_BVNULL;
|
|
struct berval pdn;
|
|
struct berval realdn = BER_BVNULL;
|
|
int colnum;
|
|
slap_mask_t mask;
|
|
|
|
#ifdef BACKSQL_SYNCPROV
|
|
/*
|
|
* NOTE: fake successful result to force contextCSN to be bumped up
|
|
*/
|
|
if ( op->o_sync ) {
|
|
char buf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
|
|
struct berval csn = BER_BVNULL;
|
|
|
|
slap_get_csn( op, buf, sizeof( buf ), &csn, 1 );
|
|
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
send_ldap_result( op, rs );
|
|
|
|
slap_graduate_commit_csn( op );
|
|
|
|
return 0;
|
|
}
|
|
#endif /* BACKSQL_SYNCPROV */
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
|
|
op->ora_e->e_name.bv_val, 0, 0 );
|
|
|
|
/* check schema */
|
|
if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
|
|
char textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
|
|
|
|
rs->sr_err = entry_schema_check( op, op->ora_e, NULL, 0,
|
|
&rs->sr_text, textbuf, sizeof( textbuf ) );
|
|
if ( rs->sr_err != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"entry failed schema check -- aborting\n",
|
|
op->ora_e->e_name.bv_val, 0, 0 );
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* search structuralObjectClass */
|
|
for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
|
|
if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* there must exist */
|
|
if ( at == NULL ) {
|
|
char buf[ SLAP_TEXT_BUFLEN ];
|
|
const char *text;
|
|
|
|
/* search structuralObjectClass */
|
|
for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
|
|
if ( at->a_desc == slap_schema.si_ad_objectClass ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( at == NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"no objectClass\n",
|
|
op->ora_e->e_name.bv_val, 0, 0 );
|
|
rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
rs->sr_err = structural_class( at->a_vals, &scname, NULL,
|
|
&text, buf, sizeof( buf ) );
|
|
if ( rs->sr_err != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"%s (%d)\n",
|
|
op->ora_e->e_name.bv_val, text, rs->sr_err );
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
} else {
|
|
scname = at->a_vals[0];
|
|
}
|
|
|
|
/* I guess we should play with sub/supertypes to find a suitable oc */
|
|
oc = backsql_name2oc( bi, &scname );
|
|
|
|
if ( oc == NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"cannot map structuralObjectClass \"%s\" -- aborting\n",
|
|
op->ora_e->e_name.bv_val,
|
|
scname.bv_val, 0 );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "operation not permitted within namingContext";
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
if ( oc->bom_create_proc == NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"create procedure is not defined "
|
|
"for structuralObjectClass \"%s\" - aborting\n",
|
|
op->ora_e->e_name.bv_val,
|
|
scname.bv_val, 0 );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "operation not permitted within namingContext";
|
|
e = NULL;
|
|
goto done;
|
|
|
|
} else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
|
|
&& oc->bom_create_keyval == NULL ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"create procedure needs select procedure, "
|
|
"but none is defined for structuralObjectClass \"%s\" "
|
|
"- aborting\n",
|
|
op->ora_e->e_name.bv_val,
|
|
scname.bv_val, 0 );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "operation not permitted within namingContext";
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
rs->sr_err = backsql_get_db_conn( op, &dbh );
|
|
if ( rs->sr_err != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"could not get connection handle - exiting\n",
|
|
op->ora_e->e_name.bv_val, 0, 0 );
|
|
rs->sr_text = ( rs->sr_err == LDAP_OTHER )
|
|
? "SQL-backend error" : NULL;
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* Check if entry exists
|
|
*
|
|
* NOTE: backsql_api_dn2odbc() is called explicitly because
|
|
* we need the mucked DN to pass it to the create procedure.
|
|
*/
|
|
realdn = op->ora_e->e_name;
|
|
if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"backsql_api_dn2odbc(\"%s\") failed\n",
|
|
op->ora_e->e_name.bv_val, realdn.bv_val, 0 );
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
rs->sr_err = backsql_dn2id( op, rs, dbh, &realdn, NULL, 0, 0 );
|
|
if ( rs->sr_err == LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"entry exists\n",
|
|
op->ora_e->e_name.bv_val, 0, 0 );
|
|
rs->sr_err = LDAP_ALREADY_EXISTS;
|
|
e = op->ora_e;
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* Get the parent dn and see if the corresponding entry exists.
|
|
*/
|
|
if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
|
|
pdn = slap_empty_bv;
|
|
|
|
} else {
|
|
dnParent( &op->ora_e->e_nname, &pdn );
|
|
}
|
|
|
|
/*
|
|
* Get the parent
|
|
*/
|
|
bsi.bsi_e = &p;
|
|
rs->sr_err = backsql_init_search( &bsi, &pdn,
|
|
LDAP_SCOPE_BASE,
|
|
(time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs,
|
|
( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
|
|
if ( rs->sr_err != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
|
|
"could not retrieve addDN parent "
|
|
"\"%s\" ID - %s matched=\"%s\"\n",
|
|
pdn.bv_val,
|
|
rs->sr_err == LDAP_REFERRAL ? "referral" : "no such entry",
|
|
rs->sr_matched ? rs->sr_matched : "(null)" );
|
|
e = &p;
|
|
goto done;
|
|
}
|
|
|
|
/* check "children" pseudo-attribute access to parent */
|
|
if ( !access_allowed( op, &p, slap_schema.si_ad_children,
|
|
NULL, ACL_WADD, NULL ) )
|
|
{
|
|
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
|
e = &p;
|
|
goto done;
|
|
}
|
|
|
|
if ( get_assert( op ) &&
|
|
( test_filter( op, op->oq_add.rs_e, get_assertion( op ) )
|
|
!= LDAP_COMPARE_TRUE ) )
|
|
{
|
|
rs->sr_err = LDAP_ASSERTION_FAILED;
|
|
e = op->ora_e;
|
|
goto done;
|
|
}
|
|
|
|
if ( !access_allowed_mask( op, op->ora_e,
|
|
slap_schema.si_ad_entry,
|
|
NULL, ACL_WADD, NULL, &mask ) )
|
|
{
|
|
rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
|
|
e = op->ora_e;
|
|
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
|
|
*/
|
|
rc = backsql_Prepare( dbh, &sth, oc->bom_create_proc, 0 );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
colnum = 1;
|
|
if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
|
|
rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &new_keyval );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"error binding keyval parameter "
|
|
"for objectClass %s\n",
|
|
op->ora_e->e_name.bv_val,
|
|
oc->bom_oc->soc_cname.bv_val, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
colnum++;
|
|
}
|
|
|
|
if ( oc->bom_create_hint ) {
|
|
at = attr_find( op->ora_e->e_attrs, oc->bom_create_hint );
|
|
if ( at && at->a_vals ) {
|
|
backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT,
|
|
at->a_vals[0].bv_val,
|
|
at->a_vals[0].bv_len );
|
|
Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
|
|
"create_proc hint: param = '%s'\n",
|
|
at->a_vals[0].bv_val, 0, 0 );
|
|
|
|
} else {
|
|
backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT,
|
|
"", 0 );
|
|
Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
|
|
"create_proc hint (%s) not avalable\n",
|
|
oc->bom_create_hint->ad_cname.bv_val,
|
|
0, 0 );
|
|
}
|
|
colnum++;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): executing \"%s\"\n",
|
|
op->ora_e->e_name.bv_val, oc->bom_create_proc, 0 );
|
|
rc = SQLExecute( sth );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"create_proc execution failed\n",
|
|
op->ora_e->e_name.bv_val, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
/* FIXME: after SQLExecute(), the row is already inserted
|
|
* (at least with PostgreSQL and unixODBC); needs investigation */
|
|
|
|
if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
|
|
SWORD ncols;
|
|
SQLINTEGER value_len;
|
|
|
|
if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rc = backsql_Prepare( dbh, &sth, oc->bom_create_keyval, 0 );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
rc = SQLExecute( sth );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
e = NULL;
|
|
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(\"%s\"): "
|
|
"create_proc result evaluation failed\n",
|
|
op->ora_e->e_name.bv_val, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
e = NULL;
|
|
goto done;
|
|
|
|
} else if ( ncols != 1 ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"create_proc result is bogus (ncols=%d)\n",
|
|
op->ora_e->e_name.bv_val, ncols, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
e = NULL;
|
|
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(\"%s\"): "
|
|
"create_proc result is empty?\n",
|
|
op->ora_e->e_name.bv_val, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"create_proc returned keyval=%ld\n",
|
|
op->ora_e->e_name.bv_val, new_keyval, 0 );
|
|
|
|
rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_stmt, 0 );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "SQL-backend error";
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realdn );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"error binding DN parameter for objectClass %s\n",
|
|
op->ora_e->e_name.bv_val,
|
|
oc->bom_oc->soc_cname.bv_val, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
rc = backsql_BindParamInt( sth, 2, SQL_PARAM_INPUT, &oc->bom_id );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"error binding objectClass ID parameter "
|
|
"for objectClass %s\n",
|
|
op->ora_e->e_name.bv_val,
|
|
oc->bom_oc->soc_cname.bv_val, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &bsi.bsi_base_id.eid_id );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"error binding parent ID parameter "
|
|
"for objectClass %s\n",
|
|
op->ora_e->e_name.bv_val,
|
|
oc->bom_oc->soc_cname.bv_val, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
rc = backsql_BindParamInt( sth, 4, SQL_PARAM_INPUT, &new_keyval );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"error binding entry ID parameter "
|
|
"for objectClass %s\n",
|
|
op->ora_e->e_name.bv_val,
|
|
oc->bom_oc->soc_cname.bv_val, 0 );
|
|
backsql_PrintErrors( bi->sql_db_env, dbh,
|
|
sth, rc );
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
rs->sr_text = "SQL-backend error";
|
|
rs->sr_err = LDAP_OTHER;
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(): executing \"%s\" for dn \"%s\"\n",
|
|
bi->sql_insentry_stmt, op->ora_e->e_name.bv_val, 0 );
|
|
#ifdef BACKSQL_ARBITRARY_KEY
|
|
Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
|
|
"p_id=%s, keyval=%ld\n",
|
|
oc->bom_id, bsi.bsi_base_id.eid_id.bv_val, new_keyval );
|
|
#else /* ! BACKSQL_ARBITRARY_KEY */
|
|
Debug( LDAP_DEBUG_TRACE, " for oc_map_id=%ld, "
|
|
"p_id=%ld, keyval=%ld\n",
|
|
oc->bom_id, bsi.bsi_base_id.eid_id, new_keyval );
|
|
#endif /* ! BACKSQL_ARBITRARY_KEY */
|
|
rc = SQLExecute( sth );
|
|
if ( rc != SQL_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_TRACE, " backsql_add(\"%s\"): "
|
|
"could not insert ldap_entries record\n",
|
|
op->ora_e->e_name.bv_val, 0, 0 );
|
|
backsql_PrintErrors( bi->sql_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";
|
|
e = NULL;
|
|
goto done;
|
|
}
|
|
|
|
SQLFreeStmt( sth, SQL_DROP );
|
|
|
|
for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
|
|
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 build the SQL entry (FIXME ?!?)
|
|
* - operational attributes
|
|
* - empty attributes (FIXME ?!?)
|
|
*/
|
|
if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
|
|
continue;
|
|
}
|
|
|
|
if ( at->a_desc == slap_schema.si_ad_objectClass ) {
|
|
at_objectClass = at;
|
|
continue;
|
|
}
|
|
|
|
rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at, new_keyval );
|
|
if ( rs->sr_err != LDAP_SUCCESS ) {
|
|
e = op->ora_e;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
if ( at_objectClass ) {
|
|
rs->sr_err = backsql_add_attr( op, rs, dbh, oc,
|
|
at_objectClass, new_keyval );
|
|
if ( rs->sr_err != LDAP_SUCCESS ) {
|
|
e = op->ora_e;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:;
|
|
/*
|
|
* Commit only if all operations succeed
|
|
*/
|
|
if ( sth != SQL_NULL_HSTMT ) {
|
|
SQLUSMALLINT CompletionType = SQL_ROLLBACK;
|
|
|
|
if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
|
|
CompletionType = SQL_COMMIT;
|
|
}
|
|
|
|
SQLTransact( SQL_NULL_HENV, dbh, CompletionType );
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
|
|
#ifdef SLAP_ACL_HONOR_DISCLOSE
|
|
if ( e != NULL ) {
|
|
int disclose = 1;
|
|
|
|
if ( e == op->ora_e && !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
|
|
/* mask already collected */
|
|
disclose = 0;
|
|
|
|
} else if ( e == &p && !access_allowed( op, &p,
|
|
slap_schema.si_ad_entry, NULL,
|
|
ACL_DISCLOSE, NULL ) )
|
|
{
|
|
disclose = 0;
|
|
}
|
|
|
|
if ( disclose == 0 ) {
|
|
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
|
rs->sr_text = NULL;
|
|
rs->sr_matched = NULL;
|
|
if ( rs->sr_ref ) {
|
|
ber_bvarray_free( rs->sr_ref );
|
|
rs->sr_ref = NULL;
|
|
}
|
|
}
|
|
}
|
|
#endif /* SLAP_ACL_HONOR_DISCLOSE */
|
|
|
|
send_ldap_result( op, rs );
|
|
|
|
if ( !BER_BVISNULL( &realdn )
|
|
&& realdn.bv_val != op->ora_e->e_name.bv_val )
|
|
{
|
|
ch_free( realdn.bv_val );
|
|
}
|
|
|
|
if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) {
|
|
(void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
|
|
}
|
|
|
|
if ( !BER_BVISNULL( &p.e_nname ) ) {
|
|
backsql_entry_clean( op, &p );
|
|
}
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
|
|
op->ora_e->e_name.bv_val,
|
|
rs->sr_err,
|
|
rs->sr_text ? rs->sr_text : "" );
|
|
|
|
rs->sr_text = NULL;
|
|
rs->sr_matched = NULL;
|
|
if ( rs->sr_ref ) {
|
|
ber_bvarray_free( rs->sr_ref );
|
|
rs->sr_ref = NULL;
|
|
}
|
|
|
|
return rs->sr_err;
|
|
}
|
|
|