Back to index

openldap  2.4.31
add.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1999-2012 The OpenLDAP Foundation.
00005  * Portions Copyright 1999 Dmitry Kovalev.
00006  * Portions Copyright 2002 Pierangelo Masarati.
00007  * Portions Copyright 2004 Mark Adamson.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without
00011  * modification, are permitted only as authorized by the OpenLDAP
00012  * Public License.
00013  *
00014  * A copy of this license is available in the file LICENSE in the
00015  * top-level directory of the distribution or, alternatively, at
00016  * <http://www.OpenLDAP.org/license.html>.
00017  */
00018 /* ACKNOWLEDGEMENTS:
00019  * This work was initially developed by Dmitry Kovalev for inclusion
00020  * by OpenLDAP Software.  Additional significant contributors include
00021  * Pierangelo Masarati and Mark Adamson.
00022 
00023  */
00024 
00025 #include "portable.h"
00026 
00027 #include <stdio.h>
00028 #include <sys/types.h>
00029 #include "ac/string.h"
00030 
00031 #include "slap.h"
00032 #include "proto-sql.h"
00033 
00034 #ifdef BACKSQL_SYNCPROV
00035 #include <lutil.h>
00036 #endif /* BACKSQL_SYNCPROV */
00037 
00038 /*
00039  * Skip:
00040  * - null values (e.g. delete modification)
00041  * - single occurrence of objectClass, because it is already used
00042  *   to determine how to build the SQL entry
00043  * - operational attributes
00044  * - empty attributes
00045  */
00046 #define backsql_opattr_skip(ad) \
00047        (is_at_operational( (ad)->ad_type ) && (ad) != slap_schema.si_ad_ref )
00048 #define       backsql_attr_skip(ad, vals) \
00049        ( \
00050               ( (ad) == slap_schema.si_ad_objectClass \
00051                             && (vals) && BER_BVISNULL( &((vals)[ 1 ]) ) ) \
00052               || backsql_opattr_skip( (ad) ) \
00053               || ( (vals) && BER_BVISNULL( &((vals)[ 0 ]) ) ) \
00054        )
00055 
00056 int
00057 backsql_modify_delete_all_values(
00058        Operation            *op,
00059        SlapReply            *rs,
00060        SQLHDBC                     dbh, 
00061        backsql_entryID             *e_id,
00062        backsql_at_map_rec   *at )
00063 {
00064        backsql_info  *bi = (backsql_info *)op->o_bd->be_private;
00065        RETCODE              rc;
00066        SQLHSTMT      asth = SQL_NULL_HSTMT;
00067        BACKSQL_ROW_NTS      row;
00068 
00069        assert( at != NULL );
00070        if ( at->bam_delete_proc == NULL ) {
00071               Debug( LDAP_DEBUG_TRACE,
00072                      "   backsql_modify_delete_all_values(): "
00073                      "missing attribute value delete procedure "
00074                      "for attr \"%s\"\n",
00075                      at->bam_ad->ad_cname.bv_val, 0, 0 );
00076               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
00077                      rs->sr_text = "SQL-backend error";
00078                      return rs->sr_err = LDAP_OTHER;
00079               }
00080 
00081               return LDAP_SUCCESS;
00082        }
00083 
00084        rc = backsql_Prepare( dbh, &asth, at->bam_query, 0 );
00085        if ( rc != SQL_SUCCESS ) {
00086               Debug( LDAP_DEBUG_TRACE,
00087                      "   backsql_modify_delete_all_values(): "
00088                      "error preparing attribute value select query "
00089                      "\"%s\"\n",
00090                      at->bam_query, 0, 0 );
00091               backsql_PrintErrors( bi->sql_db_env, dbh, 
00092                             asth, rc );
00093 
00094               rs->sr_text = "SQL-backend error";
00095               return rs->sr_err = LDAP_OTHER;
00096        }
00097 
00098        rc = backsql_BindParamID( asth, 1, SQL_PARAM_INPUT, &e_id->eid_keyval );
00099        if ( rc != SQL_SUCCESS ) {
00100               Debug( LDAP_DEBUG_TRACE,
00101                      "   backsql_modify_delete_all_values(): "
00102                      "error binding key value parameter "
00103                      "to attribute value select query\n",
00104                      0, 0, 0 );
00105               backsql_PrintErrors( bi->sql_db_env, dbh, 
00106                             asth, rc );
00107               SQLFreeStmt( asth, SQL_DROP );
00108 
00109               rs->sr_text = "SQL-backend error";
00110               return rs->sr_err = LDAP_OTHER;
00111        }
00112                      
00113        rc = SQLExecute( asth );
00114        if ( !BACKSQL_SUCCESS( rc ) ) {
00115               Debug( LDAP_DEBUG_TRACE,
00116                      "   backsql_modify_delete_all_values(): "
00117                      "error executing attribute value select query\n",
00118                      0, 0, 0 );
00119               backsql_PrintErrors( bi->sql_db_env, dbh, 
00120                             asth, rc );
00121               SQLFreeStmt( asth, SQL_DROP );
00122 
00123               rs->sr_text = "SQL-backend error";
00124               return rs->sr_err = LDAP_OTHER;
00125        }
00126 
00127        backsql_BindRowAsStrings_x( asth, &row, op->o_tmpmemctx );
00128        for ( rc = SQLFetch( asth );
00129                      BACKSQL_SUCCESS( rc );
00130                      rc = SQLFetch( asth ) )
00131        {
00132               int           i;
00133               /* first parameter no, parameter order */
00134               SQLUSMALLINT  pno = 0,
00135                             po = 0;
00136               /* procedure return code */
00137               int           prc = LDAP_SUCCESS;
00138               
00139               for ( i = 0; i < row.ncols; i++ ) {
00140                      SQLHSTMT      sth = SQL_NULL_HSTMT;
00141                      ber_len_t     col_len;
00142                      
00143                      rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
00144                      if ( rc != SQL_SUCCESS ) {
00145                             Debug( LDAP_DEBUG_TRACE,
00146                                    "   backsql_modify_delete_all_values(): "
00147                                    "error preparing attribute value "
00148                                    "delete procedure "
00149                                    "\"%s\"\n",
00150                                    at->bam_delete_proc, 0, 0 );
00151                             backsql_PrintErrors( bi->sql_db_env, dbh, 
00152                                           sth, rc );
00153 
00154                             rs->sr_text = "SQL-backend error";
00155                             rs->sr_err = LDAP_OTHER;
00156                             goto done;
00157                      }
00158 
00159                      if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
00160                             pno = 1;
00161                             rc = backsql_BindParamInt( sth, 1,
00162                                           SQL_PARAM_OUTPUT, &prc );
00163                             if ( rc != SQL_SUCCESS ) {
00164                                    Debug( LDAP_DEBUG_TRACE,
00165                                           "   backsql_modify_delete_all_values(): "
00166                                           "error binding output parameter for %s[%d]\n",
00167                                           at->bam_ad->ad_cname.bv_val, i, 0 );
00168                                    backsql_PrintErrors( bi->sql_db_env, dbh, 
00169                                           sth, rc );
00170                                    SQLFreeStmt( sth, SQL_DROP );
00171 
00172                                    rs->sr_text = "SQL-backend error";
00173                                    rs->sr_err = LDAP_OTHER;
00174                                    goto done;
00175                             }
00176                      }
00177                      po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
00178                      rc = backsql_BindParamID( sth, pno + 1 + po,
00179                             SQL_PARAM_INPUT, &e_id->eid_keyval );
00180                      if ( rc != SQL_SUCCESS ) {
00181                             Debug( LDAP_DEBUG_TRACE,
00182                                    "   backsql_modify_delete_all_values(): "
00183                                    "error binding keyval parameter for %s[%d]\n",
00184                                    at->bam_ad->ad_cname.bv_val, i, 0 );
00185                             backsql_PrintErrors( bi->sql_db_env, dbh, 
00186                                    sth, rc );
00187                             SQLFreeStmt( sth, SQL_DROP );
00188 
00189                             rs->sr_text = "SQL-backend error";
00190                             rs->sr_err = LDAP_OTHER;
00191                             goto done;
00192                      }
00193 
00194                      Debug( LDAP_DEBUG_TRACE,
00195                             "   backsql_modify_delete_all_values() "
00196                             "arg(%d)=" BACKSQL_IDFMT "\n",
00197                             pno + 1 + po,
00198                             BACKSQL_IDARG(e_id->eid_keyval), 0 );
00199 
00200                      /*
00201                       * check for syntax needed here 
00202                       * maybe need binary bind?
00203                       */
00204                      col_len = strlen( row.cols[ i ] );
00205                      rc = backsql_BindParamStr( sth, pno + 2 - po,
00206                             SQL_PARAM_INPUT, row.cols[ i ], col_len );
00207                      if ( rc != SQL_SUCCESS ) {
00208                             Debug( LDAP_DEBUG_TRACE,
00209                                    "   backsql_modify_delete_all_values(): "
00210                                    "error binding value parameter for %s[%d]\n",
00211                                    at->bam_ad->ad_cname.bv_val, i, 0 );
00212                             backsql_PrintErrors( bi->sql_db_env, dbh, 
00213                                    sth, rc );
00214                             SQLFreeStmt( sth, SQL_DROP );
00215 
00216                             rs->sr_text = "SQL-backend error";
00217                             rs->sr_err = LDAP_OTHER;
00218                             goto done;
00219                      }
00220         
00221                      Debug( LDAP_DEBUG_TRACE, 
00222                             "   backsql_modify_delete_all_values(): "
00223                             "arg(%d)=%s; executing \"%s\"\n",
00224                             pno + 2 - po, row.cols[ i ],
00225                             at->bam_delete_proc );
00226                      rc = SQLExecute( sth );
00227                      if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
00228                             rs->sr_err = LDAP_SUCCESS;
00229 
00230                      } else {
00231                             Debug( LDAP_DEBUG_TRACE,
00232                                    "   backsql_modify_delete_all_values(): "
00233                                    "delete_proc "
00234                                    "execution failed (rc=%d, prc=%d)\n",
00235                                    rc, prc, 0 );
00236                             if ( prc != LDAP_SUCCESS ) {
00237                                    /* SQL procedure executed fine 
00238                                     * but returned an error */
00239                                    rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
00240 
00241                             } else {
00242                                    backsql_PrintErrors( bi->sql_db_env, dbh,
00243                                                  sth, rc );
00244                                    rs->sr_err = LDAP_OTHER;
00245                             }
00246                             rs->sr_text = op->o_req_dn.bv_val;
00247                             SQLFreeStmt( sth, SQL_DROP );
00248                             goto done;
00249                      }
00250                      SQLFreeStmt( sth, SQL_DROP );
00251               }
00252        }
00253 
00254        rs->sr_err = LDAP_SUCCESS;
00255 
00256 done:;
00257        backsql_FreeRow_x( &row, op->o_tmpmemctx );
00258        SQLFreeStmt( asth, SQL_DROP );
00259 
00260        return rs->sr_err;
00261 }
00262 
00263 int
00264 backsql_modify_internal(
00265        Operation            *op,
00266        SlapReply            *rs,
00267        SQLHDBC                     dbh, 
00268        backsql_oc_map_rec   *oc,
00269        backsql_entryID             *e_id,
00270        Modifications        *modlist )
00271 {
00272        backsql_info  *bi = (backsql_info *)op->o_bd->be_private;
00273        RETCODE              rc;
00274        Modifications *ml;
00275 
00276        Debug( LDAP_DEBUG_TRACE, "==>backsql_modify_internal(): "
00277               "traversing modifications list\n", 0, 0, 0 );
00278 
00279        for ( ml = modlist; ml != NULL; ml = ml->sml_next ) {
00280               AttributeDescription *ad;
00281               int                  sm_op;
00282               static char          *sm_ops[] = { "add", "delete", "replace", "increment", NULL };
00283 
00284               BerVarray            sm_values;
00285 #if 0
00286               /* NOTE: some day we'll have to pass 
00287                * the normalized values as well */
00288               BerVarray            sm_nvalues;
00289 #endif
00290               backsql_at_map_rec   *at = NULL;
00291               struct berval        *at_val;
00292               int                  i;
00293               
00294               ad = ml->sml_mod.sm_desc;
00295               sm_op = ( ml->sml_mod.sm_op & LDAP_MOD_OP );
00296               sm_values = ml->sml_mod.sm_values;
00297 #if 0
00298               sm_nvalues = ml->sml_mod.sm_nvalues;
00299 #endif
00300 
00301               Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
00302                      "modifying attribute \"%s\" (%s) according to "
00303                      "mappings for objectClass \"%s\"\n",
00304                      ad->ad_cname.bv_val, sm_ops[ sm_op ], BACKSQL_OC_NAME( oc ) );
00305 
00306               if ( backsql_attr_skip( ad, sm_values ) ) {
00307                      continue;
00308               }
00309 
00310               at = backsql_ad2at( oc, ad );
00311               if ( at == NULL ) {
00312                      Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
00313                             "attribute \"%s\" is not registered "
00314                             "in objectClass \"%s\"\n",
00315                             ad->ad_cname.bv_val, BACKSQL_OC_NAME( oc ), 0 );
00316 
00317                      if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
00318                             rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00319                             rs->sr_text = "operation not permitted "
00320                                    "within namingContext";
00321                             goto done;
00322                      }
00323 
00324                      continue;
00325               }
00326   
00327               switch ( sm_op ) {
00328               case LDAP_MOD_REPLACE: {
00329                      Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
00330                             "replacing values for attribute \"%s\"\n",
00331                             at->bam_ad->ad_cname.bv_val, 0, 0 );
00332 
00333                      if ( at->bam_add_proc == NULL ) {
00334                             Debug( LDAP_DEBUG_TRACE,
00335                                    "   backsql_modify_internal(): "
00336                                    "add procedure is not defined "
00337                                    "for attribute \"%s\" "
00338                                    "- unable to perform replacements\n",
00339                                    at->bam_ad->ad_cname.bv_val, 0, 0 );
00340 
00341                             if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
00342                                    rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00343                                    rs->sr_text = "operation not permitted "
00344                                           "within namingContext";
00345                                    goto done;
00346                             }
00347 
00348                             break;
00349                      }
00350 
00351                      if ( at->bam_delete_proc == NULL ) {
00352                             if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
00353                                    Debug( LDAP_DEBUG_TRACE,
00354                                           "   backsql_modify_internal(): "
00355                                           "delete procedure is not defined "
00356                                           "for attribute \"%s\"\n",
00357                                           at->bam_ad->ad_cname.bv_val, 0, 0 );
00358 
00359                                    rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00360                                    rs->sr_text = "operation not permitted "
00361                                           "within namingContext";
00362                                    goto done;
00363                             }
00364 
00365                             Debug( LDAP_DEBUG_TRACE,
00366                                    "   backsql_modify_internal(): "
00367                                    "delete procedure is not defined "
00368                                    "for attribute \"%s\" "
00369                                    "- adding only\n",
00370                                    at->bam_ad->ad_cname.bv_val, 0, 0 );
00371 
00372                             goto add_only;
00373                      }
00374 
00375 del_all:
00376                      rs->sr_err = backsql_modify_delete_all_values( op, rs, dbh, e_id, at );
00377                      if ( rs->sr_err != LDAP_SUCCESS ) {
00378                             goto done;
00379                      }
00380 
00381                      /* LDAP_MOD_DELETE gets here if all values must be deleted */
00382                      if ( sm_op == LDAP_MOD_DELETE ) {
00383                             break;
00384                      }
00385                      }
00386 
00387               /*
00388                * PASSTHROUGH - to add new attributes -- do NOT add break
00389                */
00390               case LDAP_MOD_ADD:
00391               /* case SLAP_MOD_SOFTADD: */
00392               /* case SLAP_MOD_ADD_IF_NOT_PRESENT: */
00393 add_only:;
00394                      if ( at->bam_add_proc == NULL ) {
00395                             Debug( LDAP_DEBUG_TRACE,
00396                                    "   backsql_modify_internal(): "
00397                                    "add procedure is not defined "
00398                                    "for attribute \"%s\"\n",
00399                                    at->bam_ad->ad_cname.bv_val, 0, 0 );
00400 
00401                             if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
00402                                    rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00403                                    rs->sr_text = "operation not permitted "
00404                                           "within namingContext";
00405                                    goto done;
00406                             }
00407 
00408                             break;
00409                      }
00410                      
00411                      Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
00412                             "adding new values for attribute \"%s\"\n",
00413                             at->bam_ad->ad_cname.bv_val, 0, 0 );
00414 
00415                      /* can't add a NULL val array */
00416                      assert( sm_values != NULL );
00417                      
00418                      for ( i = 0, at_val = sm_values;
00419                                    !BER_BVISNULL( at_val ); 
00420                                    i++, at_val++ )
00421                      {
00422                             SQLHSTMT      sth = SQL_NULL_HSTMT;
00423                             /* first parameter position, parameter order */
00424                             SQLUSMALLINT  pno = 0,
00425                                           po;
00426                             /* procedure return code */
00427                             int           prc = LDAP_SUCCESS;
00428 
00429                             rc = backsql_Prepare( dbh, &sth, at->bam_add_proc, 0 );
00430                             if ( rc != SQL_SUCCESS ) {
00431                                    Debug( LDAP_DEBUG_TRACE,
00432                                           "   backsql_modify_internal(): "
00433                                           "error preparing add query\n", 
00434                                           0, 0, 0 );
00435                                    backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
00436 
00437                                    rs->sr_err = LDAP_OTHER;
00438                                    rs->sr_text = "SQL-backend error";
00439                                    goto done;
00440                             }
00441 
00442                             if ( BACKSQL_IS_ADD( at->bam_expect_return ) ) {
00443                                    pno = 1;
00444                                    rc = backsql_BindParamInt( sth, 1,
00445                                           SQL_PARAM_OUTPUT, &prc );
00446                                    if ( rc != SQL_SUCCESS ) {
00447                                           Debug( LDAP_DEBUG_TRACE,
00448                                                  "   backsql_modify_internal(): "
00449                                                  "error binding output parameter for %s[%d]\n",
00450                                                  at->bam_ad->ad_cname.bv_val, i, 0 );
00451                                           backsql_PrintErrors( bi->sql_db_env, dbh, 
00452                                                  sth, rc );
00453                                           SQLFreeStmt( sth, SQL_DROP );
00454 
00455                                           rs->sr_text = "SQL-backend error";
00456                                           rs->sr_err = LDAP_OTHER;
00457                                           goto done;
00458                                    }
00459                             }
00460                             po = ( BACKSQL_IS_ADD( at->bam_param_order ) ) > 0;
00461                             rc = backsql_BindParamID( sth, pno + 1 + po,
00462                                    SQL_PARAM_INPUT, &e_id->eid_keyval );
00463                             if ( rc != SQL_SUCCESS ) {
00464                                    Debug( LDAP_DEBUG_TRACE,
00465                                           "   backsql_modify_internal(): "
00466                                           "error binding keyval parameter for %s[%d]\n",
00467                                           at->bam_ad->ad_cname.bv_val, i, 0 );
00468                                    backsql_PrintErrors( bi->sql_db_env, dbh, 
00469                                           sth, rc );
00470                                    SQLFreeStmt( sth, SQL_DROP );
00471 
00472                                    rs->sr_text = "SQL-backend error";
00473                                    rs->sr_err = LDAP_OTHER;
00474                                    goto done;
00475                             }
00476 
00477                             Debug( LDAP_DEBUG_TRACE,
00478                                    "   backsql_modify_internal(): "
00479                                    "arg(%d)=" BACKSQL_IDFMT "\n", 
00480                                    pno + 1 + po,
00481                                    BACKSQL_IDARG(e_id->eid_keyval), 0 );
00482 
00483                             /*
00484                              * check for syntax needed here
00485                              * maybe need binary bind?
00486                              */
00487                             rc = backsql_BindParamBerVal( sth, pno + 2 - po,
00488                                    SQL_PARAM_INPUT, at_val );
00489                             if ( rc != SQL_SUCCESS ) {
00490                                    Debug( LDAP_DEBUG_TRACE,
00491                                           "   backsql_modify_internal(): "
00492                                           "error binding value parameter for %s[%d]\n",
00493                                           at->bam_ad->ad_cname.bv_val, i, 0 );
00494                                    backsql_PrintErrors( bi->sql_db_env, dbh, 
00495                                           sth, rc );
00496                                    SQLFreeStmt( sth, SQL_DROP );
00497 
00498                                    rs->sr_text = "SQL-backend error";
00499                                    rs->sr_err = LDAP_OTHER;
00500                                    goto done;
00501                             }
00502                             Debug( LDAP_DEBUG_TRACE,
00503                                    "   backsql_modify_internal(): "
00504                                    "arg(%d)=\"%s\"; executing \"%s\"\n", 
00505                                    pno + 2 - po, at_val->bv_val,
00506                                    at->bam_add_proc );
00507 
00508                             rc = SQLExecute( sth );
00509                             if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
00510                                    rs->sr_err = LDAP_SUCCESS;
00511 
00512                             } else {
00513                                    Debug( LDAP_DEBUG_TRACE,
00514                                           "   backsql_modify_internal(): "
00515                                           "add_proc execution failed "
00516                                           "(rc=%d, prc=%d)\n",
00517                                           rc, prc, 0 );
00518                                    if ( prc != LDAP_SUCCESS ) {
00519                                           /* SQL procedure executed fine 
00520                                            * but returned an error */
00521                                           SQLFreeStmt( sth, SQL_DROP );
00522 
00523                                           rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
00524                                           rs->sr_text = at->bam_ad->ad_cname.bv_val;
00525                                           return rs->sr_err;
00526                                    
00527                                    } else {
00528                                           backsql_PrintErrors( bi->sql_db_env, dbh,
00529                                                         sth, rc );
00530                                           if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) 
00531                                           {
00532                                                  SQLFreeStmt( sth, SQL_DROP );
00533 
00534                                                  rs->sr_err = LDAP_OTHER;
00535                                                  rs->sr_text = "SQL-backend error";
00536                                                  goto done;
00537                                           }
00538                                    }
00539                             }
00540                             SQLFreeStmt( sth, SQL_DROP );
00541                      }
00542                      break;
00543                      
00544               case LDAP_MOD_DELETE:
00545               /* case SLAP_MOD_SOFTDEL: */
00546                      if ( at->bam_delete_proc == NULL ) {
00547                             Debug( LDAP_DEBUG_TRACE,
00548                                    "   backsql_modify_internal(): "
00549                                    "delete procedure is not defined "
00550                                    "for attribute \"%s\"\n",
00551                                    at->bam_ad->ad_cname.bv_val, 0, 0 );
00552 
00553                             if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
00554                                    rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00555                                    rs->sr_text = "operation not permitted "
00556                                           "within namingContext";
00557                                    goto done;
00558                             }
00559 
00560                             break;
00561                      }
00562 
00563                      if ( sm_values == NULL ) {
00564                             Debug( LDAP_DEBUG_TRACE,
00565                                    "   backsql_modify_internal(): "
00566                                    "no values given to delete "
00567                                    "for attribute \"%s\" "
00568                                    "-- deleting all values\n",
00569                                    at->bam_ad->ad_cname.bv_val, 0, 0 );
00570                             goto del_all;
00571                      }
00572 
00573                      Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
00574                             "deleting values for attribute \"%s\"\n",
00575                             at->bam_ad->ad_cname.bv_val, 0, 0 );
00576 
00577                      for ( i = 0, at_val = sm_values;
00578                                    !BER_BVISNULL( at_val );
00579                                    i++, at_val++ )
00580                      {
00581                             SQLHSTMT      sth = SQL_NULL_HSTMT;
00582                             /* first parameter position, parameter order */
00583                             SQLUSMALLINT  pno = 0,
00584                                           po;
00585                             /* procedure return code */
00586                             int           prc = LDAP_SUCCESS;
00587 
00588                             rc = backsql_Prepare( dbh, &sth, at->bam_delete_proc, 0 );
00589                             if ( rc != SQL_SUCCESS ) {
00590                                    Debug( LDAP_DEBUG_TRACE,
00591                                           "   backsql_modify_internal(): "
00592                                           "error preparing delete query\n", 
00593                                           0, 0, 0 );
00594                                    backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
00595 
00596                                    rs->sr_err = LDAP_OTHER;
00597                                    rs->sr_text = "SQL-backend error";
00598                                    goto done;
00599                             }
00600 
00601                             if ( BACKSQL_IS_DEL( at->bam_expect_return ) ) {
00602                                    pno = 1;
00603                                    rc = backsql_BindParamInt( sth, 1,
00604                                           SQL_PARAM_OUTPUT, &prc );
00605                                    if ( rc != SQL_SUCCESS ) {
00606                                           Debug( LDAP_DEBUG_TRACE,
00607                                                  "   backsql_modify_internal(): "
00608                                                  "error binding output parameter for %s[%d]\n",
00609                                                  at->bam_ad->ad_cname.bv_val, i, 0 );
00610                                           backsql_PrintErrors( bi->sql_db_env, dbh, 
00611                                                  sth, rc );
00612                                           SQLFreeStmt( sth, SQL_DROP );
00613 
00614                                           rs->sr_text = "SQL-backend error";
00615                                           rs->sr_err = LDAP_OTHER;
00616                                           goto done;
00617                                    }
00618                             }
00619                             po = ( BACKSQL_IS_DEL( at->bam_param_order ) ) > 0;
00620                             rc = backsql_BindParamID( sth, pno + 1 + po,
00621                                    SQL_PARAM_INPUT, &e_id->eid_keyval );
00622                             if ( rc != SQL_SUCCESS ) {
00623                                    Debug( LDAP_DEBUG_TRACE,
00624                                           "   backsql_modify_internal(): "
00625                                           "error binding keyval parameter for %s[%d]\n",
00626                                           at->bam_ad->ad_cname.bv_val, i, 0 );
00627                                    backsql_PrintErrors( bi->sql_db_env, dbh, 
00628                                           sth, rc );
00629                                    SQLFreeStmt( sth, SQL_DROP );
00630 
00631                                    rs->sr_text = "SQL-backend error";
00632                                    rs->sr_err = LDAP_OTHER;
00633                                    goto done;
00634                             }
00635 
00636                             Debug( LDAP_DEBUG_TRACE,
00637                                    "   backsql_modify_internal(): "
00638                                    "arg(%d)=" BACKSQL_IDFMT "\n", 
00639                                    pno + 1 + po,
00640                                    BACKSQL_IDARG(e_id->eid_keyval), 0 );
00641 
00642                             /*
00643                              * check for syntax needed here 
00644                              * maybe need binary bind?
00645                              */
00646                             rc = backsql_BindParamBerVal( sth, pno + 2 - po,
00647                                    SQL_PARAM_INPUT, at_val );
00648                             if ( rc != SQL_SUCCESS ) {
00649                                    Debug( LDAP_DEBUG_TRACE,
00650                                           "   backsql_modify_internal(): "
00651                                           "error binding value parameter for %s[%d]\n",
00652                                           at->bam_ad->ad_cname.bv_val, i, 0 );
00653                                    backsql_PrintErrors( bi->sql_db_env, dbh, 
00654                                           sth, rc );
00655                                    SQLFreeStmt( sth, SQL_DROP );
00656 
00657                                    rs->sr_text = "SQL-backend error";
00658                                    rs->sr_err = LDAP_OTHER;
00659                                    goto done;
00660                             }
00661 
00662                             Debug( LDAP_DEBUG_TRACE,
00663                                    "   backsql_modify_internal(): "
00664                                    "executing \"%s\"\n", 
00665                                    at->bam_delete_proc, 0, 0 );
00666                             rc = SQLExecute( sth );
00667                             if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS )
00668                             {
00669                                    rs->sr_err = LDAP_SUCCESS;
00670                                    
00671                             } else {
00672                                    Debug( LDAP_DEBUG_TRACE,
00673                                           "   backsql_modify_internal(): "
00674                                           "delete_proc execution "
00675                                           "failed (rc=%d, prc=%d)\n",
00676                                           rc, prc, 0 );
00677 
00678                                    if ( prc != LDAP_SUCCESS ) {
00679                                           /* SQL procedure executed fine
00680                                            * but returned an error */
00681                                           rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
00682                                           rs->sr_text = at->bam_ad->ad_cname.bv_val;
00683                                           goto done;
00684                                           
00685                                    } else {
00686                                           backsql_PrintErrors( bi->sql_db_env,
00687                                                         dbh, sth, rc );
00688                                           SQLFreeStmt( sth, SQL_DROP );
00689                                           rs->sr_err = LDAP_OTHER;
00690                                           rs->sr_text = at->bam_ad->ad_cname.bv_val;
00691                                           goto done;
00692                                    }
00693                             }
00694                             SQLFreeStmt( sth, SQL_DROP );
00695                      }
00696                      break;
00697 
00698               case LDAP_MOD_INCREMENT:
00699                      Debug( LDAP_DEBUG_TRACE, "   backsql_modify_internal(): "
00700                             "increment not supported yet\n", 0, 0, 0 );
00701                      if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
00702                             rs->sr_err = LDAP_OTHER;
00703                             rs->sr_text = "SQL-backend error";
00704                             goto done;
00705                      }
00706                      break;
00707               }
00708        }
00709 
00710 done:;
00711        Debug( LDAP_DEBUG_TRACE, "<==backsql_modify_internal(): %d%s%s\n",
00712               rs->sr_err,
00713               rs->sr_text ? ": " : "",
00714               rs->sr_text ? rs->sr_text : "" );
00715 
00716        /*
00717         * FIXME: should fail in case one change fails?
00718         */
00719        return rs->sr_err;
00720 }
00721 
00722 static int
00723 backsql_add_attr(
00724        Operation            *op,
00725        SlapReply            *rs,
00726        SQLHDBC              dbh,
00727        backsql_oc_map_rec   *oc,
00728        Attribute            *at,
00729        backsql_key_t        new_keyval )
00730 {
00731        backsql_info         *bi = (backsql_info*)op->o_bd->be_private;
00732        backsql_at_map_rec   *at_rec = NULL;
00733        struct berval        *at_val;
00734        unsigned long        i;
00735        RETCODE                     rc;
00736        SQLUSMALLINT         currpos;
00737        SQLHSTMT             sth = SQL_NULL_HSTMT;
00738 
00739        at_rec = backsql_ad2at( oc, at->a_desc ); 
00740   
00741        if ( at_rec == NULL ) {
00742               Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
00743                      "attribute \"%s\" is not registered "
00744                      "in objectclass \"%s\"\n",
00745                      op->ora_e->e_name.bv_val,
00746                      at->a_desc->ad_cname.bv_val,
00747                      BACKSQL_OC_NAME( oc ) );
00748 
00749               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
00750                      rs->sr_text = "operation not permitted "
00751                             "within namingContext";
00752                      return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00753               }
00754 
00755               return LDAP_SUCCESS;
00756        }
00757        
00758        if ( at_rec->bam_add_proc == NULL ) {
00759               Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
00760                      "add procedure is not defined "
00761                      "for attribute \"%s\" "
00762                      "of structuralObjectClass \"%s\"\n",
00763                      op->ora_e->e_name.bv_val,
00764                      at->a_desc->ad_cname.bv_val,
00765                      BACKSQL_OC_NAME( oc ) );
00766 
00767               if ( BACKSQL_FAIL_IF_NO_MAPPING( bi ) ) {
00768                      rs->sr_text = "operation not permitted "
00769                             "within namingContext";
00770                      return rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
00771               }
00772 
00773               return LDAP_SUCCESS;
00774        }
00775 
00776        for ( i = 0, at_val = &at->a_vals[ i ];
00777                             !BER_BVISNULL( at_val );
00778                      i++, at_val = &at->a_vals[ i ] )
00779        {
00780               /* procedure return code */
00781               int           prc = LDAP_SUCCESS;
00782               /* first parameter #, parameter order */
00783               SQLUSMALLINT  pno, po;
00784               char          logbuf[ STRLENOF("val[], id=") + 2*LDAP_PVT_INTTYPE_CHARS(unsigned long)];
00785               
00786               /*
00787                * Do not deal with the objectClass that is used
00788                * to build the entry
00789                */
00790               if ( at->a_desc == slap_schema.si_ad_objectClass ) {
00791                      if ( dn_match( at_val, &oc->bom_oc->soc_cname ) )
00792                      {
00793                             continue;
00794                      }
00795               }
00796 
00797               rc = backsql_Prepare( dbh, &sth, at_rec->bam_add_proc, 0 );
00798               if ( rc != SQL_SUCCESS ) {
00799                      rs->sr_text = "SQL-backend error";
00800                      return rs->sr_err = LDAP_OTHER;
00801               }
00802 
00803               if ( BACKSQL_IS_ADD( at_rec->bam_expect_return ) ) {
00804                      pno = 1;
00805                      rc = backsql_BindParamInt( sth, 1, SQL_PARAM_OUTPUT, &prc );
00806                      if ( rc != SQL_SUCCESS ) {
00807                             Debug( LDAP_DEBUG_TRACE,
00808                                    "   backsql_add_attr(): "
00809                                    "error binding output parameter for %s[%lu]\n",
00810                                    at_rec->bam_ad->ad_cname.bv_val, i, 0 );
00811                             backsql_PrintErrors( bi->sql_db_env, dbh, 
00812                                    sth, rc );
00813                             SQLFreeStmt( sth, SQL_DROP );
00814 
00815                             rs->sr_text = "SQL-backend error";
00816                             return rs->sr_err = LDAP_OTHER;
00817                      }
00818 
00819               } else {
00820                      pno = 0;
00821               }
00822 
00823               po = ( BACKSQL_IS_ADD( at_rec->bam_param_order ) ) > 0;
00824               currpos = pno + 1 + po;
00825               rc = backsql_BindParamNumID( sth, currpos,
00826                             SQL_PARAM_INPUT, &new_keyval );
00827               if ( rc != SQL_SUCCESS ) {
00828                      Debug( LDAP_DEBUG_TRACE,
00829                             "   backsql_add_attr(): "
00830                             "error binding keyval parameter for %s[%lu]\n",
00831                             at_rec->bam_ad->ad_cname.bv_val, i, 0 );
00832                      backsql_PrintErrors( bi->sql_db_env, dbh, 
00833                             sth, rc );
00834                      SQLFreeStmt( sth, SQL_DROP );
00835 
00836                      rs->sr_text = "SQL-backend error";
00837                      return rs->sr_err = LDAP_OTHER;
00838               }
00839 
00840               currpos = pno + 2 - po;
00841 
00842               /*
00843                * check for syntax needed here 
00844                * maybe need binary bind?
00845                */
00846 
00847               rc = backsql_BindParamBerVal( sth, currpos, SQL_PARAM_INPUT, at_val );
00848               if ( rc != SQL_SUCCESS ) {
00849                      Debug( LDAP_DEBUG_TRACE,
00850                             "   backsql_add_attr(): "
00851                             "error binding value parameter for %s[%lu]\n",
00852                             at_rec->bam_ad->ad_cname.bv_val, i, 0 );
00853                      backsql_PrintErrors( bi->sql_db_env, dbh, 
00854                             sth, rc );
00855                      SQLFreeStmt( sth, SQL_DROP );
00856 
00857                      rs->sr_text = "SQL-backend error";
00858                      return rs->sr_err = LDAP_OTHER;
00859               }
00860 
00861 #ifdef LDAP_DEBUG
00862               if ( LogTest( LDAP_DEBUG_TRACE ) ) {
00863                      snprintf( logbuf, sizeof( logbuf ), "val[%lu], id=" BACKSQL_IDNUMFMT,
00864                                    i, new_keyval );
00865                      Debug( LDAP_DEBUG_TRACE, "   backsql_add_attr(\"%s\"): "
00866                             "executing \"%s\" %s\n", 
00867                             op->ora_e->e_name.bv_val,
00868                             at_rec->bam_add_proc, logbuf );
00869               }
00870 #endif
00871               rc = SQLExecute( sth );
00872               if ( rc == SQL_SUCCESS && prc == LDAP_SUCCESS ) {
00873                      rs->sr_err = LDAP_SUCCESS;
00874 
00875               } else {
00876                      Debug( LDAP_DEBUG_TRACE,
00877                             "   backsql_add_attr(\"%s\"): "
00878                             "add_proc execution failed (rc=%d, prc=%d)\n", 
00879                             op->ora_e->e_name.bv_val, rc, prc );
00880                      if ( prc != LDAP_SUCCESS ) {
00881                             /* SQL procedure executed fine
00882                              * but returned an error */
00883                             rs->sr_err = BACKSQL_SANITIZE_ERROR( prc );
00884                             rs->sr_text = op->ora_e->e_name.bv_val;
00885                             SQLFreeStmt( sth, SQL_DROP );
00886                             return rs->sr_err;
00887 
00888                      } else {
00889                             backsql_PrintErrors( bi->sql_db_env, dbh,
00890                                           sth, rc );
00891                             rs->sr_err = LDAP_OTHER;
00892                             rs->sr_text = op->ora_e->e_name.bv_val;
00893                             SQLFreeStmt( sth, SQL_DROP );
00894                             return rs->sr_err;
00895                      }
00896               }
00897               SQLFreeStmt( sth, SQL_DROP );
00898        }
00899 
00900        return LDAP_SUCCESS;
00901 }
00902 
00903 int
00904 backsql_add( Operation *op, SlapReply *rs )
00905 {
00906        backsql_info         *bi = (backsql_info*)op->o_bd->be_private;
00907        SQLHDBC              dbh = SQL_NULL_HDBC;
00908        SQLHSTMT             sth = SQL_NULL_HSTMT;
00909        backsql_key_t        new_keyval = 0;
00910        RETCODE                     rc;
00911        backsql_oc_map_rec   *oc = NULL;
00912        backsql_srch_info    bsi = { 0 };
00913        Entry                p = { 0 }, *e = NULL;
00914        Attribute            *at,
00915                             *at_objectClass = NULL;
00916        ObjectClass          *soc = NULL;
00917        struct berval        scname = BER_BVNULL;
00918        struct berval        pdn;
00919        struct berval        realdn = BER_BVNULL;
00920        int                  colnum;
00921        slap_mask_t          mask;
00922 
00923        char                 textbuf[ SLAP_TEXT_BUFLEN ];
00924        size_t               textlen = sizeof( textbuf );
00925 
00926 #ifdef BACKSQL_SYNCPROV
00927        /*
00928         * NOTE: fake successful result to force contextCSN to be bumped up
00929         */
00930        if ( op->o_sync ) {
00931               char          buf[ LDAP_PVT_CSNSTR_BUFSIZE ];
00932               struct berval csn;
00933 
00934               csn.bv_val = buf;
00935               csn.bv_len = sizeof( buf );
00936               slap_get_csn( op, &csn, 1 );
00937 
00938               rs->sr_err = LDAP_SUCCESS;
00939               send_ldap_result( op, rs );
00940 
00941               slap_graduate_commit_csn( op );
00942 
00943               return 0;
00944        }
00945 #endif /* BACKSQL_SYNCPROV */
00946 
00947        Debug( LDAP_DEBUG_TRACE, "==>backsql_add(\"%s\")\n",
00948                      op->ora_e->e_name.bv_val, 0, 0 );
00949 
00950        /* check schema */
00951        if ( BACKSQL_CHECK_SCHEMA( bi ) ) {
00952               char          textbuf[ SLAP_TEXT_BUFLEN ] = { '\0' };
00953 
00954               rs->sr_err = entry_schema_check( op, op->ora_e, NULL, 0, 1, NULL,
00955                      &rs->sr_text, textbuf, sizeof( textbuf ) );
00956               if ( rs->sr_err != LDAP_SUCCESS ) {
00957                      Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
00958                             "entry failed schema check -- aborting\n",
00959                             op->ora_e->e_name.bv_val, 0, 0 );
00960                      e = NULL;
00961                      goto done;
00962               }
00963        }
00964 
00965        slap_add_opattrs( op, &rs->sr_text, textbuf, textlen, 1 );
00966 
00967        if ( get_assert( op ) &&
00968               ( test_filter( op, op->ora_e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
00969        {
00970               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
00971                      "assertion control failed -- aborting\n",
00972                      op->ora_e->e_name.bv_val, 0, 0 );
00973               e = NULL;
00974               rs->sr_err = LDAP_ASSERTION_FAILED;
00975               goto done;
00976        }
00977 
00978        /* search structuralObjectClass */
00979        for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
00980               if ( at->a_desc == slap_schema.si_ad_structuralObjectClass ) {
00981                      break;
00982               }
00983        }
00984 
00985        /* there must exist */
00986        if ( at == NULL ) {
00987               char          buf[ SLAP_TEXT_BUFLEN ];
00988               const char    *text;
00989 
00990               /* search structuralObjectClass */
00991               for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
00992                      if ( at->a_desc == slap_schema.si_ad_objectClass ) {
00993                             break;
00994                      }
00995               }
00996 
00997               if ( at == NULL ) {
00998                      Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
00999                             "no objectClass\n",
01000                             op->ora_e->e_name.bv_val, 0, 0 );
01001                      rs->sr_err = LDAP_OBJECT_CLASS_VIOLATION;
01002                      e = NULL;
01003                      goto done;
01004               }
01005 
01006               rs->sr_err = structural_class( at->a_vals, &soc, NULL,
01007                             &text, buf, sizeof( buf ), op->o_tmpmemctx );
01008               if ( rs->sr_err != LDAP_SUCCESS ) {
01009                      Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01010                             "%s (%d)\n",
01011                             op->ora_e->e_name.bv_val, text, rs->sr_err );
01012                      e = NULL;
01013                      goto done;
01014               }
01015               scname = soc->soc_cname;
01016 
01017        } else {
01018               scname = at->a_vals[0];
01019        }
01020 
01021        /* I guess we should play with sub/supertypes to find a suitable oc */
01022        oc = backsql_name2oc( bi, &scname );
01023 
01024        if ( oc == NULL ) {
01025               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01026                      "cannot map structuralObjectClass \"%s\" -- aborting\n",
01027                      op->ora_e->e_name.bv_val,
01028                      scname.bv_val, 0 );
01029               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01030               rs->sr_text = "operation not permitted within namingContext";
01031               e = NULL;
01032               goto done;
01033        }
01034 
01035        if ( oc->bom_create_proc == NULL ) {
01036               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01037                      "create procedure is not defined "
01038                      "for structuralObjectClass \"%s\" - aborting\n",
01039                      op->ora_e->e_name.bv_val,
01040                      scname.bv_val, 0 );
01041               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01042               rs->sr_text = "operation not permitted within namingContext";
01043               e = NULL;
01044               goto done;
01045 
01046        } else if ( BACKSQL_CREATE_NEEDS_SELECT( bi )
01047                      && oc->bom_create_keyval == NULL ) {
01048               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01049                      "create procedure needs select procedure, "
01050                      "but none is defined for structuralObjectClass \"%s\" "
01051                      "- aborting\n",
01052                      op->ora_e->e_name.bv_val,
01053                      scname.bv_val, 0 );
01054               rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
01055               rs->sr_text = "operation not permitted within namingContext";
01056               e = NULL;
01057               goto done;
01058        }
01059 
01060        /* check write access */
01061        if ( !access_allowed_mask( op, op->ora_e,
01062                             slap_schema.si_ad_entry,
01063                             NULL, ACL_WADD, NULL, &mask ) )
01064        {
01065               rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
01066               e = op->ora_e;
01067               goto done;
01068        }
01069 
01070        rs->sr_err = backsql_get_db_conn( op, &dbh );
01071        if ( rs->sr_err != LDAP_SUCCESS ) {
01072               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01073                      "could not get connection handle - exiting\n", 
01074                      op->ora_e->e_name.bv_val, 0, 0 );
01075               rs->sr_text = ( rs->sr_err == LDAP_OTHER )
01076                      ?  "SQL-backend error" : NULL;
01077               e = NULL;
01078               goto done;
01079        }
01080 
01081        /*
01082         * Check if entry exists
01083         *
01084         * NOTE: backsql_api_dn2odbc() is called explicitly because
01085         * we need the mucked DN to pass it to the create procedure.
01086         */
01087        realdn = op->ora_e->e_name;
01088        if ( backsql_api_dn2odbc( op, rs, &realdn ) ) {
01089               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01090                      "backsql_api_dn2odbc(\"%s\") failed\n", 
01091                      op->ora_e->e_name.bv_val, realdn.bv_val, 0 );
01092               rs->sr_err = LDAP_OTHER;
01093               rs->sr_text = "SQL-backend error";
01094               e = NULL;
01095               goto done;
01096        }
01097 
01098        rs->sr_err = backsql_dn2id( op, rs, dbh, &realdn, NULL, 0, 0 );
01099        if ( rs->sr_err == LDAP_SUCCESS ) {
01100               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01101                      "entry exists\n",
01102                      op->ora_e->e_name.bv_val, 0, 0 );
01103               rs->sr_err = LDAP_ALREADY_EXISTS;
01104               e = op->ora_e;
01105               goto done;
01106        }
01107 
01108        /*
01109         * Get the parent dn and see if the corresponding entry exists.
01110         */
01111        if ( be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
01112               pdn = slap_empty_bv;
01113 
01114        } else {
01115               dnParent( &op->ora_e->e_nname, &pdn );
01116 
01117               /*
01118                * Get the parent
01119                */
01120               bsi.bsi_e = &p;
01121               rs->sr_err = backsql_init_search( &bsi, &pdn,
01122                             LDAP_SCOPE_BASE, 
01123                             (time_t)(-1), NULL, dbh, op, rs, slap_anlist_no_attrs,
01124                             ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
01125               if ( rs->sr_err != LDAP_SUCCESS ) {
01126                      Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
01127                             "could not retrieve addDN parent "
01128                             "\"%s\" ID - %s matched=\"%s\"\n", 
01129                             pdn.bv_val,
01130                             rs->sr_err == LDAP_REFERRAL ? "referral" : "no such entry",
01131                             rs->sr_matched ? rs->sr_matched : "(null)" );
01132                      e = &p;
01133                      goto done;
01134               }
01135 
01136               /* check "children" pseudo-attribute access to parent */
01137               if ( !access_allowed( op, &p, slap_schema.si_ad_children,
01138                                    NULL, ACL_WADD, NULL ) )
01139               {
01140                      rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
01141                      e = &p;
01142                      goto done;
01143               }
01144        }
01145 
01146        /*
01147         * create_proc is executed; if expect_return is set, then
01148         * an output parameter is bound, which should contain 
01149         * the id of the added row; otherwise the procedure
01150         * is expected to return the id as the first column of a select
01151         */
01152        rc = backsql_Prepare( dbh, &sth, oc->bom_create_proc, 0 );
01153        if ( rc != SQL_SUCCESS ) {
01154               rs->sr_err = LDAP_OTHER;
01155               rs->sr_text = "SQL-backend error";
01156               e = NULL;
01157               goto done;
01158        }
01159 
01160        colnum = 1;
01161        if ( BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
01162               rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_OUTPUT, &new_keyval );
01163               if ( rc != SQL_SUCCESS ) {
01164                      Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01165                             "error binding keyval parameter "
01166                             "for objectClass %s\n",
01167                             op->ora_e->e_name.bv_val,
01168                             oc->bom_oc->soc_cname.bv_val, 0 );
01169                      backsql_PrintErrors( bi->sql_db_env, dbh, 
01170                             sth, rc );
01171                      SQLFreeStmt( sth, SQL_DROP );
01172 
01173                      rs->sr_text = "SQL-backend error";
01174                      rs->sr_err = LDAP_OTHER;
01175                      e = NULL;
01176                      goto done;
01177               }
01178               colnum++;
01179        }
01180 
01181        if ( oc->bom_create_hint ) {
01182               at = attr_find( op->ora_e->e_attrs, oc->bom_create_hint );
01183               if ( at && at->a_vals ) {
01184                      backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT,
01185                                    at->a_vals[0].bv_val,
01186                                    at->a_vals[0].bv_len );
01187                      Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
01188                                    "create_proc hint: param = '%s'\n",
01189                                    at->a_vals[0].bv_val, 0, 0 );
01190 
01191               } else {
01192                      backsql_BindParamStr( sth, colnum, SQL_PARAM_INPUT,
01193                                    "", 0 );
01194                      Debug( LDAP_DEBUG_TRACE, "backsql_add(): "
01195                                    "create_proc hint (%s) not avalable\n",
01196                                    oc->bom_create_hint->ad_cname.bv_val,
01197                                    0, 0 );
01198               }
01199               colnum++;
01200        }
01201 
01202        Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): executing \"%s\"\n",
01203               op->ora_e->e_name.bv_val, oc->bom_create_proc, 0 );
01204        rc = SQLExecute( sth );
01205        if ( rc != SQL_SUCCESS ) {
01206               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01207                      "create_proc execution failed\n",
01208                      op->ora_e->e_name.bv_val, 0, 0 );
01209               backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
01210               SQLFreeStmt( sth, SQL_DROP );
01211               rs->sr_err = LDAP_OTHER;
01212               rs->sr_text = "SQL-backend error";
01213               e = NULL;
01214               goto done;
01215        }
01216 
01217        /* FIXME: after SQLExecute(), the row is already inserted
01218         * (at least with PostgreSQL and unixODBC); needs investigation */
01219 
01220        if ( !BACKSQL_IS_ADD( oc->bom_expect_return ) ) {
01221               SWORD         ncols;
01222               SQLLEN        value_len;
01223 
01224               if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
01225                      SQLFreeStmt( sth, SQL_DROP );
01226 
01227                      rc = backsql_Prepare( dbh, &sth, oc->bom_create_keyval, 0 );
01228                      if ( rc != SQL_SUCCESS ) {
01229                             rs->sr_err = LDAP_OTHER;
01230                             rs->sr_text = "SQL-backend error";
01231                             e = NULL;
01232                             goto done;
01233                      }
01234 
01235                      rc = SQLExecute( sth );
01236                      if ( rc != SQL_SUCCESS ) {
01237                             rs->sr_err = LDAP_OTHER;
01238                             rs->sr_text = "SQL-backend error";
01239                             e = NULL;
01240                             goto done;
01241                      }
01242               }
01243 
01244               /*
01245                * the query to know the id of the inserted entry
01246                * must be embedded in the create procedure
01247                */
01248               rc = SQLNumResultCols( sth, &ncols );
01249               if ( rc != SQL_SUCCESS ) {
01250                      Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01251                             "create_proc result evaluation failed\n",
01252                             op->ora_e->e_name.bv_val, 0, 0 );
01253                      backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
01254                      SQLFreeStmt( sth, SQL_DROP );
01255                      rs->sr_err = LDAP_OTHER;
01256                      rs->sr_text = "SQL-backend error";
01257                      e = NULL;
01258                      goto done;
01259 
01260               } else if ( ncols != 1 ) {
01261                      Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01262                             "create_proc result is bogus (ncols=%d)\n",
01263                             op->ora_e->e_name.bv_val, ncols, 0 );
01264                      backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
01265                      SQLFreeStmt( sth, SQL_DROP );
01266                      rs->sr_err = LDAP_OTHER;
01267                      rs->sr_text = "SQL-backend error";
01268                      e = NULL;
01269                      goto done;
01270               }
01271 
01272 #if 0
01273               {
01274                      SQLCHAR              colname[ 64 ];
01275                      SQLSMALLINT   name_len, col_type, col_scale, col_null;
01276                      UDWORD        col_prec;
01277 
01278                      /*
01279                       * FIXME: check whether col_type is compatible,
01280                       * if it can be null and so on ...
01281                       */
01282                      rc = SQLDescribeCol( sth, (SQLUSMALLINT)1, 
01283                                    &colname[ 0 ], 
01284                                    (SQLUINTEGER)( sizeof( colname ) - 1 ),
01285                                    &name_len, &col_type,
01286                                    &col_prec, &col_scale, &col_null );
01287               }
01288 #endif
01289 
01290               rc = SQLBindCol( sth, (SQLUSMALLINT)1, SQL_C_ULONG,
01291                             (SQLPOINTER)&new_keyval, 
01292                             (SQLINTEGER)sizeof( new_keyval ), 
01293                             &value_len );
01294 
01295               rc = SQLFetch( sth );
01296 
01297               if ( value_len <= 0 ) {
01298                      Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01299                             "create_proc result is empty?\n",
01300                             op->ora_e->e_name.bv_val, 0, 0 );
01301                      backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc);
01302                      SQLFreeStmt( sth, SQL_DROP );
01303                      rs->sr_err = LDAP_OTHER;
01304                      rs->sr_text = "SQL-backend error";
01305                      e = NULL;
01306                      goto done;
01307               }
01308        }
01309 
01310        SQLFreeStmt( sth, SQL_DROP );
01311 
01312        Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01313               "create_proc returned keyval=" BACKSQL_IDNUMFMT "\n",
01314               op->ora_e->e_name.bv_val, new_keyval, 0 );
01315 
01316        rc = backsql_Prepare( dbh, &sth, bi->sql_insentry_stmt, 0 );
01317        if ( rc != SQL_SUCCESS ) {
01318               rs->sr_err = LDAP_OTHER;
01319               rs->sr_text = "SQL-backend error";
01320               e = NULL;
01321               goto done;
01322        }
01323        
01324        rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &realdn );
01325        if ( rc != SQL_SUCCESS ) {
01326               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01327                      "error binding DN parameter for objectClass %s\n",
01328                      op->ora_e->e_name.bv_val,
01329                      oc->bom_oc->soc_cname.bv_val, 0 );
01330               backsql_PrintErrors( bi->sql_db_env, dbh, 
01331                      sth, rc );
01332               SQLFreeStmt( sth, SQL_DROP );
01333 
01334               rs->sr_text = "SQL-backend error";
01335               rs->sr_err = LDAP_OTHER;
01336               e = NULL;
01337               goto done;
01338        }
01339 
01340        rc = backsql_BindParamNumID( sth, 2, SQL_PARAM_INPUT, &oc->bom_id );
01341        if ( rc != SQL_SUCCESS ) {
01342               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01343                      "error binding objectClass ID parameter "
01344                      "for objectClass %s\n",
01345                      op->ora_e->e_name.bv_val,
01346                      oc->bom_oc->soc_cname.bv_val, 0 );
01347               backsql_PrintErrors( bi->sql_db_env, dbh, 
01348                      sth, rc );
01349               SQLFreeStmt( sth, SQL_DROP );
01350 
01351               rs->sr_text = "SQL-backend error";
01352               rs->sr_err = LDAP_OTHER;
01353               e = NULL;
01354               goto done;
01355        }
01356 
01357        rc = backsql_BindParamID( sth, 3, SQL_PARAM_INPUT, &bsi.bsi_base_id.eid_id );
01358        if ( rc != SQL_SUCCESS ) {
01359               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01360                      "error binding parent ID parameter "
01361                      "for objectClass %s\n",
01362                      op->ora_e->e_name.bv_val,
01363                      oc->bom_oc->soc_cname.bv_val, 0 );
01364               backsql_PrintErrors( bi->sql_db_env, dbh, 
01365                      sth, rc );
01366               SQLFreeStmt( sth, SQL_DROP );
01367 
01368               rs->sr_text = "SQL-backend error";
01369               rs->sr_err = LDAP_OTHER;
01370               e = NULL;
01371               goto done;
01372        }
01373 
01374        rc = backsql_BindParamNumID( sth, 4, SQL_PARAM_INPUT, &new_keyval );
01375        if ( rc != SQL_SUCCESS ) {
01376               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01377                      "error binding entry ID parameter "
01378                      "for objectClass %s\n",
01379                      op->ora_e->e_name.bv_val,
01380                      oc->bom_oc->soc_cname.bv_val, 0 );
01381               backsql_PrintErrors( bi->sql_db_env, dbh, 
01382                      sth, rc );
01383               SQLFreeStmt( sth, SQL_DROP );
01384 
01385               rs->sr_text = "SQL-backend error";
01386               rs->sr_err = LDAP_OTHER;
01387               e = NULL;
01388               goto done;
01389        }
01390 
01391        if ( LogTest( LDAP_DEBUG_TRACE ) ) {
01392               char buf[ SLAP_TEXT_BUFLEN ];
01393 
01394               snprintf( buf, sizeof(buf),
01395                      "executing \"%s\" for dn=\"%s\"  oc_map_id=" BACKSQL_IDNUMFMT " p_id=" BACKSQL_IDFMT " keyval=" BACKSQL_IDNUMFMT,
01396                      bi->sql_insentry_stmt, op->ora_e->e_name.bv_val,
01397                      oc->bom_id, BACKSQL_IDARG(bsi.bsi_base_id.eid_id),
01398                      new_keyval );
01399               Debug( LDAP_DEBUG_TRACE, "   backsql_add(): %s\n", buf, 0, 0 );
01400        }
01401 
01402        rc = SQLExecute( sth );
01403        if ( rc != SQL_SUCCESS ) {
01404               Debug( LDAP_DEBUG_TRACE, "   backsql_add(\"%s\"): "
01405                      "could not insert ldap_entries record\n",
01406                      op->ora_e->e_name.bv_val, 0, 0 );
01407               backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
01408               
01409               /*
01410                * execute delete_proc to delete data added !!!
01411                */
01412               SQLFreeStmt( sth, SQL_DROP );
01413               rs->sr_err = LDAP_OTHER;
01414               rs->sr_text = "SQL-backend error";
01415               e = NULL;
01416               goto done;
01417        }
01418 
01419        SQLFreeStmt( sth, SQL_DROP );
01420 
01421        for ( at = op->ora_e->e_attrs; at != NULL; at = at->a_next ) {
01422               Debug( LDAP_DEBUG_TRACE, "   backsql_add(): "
01423                      "adding attribute \"%s\"\n", 
01424                      at->a_desc->ad_cname.bv_val, 0, 0 );
01425 
01426               /*
01427                * Skip:
01428                * - the first occurrence of objectClass, which is used
01429                *   to determine how to build the SQL entry (FIXME ?!?)
01430                * - operational attributes
01431                * - empty attributes (FIXME ?!?)
01432                */
01433               if ( backsql_attr_skip( at->a_desc, at->a_vals ) ) {
01434                      continue;
01435               }
01436 
01437               if ( at->a_desc == slap_schema.si_ad_objectClass ) {
01438                      at_objectClass = at;
01439                      continue;
01440               }
01441 
01442               rs->sr_err = backsql_add_attr( op, rs, dbh, oc, at, new_keyval );
01443               if ( rs->sr_err != LDAP_SUCCESS ) {
01444                      e = op->ora_e;
01445                      goto done;
01446               }
01447        }
01448 
01449        if ( at_objectClass ) {
01450               rs->sr_err = backsql_add_attr( op, rs, dbh, oc,
01451                             at_objectClass, new_keyval );
01452               if ( rs->sr_err != LDAP_SUCCESS ) {
01453                      e = op->ora_e;
01454                      goto done;
01455               }
01456        }
01457 
01458 done:;
01459        /*
01460         * Commit only if all operations succeed
01461         */
01462        if ( sth != SQL_NULL_HSTMT ) {
01463               SQLUSMALLINT  CompletionType = SQL_ROLLBACK;
01464 
01465               if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) {
01466                      assert( e == NULL );
01467                      CompletionType = SQL_COMMIT;
01468               }
01469 
01470               SQLTransact( SQL_NULL_HENV, dbh, CompletionType );
01471        }
01472 
01473        /*
01474         * FIXME: NOOP does not work for add -- it works for all 
01475         * the other operations, and I don't get the reason :(
01476         * 
01477         * hint: there might be some autocommit in Postgres
01478         * so that when the unique id of the key table is
01479         * automatically increased, there's no rollback.
01480         * We might implement a "rollback" procedure consisting
01481         * in deleting that row.
01482         */
01483 
01484        if ( e != NULL ) {
01485               int    disclose = 1;
01486 
01487               if ( e == op->ora_e && !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
01488                      /* mask already collected */
01489                      disclose = 0;
01490 
01491               } else if ( e == &p && !access_allowed( op, &p,
01492                                    slap_schema.si_ad_entry, NULL,
01493                                    ACL_DISCLOSE, NULL ) )
01494               {
01495                      disclose = 0;
01496               }
01497 
01498               if ( disclose == 0 ) {
01499                      rs->sr_err = LDAP_NO_SUCH_OBJECT;
01500                      rs->sr_text = NULL;
01501                      rs->sr_matched = NULL;
01502                      if ( rs->sr_ref ) {
01503                             ber_bvarray_free( rs->sr_ref );
01504                             rs->sr_ref = NULL;
01505                      }
01506               }
01507        }
01508 
01509        if ( op->o_noop && rs->sr_err == LDAP_SUCCESS ) {
01510               rs->sr_err = LDAP_X_NO_OPERATION;
01511        }
01512 
01513        send_ldap_result( op, rs );
01514        slap_graduate_commit_csn( op );
01515 
01516        if ( !BER_BVISNULL( &realdn )
01517                      && realdn.bv_val != op->ora_e->e_name.bv_val )
01518        {
01519               ch_free( realdn.bv_val );
01520        }
01521 
01522        if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) {
01523               (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
01524        }
01525 
01526        if ( !BER_BVISNULL( &p.e_nname ) ) {
01527               backsql_entry_clean( op, &p );
01528        }
01529 
01530        Debug( LDAP_DEBUG_TRACE, "<==backsql_add(\"%s\"): %d \"%s\"\n",
01531                      op->ora_e->e_name.bv_val,
01532                      rs->sr_err,
01533                      rs->sr_text ? rs->sr_text : "" );
01534 
01535        rs->sr_text = NULL;
01536        rs->sr_matched = NULL;
01537        if ( rs->sr_ref ) {
01538               ber_bvarray_free( rs->sr_ref );
01539               rs->sr_ref = NULL;
01540        }
01541 
01542        return rs->sr_err;
01543 }
01544