]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/init.c
Sync with HEAD
[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-2005 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 "proto-sql.h"
31
32 int
33 sql_back_initialize(
34         BackendInfo     *bi )
35
36         static char *controls[] = {
37                 LDAP_CONTROL_ASSERT,
38                 LDAP_CONTROL_MANAGEDSAIT,
39 #if 0 /* needs improvements */
40                 LDAP_CONTROL_NOOP,
41 #endif
42 #ifdef SLAP_CONTROL_X_TREE_DELETE
43                 SLAP_CONTROL_X_TREE_DELETE,
44 #endif /* SLAP_CONTROL_X_TREE_DELETE */
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 {
99         backsql_info    *bi;
100         int             rc = 0;
101  
102         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_init()\n", 0, 0, 0 );
103
104         bi = (backsql_info *)ch_calloc( 1, sizeof( backsql_info ) );
105         ldap_pvt_thread_mutex_init( &bi->sql_dbconn_mutex );
106         ldap_pvt_thread_mutex_init( &bi->sql_schema_mutex );
107
108         if ( backsql_init_db_env( bi ) != SQL_SUCCESS ) {
109                 rc = -1;
110         }
111
112         bd->be_private = bi;
113
114         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_init()\n", 0, 0, 0 );
115
116         return rc;
117 }
118
119 int
120 backsql_db_destroy(
121         BackendDB       *bd )
122 {
123         backsql_info    *bi = (backsql_info*)bd->be_private;
124  
125         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_destroy()\n", 0, 0, 0 );
126
127         ldap_pvt_thread_mutex_lock( &bi->sql_dbconn_mutex );
128         backsql_free_db_env( bi );
129         ldap_pvt_thread_mutex_unlock( &bi->sql_dbconn_mutex );
130         ldap_pvt_thread_mutex_destroy( &bi->sql_dbconn_mutex );
131         ldap_pvt_thread_mutex_lock( &bi->sql_schema_mutex );
132         backsql_destroy_schema_map( bi );
133         ldap_pvt_thread_mutex_unlock( &bi->sql_schema_mutex );
134         ldap_pvt_thread_mutex_destroy( &bi->sql_schema_mutex );
135
136         if ( bi->sql_dbname ) {
137                 ch_free( bi->sql_dbname );
138         }
139         if ( bi->sql_dbuser ) {
140                 ch_free( bi->sql_dbuser );
141         }
142         if ( bi->sql_dbpasswd ) {
143                 ch_free( bi->sql_dbpasswd );
144         }
145         if ( bi->sql_dbhost ) {
146                 ch_free( bi->sql_dbhost );
147         }
148         if ( bi->sql_upper_func.bv_val ) {
149                 ch_free( bi->sql_upper_func.bv_val );
150                 ch_free( bi->sql_upper_func_open.bv_val );
151                 ch_free( bi->sql_upper_func_close.bv_val );
152         }
153         if ( bi->sql_concat_func ) {
154                 ber_bvarray_free( bi->sql_concat_func );
155         }
156         if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
157                 ch_free( bi->sql_strcast_func.bv_val );
158         }
159         if ( !BER_BVISNULL( &bi->sql_children_cond ) ) {
160                 ch_free( bi->sql_children_cond.bv_val );
161         }
162         if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
163                 ch_free( bi->sql_subtree_cond.bv_val );
164         }
165         if ( !BER_BVISNULL( &bi->sql_dn_oc_aliasing ) ) {
166                 ch_free( bi->sql_dn_oc_aliasing.bv_val );
167         }
168         if ( bi->sql_oc_query ) {
169                 ch_free( bi->sql_oc_query );
170         }
171         if ( bi->sql_at_query ) {
172                 ch_free( bi->sql_at_query );
173         }
174         if ( bi->sql_id_query ) {
175                 ch_free( bi->sql_id_query );
176         }
177         if ( bi->sql_has_children_query ) {
178                 ch_free( bi->sql_has_children_query );
179         }
180         if ( bi->sql_insentry_stmt ) {
181                 ch_free( bi->sql_insentry_stmt );
182         }
183         if ( bi->sql_delentry_stmt ) {
184                 ch_free( bi->sql_delentry_stmt );
185         }
186         if ( bi->sql_renentry_stmt ) {
187                 ch_free( bi->sql_renentry_stmt );
188         }
189         if ( bi->sql_delobjclasses_stmt ) {
190                 ch_free( bi->sql_delobjclasses_stmt );
191         }
192         if ( !BER_BVISNULL( &bi->sql_aliasing ) ) {
193                 ch_free( bi->sql_aliasing.bv_val );
194         }
195         if ( !BER_BVISNULL( &bi->sql_aliasing_quote ) ) {
196                 ch_free( bi->sql_aliasing_quote.bv_val );
197         }
198
199         if ( bi->sql_anlist ) {
200                 int     i;
201
202                 for ( i = 0; !BER_BVISNULL( &bi->sql_anlist[ i ].an_name ); i++ )
203                 {
204                         ch_free( bi->sql_anlist[ i ].an_name.bv_val );
205                 }
206                 ch_free( bi->sql_anlist );
207         }
208
209         if ( bi->sql_baseObject ) {
210                 entry_free( bi->sql_baseObject );
211         }
212         
213         ch_free( bi );
214         
215         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_destroy()\n", 0, 0, 0 );
216         return 0;
217 }
218
219 int
220 backsql_db_open(
221         BackendDB       *bd )
222 {
223         backsql_info    *bi = (backsql_info*)bd->be_private;
224         SQLHDBC         dbh = SQL_NULL_HDBC;
225         struct berbuf   bb = BB_NULL;
226
227         char            opbuf[ OPERATION_BUFFER_SIZE ];
228         Operation*      op = (Operation *)opbuf;
229         
230         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_open(): "
231                 "testing RDBMS connection\n", 0, 0, 0 );
232         if ( bi->sql_dbname == NULL ) {
233                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
234                         "datasource name not specified "
235                         "(use \"dbname\" directive in slapd.conf)\n", 0, 0, 0 );
236                 return 1;
237         }
238
239         if ( bi->sql_concat_func == NULL ) {
240                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
241                         "concat func not specified (use \"concat_pattern\" "
242                         "directive in slapd.conf)\n", 0, 0, 0 );
243
244                 if ( backsql_split_pattern( backsql_def_concat_func, 
245                                 &bi->sql_concat_func, 2 ) ) {
246                         Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
247                                 "unable to parse pattern \"%s\"",
248                                 backsql_def_concat_func, 0, 0 );
249                         return 1;
250                 }
251         }
252
253         /*
254          * see back-sql.h for default values
255          */
256         if ( BER_BVISNULL( &bi->sql_aliasing ) ) {
257                 ber_str2bv( BACKSQL_ALIASING,
258                         STRLENOF( BACKSQL_ALIASING ),
259                         1, &bi->sql_aliasing );
260         }
261
262         if ( BER_BVISNULL( &bi->sql_aliasing_quote ) ) {
263                 ber_str2bv( BACKSQL_ALIASING_QUOTE,
264                         STRLENOF( BACKSQL_ALIASING_QUOTE ),
265                         1, &bi->sql_aliasing_quote );
266         }
267
268         /*
269          * Prepare cast string as required
270          */
271         if ( bi->sql_upper_func.bv_val ) {
272                 char buf[1024];
273
274                 if ( BACKSQL_UPPER_NEEDS_CAST( bi ) ) {
275                         snprintf( buf, sizeof( buf ), 
276                                 "%s(cast (" /* ? as varchar(%d))) */ , 
277                                 bi->sql_upper_func.bv_val );
278                         ber_str2bv( buf, 0, 1, &bi->sql_upper_func_open );
279
280                         snprintf( buf, sizeof( buf ),
281                                 /* (cast(? */ " as varchar(%d)))",
282                                 BACKSQL_MAX_DN_LEN );
283                         ber_str2bv( buf, 0, 1, &bi->sql_upper_func_close );
284
285                 } else {
286                         snprintf( buf, sizeof( buf ), "%s(" /* ?) */ ,
287                                         bi->sql_upper_func.bv_val );
288                         ber_str2bv( buf, 0, 1, &bi->sql_upper_func_open );
289
290                         ber_str2bv( /* (? */ ")", 0, 1, &bi->sql_upper_func_close );
291                 }
292         }
293
294         /* normalize filter values only if necessary */
295         bi->sql_caseIgnoreMatch = mr_find( "caseIgnoreMatch" );
296         assert( bi->sql_caseIgnoreMatch != NULL );
297
298         bi->sql_telephoneNumberMatch = mr_find( "telephoneNumberMatch" );
299         assert( bi->sql_telephoneNumberMatch != NULL );
300
301         if ( bi->sql_dbuser == NULL ) {
302                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
303                         "user name not specified "
304                         "(use \"dbuser\" directive in slapd.conf)\n", 0, 0, 0 );
305                 return 1;
306         }
307         
308         if ( BER_BVISNULL( &bi->sql_subtree_cond ) ) {
309                 /*
310                  * Prepare concat function for subtree search condition
311                  */
312                 struct berval   concat;
313                 struct berval   values[] = {
314                         BER_BVC( "'%'" ),
315                         BER_BVC( "?" ),
316                         BER_BVNULL
317                 };
318                 struct berbuf   bb = BB_NULL;
319
320                 if ( backsql_prepare_pattern( bi->sql_concat_func, values, 
321                                 &concat ) ) {
322                         Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
323                                 "unable to prepare CONCAT pattern", 0, 0, 0 );
324                         return 1;
325                 }
326                         
327                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
328                         "subtree search SQL condition not specified "
329                         "(use \"subtree_cond\" directive in slapd.conf)\n", 
330                         0, 0, 0);
331
332                 if ( bi->sql_upper_func.bv_val ) {
333
334                         /*
335                          * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%',?))
336                          */
337
338                         backsql_strfcat( &bb, "blbbb",
339                                         &bi->sql_upper_func,
340                                         (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ),
341                                                 "(ldap_entries.dn) LIKE ",
342                                         &bi->sql_upper_func_open,
343                                         &concat,
344                                         &bi->sql_upper_func_close );
345
346                 } else {
347
348                         /*
349                          * ldap_entries.dn LIKE CONCAT('%',?)
350                          */
351
352                         backsql_strfcat( &bb, "lb",
353                                         (ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ),
354                                                 "ldap_entries.dn LIKE ",
355                                         &concat );
356                 }
357
358                 ch_free( concat.bv_val );
359
360                 bi->sql_subtree_cond = bb.bb_val;
361                         
362                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
363                         "setting \"%s\" as default\n",
364                         bi->sql_subtree_cond.bv_val, 0, 0 );
365         }
366
367         if ( bi->sql_children_cond.bv_val == NULL ) {
368                 struct berbuf   bb = BB_NULL;
369
370                 if ( bi->sql_upper_func.bv_val ) {
371
372                         /*
373                          * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%,',?))
374                          */
375
376                         backsql_strfcat( &bb, "blbl",
377                                         &bi->sql_upper_func,
378                                         (ber_len_t)STRLENOF( "(ldap_entries.dn)=" ),
379                                                 "(ldap_entries.dn)=",
380                                         &bi->sql_upper_func,
381                                         (ber_len_t)STRLENOF( "(?)" ), "(?)" );
382
383                 } else {
384
385                         /*
386                          * ldap_entries.dn LIKE CONCAT('%,',?)
387                          */
388
389                         backsql_strfcat( &bb, "l",
390                                         (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
391                                                 "ldap_entries.dn=?");
392                 }
393
394                 bi->sql_children_cond = bb.bb_val;
395                         
396                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
397                         "setting \"%s\" as default\n",
398                         bi->sql_children_cond.bv_val, 0, 0 );
399         }
400
401         if ( bi->sql_oc_query == NULL ) {
402                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
403                         bi->sql_oc_query =
404                                 ch_strdup( backsql_def_needs_select_oc_query );
405
406                 } else {
407                         bi->sql_oc_query = ch_strdup( backsql_def_oc_query );
408                 }
409
410                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
411                         "objectclass mapping SQL statement not specified "
412                         "(use \"oc_query\" directive in slapd.conf)\n", 
413                         0, 0, 0 );
414                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
415                         "setting \"%s\" by default\n", bi->sql_oc_query, 0, 0 );
416         }
417         
418         if ( bi->sql_at_query == NULL ) {
419                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
420                         "attribute mapping SQL statement not specified "
421                         "(use \"at_query\" directive in slapd.conf)\n",
422                         0, 0, 0 );
423                 Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
424                         "setting \"%s\" by default\n",
425                         backsql_def_at_query, 0, 0 );
426                 bi->sql_at_query = ch_strdup( backsql_def_at_query );
427         }
428         
429         if ( bi->sql_insentry_stmt == NULL ) {
430                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
431                         "entry insertion SQL statement not specified "
432                         "(use \"insentry_stmt\" directive in slapd.conf)\n",
433                         0, 0, 0 );
434                 Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
435                         "setting \"%s\" by default\n",
436                         backsql_def_insentry_stmt, 0, 0 );
437                 bi->sql_insentry_stmt = ch_strdup( backsql_def_insentry_stmt );
438         }
439         
440         if ( bi->sql_delentry_stmt == NULL ) {
441                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
442                         "entry deletion SQL statement not specified "
443                         "(use \"delentry_stmt\" directive in slapd.conf)\n",
444                         0, 0, 0 );
445                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
446                         "setting \"%s\" by default\n",
447                         backsql_def_delentry_stmt, 0, 0 );
448                 bi->sql_delentry_stmt = ch_strdup( backsql_def_delentry_stmt );
449         }
450
451         if ( bi->sql_renentry_stmt == NULL ) {
452                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
453                         "entry deletion SQL statement not specified "
454                         "(use \"renentry_stmt\" directive in slapd.conf)\n",
455                         0, 0, 0 );
456                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
457                         "setting \"%s\" by default\n",
458                         backsql_def_renentry_stmt, 0, 0 );
459                 bi->sql_renentry_stmt = ch_strdup( backsql_def_renentry_stmt );
460         }
461
462         if ( bi->sql_delobjclasses_stmt == NULL ) {
463                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
464                         "objclasses deletion SQL statement not specified "
465                         "(use \"delobjclasses_stmt\" directive in slapd.conf)\n",
466                         0, 0, 0 );
467                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
468                         "setting \"%s\" by default\n",
469                         backsql_def_delobjclasses_stmt, 0, 0 );
470                 bi->sql_delobjclasses_stmt = ch_strdup( backsql_def_delobjclasses_stmt );
471         }
472
473         /* This should just be to force schema loading */
474         op->o_hdr = (Opheader *)&op[ 1 ];
475         op->o_connid = (unsigned long)(-1);
476         op->o_bd = bd;
477         if ( backsql_get_db_conn( op, &dbh ) != LDAP_SUCCESS ) {
478                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
479                         "connection failed, exiting\n", 0, 0, 0 );
480                 return 1;
481         }
482
483         if ( backsql_free_db_conn( op ) != SQL_SUCCESS ) {
484                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
485                         "connection free failed\n", 0, 0, 0 );
486         }
487         if ( !BACKSQL_SCHEMA_LOADED( bi ) ) {
488                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
489                         "test failed, schema map not loaded - exiting\n",
490                         0, 0, 0 );
491                 return 1;
492         }
493
494         /*
495          * Prepare ID selection query
496          */
497         if ( bi->sql_id_query == NULL ) {
498                 /* no custom id_query provided */
499                 if ( bi->sql_upper_func.bv_val == NULL ) {
500                         backsql_strcat( &bb, backsql_id_query, "dn=?", NULL );
501
502                 } else {
503                         if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
504                                 backsql_strcat( &bb, backsql_id_query,
505                                                 "dn_ru=?", NULL );
506                         } else {
507                                 if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
508                                         backsql_strfcat( &bb, "sbl",
509                                                         backsql_id_query,
510                                                         &bi->sql_upper_func, 
511                                                         (ber_len_t)STRLENOF( "(dn)=?" ), "(dn)=?" );
512                                 } else {
513                                         backsql_strfcat( &bb, "sblbcb",
514                                                         backsql_id_query,
515                                                         &bi->sql_upper_func, 
516                                                         (ber_len_t)STRLENOF( "(dn)=" ), "(dn)=",
517                                                         &bi->sql_upper_func_open, 
518                                                         '?', 
519                                                         &bi->sql_upper_func_close );
520                                 }
521                         }
522                 }
523                 bi->sql_id_query = bb.bb_val.bv_val;
524         }
525
526         /*
527          * Prepare children ID selection query
528          */
529         BER_BVZERO( &bb.bb_val );
530         bb.bb_len = 0;
531         backsql_strfcat( &bb, "sbsb",
532                         "SELECT COUNT(distinct subordinates.id) "
533                         "FROM ldap_entries,ldap_entries ",
534                         &bi->sql_aliasing, "subordinates "
535                         "WHERE subordinates.parent=ldap_entries.id AND ",
536                         &bi->sql_children_cond );
537         bi->sql_has_children_query = bb.bb_val.bv_val;
538  
539         /*
540          * Prepare DN and objectClass aliasing bit of query
541          */
542         BER_BVZERO( &bb.bb_val );
543         bb.bb_len = 0;
544         backsql_strfcat( &bb, "sbbsbsbbsb",
545                         " ", &bi->sql_aliasing, &bi->sql_aliasing_quote,
546                         "objectClass", &bi->sql_aliasing_quote,
547                         ",ldap_entries.dn ", &bi->sql_aliasing,
548                         &bi->sql_aliasing_quote, "dn", &bi->sql_aliasing_quote );
549         bi->sql_dn_oc_aliasing = bb.bb_val;
550  
551         /* should never happen! */
552         assert( bd->be_nsuffix != NULL );
553         
554         if ( BER_BVISNULL( &bd->be_nsuffix[ 1 ] ) ) {
555                 /* enable if only one suffix is defined */
556                 bi->sql_flags |= BSQLF_USE_SUBTREE_SHORTCUT;
557         }
558
559         bi->sql_flags |= BSQLF_CHECK_SCHEMA;
560         
561         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_open(): "
562                 "test succeeded, schema map loaded\n", 0, 0, 0 );
563         return 0;
564 }
565
566 int
567 backsql_db_close(
568         BackendDB       *bd )
569 {
570         backsql_info    *bi = (backsql_info*)bd->be_private;
571
572         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_close()\n", 0, 0, 0 );
573
574         backsql_conn_destroy( bi );
575
576         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_close()\n", 0, 0, 0 );
577
578         return 0;
579 }
580
581 int
582 backsql_connection_destroy( Backend *bd, Connection *c )
583 {
584         char            opbuf[ OPERATION_BUFFER_SIZE ];
585         Operation*      op = (Operation *)opbuf;
586
587         op->o_hdr = (Opheader *)&op[ 1 ];
588         op->o_connid = c->c_connid;
589         op->o_bd = bd;
590
591         Debug( LDAP_DEBUG_TRACE, "==>backsql_connection_destroy()\n", 0, 0, 0 );
592         backsql_free_db_conn( op );
593         Debug( LDAP_DEBUG_TRACE, "<==backsql_connection_destroy()\n", 0, 0, 0 );
594
595         return 0;
596 }
597
598 #if SLAPD_SQL == SLAPD_MOD_DYNAMIC
599
600 /* conditionally define the init_module() function */
601 SLAP_BACKEND_INIT_MODULE( sql )
602
603 #endif /* SLAPD_SQL == SLAPD_MOD_DYNAMIC */
604