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