xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/back-sql/init.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: init.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
2 
3 /* OpenLDAP: pkg/ldap/servers/slapd/back-sql/init.c,v 1.73.2.7 2009/11/18 01:25:49 quanah Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1999-2009 The OpenLDAP Foundation.
7  * Portions Copyright 1999 Dmitry Kovalev.
8  * Portions Copyright 2002 Pierangelo Masarati.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work was initially developed by Dmitry Kovalev for inclusion
21  * by OpenLDAP Software.  Additional significant contributors include
22  * Pierangelo Masarati.
23  */
24 
25 #include "portable.h"
26 
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include "ac/string.h"
30 
31 #include "slap.h"
32 #include "config.h"
33 #include "proto-sql.h"
34 
35 int
36 sql_back_initialize(
37 	BackendInfo	*bi )
38 {
39 	static char *controls[] = {
40 		LDAP_CONTROL_ASSERT,
41 		LDAP_CONTROL_MANAGEDSAIT,
42 		LDAP_CONTROL_NOOP,
43 #ifdef SLAP_CONTROL_X_TREE_DELETE
44 		SLAP_CONTROL_X_TREE_DELETE,
45 #endif /* SLAP_CONTROL_X_TREE_DELETE */
46 #ifndef BACKSQL_ARBITRARY_KEY
47 		LDAP_CONTROL_PAGEDRESULTS,
48 #endif /* ! BACKSQL_ARBITRARY_KEY */
49 		NULL
50 	};
51 
52 	bi->bi_controls = controls;
53 
54 	bi->bi_flags |=
55 #if 0
56 		SLAP_BFLAG_INCREMENT |
57 #endif
58 		SLAP_BFLAG_REFERRALS;
59 
60 	Debug( LDAP_DEBUG_TRACE,"==>sql_back_initialize()\n", 0, 0, 0 );
61 
62 	bi->bi_db_init = backsql_db_init;
63 	bi->bi_db_config = backsql_db_config;
64 	bi->bi_db_open = backsql_db_open;
65 	bi->bi_db_close = backsql_db_close;
66 	bi->bi_db_destroy = backsql_db_destroy;
67 
68 	bi->bi_op_abandon = 0;
69 	bi->bi_op_compare = backsql_compare;
70 	bi->bi_op_bind = backsql_bind;
71 	bi->bi_op_unbind = 0;
72 	bi->bi_op_search = backsql_search;
73 	bi->bi_op_modify = backsql_modify;
74 	bi->bi_op_modrdn = backsql_modrdn;
75 	bi->bi_op_add = backsql_add;
76 	bi->bi_op_delete = backsql_delete;
77 
78 	bi->bi_chk_referrals = 0;
79 	bi->bi_operational = backsql_operational;
80 	bi->bi_entry_get_rw = backsql_entry_get;
81 	bi->bi_entry_release_rw = backsql_entry_release;
82 
83 	bi->bi_connection_init = 0;
84 
85 	Debug( LDAP_DEBUG_TRACE,"<==sql_back_initialize()\n", 0, 0, 0 );
86 	return 0;
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 
672