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
33int
34sql_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
89int
90backsql_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
98int
99backsql_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
123int
124backsql_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
223int
224backsql_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
649int
650backsql_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 */
668SLAP_BACKEND_INIT_MODULE( sql )
669
670#endif /* SLAPD_SQL == SLAPD_MOD_DYNAMIC */
671
672