xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-sql/init.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/init.c,v 1.73.2.4 2008/02/11 23:26:48 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2008 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 		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 
81 	Debug( LDAP_DEBUG_TRACE,"<==sql_back_initialize()\n", 0, 0, 0 );
82 	return 0;
83 }
84 
85 int
86 backsql_destroy(
87 	BackendInfo 	*bi )
88 {
89 	Debug( LDAP_DEBUG_TRACE, "==>backsql_destroy()\n", 0, 0, 0 );
90 	Debug( LDAP_DEBUG_TRACE, "<==backsql_destroy()\n", 0, 0, 0 );
91 	return 0;
92 }
93 
94 int
95 backsql_db_init(
96 	BackendDB 	*bd,
97 	ConfigReply	*cr )
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 	ConfigReply	*cr )
123 {
124 	backsql_info	*bi = (backsql_info*)bd->be_private;
125 
126 	Debug( LDAP_DEBUG_TRACE, "==>backsql_db_destroy()\n", 0, 0, 0 );
127 
128 	backsql_free_db_env( bi );
129 	ldap_pvt_thread_mutex_destroy( &bi->sql_dbconn_mutex );
130 	backsql_destroy_schema_map( bi );
131 	ldap_pvt_thread_mutex_destroy( &bi->sql_schema_mutex );
132 
133 	if ( bi->sql_dbname ) {
134 		ch_free( bi->sql_dbname );
135 	}
136 	if ( bi->sql_dbuser ) {
137 		ch_free( bi->sql_dbuser );
138 	}
139 	if ( bi->sql_dbpasswd ) {
140 		ch_free( bi->sql_dbpasswd );
141 	}
142 	if ( bi->sql_dbhost ) {
143 		ch_free( bi->sql_dbhost );
144 	}
145 	if ( bi->sql_upper_func.bv_val ) {
146 		ch_free( bi->sql_upper_func.bv_val );
147 		ch_free( bi->sql_upper_func_open.bv_val );
148 		ch_free( bi->sql_upper_func_close.bv_val );
149 	}
150 	if ( bi->sql_concat_func ) {
151 		ber_bvarray_free( bi->sql_concat_func );
152 	}
153 	if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
154 		ch_free( bi->sql_strcast_func.bv_val );
155 	}
156 	if ( !BER_BVISNULL( &bi->sql_children_cond ) ) {
157 		ch_free( bi->sql_children_cond.bv_val );
158 	}
159 	if ( !BER_BVISNULL( &bi->sql_dn_match_cond ) ) {
160 		ch_free( bi->sql_dn_match_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 	ConfigReply	*cr )
223 {
224 	backsql_info 	*bi = (backsql_info*)bd->be_private;
225 	struct berbuf	bb = BB_NULL;
226 
227 	Connection	conn = { 0 };
228 	OperationBuffer opbuf;
229 	Operation*	op;
230 	SQLHDBC		dbh = SQL_NULL_HDBC;
231 	void		*thrctx = ldap_pvt_thread_pool_context();
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 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
324 			"subtree search SQL condition not specified "
325 			"(use \"subtree_cond\" directive in slapd.conf); "
326 			"preparing default\n",
327 			0, 0, 0);
328 
329 		if ( backsql_prepare_pattern( bi->sql_concat_func, values,
330 				&concat ) ) {
331 			Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
332 				"unable to prepare CONCAT pattern for subtree search",
333 				0, 0, 0 );
334 			return 1;
335 		}
336 
337 		if ( bi->sql_upper_func.bv_val ) {
338 
339 			/*
340 			 * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%',?))
341 			 */
342 
343 			backsql_strfcat_x( &bb, NULL, "blbbb",
344 					&bi->sql_upper_func,
345 					(ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ),
346 						"(ldap_entries.dn) LIKE ",
347 					&bi->sql_upper_func_open,
348 					&concat,
349 					&bi->sql_upper_func_close );
350 
351 		} else {
352 
353 			/*
354 			 * ldap_entries.dn LIKE CONCAT('%',?)
355 			 */
356 
357 			backsql_strfcat_x( &bb, NULL, "lb",
358 					(ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ),
359 						"ldap_entries.dn LIKE ",
360 					&concat );
361 		}
362 
363 		ch_free( concat.bv_val );
364 
365 		bi->sql_subtree_cond = bb.bb_val;
366 
367 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
368 			"setting \"%s\" as default \"subtree_cond\"\n",
369 			bi->sql_subtree_cond.bv_val, 0, 0 );
370 	}
371 
372 	if ( bi->sql_children_cond.bv_val == NULL ) {
373 		/*
374 		 * Prepare concat function for children search condition
375 		 */
376 		struct berval	concat;
377 		struct berval	values[] = {
378 			BER_BVC( "'%,'" ),
379 			BER_BVC( "?" ),
380 			BER_BVNULL
381 		};
382 		struct berbuf	bb = BB_NULL;
383 
384 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
385 			"children search SQL condition not specified "
386 			"(use \"children_cond\" directive in slapd.conf); "
387 			"preparing default\n",
388 			0, 0, 0);
389 
390 		if ( backsql_prepare_pattern( bi->sql_concat_func, values,
391 				&concat ) ) {
392 			Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
393 				"unable to prepare CONCAT pattern for children search", 0, 0, 0 );
394 			return 1;
395 		}
396 
397 		if ( bi->sql_upper_func.bv_val ) {
398 
399 			/*
400 			 * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%,',?))
401 			 */
402 
403 			backsql_strfcat_x( &bb, NULL, "blbbb",
404 					&bi->sql_upper_func,
405 					(ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE " ),
406 						"(ldap_entries.dn) LIKE ",
407 					&bi->sql_upper_func_open,
408 					&concat,
409 					&bi->sql_upper_func_close );
410 
411 		} else {
412 
413 			/*
414 			 * ldap_entries.dn LIKE CONCAT('%,',?)
415 			 */
416 
417 			backsql_strfcat_x( &bb, NULL, "lb",
418 					(ber_len_t)STRLENOF( "ldap_entries.dn LIKE " ),
419 						"ldap_entries.dn LIKE ",
420 					&concat );
421 		}
422 
423 		ch_free( concat.bv_val );
424 
425 		bi->sql_children_cond = bb.bb_val;
426 
427 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
428 			"setting \"%s\" as default \"children_cond\"\n",
429 			bi->sql_children_cond.bv_val, 0, 0 );
430 	}
431 
432 	if ( bi->sql_dn_match_cond.bv_val == NULL ) {
433 		/*
434 		 * Prepare concat function for dn match search condition
435 		 */
436 		struct berbuf	bb = BB_NULL;
437 
438 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
439 			"DN match search SQL condition not specified "
440 			"(use \"dn_match_cond\" directive in slapd.conf); "
441 			"preparing default\n",
442 			0, 0, 0);
443 
444 		if ( bi->sql_upper_func.bv_val ) {
445 
446 			/*
447 			 * UPPER(ldap_entries.dn)=?
448 			 */
449 
450 			backsql_strfcat_x( &bb, NULL, "blbcb",
451 					&bi->sql_upper_func,
452 					(ber_len_t)STRLENOF( "(ldap_entries.dn)=" ),
453 						"(ldap_entries.dn)=",
454 					&bi->sql_upper_func_open,
455 					'?',
456 					&bi->sql_upper_func_close );
457 
458 		} else {
459 
460 			/*
461 			 * ldap_entries.dn=?
462 			 */
463 
464 			backsql_strfcat_x( &bb, NULL, "l",
465 					(ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
466 						"ldap_entries.dn=?" );
467 		}
468 
469 		bi->sql_dn_match_cond = bb.bb_val;
470 
471 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
472 			"setting \"%s\" as default \"dn_match_cond\"\n",
473 			bi->sql_dn_match_cond.bv_val, 0, 0 );
474 	}
475 
476 	if ( bi->sql_oc_query == NULL ) {
477 		if ( BACKSQL_CREATE_NEEDS_SELECT( bi ) ) {
478 			bi->sql_oc_query =
479 				ch_strdup( backsql_def_needs_select_oc_query );
480 
481 		} else {
482 			bi->sql_oc_query = ch_strdup( backsql_def_oc_query );
483 		}
484 
485 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
486 			"objectclass mapping SQL statement not specified "
487 			"(use \"oc_query\" directive in slapd.conf)\n",
488 			0, 0, 0 );
489 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
490 			"setting \"%s\" by default\n", bi->sql_oc_query, 0, 0 );
491 	}
492 
493 	if ( bi->sql_at_query == NULL ) {
494 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
495 			"attribute mapping SQL statement not specified "
496 			"(use \"at_query\" directive in slapd.conf)\n",
497 			0, 0, 0 );
498 		Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
499 			"setting \"%s\" by default\n",
500 			backsql_def_at_query, 0, 0 );
501 		bi->sql_at_query = ch_strdup( backsql_def_at_query );
502 	}
503 
504 	if ( bi->sql_insentry_stmt == NULL ) {
505 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
506 			"entry insertion SQL statement not specified "
507 			"(use \"insentry_stmt\" directive in slapd.conf)\n",
508 			0, 0, 0 );
509 		Debug(LDAP_DEBUG_TRACE, "backsql_db_open(): "
510 			"setting \"%s\" by default\n",
511 			backsql_def_insentry_stmt, 0, 0 );
512 		bi->sql_insentry_stmt = ch_strdup( backsql_def_insentry_stmt );
513 	}
514 
515 	if ( bi->sql_delentry_stmt == NULL ) {
516 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
517 			"entry deletion SQL statement not specified "
518 			"(use \"delentry_stmt\" directive in slapd.conf)\n",
519 			0, 0, 0 );
520 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
521 			"setting \"%s\" by default\n",
522 			backsql_def_delentry_stmt, 0, 0 );
523 		bi->sql_delentry_stmt = ch_strdup( backsql_def_delentry_stmt );
524 	}
525 
526 	if ( bi->sql_renentry_stmt == NULL ) {
527 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
528 			"entry deletion SQL statement not specified "
529 			"(use \"renentry_stmt\" directive in slapd.conf)\n",
530 			0, 0, 0 );
531 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
532 			"setting \"%s\" by default\n",
533 			backsql_def_renentry_stmt, 0, 0 );
534 		bi->sql_renentry_stmt = ch_strdup( backsql_def_renentry_stmt );
535 	}
536 
537 	if ( bi->sql_delobjclasses_stmt == NULL ) {
538 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
539 			"objclasses deletion SQL statement not specified "
540 			"(use \"delobjclasses_stmt\" directive in slapd.conf)\n",
541 			0, 0, 0 );
542 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
543 			"setting \"%s\" by default\n",
544 			backsql_def_delobjclasses_stmt, 0, 0 );
545 		bi->sql_delobjclasses_stmt = ch_strdup( backsql_def_delobjclasses_stmt );
546 	}
547 
548 	/* This should just be to force schema loading */
549 	connection_fake_init( &conn, &opbuf, thrctx );
550 	op = &opbuf.ob_op;
551 	op->o_bd = bd;
552 	if ( backsql_get_db_conn( op, &dbh ) != LDAP_SUCCESS ) {
553 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
554 			"connection failed, exiting\n", 0, 0, 0 );
555 		return 1;
556 	}
557 	if ( backsql_load_schema_map( bi, dbh ) != LDAP_SUCCESS ) {
558 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
559 			"schema mapping failed, exiting\n", 0, 0, 0 );
560 		return 1;
561 	}
562 	if ( backsql_free_db_conn( op, dbh ) != SQL_SUCCESS ) {
563 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
564 			"connection free failed\n", 0, 0, 0 );
565 	}
566 	if ( !BACKSQL_SCHEMA_LOADED( bi ) ) {
567 		Debug( LDAP_DEBUG_TRACE, "backsql_db_open(): "
568 			"test failed, schema map not loaded - exiting\n",
569 			0, 0, 0 );
570 		return 1;
571 	}
572 
573 	/*
574 	 * Prepare ID selection query
575 	 */
576 	if ( bi->sql_id_query == NULL ) {
577 		/* no custom id_query provided */
578 		if ( bi->sql_upper_func.bv_val == NULL ) {
579 			backsql_strcat_x( &bb, NULL, backsql_id_query, "dn=?", NULL );
580 
581 		} else {
582 			if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
583 				backsql_strcat_x( &bb, NULL, backsql_id_query,
584 						"dn_ru=?", NULL );
585 			} else {
586 				if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
587 					backsql_strfcat_x( &bb, NULL, "sbl",
588 							backsql_id_query,
589 							&bi->sql_upper_func,
590 							(ber_len_t)STRLENOF( "(dn)=?" ), "(dn)=?" );
591 				} else {
592 					backsql_strfcat_x( &bb, NULL, "sblbcb",
593 							backsql_id_query,
594 							&bi->sql_upper_func,
595 							(ber_len_t)STRLENOF( "(dn)=" ), "(dn)=",
596 							&bi->sql_upper_func_open,
597 							'?',
598 							&bi->sql_upper_func_close );
599 				}
600 			}
601 		}
602 		bi->sql_id_query = bb.bb_val.bv_val;
603 	}
604 
605 	/*
606 	 * Prepare children count query
607 	 */
608 	BER_BVZERO( &bb.bb_val );
609 	bb.bb_len = 0;
610 	backsql_strfcat_x( &bb, NULL, "sbsb",
611 			"SELECT COUNT(distinct subordinates.id) "
612 			"FROM ldap_entries,ldap_entries ",
613 			&bi->sql_aliasing, "subordinates "
614 			"WHERE subordinates.parent=ldap_entries.id AND ",
615 			&bi->sql_dn_match_cond );
616 	bi->sql_has_children_query = bb.bb_val.bv_val;
617 
618 	/*
619 	 * Prepare DN and objectClass aliasing bit of query
620 	 */
621 	BER_BVZERO( &bb.bb_val );
622 	bb.bb_len = 0;
623 	backsql_strfcat_x( &bb, NULL, "sbbsbsbbsb",
624 			" ", &bi->sql_aliasing, &bi->sql_aliasing_quote,
625 			"objectClass", &bi->sql_aliasing_quote,
626 			",ldap_entries.dn ", &bi->sql_aliasing,
627 			&bi->sql_aliasing_quote, "dn", &bi->sql_aliasing_quote );
628 	bi->sql_dn_oc_aliasing = bb.bb_val;
629 
630 	/* should never happen! */
631 	assert( bd->be_nsuffix != NULL );
632 
633 	if ( BER_BVISNULL( &bd->be_nsuffix[ 1 ] ) ) {
634 		/* enable if only one suffix is defined */
635 		bi->sql_flags |= BSQLF_USE_SUBTREE_SHORTCUT;
636 	}
637 
638 	bi->sql_flags |= BSQLF_CHECK_SCHEMA;
639 
640 	Debug( LDAP_DEBUG_TRACE, "<==backsql_db_open(): "
641 		"test succeeded, schema map loaded\n", 0, 0, 0 );
642 	return 0;
643 }
644 
645 int
646 backsql_db_close(
647 	BackendDB	*bd,
648 	ConfigReply	*cr )
649 {
650 	backsql_info 	*bi = (backsql_info*)bd->be_private;
651 
652 	Debug( LDAP_DEBUG_TRACE, "==>backsql_db_close()\n", 0, 0, 0 );
653 
654 	backsql_conn_destroy( bi );
655 
656 	Debug( LDAP_DEBUG_TRACE, "<==backsql_db_close()\n", 0, 0, 0 );
657 
658 	return 0;
659 }
660 
661 #if SLAPD_SQL == SLAPD_MOD_DYNAMIC
662 
663 /* conditionally define the init_module() function */
664 SLAP_BACKEND_INIT_MODULE( sql )
665 
666 #endif /* SLAPD_SQL == SLAPD_MOD_DYNAMIC */
667 
668