]> git.sur5r.net Git - openldap/blob - servers/slapd/back-sql/init.c
Merge remote branch 'origin/mdb.master'
[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-2011 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 #ifdef SLAP_CONTROL_X_TREE_DELETE
42                 SLAP_CONTROL_X_TREE_DELETE,
43 #endif /* SLAP_CONTROL_X_TREE_DELETE */
44 #ifndef BACKSQL_ARBITRARY_KEY
45                 LDAP_CONTROL_PAGEDRESULTS,
46 #endif /* ! BACKSQL_ARBITRARY_KEY */
47                 NULL
48         };
49
50         bi->bi_controls = controls;
51
52         bi->bi_flags |=
53 #if 0
54                 SLAP_BFLAG_INCREMENT |
55 #endif
56                 SLAP_BFLAG_REFERRALS;
57
58         Debug( LDAP_DEBUG_TRACE,"==>sql_back_initialize()\n", 0, 0, 0 );
59         
60         bi->bi_db_init = backsql_db_init;
61         bi->bi_db_config = backsql_db_config;
62         bi->bi_db_open = backsql_db_open;
63         bi->bi_db_close = backsql_db_close;
64         bi->bi_db_destroy = backsql_db_destroy;
65
66         bi->bi_op_abandon = 0;
67         bi->bi_op_compare = backsql_compare;
68         bi->bi_op_bind = backsql_bind;
69         bi->bi_op_unbind = 0;
70         bi->bi_op_search = backsql_search;
71         bi->bi_op_modify = backsql_modify;
72         bi->bi_op_modrdn = backsql_modrdn;
73         bi->bi_op_add = backsql_add;
74         bi->bi_op_delete = backsql_delete;
75         
76         bi->bi_chk_referrals = 0;
77         bi->bi_operational = backsql_operational;
78         bi->bi_entry_get_rw = backsql_entry_get;
79         bi->bi_entry_release_rw = backsql_entry_release;
80  
81         bi->bi_connection_init = 0;
82
83         Debug( LDAP_DEBUG_TRACE,"<==sql_back_initialize()\n", 0, 0, 0 );
84         return 0;
85 }
86
87 int
88 backsql_destroy( 
89         BackendInfo     *bi )
90 {
91         Debug( LDAP_DEBUG_TRACE, "==>backsql_destroy()\n", 0, 0, 0 );
92         Debug( LDAP_DEBUG_TRACE, "<==backsql_destroy()\n", 0, 0, 0 );
93         return 0;
94 }
95
96 int
97 backsql_db_init(
98         BackendDB       *bd,
99         ConfigReply     *cr )
100 {
101         backsql_info    *bi;
102         int             rc = 0;
103  
104         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_init()\n", 0, 0, 0 );
105
106         bi = (backsql_info *)ch_calloc( 1, sizeof( backsql_info ) );
107         ldap_pvt_thread_mutex_init( &bi->sql_dbconn_mutex );
108         ldap_pvt_thread_mutex_init( &bi->sql_schema_mutex );
109
110         if ( backsql_init_db_env( bi ) != SQL_SUCCESS ) {
111                 rc = -1;
112         }
113
114         bd->be_private = bi;
115
116         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_init()\n", 0, 0, 0 );
117
118         return rc;
119 }
120
121 int
122 backsql_db_destroy(
123         BackendDB       *bd,
124         ConfigReply     *cr )
125 {
126         backsql_info    *bi = (backsql_info*)bd->be_private;
127  
128         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_destroy()\n", 0, 0, 0 );
129
130         backsql_free_db_env( bi );
131         ldap_pvt_thread_mutex_destroy( &bi->sql_dbconn_mutex );
132         backsql_destroy_schema_map( bi );
133         ldap_pvt_thread_mutex_destroy( &bi->sql_schema_mutex );
134
135         if ( bi->sql_dbname ) {
136                 ch_free( bi->sql_dbname );
137         }
138         if ( bi->sql_dbuser ) {
139                 ch_free( bi->sql_dbuser );
140         }
141         if ( bi->sql_dbpasswd ) {
142                 ch_free( bi->sql_dbpasswd );
143         }
144         if ( bi->sql_dbhost ) {
145                 ch_free( bi->sql_dbhost );
146         }
147         if ( bi->sql_upper_func.bv_val ) {
148                 ch_free( bi->sql_upper_func.bv_val );
149                 ch_free( bi->sql_upper_func_open.bv_val );
150                 ch_free( bi->sql_upper_func_close.bv_val );
151         }
152         if ( bi->sql_concat_func ) {
153                 ber_bvarray_free( bi->sql_concat_func );
154         }
155         if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
156                 ch_free( bi->sql_strcast_func.bv_val );
157         }
158         if ( !BER_BVISNULL( &bi->sql_children_cond ) ) {
159                 ch_free( bi->sql_children_cond.bv_val );
160         }
161         if ( !BER_BVISNULL( &bi->sql_dn_match_cond ) ) {
162                 ch_free( bi->sql_dn_match_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         struct berbuf   bb = BB_NULL;
228
229         Connection      conn = { 0 };
230         OperationBuffer opbuf;
231         Operation*      op;
232         SQLHDBC         dbh = SQL_NULL_HDBC;
233         void            *thrctx = ldap_pvt_thread_pool_context();
234
235         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_open(): "
236                 "testing RDBMS connection\n", 0, 0, 0 );
237         if ( bi->sql_dbname == NULL ) {
238                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
239                         "datasource name not specified "
240                         "(use \"dbname\" directive in slapd.conf)\n", 0, 0, 0 );
241                 return 1;
242         }
243
244         if ( bi->sql_concat_func == NULL ) {
245                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
246                         "concat func not specified (use \"concat_pattern\" "
247                         "directive in slapd.conf)\n", 0, 0, 0 );
248
249                 if ( backsql_split_pattern( backsql_def_concat_func, 
250                                 &bi->sql_concat_func, 2 ) ) {
251                         Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
252                                 "unable to parse pattern \"%s\"",
253                                 backsql_def_concat_func, 0, 0 );
254                         return 1;
255                 }
256         }
257
258         /*
259          * see back-sql.h for default values
260          */
261         if ( BER_BVISNULL( &bi->sql_aliasing ) ) {
262                 ber_str2bv( BACKSQL_ALIASING,
263                         STRLENOF( BACKSQL_ALIASING ),
264                         1, &bi->sql_aliasing );
265         }
266
267         if ( BER_BVISNULL( &bi->sql_aliasing_quote ) ) {
268                 ber_str2bv( BACKSQL_ALIASING_QUOTE,
269                         STRLENOF( BACKSQL_ALIASING_QUOTE ),
270                         1, &bi->sql_aliasing_quote );
271         }
272
273         /*
274          * Prepare cast string as required
275          */
276         if ( bi->sql_upper_func.bv_val ) {
277                 char buf[1024];
278
279                 if ( BACKSQL_UPPER_NEEDS_CAST( bi ) ) {
280                         snprintf( buf, sizeof( buf ), 
281                                 "%s(cast (" /* ? as varchar(%d))) */ , 
282                                 bi->sql_upper_func.bv_val );
283                         ber_str2bv( buf, 0, 1, &bi->sql_upper_func_open );
284
285                         snprintf( buf, sizeof( buf ),
286                                 /* (cast(? */ " as varchar(%d)))",
287                                 BACKSQL_MAX_DN_LEN );
288                         ber_str2bv( buf, 0, 1, &bi->sql_upper_func_close );
289
290                 } else {
291                         snprintf( buf, sizeof( buf ), "%s(" /* ?) */ ,
292                                         bi->sql_upper_func.bv_val );
293                         ber_str2bv( buf, 0, 1, &bi->sql_upper_func_open );
294
295                         ber_str2bv( /* (? */ ")", 0, 1, &bi->sql_upper_func_close );
296                 }
297         }
298
299         /* normalize filter values only if necessary */
300         bi->sql_caseIgnoreMatch = mr_find( "caseIgnoreMatch" );
301         assert( bi->sql_caseIgnoreMatch != NULL );
302
303         bi->sql_telephoneNumberMatch = mr_find( "telephoneNumberMatch" );
304         assert( bi->sql_telephoneNumberMatch != NULL );
305
306         if ( bi->sql_dbuser == NULL ) {
307                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
308                         "user name not specified "
309                         "(use \"dbuser\" directive in slapd.conf)\n", 0, 0, 0 );
310                 return 1;
311         }
312         
313         if ( BER_BVISNULL( &bi->sql_subtree_cond ) ) {
314                 /*
315                  * Prepare concat function for subtree search condition
316                  */
317                 struct berval   concat;
318                 struct berval   values[] = {
319                         BER_BVC( "'%'" ),
320                         BER_BVC( "?" ),
321                         BER_BVNULL
322                 };
323                 struct berbuf   bb = BB_NULL;
324
325                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
326                         "subtree search SQL condition not specified "
327                         "(use \"subtree_cond\" directive in slapd.conf); "
328                         "preparing default\n", 
329                         0, 0, 0);
330
331                 if ( backsql_prepare_pattern( bi->sql_concat_func, values, 
332                                 &concat ) ) {
333                         Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
334                                 "unable to prepare CONCAT pattern for subtree search",
335                                 0, 0, 0 );
336                         return 1;
337                 }
338                         
339                 if ( bi->sql_upper_func.bv_val ) {
340
341                         /*
342                          * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%',?))
343                          */
344
345                         backsql_strfcat_x( &bb, NULL, "blbbb",
346                                         &bi->sql_upper_func,
347                                         (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ),
348                                                 "(ldap_entries.dn) LIKE ",
349                                         &bi->sql_upper_func_open,
350                                         &concat,
351                                         &bi->sql_upper_func_close );
352
353                 } else {
354
355                         /*
356                          * ldap_entries.dn LIKE CONCAT('%',?)
357                          */
358
359                         backsql_strfcat_x( &bb, NULL, "lb",
360                                         (ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ),
361                                                 "ldap_entries.dn LIKE ",
362                                         &concat );
363                 }
364
365                 ch_free( concat.bv_val );
366
367                 bi->sql_subtree_cond = bb.bb_val;
368                         
369                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
370                         "setting \"%s\" as default \"subtree_cond\"\n",
371                         bi->sql_subtree_cond.bv_val, 0, 0 );
372         }
373
374         if ( bi->sql_children_cond.bv_val == NULL ) {
375                 /*
376                  * Prepare concat function for children search condition
377                  */
378                 struct berval   concat;
379                 struct berval   values[] = {
380                         BER_BVC( "'%,'" ),
381                         BER_BVC( "?" ),
382                         BER_BVNULL
383                 };
384                 struct berbuf   bb = BB_NULL;
385
386                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
387                         "children search SQL condition not specified "
388                         "(use \"children_cond\" directive in slapd.conf); "
389                         "preparing default\n", 
390                         0, 0, 0);
391
392                 if ( backsql_prepare_pattern( bi->sql_concat_func, values, 
393                                 &concat ) ) {
394                         Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
395                                 "unable to prepare CONCAT pattern for children search", 0, 0, 0 );
396                         return 1;
397                 }
398                         
399                 if ( bi->sql_upper_func.bv_val ) {
400
401                         /*
402                          * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%,',?))
403                          */
404
405                         backsql_strfcat_x( &bb, NULL, "blbbb",
406                                         &bi->sql_upper_func,
407                                         (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ),
408                                                 "(ldap_entries.dn) LIKE ",
409                                         &bi->sql_upper_func_open,
410                                         &concat,
411                                         &bi->sql_upper_func_close );
412
413                 } else {
414
415                         /*
416                          * ldap_entries.dn LIKE CONCAT('%,',?)
417                          */
418
419                         backsql_strfcat_x( &bb, NULL, "lb",
420                                         (ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ),
421                                                 "ldap_entries.dn LIKE ",
422                                         &concat );
423                 }
424
425                 ch_free( concat.bv_val );
426
427                 bi->sql_children_cond = bb.bb_val;
428                         
429                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
430                         "setting \"%s\" as default \"children_cond\"\n",
431                         bi->sql_children_cond.bv_val, 0, 0 );
432         }
433
434         if ( bi->sql_dn_match_cond.bv_val == NULL ) {
435                 /*
436                  * Prepare concat function for dn match search condition
437                  */
438                 struct berbuf   bb = BB_NULL;
439
440                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
441                         "DN match search SQL condition not specified "
442                         "(use \"dn_match_cond\" directive in slapd.conf); "
443                         "preparing default\n", 
444                         0, 0, 0);
445
446                 if ( bi->sql_upper_func.bv_val ) {
447
448                         /*
449                          * UPPER(ldap_entries.dn)=?
450                          */
451
452                         backsql_strfcat_x( &bb, NULL, "blbcb",
453                                         &bi->sql_upper_func,
454                                         (ber_len_t)STRLENOF( "(ldap_entries.dn)=" ),
455                                                 "(ldap_entries.dn)=",
456                                         &bi->sql_upper_func_open,
457                                         '?',
458                                         &bi->sql_upper_func_close );
459
460                 } else {
461
462                         /*
463                          * ldap_entries.dn=?
464                          */
465
466                         backsql_strfcat_x( &bb, NULL, "l",
467                                         (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
468                                                 "ldap_entries.dn=?" );
469                 }
470
471                 bi->sql_dn_match_cond = bb.bb_val;
472                         
473                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
474                         "setting \"%s\" as default \"dn_match_cond\"\n",
475                         bi->sql_dn_match_cond.bv_val, 0, 0 );
476         }
477
478         if ( bi->sql_oc_query == NULL ) {
479                 if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
480                         bi->sql_oc_query =
481                                 ch_strdup( backsql_def_needs_select_oc_query );
482
483                 } else {
484                         bi->sql_oc_query = ch_strdup( backsql_def_oc_query );
485                 }
486
487                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
488                         "objectclass mapping SQL statement not specified "
489                         "(use \"oc_query\" directive in slapd.conf)\n", 
490                         0, 0, 0 );
491                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
492                         "setting \"%s\" by default\n", bi->sql_oc_query, 0, 0 );
493         }
494         
495         if ( bi->sql_at_query == NULL ) {
496                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
497                         "attribute mapping SQL statement not specified "
498                         "(use \"at_query\" directive in slapd.conf)\n",
499                         0, 0, 0 );
500                 Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
501                         "setting \"%s\" by default\n",
502                         backsql_def_at_query, 0, 0 );
503                 bi->sql_at_query = ch_strdup( backsql_def_at_query );
504         }
505         
506         if ( bi->sql_insentry_stmt == NULL ) {
507                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
508                         "entry insertion SQL statement not specified "
509                         "(use \"insentry_stmt\" directive in slapd.conf)\n",
510                         0, 0, 0 );
511                 Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
512                         "setting \"%s\" by default\n",
513                         backsql_def_insentry_stmt, 0, 0 );
514                 bi->sql_insentry_stmt = ch_strdup( backsql_def_insentry_stmt );
515         }
516         
517         if ( bi->sql_delentry_stmt == NULL ) {
518                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
519                         "entry deletion SQL statement not specified "
520                         "(use \"delentry_stmt\" directive in slapd.conf)\n",
521                         0, 0, 0 );
522                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
523                         "setting \"%s\" by default\n",
524                         backsql_def_delentry_stmt, 0, 0 );
525                 bi->sql_delentry_stmt = ch_strdup( backsql_def_delentry_stmt );
526         }
527
528         if ( bi->sql_renentry_stmt == NULL ) {
529                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
530                         "entry deletion SQL statement not specified "
531                         "(use \"renentry_stmt\" directive in slapd.conf)\n",
532                         0, 0, 0 );
533                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
534                         "setting \"%s\" by default\n",
535                         backsql_def_renentry_stmt, 0, 0 );
536                 bi->sql_renentry_stmt = ch_strdup( backsql_def_renentry_stmt );
537         }
538
539         if ( bi->sql_delobjclasses_stmt == NULL ) {
540                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
541                         "objclasses deletion SQL statement not specified "
542                         "(use \"delobjclasses_stmt\" directive in slapd.conf)\n",
543                         0, 0, 0 );
544                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
545                         "setting \"%s\" by default\n",
546                         backsql_def_delobjclasses_stmt, 0, 0 );
547                 bi->sql_delobjclasses_stmt = ch_strdup( backsql_def_delobjclasses_stmt );
548         }
549
550         /* This should just be to force schema loading */
551         connection_fake_init2( &conn, &opbuf, thrctx, 0 );
552         op = &opbuf.ob_op;
553         op->o_bd = bd;
554         if ( backsql_get_db_conn( op, &dbh ) != LDAP_SUCCESS ) {
555                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
556                         "connection failed, exiting\n", 0, 0, 0 );
557                 return 1;
558         }
559         if ( backsql_load_schema_map( bi, dbh ) != LDAP_SUCCESS ) {
560                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
561                         "schema mapping failed, exiting\n", 0, 0, 0 );
562                 return 1;
563         }
564         if ( backsql_free_db_conn( op, dbh ) != SQL_SUCCESS ) {
565                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
566                         "connection free failed\n", 0, 0, 0 );
567         }
568         if ( !BACKSQL_SCHEMA_LOADED( bi ) ) {
569                 Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
570                         "test failed, schema map not loaded - exiting\n",
571                         0, 0, 0 );
572                 return 1;
573         }
574
575         /*
576          * Prepare ID selection query
577          */
578         if ( bi->sql_id_query == NULL ) {
579                 /* no custom id_query provided */
580                 if ( bi->sql_upper_func.bv_val == NULL ) {
581                         backsql_strcat_x( &bb, NULL, backsql_id_query, "dn=?", NULL );
582
583                 } else {
584                         if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
585                                 backsql_strcat_x( &bb, NULL, backsql_id_query,
586                                                 "dn_ru=?", NULL );
587                         } else {
588                                 if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
589                                         backsql_strfcat_x( &bb, NULL, "sbl",
590                                                         backsql_id_query,
591                                                         &bi->sql_upper_func, 
592                                                         (ber_len_t)STRLENOF( "(dn)=?" ), "(dn)=?" );
593                                 } else {
594                                         backsql_strfcat_x( &bb, NULL, "sblbcb",
595                                                         backsql_id_query,
596                                                         &bi->sql_upper_func, 
597                                                         (ber_len_t)STRLENOF( "(dn)=" ), "(dn)=",
598                                                         &bi->sql_upper_func_open, 
599                                                         '?', 
600                                                         &bi->sql_upper_func_close );
601                                 }
602                         }
603                 }
604                 bi->sql_id_query = bb.bb_val.bv_val;
605         }
606
607         /*
608          * Prepare children count query
609          */
610         BER_BVZERO( &bb.bb_val );
611         bb.bb_len = 0;
612         backsql_strfcat_x( &bb, NULL, "sbsb",
613                         "SELECT COUNT(distinct subordinates.id) "
614                         "FROM ldap_entries,ldap_entries ",
615                         &bi->sql_aliasing, "subordinates "
616                         "WHERE subordinates.parent=ldap_entries.id AND ",
617                         &bi->sql_dn_match_cond );
618         bi->sql_has_children_query = bb.bb_val.bv_val;
619  
620         /*
621          * Prepare DN and objectClass aliasing bit of query
622          */
623         BER_BVZERO( &bb.bb_val );
624         bb.bb_len = 0;
625         backsql_strfcat_x( &bb, NULL, "sbbsbsbbsb",
626                         " ", &bi->sql_aliasing, &bi->sql_aliasing_quote,
627                         "objectClass", &bi->sql_aliasing_quote,
628                         ",ldap_entries.dn ", &bi->sql_aliasing,
629                         &bi->sql_aliasing_quote, "dn", &bi->sql_aliasing_quote );
630         bi->sql_dn_oc_aliasing = bb.bb_val;
631  
632         /* should never happen! */
633         assert( bd->be_nsuffix != NULL );
634         
635         if ( BER_BVISNULL( &bd->be_nsuffix[ 1 ] ) ) {
636                 /* enable if only one suffix is defined */
637                 bi->sql_flags |= BSQLF_USE_SUBTREE_SHORTCUT;
638         }
639
640         bi->sql_flags |= BSQLF_CHECK_SCHEMA;
641         
642         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_open(): "
643                 "test succeeded, schema map loaded\n", 0, 0, 0 );
644         return 0;
645 }
646
647 int
648 backsql_db_close(
649         BackendDB       *bd,
650         ConfigReply     *cr )
651 {
652         backsql_info    *bi = (backsql_info*)bd->be_private;
653
654         Debug( LDAP_DEBUG_TRACE, "==>backsql_db_close()\n", 0, 0, 0 );
655
656         backsql_conn_destroy( bi );
657
658         Debug( LDAP_DEBUG_TRACE, "<==backsql_db_close()\n", 0, 0, 0 );
659
660         return 0;
661 }
662
663 #if SLAPD_SQL == SLAPD_MOD_DYNAMIC
664
665 /* conditionally define the init_module() function */
666 SLAP_BACKEND_INIT_MODULE( sql )
667
668 #endif /* SLAPD_SQL == SLAPD_MOD_DYNAMIC */
669