]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/back-sql/init.c
ITS#7158 Fix a crash in back-sql
[openldap] / servers / slapd / back-sql / init.c
index f78b0c7627a14ea95f8253ada8f9f28d460e05b8..055380f9cd312be80eea5bcc61fd0cba877eeb8e 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1999-2005 The OpenLDAP Foundation.
+ * Copyright 1999-2012 The OpenLDAP Foundation.
  * Portions Copyright 1999 Dmitry Kovalev.
  * Portions Copyright 2002 Pierangelo Masarati.
  * All rights reserved.
@@ -27,6 +27,7 @@
 #include "ac/string.h"
 
 #include "slap.h"
+#include "config.h"
 #include "proto-sql.h"
 
 int
@@ -36,14 +37,16 @@ sql_back_initialize(
        static char *controls[] = {
                LDAP_CONTROL_ASSERT,
                LDAP_CONTROL_MANAGEDSAIT,
-#if 0 /* needs improvements */
                LDAP_CONTROL_NOOP,
-#endif
-#ifdef LDAP_CONTROL_VALUESRETURNFILTER
-               LDAP_CONTROL_VALUESRETURNFILTER,
-#endif /* LDAP_CONTROL_VALUESRETURNFILTER */
+#ifdef SLAP_CONTROL_X_TREE_DELETE
+               SLAP_CONTROL_X_TREE_DELETE,
+#endif /* SLAP_CONTROL_X_TREE_DELETE */
+#ifndef BACKSQL_ARBITRARY_KEY
+               LDAP_CONTROL_PAGEDRESULTS,
+#endif /* ! BACKSQL_ARBITRARY_KEY */
                NULL
        };
+       int rc;
 
        bi->bi_controls = controls;
 
@@ -56,7 +59,7 @@ sql_back_initialize(
        Debug( LDAP_DEBUG_TRACE,"==>sql_back_initialize()\n", 0, 0, 0 );
        
        bi->bi_db_init = backsql_db_init;
-       bi->bi_db_config = backsql_db_config;
+       bi->bi_db_config = config_generic_wrapper;
        bi->bi_db_open = backsql_db_open;
        bi->bi_db_close = backsql_db_close;
        bi->bi_db_destroy = backsql_db_destroy;
@@ -74,12 +77,13 @@ sql_back_initialize(
        bi->bi_chk_referrals = 0;
        bi->bi_operational = backsql_operational;
        bi->bi_entry_get_rw = backsql_entry_get;
+       bi->bi_entry_release_rw = backsql_entry_release;
  
        bi->bi_connection_init = 0;
-       bi->bi_connection_destroy = backsql_connection_destroy;
 
+       rc = backsql_init_cf( bi );
        Debug( LDAP_DEBUG_TRACE,"<==sql_back_initialize()\n", 0, 0, 0 );
-       return 0;
+       return rc;
 }
 
 int
@@ -93,65 +97,116 @@ backsql_destroy(
 
 int
 backsql_db_init(
-       BackendDB       *bd )
+       BackendDB       *bd,
+       ConfigReply     *cr )
 {
        backsql_info    *bi;
+       int             rc = 0;
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_db_init()\n", 0, 0, 0 );
+
        bi = (backsql_info *)ch_calloc( 1, sizeof( backsql_info ) );
-       memset( bi, '\0', sizeof( backsql_info ) );
        ldap_pvt_thread_mutex_init( &bi->sql_dbconn_mutex );
        ldap_pvt_thread_mutex_init( &bi->sql_schema_mutex );
-       backsql_init_db_env( bi );
+
+       if ( backsql_init_db_env( bi ) != SQL_SUCCESS ) {
+               rc = -1;
+       }
 
        bd->be_private = bi;
+       bd->be_cf_ocs = bd->bd_info->bi_cf_ocs;
+
        Debug( LDAP_DEBUG_TRACE, "<==backsql_db_init()\n", 0, 0, 0 );
-       return 0;
+
+       return rc;
 }
 
 int
 backsql_db_destroy(
-       BackendDB       *bd )
+       BackendDB       *bd,
+       ConfigReply     *cr )
 {
        backsql_info    *bi = (backsql_info*)bd->be_private;
  
        Debug( LDAP_DEBUG_TRACE, "==>backsql_db_destroy()\n", 0, 0, 0 );
-       ldap_pvt_thread_mutex_lock( &bi->sql_dbconn_mutex );
+
        backsql_free_db_env( bi );
-       ldap_pvt_thread_mutex_unlock( &bi->sql_dbconn_mutex );
        ldap_pvt_thread_mutex_destroy( &bi->sql_dbconn_mutex );
-       ldap_pvt_thread_mutex_lock( &bi->sql_schema_mutex );
        backsql_destroy_schema_map( bi );
-       ldap_pvt_thread_mutex_unlock( &bi->sql_schema_mutex );
        ldap_pvt_thread_mutex_destroy( &bi->sql_schema_mutex );
-       free( bi->sql_dbname );
-       free( bi->sql_dbuser );
+
+       if ( bi->sql_dbname ) {
+               ch_free( bi->sql_dbname );
+       }
+       if ( bi->sql_dbuser ) {
+               ch_free( bi->sql_dbuser );
+       }
        if ( bi->sql_dbpasswd ) {
-               free( bi->sql_dbpasswd );
+               ch_free( bi->sql_dbpasswd );
        }
        if ( bi->sql_dbhost ) {
-               free( bi->sql_dbhost );
+               ch_free( bi->sql_dbhost );
        }
        if ( bi->sql_upper_func.bv_val ) {
-               free( bi->sql_upper_func.bv_val );
-               free( bi->sql_upper_func_open.bv_val );
-               free( bi->sql_upper_func_close.bv_val );
+               ch_free( bi->sql_upper_func.bv_val );
+               ch_free( bi->sql_upper_func_open.bv_val );
+               ch_free( bi->sql_upper_func_close.bv_val );
+       }
+       if ( bi->sql_concat_func ) {
+               ber_bvarray_free( bi->sql_concat_func );
+       }
+       if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
+               ch_free( bi->sql_strcast_func.bv_val );
+       }
+       if ( !BER_BVISNULL( &bi->sql_children_cond ) ) {
+               ch_free( bi->sql_children_cond.bv_val );
+       }
+       if ( !BER_BVISNULL( &bi->sql_dn_match_cond ) ) {
+               ch_free( bi->sql_dn_match_cond.bv_val );
+       }
+       if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
+               ch_free( bi->sql_subtree_cond.bv_val );
+       }
+       if ( !BER_BVISNULL( &bi->sql_dn_oc_aliasing ) ) {
+               ch_free( bi->sql_dn_oc_aliasing.bv_val );
+       }
+       if ( bi->sql_oc_query ) {
+               ch_free( bi->sql_oc_query );
+       }
+       if ( bi->sql_at_query ) {
+               ch_free( bi->sql_at_query );
+       }
+       if ( bi->sql_id_query ) {
+               ch_free( bi->sql_id_query );
+       }
+       if ( bi->sql_has_children_query ) {
+               ch_free( bi->sql_has_children_query );
+       }
+       if ( bi->sql_insentry_stmt ) {
+               ch_free( bi->sql_insentry_stmt );
+       }
+       if ( bi->sql_delentry_stmt ) {
+               ch_free( bi->sql_delentry_stmt );
+       }
+       if ( bi->sql_renentry_stmt ) {
+               ch_free( bi->sql_renentry_stmt );
+       }
+       if ( bi->sql_delobjclasses_stmt ) {
+               ch_free( bi->sql_delobjclasses_stmt );
+       }
+       if ( !BER_BVISNULL( &bi->sql_aliasing ) ) {
+               ch_free( bi->sql_aliasing.bv_val );
+       }
+       if ( !BER_BVISNULL( &bi->sql_aliasing_quote ) ) {
+               ch_free( bi->sql_aliasing_quote.bv_val );
        }
-       
-       free( bi->sql_subtree_cond.bv_val );
-       free( bi->sql_oc_query );
-       free( bi->sql_at_query );
-       free( bi->sql_insentry_stmt );
-       free( bi->sql_delentry_stmt );
-       free( bi->sql_renentry_stmt );
-       free( bi->sql_delobjclasses_stmt );
 
        if ( bi->sql_anlist ) {
                int     i;
 
-               for ( i = 0; !BER_BVISNULL( &bi->sql_anlist[i].an_name ); i++ )
+               for ( i = 0; !BER_BVISNULL( &bi->sql_anlist[ i ].an_name ); i++ )
                {
-                       ch_free( bi->sql_anlist[i].an_name.bv_val );
+                       ch_free( bi->sql_anlist[ i ].an_name.bv_val );
                }
                ch_free( bi->sql_anlist );
        }
@@ -160,7 +215,7 @@ backsql_db_destroy(
                entry_free( bi->sql_baseObject );
        }
        
-       free( bi );
+       ch_free( bi );
        
        Debug( LDAP_DEBUG_TRACE, "<==backsql_db_destroy()\n", 0, 0, 0 );
        return 0;
@@ -168,15 +223,18 @@ backsql_db_destroy(
 
 int
 backsql_db_open(
-       BackendDB       *bd )
+       BackendDB       *bd,
+       ConfigReply     *cr )
 {
        backsql_info    *bi = (backsql_info*)bd->be_private;
-       SQLHDBC         dbh = SQL_NULL_HDBC;
        struct berbuf   bb = BB_NULL;
 
-       char            opbuf[ OPERATION_BUFFER_SIZE ];
-       Operation*      op = (Operation *)opbuf;
-       
+       Connection      conn = { 0 };
+       OperationBuffer opbuf;
+       Operation*      op;
+       SQLHDBC         dbh = SQL_NULL_HDBC;
+       void            *thrctx = ldap_pvt_thread_pool_context();
+
        Debug( LDAP_DEBUG_TRACE, "==>backsql_db_open(): "
                "testing RDBMS connection\n", 0, 0, 0 );
        if ( bi->sql_dbname == NULL ) {
@@ -200,6 +258,21 @@ backsql_db_open(
                }
        }
 
+       /*
+        * see back-sql.h for default values
+        */
+       if ( BER_BVISNULL( &bi->sql_aliasing ) ) {
+               ber_str2bv( BACKSQL_ALIASING,
+                       STRLENOF( BACKSQL_ALIASING ),
+                       1, &bi->sql_aliasing );
+       }
+
+       if ( BER_BVISNULL( &bi->sql_aliasing_quote ) ) {
+               ber_str2bv( BACKSQL_ALIASING_QUOTE,
+                       STRLENOF( BACKSQL_ALIASING_QUOTE ),
+                       1, &bi->sql_aliasing_quote );
+       }
+
        /*
         * Prepare cast string as required
         */
@@ -228,10 +301,10 @@ backsql_db_open(
 
        /* normalize filter values only if necessary */
        bi->sql_caseIgnoreMatch = mr_find( "caseIgnoreMatch" );
-       assert( bi->sql_caseIgnoreMatch );
+       assert( bi->sql_caseIgnoreMatch != NULL );
 
        bi->sql_telephoneNumberMatch = mr_find( "telephoneNumberMatch" );
-       assert( bi->sql_telephoneNumberMatch );
+       assert( bi->sql_telephoneNumberMatch != NULL );
 
        if ( bi->sql_dbuser == NULL ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
@@ -240,7 +313,7 @@ backsql_db_open(
                return 1;
        }
        
-       if ( bi->sql_subtree_cond.bv_val == NULL ) {
+       if ( BER_BVISNULL( &bi->sql_subtree_cond ) ) {
                /*
                 * Prepare concat function for subtree search condition
                 */
@@ -252,25 +325,27 @@ backsql_db_open(
                };
                struct berbuf   bb = BB_NULL;
 
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "subtree search SQL condition not specified "
+                       "(use \"subtree_cond\" directive in slapd.conf); "
+                       "preparing default\n", 
+                       0, 0, 0);
+
                if ( backsql_prepare_pattern( bi->sql_concat_func, values, 
                                &concat ) ) {
                        Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
-                               "unable to prepare CONCAT pattern", 0, 0, 0 );
+                               "unable to prepare CONCAT pattern for subtree search",
+                               0, 0, 0 );
                        return 1;
                }
                        
-               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
-                       "subtree search SQL condition not specified "
-                       "(use \"subtree_cond\" directive in slapd.conf)\n", 
-                       0, 0, 0);
-
                if ( bi->sql_upper_func.bv_val ) {
 
                        /*
                         * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%',?))
                         */
 
-                       backsql_strfcat( &bb, "blbbb",
+                       backsql_strfcat_x( &bb, NULL, "blbbb",
                                        &bi->sql_upper_func,
                                        (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ),
                                                "(ldap_entries.dn) LIKE ",
@@ -284,34 +359,59 @@ backsql_db_open(
                         * ldap_entries.dn LIKE CONCAT('%',?)
                         */
 
-                       backsql_strfcat( &bb, "lb",
+                       backsql_strfcat_x( &bb, NULL, "lb",
                                        (ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ),
                                                "ldap_entries.dn LIKE ",
                                        &concat );
                }
 
+               ch_free( concat.bv_val );
+
                bi->sql_subtree_cond = bb.bb_val;
                        
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
-                       "setting \"%s\" as default\n",
+                       "setting \"%s\" as default \"subtree_cond\"\n",
                        bi->sql_subtree_cond.bv_val, 0, 0 );
        }
 
        if ( bi->sql_children_cond.bv_val == NULL ) {
+               /*
+                * Prepare concat function for children search condition
+                */
+               struct berval   concat;
+               struct berval   values[] = {
+                       BER_BVC( "'%,'" ),
+                       BER_BVC( "?" ),
+                       BER_BVNULL
+               };
                struct berbuf   bb = BB_NULL;
 
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "children search SQL condition not specified "
+                       "(use \"children_cond\" directive in slapd.conf); "
+                       "preparing default\n", 
+                       0, 0, 0);
+
+               if ( backsql_prepare_pattern( bi->sql_concat_func, values, 
+                               &concat ) ) {
+                       Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                               "unable to prepare CONCAT pattern for children search", 0, 0, 0 );
+                       return 1;
+               }
+                       
                if ( bi->sql_upper_func.bv_val ) {
 
                        /*
                         * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%,',?))
                         */
 
-                       backsql_strfcat( &bb, "blbl",
+                       backsql_strfcat_x( &bb, NULL, "blbbb",
                                        &bi->sql_upper_func,
-                                       (ber_len_t)STRLENOF( "(ldap_entries.dn)=" ),
-                                               "(ldap_entries.dn)=",
-                                       &bi->sql_upper_func,
-                                       (ber_len_t)STRLENOF( "(?)" ), "(?)" );
+                                       (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ),
+                                               "(ldap_entries.dn) LIKE ",
+                                       &bi->sql_upper_func_open,
+                                       &concat,
+                                       &bi->sql_upper_func_close );
 
                } else {
 
@@ -319,18 +419,65 @@ backsql_db_open(
                         * ldap_entries.dn LIKE CONCAT('%,',?)
                         */
 
-                       backsql_strfcat( &bb, "l",
-                                       (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
-                                               "ldap_entries.dn=?");
+                       backsql_strfcat_x( &bb, NULL, "lb",
+                                       (ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ),
+                                               "ldap_entries.dn LIKE ",
+                                       &concat );
                }
 
+               ch_free( concat.bv_val );
+
                bi->sql_children_cond = bb.bb_val;
                        
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
-                       "setting \"%s\" as default\n",
+                       "setting \"%s\" as default \"children_cond\"\n",
                        bi->sql_children_cond.bv_val, 0, 0 );
        }
 
+       if ( bi->sql_dn_match_cond.bv_val == NULL ) {
+               /*
+                * Prepare concat function for dn match search condition
+                */
+               struct berbuf   bb = BB_NULL;
+
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "DN match search SQL condition not specified "
+                       "(use \"dn_match_cond\" directive in slapd.conf); "
+                       "preparing default\n", 
+                       0, 0, 0);
+
+               if ( bi->sql_upper_func.bv_val ) {
+
+                       /*
+                        * UPPER(ldap_entries.dn)=?
+                        */
+
+                       backsql_strfcat_x( &bb, NULL, "blbcb",
+                                       &bi->sql_upper_func,
+                                       (ber_len_t)STRLENOF( "(ldap_entries.dn)=" ),
+                                               "(ldap_entries.dn)=",
+                                       &bi->sql_upper_func_open,
+                                       '?',
+                                       &bi->sql_upper_func_close );
+
+               } else {
+
+                       /*
+                        * ldap_entries.dn=?
+                        */
+
+                       backsql_strfcat_x( &bb, NULL, "l",
+                                       (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
+                                               "ldap_entries.dn=?" );
+               }
+
+               bi->sql_dn_match_cond = bb.bb_val;
+                       
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "setting \"%s\" as default \"dn_match_cond\"\n",
+                       bi->sql_dn_match_cond.bv_val, 0, 0 );
+       }
+
        if ( bi->sql_oc_query == NULL ) {
                if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
                        bi->sql_oc_query =
@@ -403,14 +550,30 @@ backsql_db_open(
                bi->sql_delobjclasses_stmt = ch_strdup( backsql_def_delobjclasses_stmt );
        }
 
-       op->o_hdr = (Opheader *)&op[ 1 ];
-       op->o_connid = (unsigned long)(-1);
+       /* This should just be to force schema loading */
+       connection_fake_init2( &conn, &opbuf, thrctx, 0 );
+       op = &opbuf.ob_op;
        op->o_bd = bd;
        if ( backsql_get_db_conn( op, &dbh ) != LDAP_SUCCESS ) {
                Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
                        "connection failed, exiting\n", 0, 0, 0 );
                return 1;
        }
+       if ( backsql_load_schema_map( bi, dbh ) != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "schema mapping failed, exiting\n", 0, 0, 0 );
+               return 1;
+       }
+       if ( backsql_free_db_conn( op, dbh ) != SQL_SUCCESS ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "connection free failed\n", 0, 0, 0 );
+       }
+       if ( !BACKSQL_SCHEMA_LOADED( bi ) ) {
+               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
+                       "test failed, schema map not loaded - exiting\n",
+                       0, 0, 0 );
+               return 1;
+       }
 
        /*
         * Prepare ID selection query
@@ -418,20 +581,20 @@ backsql_db_open(
        if ( bi->sql_id_query == NULL ) {
                /* no custom id_query provided */
                if ( bi->sql_upper_func.bv_val == NULL ) {
-                       backsql_strcat( &bb, backsql_id_query, "dn=?", NULL );
+                       backsql_strcat_x( &bb, NULL, backsql_id_query, "dn=?", NULL );
 
                } else {
                        if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
-                               backsql_strcat( &bb, backsql_id_query,
+                               backsql_strcat_x( &bb, NULL, backsql_id_query,
                                                "dn_ru=?", NULL );
                        } else {
                                if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
-                                       backsql_strfcat( &bb, "sbl",
+                                       backsql_strfcat_x( &bb, NULL, "sbl",
                                                        backsql_id_query,
                                                        &bi->sql_upper_func, 
                                                        (ber_len_t)STRLENOF( "(dn)=?" ), "(dn)=?" );
                                } else {
-                                       backsql_strfcat( &bb, "sblbcb",
+                                       backsql_strfcat_x( &bb, NULL, "sblbcb",
                                                        backsql_id_query,
                                                        &bi->sql_upper_func, 
                                                        (ber_len_t)STRLENOF( "(dn)=" ), "(dn)=",
@@ -444,28 +607,31 @@ backsql_db_open(
                bi->sql_id_query = bb.bb_val.bv_val;
        }
 
-               /*
-        * Prepare children ID selection query
+       /*
+        * Prepare children count query
         */
-       bi->sql_has_children_query = NULL;
-
-       bb.bb_val.bv_val = NULL;
-       bb.bb_val.bv_len = 0;
+       BER_BVZERO( &bb.bb_val );
        bb.bb_len = 0;
-       backsql_strfcat( &bb, "sb",
-                       "SELECT COUNT(distinct subordinates.id) FROM ldap_entries,ldap_entries subordinates WHERE subordinates.parent=ldap_entries.id AND ",
-
-                       &bi->sql_children_cond );
+       backsql_strfcat_x( &bb, NULL, "sbsb",
+                       "SELECT COUNT(distinct subordinates.id) "
+                       "FROM ldap_entries,ldap_entries ",
+                       &bi->sql_aliasing, "subordinates "
+                       "WHERE subordinates.parent=ldap_entries.id AND ",
+                       &bi->sql_dn_match_cond );
        bi->sql_has_children_query = bb.bb_val.bv_val;
  
-       backsql_free_db_conn( op );
-       if ( !BACKSQL_SCHEMA_LOADED( bi ) ) {
-               Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
-                       "test failed, schema map not loaded - exiting\n",
-                       0, 0, 0 );
-               return 1;
-       }
-
+       /*
+        * Prepare DN and objectClass aliasing bit of query
+        */
+       BER_BVZERO( &bb.bb_val );
+       bb.bb_len = 0;
+       backsql_strfcat_x( &bb, NULL, "sbbsbsbbsb",
+                       " ", &bi->sql_aliasing, &bi->sql_aliasing_quote,
+                       "objectClass", &bi->sql_aliasing_quote,
+                       ",ldap_entries.dn ", &bi->sql_aliasing,
+                       &bi->sql_aliasing_quote, "dn", &bi->sql_aliasing_quote );
+       bi->sql_dn_oc_aliasing = bb.bb_val;
        /* should never happen! */
        assert( bd->be_nsuffix != NULL );
        
@@ -473,6 +639,8 @@ backsql_db_open(
                /* enable if only one suffix is defined */
                bi->sql_flags |= BSQLF_USE_SUBTREE_SHORTCUT;
        }
+
+       bi->sql_flags |= BSQLF_CHECK_SCHEMA;
        
        Debug( LDAP_DEBUG_TRACE, "<==backsql_db_open(): "
                "test succeeded, schema map loaded\n", 0, 0, 0 );
@@ -481,26 +649,16 @@ backsql_db_open(
 
 int
 backsql_db_close(
-       BackendDB       *bd )
+       BackendDB       *bd,
+       ConfigReply     *cr )
 {
-       Debug( LDAP_DEBUG_TRACE, "==>backsql_db_close()\n", 0, 0, 0 );
-       Debug( LDAP_DEBUG_TRACE, "<==backsql_db_close()\n", 0, 0, 0 );
-       return 0;
-}
+       backsql_info    *bi = (backsql_info*)bd->be_private;
 
-int
-backsql_connection_destroy( Backend *bd, Connection *c )
-{
-       char            opbuf[ OPERATION_BUFFER_SIZE ];
-       Operation*      op = (Operation *)opbuf;
+       Debug( LDAP_DEBUG_TRACE, "==>backsql_db_close()\n", 0, 0, 0 );
 
-       op->o_hdr = (Opheader *)&op[ 1 ];
-       op->o_connid = c->c_connid;
-       op->o_bd = bd;
+       backsql_conn_destroy( bi );
 
-       Debug( LDAP_DEBUG_TRACE, "==>backsql_connection_destroy()\n", 0, 0, 0 );
-       backsql_free_db_conn( op );
-       Debug( LDAP_DEBUG_TRACE, "<==backsql_connection_destroy()\n", 0, 0, 0 );
+       Debug( LDAP_DEBUG_TRACE, "<==backsql_db_close()\n", 0, 0, 0 );
 
        return 0;
 }