]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/init.c
c317d3cb708407184ca166533ce7a6b22bbad6db
[openldap] / servers / slapd / back-sql / init.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2007 The OpenLDAP Foundation.
5  * Portions Copyright 1999 Dmitry Kovalev.
6  * Portions Copyright 2002 Pierangelo Masarati.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 /* ACKNOWLEDGEMENTS:
18  * This work was initially developed by Dmitry Kovalev for inclusion
19  * by OpenLDAP Software.  Additional significant contributors include
20  * Pierangelo Masarati.
21  */
22
23 #include "portable.h"
24
25 #include <stdio.h>
26 #include <sys/types.h>
27 #include "ac/string.h"
28
29 #include "slap.h"
30 #include "config.h"
31 #include "proto-sql.h"
32
33 int
34 sql_back_initialize(
35         BackendInfo     *bi )
36
37         static char *controls[] = {
38                 LDAP_CONTROL_ASSERT,
39                 LDAP_CONTROL_MANAGEDSAIT,
40                 LDAP_CONTROL_NOOP,
41 #if 0 /* SLAP_CONTROL_X_TREE_DELETE */
42                 SLAP_CONTROL_X_TREE_DELETE,
43 #endif /* SLAP_CONTROL_X_TREE_DELETE */
44                 LDAP_CONTROL_PAGEDRESULTS,
45                 NULL
46         };
47
48         bi->bi_controls = controls;
49
50         bi->bi_flags |=
51 #if 0
52                 SLAP_BFLAG_INCREMENT |
53 #endif
54                 SLAP_BFLAG_REFERRALS;
55
56         Debug( LDAP_DEBUG_TRACE,"==>sql_back_initialize()\n", 0, 0, 0 );
57         
58         bi->bi_db_init = backsql_db_init;
59         bi->bi_db_config = backsql_db_config;
60         bi->bi_db_open = backsql_db_open;
61         bi->bi_db_close = backsql_db_close;
62         bi->bi_db_destroy = backsql_db_destroy;
63
64         bi->bi_op_abandon = 0;
65         bi->bi_op_compare = backsql_compare;
66         bi->bi_op_bind = backsql_bind;
67         bi->bi_op_unbind = 0;
68         bi->bi_op_search = backsql_search;
69         bi->bi_op_modify = backsql_modify;
70         bi->bi_op_modrdn = backsql_modrdn;
71         bi->bi_op_add = backsql_add;
72         bi->bi_op_delete = backsql_delete;
73         
74         bi->bi_chk_referrals = 0;
75         bi->bi_operational = backsql_operational;
76         bi->bi_entry_get_rw = backsql_entry_get;
77         bi->bi_entry_release_rw = backsql_entry_release;
78  
79         bi->bi_connection_init = 0;
80         bi->bi_connection_destroy = backsql_connection_destroy;
81
82         Debug( LDAP_DEBUG_TRACE,"<==sql_back_initialize()\n", 0, 0, 0 );
83         return 0;
84 }
85
86 int
87 backsql_destroy( 
88         BackendInfo     *bi )
89 {
90         Debug( LDAP_DEBUG_TRACE, "==>backsql_destroy()\n", 0, 0, 0 );
91         Debug( LDAP_DEBUG_TRACE, "<==backsql_destroy()\n", 0, 0, 0 );
92         return 0;
93 }
94
95 int
96 backsql_db_init(
97         BackendDB       *bd,
98         ConfigReply     *cr )
99 {
100         backsql_info    *bi;
101         int             rc = 0;
102  
103         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_init()\n", 0, 0, 0 );
104
105         bi = (backsql_info *)ch_calloc( 1, sizeof( backsql_info ) );
106         ldap_pvt_thread_mutex_init( &bi->sql_dbconn_mutex );
107         ldap_pvt_thread_mutex_init( &bi->sql_schema_mutex );
108
109         if ( backsql_init_db_env( bi ) != SQL_SUCCESS ) {
110                 rc = -1;
111         }
112
113         bd->be_private = bi;
114
115         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_init()\n", 0, 0, 0 );
116
117         return rc;
118 }
119
120 int
121 backsql_db_destroy(
122         BackendDB       *bd,
123         ConfigReply     *cr )
124 {
125         backsql_info    *bi = (backsql_info*)bd->be_private;
126  
127         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_destroy()\n", 0, 0, 0 );
128
129         ldap_pvt_thread_mutex_lock( &bi->sql_dbconn_mutex );
130         backsql_free_db_env( bi );
131         ldap_pvt_thread_mutex_unlock( &bi->sql_dbconn_mutex );
132         ldap_pvt_thread_mutex_destroy( &bi->sql_dbconn_mutex );
133         ldap_pvt_thread_mutex_lock( &bi->sql_schema_mutex );
134         backsql_destroy_schema_map( bi );
135         ldap_pvt_thread_mutex_unlock( &bi->sql_schema_mutex );
136         ldap_pvt_thread_mutex_destroy( &bi->sql_schema_mutex );
137
138         if ( bi->sql_dbname ) {
139                 ch_free( bi->sql_dbname );
140         }
141         if ( bi->sql_dbuser ) {
142                 ch_free( bi->sql_dbuser );
143         }
144         if ( bi->sql_dbpasswd ) {
145                 ch_free( bi->sql_dbpasswd );
146         }
147         if ( bi->sql_dbhost ) {
148                 ch_free( bi->sql_dbhost );
149         }
150         if ( bi->sql_upper_func.bv_val ) {
151                 ch_free( bi->sql_upper_func.bv_val );
152                 ch_free( bi->sql_upper_func_open.bv_val );
153                 ch_free( bi->sql_upper_func_close.bv_val );
154         }
155         if ( bi->sql_concat_func ) {
156                 ber_bvarray_free( bi->sql_concat_func );
157         }
158         if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
159                 ch_free( bi->sql_strcast_func.bv_val );
160         }
161         if ( !BER_BVISNULL( &bi->sql_children_cond ) ) {
162                 ch_free( bi->sql_children_cond.bv_val );
163         }
164         if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
165                 ch_free( bi->sql_subtree_cond.bv_val );
166         }
167         if ( !BER_BVISNULL( &bi->sql_dn_oc_aliasing ) ) {
168                 ch_free( bi->sql_dn_oc_aliasing.bv_val );
169         }
170         if ( bi->sql_oc_query ) {
171                 ch_free( bi->sql_oc_query );
172         }
173         if ( bi->sql_at_query ) {
174                 ch_free( bi->sql_at_query );
175         }
176         if ( bi->sql_id_query ) {
177                 ch_free( bi->sql_id_query );
178         }
179         if ( bi->sql_has_children_query ) {
180                 ch_free( bi->sql_has_children_query );
181         }
182         if ( bi->sql_insentry_stmt ) {
183                 ch_free( bi->sql_insentry_stmt );
184         }
185         if ( bi->sql_delentry_stmt ) {
186                 ch_free( bi->sql_delentry_stmt );
187         }
188         if ( bi->sql_renentry_stmt ) {
189                 ch_free( bi->sql_renentry_stmt );
190         }
191         if ( bi->sql_delobjclasses_stmt ) {
192                 ch_free( bi->sql_delobjclasses_stmt );
193         }
194         if ( !BER_BVISNULL( &bi->sql_aliasing ) ) {
195                 ch_free( bi->sql_aliasing.bv_val );
196         }
197         if ( !BER_BVISNULL( &bi->sql_aliasing_quote ) ) {
198                 ch_free( bi->sql_aliasing_quote.bv_val );
199         }
200
201         if ( bi->sql_anlist ) {
202                 int     i;
203
204                 for ( i = 0; !BER_BVISNULL( &bi->sql_anlist[ i ].an_name ); i++ )
205                 {
206                         ch_free( bi->sql_anlist[ i ].an_name.bv_val );
207                 }
208                 ch_free( bi->sql_anlist );
209         }
210
211         if ( bi->sql_baseObject ) {
212                 entry_free( bi->sql_baseObject );
213         }
214         
215         ch_free( bi );
216         
217         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_destroy()\n", 0, 0, 0 );
218         return 0;
219 }
220
221 int
222 backsql_db_open(
223         BackendDB       *bd,
224         ConfigReply     *cr )
225 {
226         backsql_info    *bi = (backsql_info*)bd->be_private;
227         SQLHDBC         dbh = SQL_NULL_HDBC;
228         struct berbuf   bb = BB_NULL;
229
230         OperationBuffer opbuf;
231         Operation*      op;
232         
233         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_open(): "
234                 "testing RDBMS connection\n", 0, 0, 0 );
235         if ( bi->sql_dbname == NULL ) {
236                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
237                         "datasource name not specified "
238                         "(use \"dbname\" directive in slapd.conf)\n", 0, 0, 0 );
239                 return 1;
240         }
241
242         if ( bi->sql_concat_func == NULL ) {
243                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
244                         "concat func not specified (use \"concat_pattern\" "
245                         "directive in slapd.conf)\n", 0, 0, 0 );
246
247                 if ( backsql_split_pattern( backsql_def_concat_func, 
248                                 &bi->sql_concat_func, 2 ) ) {
249                         Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
250                                 "unable to parse pattern \"%s\"",
251                                 backsql_def_concat_func, 0, 0 );
252                         return 1;
253                 }
254         }
255
256         /*
257          * see back-sql.h for default values
258          */
259         if ( BER_BVISNULL( &bi->sql_aliasing ) ) {
260                 ber_str2bv( BACKSQL_ALIASING,
261                         STRLENOF( BACKSQL_ALIASING ),
262                         1, &bi->sql_aliasing );
263         }
264
265         if ( BER_BVISNULL( &bi->sql_aliasing_quote ) ) {
266                 ber_str2bv( BACKSQL_ALIASING_QUOTE,
267                         STRLENOF( BACKSQL_ALIASING_QUOTE ),
268                         1, &bi->sql_aliasing_quote );
269         }
270
271         /*
272          * Prepare cast string as required
273          */
274         if ( bi->sql_upper_func.bv_val ) {
275                 char buf[1024];
276
277                 if ( BACKSQL_UPPER_NEEDS_CAST( bi ) ) {
278                         snprintf( buf, sizeof( buf ), 
279                                 "%s(cast (" /* ? as varchar(%d))) */ , 
280                                 bi->sql_upper_func.bv_val );
281                         ber_str2bv( buf, 0, 1, &bi->sql_upper_func_open );
282
283                         snprintf( buf, sizeof( buf ),
284                                 /* (cast(? */ " as varchar(%d)))",
285                                 BACKSQL_MAX_DN_LEN );
286                         ber_str2bv( buf, 0, 1, &bi->sql_upper_func_close );
287
288                 } else {
289                         snprintf( buf, sizeof( buf ), "%s(" /* ?) */ ,
290                                         bi->sql_upper_func.bv_val );
291                         ber_str2bv( buf, 0, 1, &bi->sql_upper_func_open );
292
293                         ber_str2bv( /* (? */ ")", 0, 1, &bi->sql_upper_func_close );
294                 }
295         }
296
297         /* normalize filter values only if necessary */
298         bi->sql_caseIgnoreMatch = mr_find( "caseIgnoreMatch" );
299         assert( bi->sql_caseIgnoreMatch != NULL );
300
301         bi->sql_telephoneNumberMatch = mr_find( "telephoneNumberMatch" );
302         assert( bi->sql_telephoneNumberMatch != NULL );
303
304         if ( bi->sql_dbuser == NULL ) {
305                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
306                         "user name not specified "
307                         "(use \"dbuser\" directive in slapd.conf)\n", 0, 0, 0 );
308                 return 1;
309         }
310         
311         if ( BER_BVISNULL( &bi->sql_subtree_cond ) ) {
312                 /*
313                  * Prepare concat function for subtree search condition
314                  */
315                 struct berval   concat;
316                 struct berval   values[] = {
317                         BER_BVC( "'%'" ),
318                         BER_BVC( "?" ),
319                         BER_BVNULL
320                 };
321                 struct berbuf   bb = BB_NULL;
322
323                 if ( backsql_prepare_pattern( bi->sql_concat_func, values, 
324                                 &concat ) ) {
325                         Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
326                                 "unable to prepare CONCAT pattern", 0, 0, 0 );
327                         return 1;
328                 }
329                         
330                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
331                         "subtree search SQL condition not specified "
332                         "(use \"subtree_cond\" directive in slapd.conf)\n", 
333                         0, 0, 0);
334
335                 if ( bi->sql_upper_func.bv_val ) {
336
337                         /*
338                          * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%',?))
339                          */
340
341                         backsql_strfcat_x( &bb, NULL, "blbbb",
342                                         &bi->sql_upper_func,
343                                         (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ),
344                                                 "(ldap_entries.dn) LIKE ",
345                                         &bi->sql_upper_func_open,
346                                         &concat,
347                                         &bi->sql_upper_func_close );
348
349                 } else {
350
351                         /*
352                          * ldap_entries.dn LIKE CONCAT('%',?)
353                          */
354
355                         backsql_strfcat_x( &bb, NULL, "lb",
356                                         (ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ),
357                                                 "ldap_entries.dn LIKE ",
358                                         &concat );
359                 }
360
361                 ch_free( concat.bv_val );
362
363                 bi->sql_subtree_cond = bb.bb_val;
364                         
365                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
366                         "setting \"%s\" as default\n",
367                         bi->sql_subtree_cond.bv_val, 0, 0 );
368         }
369
370         if ( bi->sql_children_cond.bv_val == NULL ) {
371                 struct berbuf   bb = BB_NULL;
372
373                 if ( bi->sql_upper_func.bv_val ) {
374
375                         /*
376                          * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%,',?))
377                          */
378
379                         backsql_strfcat_x( &bb, NULL, "blbl",
380                                         &bi->sql_upper_func,
381                                         (ber_len_t)STRLENOF( "(ldap_entries.dn)=" ),
382                                                 "(ldap_entries.dn)=",
383                                         &bi->sql_upper_func,
384                                         (ber_len_t)STRLENOF( "(?)" ), "(?)" );
385
386                 } else {
387
388                         /*
389                          * ldap_entries.dn LIKE CONCAT('%,',?)
390                          */
391
392                         backsql_strfcat_x( &bb, NULL, "l",
393                                         (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
394                                                 "ldap_entries.dn=?");
395                 }
396
397                 bi->sql_children_cond = bb.bb_val;
398                         
399                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
400                         "setting \"%s\" as default\n",
401                         bi->sql_children_cond.bv_val, 0, 0 );
402         }
403
404         if ( bi->sql_oc_query == NULL ) {
405                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
406                         bi->sql_oc_query =
407                                 ch_strdup( backsql_def_needs_select_oc_query );
408
409                 } else {
410                         bi->sql_oc_query = ch_strdup( backsql_def_oc_query );
411                 }
412
413                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
414                         "objectclass mapping SQL statement not specified "
415                         "(use \"oc_query\" directive in slapd.conf)\n", 
416                         0, 0, 0 );
417                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
418                         "setting \"%s\" by default\n", bi->sql_oc_query, 0, 0 );
419         }
420         
421         if ( bi->sql_at_query == NULL ) {
422                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
423                         "attribute mapping SQL statement not specified "
424                         "(use \"at_query\" directive in slapd.conf)\n",
425                         0, 0, 0 );
426                 Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
427                         "setting \"%s\" by default\n",
428                         backsql_def_at_query, 0, 0 );
429                 bi->sql_at_query = ch_strdup( backsql_def_at_query );
430         }
431         
432         if ( bi->sql_insentry_stmt == NULL ) {
433                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
434                         "entry insertion SQL statement not specified "
435                         "(use \"insentry_stmt\" directive in slapd.conf)\n",
436                         0, 0, 0 );
437                 Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
438                         "setting \"%s\" by default\n",
439                         backsql_def_insentry_stmt, 0, 0 );
440                 bi->sql_insentry_stmt = ch_strdup( backsql_def_insentry_stmt );
441         }
442         
443         if ( bi->sql_delentry_stmt == NULL ) {
444                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
445                         "entry deletion SQL statement not specified "
446                         "(use \"delentry_stmt\" directive in slapd.conf)\n",
447                         0, 0, 0 );
448                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
449                         "setting \"%s\" by default\n",
450                         backsql_def_delentry_stmt, 0, 0 );
451                 bi->sql_delentry_stmt = ch_strdup( backsql_def_delentry_stmt );
452         }
453
454         if ( bi->sql_renentry_stmt == NULL ) {
455                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
456                         "entry deletion SQL statement not specified "
457                         "(use \"renentry_stmt\" directive in slapd.conf)\n",
458                         0, 0, 0 );
459                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
460                         "setting \"%s\" by default\n",
461                         backsql_def_renentry_stmt, 0, 0 );
462                 bi->sql_renentry_stmt = ch_strdup( backsql_def_renentry_stmt );
463         }
464
465         if ( bi->sql_delobjclasses_stmt == NULL ) {
466                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
467                         "objclasses deletion SQL statement not specified "
468                         "(use \"delobjclasses_stmt\" directive in slapd.conf)\n",
469                         0, 0, 0 );
470                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
471                         "setting \"%s\" by default\n",
472                         backsql_def_delobjclasses_stmt, 0, 0 );
473                 bi->sql_delobjclasses_stmt = ch_strdup( backsql_def_delobjclasses_stmt );
474         }
475
476         /* This should just be to force schema loading */
477         op = &opbuf.ob_op;
478         op->o_hdr = &opbuf.ob_hdr;
479         op->o_connid = (unsigned long)(-1);
480         op->o_bd = bd;
481         if ( backsql_get_db_conn( op, &dbh ) != LDAP_SUCCESS ) {
482                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
483                         "connection failed, exiting\n", 0, 0, 0 );
484                 return 1;
485         }
486
487         if ( backsql_free_db_conn( op ) != SQL_SUCCESS ) {
488                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
489                         "connection free failed\n", 0, 0, 0 );
490         }
491         if ( !BACKSQL_SCHEMA_LOADED( bi ) ) {
492                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
493                         "test failed, schema map not loaded - exiting\n",
494                         0, 0, 0 );
495                 return 1;
496         }
497
498         /*
499          * Prepare ID selection query
500          */
501         if ( bi->sql_id_query == NULL ) {
502                 /* no custom id_query provided */
503                 if ( bi->sql_upper_func.bv_val == NULL ) {
504                         backsql_strcat_x( &bb, NULL, backsql_id_query, "dn=?", NULL );
505
506                 } else {
507                         if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
508                                 backsql_strcat_x( &bb, NULL, backsql_id_query,
509                                                 "dn_ru=?", NULL );
510                         } else {
511                                 if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
512                                         backsql_strfcat_x( &bb, NULL, "sbl",
513                                                         backsql_id_query,
514                                                         &bi->sql_upper_func, 
515                                                         (ber_len_t)STRLENOF( "(dn)=?" ), "(dn)=?" );
516                                 } else {
517                                         backsql_strfcat_x( &bb, NULL, "sblbcb",
518                                                         backsql_id_query,
519                                                         &bi->sql_upper_func, 
520                                                         (ber_len_t)STRLENOF( "(dn)=" ), "(dn)=",
521                                                         &bi->sql_upper_func_open, 
522                                                         '?', 
523                                                         &bi->sql_upper_func_close );
524                                 }
525                         }
526                 }
527                 bi->sql_id_query = bb.bb_val.bv_val;
528         }
529
530         /*
531          * Prepare children ID selection query
532          */
533         BER_BVZERO( &bb.bb_val );
534         bb.bb_len = 0;
535         backsql_strfcat_x( &bb, NULL, "sbsb",
536                         "SELECT COUNT(distinct subordinates.id) "
537                         "FROM ldap_entries,ldap_entries ",
538                         &bi->sql_aliasing, "subordinates "
539                         "WHERE subordinates.parent=ldap_entries.id AND ",
540                         &bi->sql_children_cond );
541         bi->sql_has_children_query = bb.bb_val.bv_val;
542  
543         /*
544          * Prepare DN and objectClass aliasing bit of query
545          */
546         BER_BVZERO( &bb.bb_val );
547         bb.bb_len = 0;
548         backsql_strfcat_x( &bb, NULL, "sbbsbsbbsb",
549                         " ", &bi->sql_aliasing, &bi->sql_aliasing_quote,
550                         "objectClass", &bi->sql_aliasing_quote,
551                         ",ldap_entries.dn ", &bi->sql_aliasing,
552                         &bi->sql_aliasing_quote, "dn", &bi->sql_aliasing_quote );
553         bi->sql_dn_oc_aliasing = bb.bb_val;
554  
555         /* should never happen! */
556         assert( bd->be_nsuffix != NULL );
557         
558         if ( BER_BVISNULL( &bd->be_nsuffix[ 1 ] ) ) {
559                 /* enable if only one suffix is defined */
560                 bi->sql_flags |= BSQLF_USE_SUBTREE_SHORTCUT;
561         }
562
563         bi->sql_flags |= BSQLF_CHECK_SCHEMA;
564         
565         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_open(): "
566                 "test succeeded, schema map loaded\n", 0, 0, 0 );
567         return 0;
568 }
569
570 int
571 backsql_db_close(
572         BackendDB       *bd,
573         ConfigReply     *cr )
574 {
575         backsql_info    *bi = (backsql_info*)bd->be_private;
576
577         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_close()\n", 0, 0, 0 );
578
579         backsql_conn_destroy( bi );
580
581         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_close()\n", 0, 0, 0 );
582
583         return 0;
584 }
585
586 int
587 backsql_connection_destroy( Backend *bd, Connection *c )
588 {
589         OperationBuffer opbuf;
590         Operation*      op = &opbuf.ob_op;
591
592         op->o_hdr = &opbuf.ob_hdr;
593         op->o_connid = c->c_connid;
594         op->o_bd = bd;
595
596         Debug( LDAP_DEBUG_TRACE, "==>backsql_connection_destroy()\n", 0, 0, 0 );
597         backsql_free_db_conn( op );
598         Debug( LDAP_DEBUG_TRACE, "<==backsql_connection_destroy()\n", 0, 0, 0 );
599
600         return 0;
601 }
602
603 #if SLAPD_SQL == SLAPD_MOD_DYNAMIC
604
605 /* conditionally define the init_module() function */
606 SLAP_BACKEND_INIT_MODULE( sql )
607
608 #endif /* SLAPD_SQL == SLAPD_MOD_DYNAMIC */
609