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