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/>.
4 * Copyright 1999-2008 The OpenLDAP Foundation.
5 * Portions Copyright 1999 Dmitry Kovalev.
6 * Portions Copyright 2002 Pierangelo Masarati.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
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>.
18 * This work was initially developed by Dmitry Kovalev for inclusion
19 * by OpenLDAP Software. Additional significant contributors include
20 * Pierangelo Masarati.
26 #include <sys/types.h>
27 #include "ac/string.h"
31 #include "proto-sql.h"
37 static char *controls
[] = {
39 LDAP_CONTROL_MANAGEDSAIT
,
41 #ifdef SLAP_CONTROL_X_TREE_DELETE
42 SLAP_CONTROL_X_TREE_DELETE
,
43 #endif /* SLAP_CONTROL_X_TREE_DELETE */
44 LDAP_CONTROL_PAGEDRESULTS
,
48 bi
->bi_controls
= controls
;
52 SLAP_BFLAG_INCREMENT
|
56 Debug( LDAP_DEBUG_TRACE
,"==>sql_back_initialize()\n", 0, 0, 0 );
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
;
64 bi
->bi_op_abandon
= 0;
65 bi
->bi_op_compare
= backsql_compare
;
66 bi
->bi_op_bind
= backsql_bind
;
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
;
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
;
79 bi
->bi_connection_init
= 0;
81 Debug( LDAP_DEBUG_TRACE
,"<==sql_back_initialize()\n", 0, 0, 0 );
89 Debug( LDAP_DEBUG_TRACE
, "==>backsql_destroy()\n", 0, 0, 0 );
90 Debug( LDAP_DEBUG_TRACE
, "<==backsql_destroy()\n", 0, 0, 0 );
102 Debug( LDAP_DEBUG_TRACE
, "==>backsql_db_init()\n", 0, 0, 0 );
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
);
108 if ( backsql_init_db_env( bi
) != SQL_SUCCESS
) {
114 Debug( LDAP_DEBUG_TRACE
, "<==backsql_db_init()\n", 0, 0, 0 );
124 backsql_info
*bi
= (backsql_info
*)bd
->be_private
;
126 Debug( LDAP_DEBUG_TRACE
, "==>backsql_db_destroy()\n", 0, 0, 0 );
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
);
133 if ( bi
->sql_dbname
) {
134 ch_free( bi
->sql_dbname
);
136 if ( bi
->sql_dbuser
) {
137 ch_free( bi
->sql_dbuser
);
139 if ( bi
->sql_dbpasswd
) {
140 ch_free( bi
->sql_dbpasswd
);
142 if ( bi
->sql_dbhost
) {
143 ch_free( bi
->sql_dbhost
);
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
);
150 if ( bi
->sql_concat_func
) {
151 ber_bvarray_free( bi
->sql_concat_func
);
153 if ( !BER_BVISNULL( &bi
->sql_strcast_func
) ) {
154 ch_free( bi
->sql_strcast_func
.bv_val
);
156 if ( !BER_BVISNULL( &bi
->sql_children_cond
) ) {
157 ch_free( bi
->sql_children_cond
.bv_val
);
159 if ( !BER_BVISNULL( &bi
->sql_dn_match_cond
) ) {
160 ch_free( bi
->sql_dn_match_cond
.bv_val
);
162 if ( !BER_BVISNULL( &bi
->sql_subtree_cond
) ) {
163 ch_free( bi
->sql_subtree_cond
.bv_val
);
165 if ( !BER_BVISNULL( &bi
->sql_dn_oc_aliasing
) ) {
166 ch_free( bi
->sql_dn_oc_aliasing
.bv_val
);
168 if ( bi
->sql_oc_query
) {
169 ch_free( bi
->sql_oc_query
);
171 if ( bi
->sql_at_query
) {
172 ch_free( bi
->sql_at_query
);
174 if ( bi
->sql_id_query
) {
175 ch_free( bi
->sql_id_query
);
177 if ( bi
->sql_has_children_query
) {
178 ch_free( bi
->sql_has_children_query
);
180 if ( bi
->sql_insentry_stmt
) {
181 ch_free( bi
->sql_insentry_stmt
);
183 if ( bi
->sql_delentry_stmt
) {
184 ch_free( bi
->sql_delentry_stmt
);
186 if ( bi
->sql_renentry_stmt
) {
187 ch_free( bi
->sql_renentry_stmt
);
189 if ( bi
->sql_delobjclasses_stmt
) {
190 ch_free( bi
->sql_delobjclasses_stmt
);
192 if ( !BER_BVISNULL( &bi
->sql_aliasing
) ) {
193 ch_free( bi
->sql_aliasing
.bv_val
);
195 if ( !BER_BVISNULL( &bi
->sql_aliasing_quote
) ) {
196 ch_free( bi
->sql_aliasing_quote
.bv_val
);
199 if ( bi
->sql_anlist
) {
202 for ( i
= 0; !BER_BVISNULL( &bi
->sql_anlist
[ i
].an_name
); i
++ )
204 ch_free( bi
->sql_anlist
[ i
].an_name
.bv_val
);
206 ch_free( bi
->sql_anlist
);
209 if ( bi
->sql_baseObject
) {
210 entry_free( bi
->sql_baseObject
);
215 Debug( LDAP_DEBUG_TRACE
, "<==backsql_db_destroy()\n", 0, 0, 0 );
224 backsql_info
*bi
= (backsql_info
*)bd
->be_private
;
225 struct berbuf bb
= BB_NULL
;
227 Connection conn
= { 0 };
228 OperationBuffer opbuf
;
230 SQLHDBC dbh
= SQL_NULL_HDBC
;
231 void *thrctx
= ldap_pvt_thread_pool_context();
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 );
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 );
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 );
257 * see back-sql.h for default values
259 if ( BER_BVISNULL( &bi
->sql_aliasing
) ) {
260 ber_str2bv( BACKSQL_ALIASING
,
261 STRLENOF( BACKSQL_ALIASING
),
262 1, &bi
->sql_aliasing
);
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
);
272 * Prepare cast string as required
274 if ( bi
->sql_upper_func
.bv_val
) {
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
);
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
);
289 snprintf( buf
, sizeof( buf
), "%s(" /* ?) */ ,
290 bi
->sql_upper_func
.bv_val
);
291 ber_str2bv( buf
, 0, 1, &bi
->sql_upper_func_open
);
293 ber_str2bv( /* (? */ ")", 0, 1, &bi
->sql_upper_func_close
);
297 /* normalize filter values only if necessary */
298 bi
->sql_caseIgnoreMatch
= mr_find( "caseIgnoreMatch" );
299 assert( bi
->sql_caseIgnoreMatch
!= NULL
);
301 bi
->sql_telephoneNumberMatch
= mr_find( "telephoneNumberMatch" );
302 assert( bi
->sql_telephoneNumberMatch
!= NULL
);
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 );
311 if ( BER_BVISNULL( &bi
->sql_subtree_cond
) ) {
313 * Prepare concat function for subtree search condition
315 struct berval concat
;
316 struct berval values
[] = {
321 struct berbuf bb
= BB_NULL
;
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",
329 if ( backsql_prepare_pattern( bi
->sql_concat_func
, values
,
331 Debug( LDAP_DEBUG_TRACE
, "backsql_db_open(): "
332 "unable to prepare CONCAT pattern for subtree search",
337 if ( bi
->sql_upper_func
.bv_val
) {
340 * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%',?))
343 backsql_strfcat_x( &bb
, NULL
, "blbbb",
345 (ber_len_t
)STRLENOF( "(ldap_entries.dn) LIKE " ),
346 "(ldap_entries.dn) LIKE ",
347 &bi
->sql_upper_func_open
,
349 &bi
->sql_upper_func_close
);
354 * ldap_entries.dn LIKE CONCAT('%',?)
357 backsql_strfcat_x( &bb
, NULL
, "lb",
358 (ber_len_t
)STRLENOF( "ldap_entries.dn LIKE " ),
359 "ldap_entries.dn LIKE ",
363 ch_free( concat
.bv_val
);
365 bi
->sql_subtree_cond
= bb
.bb_val
;
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 );
372 if ( bi
->sql_children_cond
.bv_val
== NULL
) {
374 * Prepare concat function for children search condition
376 struct berval concat
;
377 struct berval values
[] = {
382 struct berbuf bb
= BB_NULL
;
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",
390 if ( backsql_prepare_pattern( bi
->sql_concat_func
, values
,
392 Debug( LDAP_DEBUG_TRACE
, "backsql_db_open(): "
393 "unable to prepare CONCAT pattern for children search", 0, 0, 0 );
397 if ( bi
->sql_upper_func
.bv_val
) {
400 * UPPER(ldap_entries.dn) LIKE UPPER(CONCAT('%,',?))
403 backsql_strfcat_x( &bb
, NULL
, "blbbb",
405 (ber_len_t
)STRLENOF( "(ldap_entries.dn) LIKE " ),
406 "(ldap_entries.dn) LIKE ",
407 &bi
->sql_upper_func_open
,
409 &bi
->sql_upper_func_close
);
414 * ldap_entries.dn LIKE CONCAT('%,',?)
417 backsql_strfcat_x( &bb
, NULL
, "lb",
418 (ber_len_t
)STRLENOF( "ldap_entries.dn LIKE " ),
419 "ldap_entries.dn LIKE ",
423 ch_free( concat
.bv_val
);
425 bi
->sql_children_cond
= bb
.bb_val
;
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 );
432 if ( bi
->sql_dn_match_cond
.bv_val
== NULL
) {
434 * Prepare concat function for dn match search condition
436 struct berbuf bb
= BB_NULL
;
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",
444 if ( bi
->sql_upper_func
.bv_val
) {
447 * UPPER(ldap_entries.dn)=?
450 backsql_strfcat_x( &bb
, NULL
, "blbcb",
452 (ber_len_t
)STRLENOF( "(ldap_entries.dn)=" ),
453 "(ldap_entries.dn)=",
454 &bi
->sql_upper_func_open
,
456 &bi
->sql_upper_func_close
);
464 backsql_strfcat_x( &bb
, NULL
, "l",
465 (ber_len_t
)STRLENOF( "ldap_entries.dn=?" ),
466 "ldap_entries.dn=?" );
469 bi
->sql_dn_match_cond
= bb
.bb_val
;
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 );
476 if ( bi
->sql_oc_query
== NULL
) {
477 if ( BACKSQL_CREATE_NEEDS_SELECT( bi
) ) {
479 ch_strdup( backsql_def_needs_select_oc_query
);
482 bi
->sql_oc_query
= ch_strdup( backsql_def_oc_query
);
485 Debug( LDAP_DEBUG_TRACE
, "backsql_db_open(): "
486 "objectclass mapping SQL statement not specified "
487 "(use \"oc_query\" directive in slapd.conf)\n",
489 Debug( LDAP_DEBUG_TRACE
, "backsql_db_open(): "
490 "setting \"%s\" by default\n", bi
->sql_oc_query
, 0, 0 );
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",
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
);
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",
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
);
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",
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
);
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",
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
);
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",
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
);
548 /* This should just be to force schema loading */
549 connection_fake_init( &conn
, &opbuf
, thrctx
);
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 );
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 );
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 );
566 if ( !BACKSQL_SCHEMA_LOADED( bi
) ) {
567 Debug( LDAP_DEBUG_TRACE
, "backsql_db_open(): "
568 "test failed, schema map not loaded - exiting\n",
574 * Prepare ID selection query
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
);
582 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi
) ) {
583 backsql_strcat_x( &bb
, NULL
, backsql_id_query
,
586 if ( BACKSQL_USE_REVERSE_DN( bi
) ) {
587 backsql_strfcat_x( &bb
, NULL
, "sbl",
590 (ber_len_t
)STRLENOF( "(dn)=?" ), "(dn)=?" );
592 backsql_strfcat_x( &bb
, NULL
, "sblbcb",
595 (ber_len_t
)STRLENOF( "(dn)=" ), "(dn)=",
596 &bi
->sql_upper_func_open
,
598 &bi
->sql_upper_func_close
);
602 bi
->sql_id_query
= bb
.bb_val
.bv_val
;
606 * Prepare children count query
608 BER_BVZERO( &bb
.bb_val
);
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
;
619 * Prepare DN and objectClass aliasing bit of query
621 BER_BVZERO( &bb
.bb_val
);
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
;
630 /* should never happen! */
631 assert( bd
->be_nsuffix
!= NULL
);
633 if ( BER_BVISNULL( &bd
->be_nsuffix
[ 1 ] ) ) {
634 /* enable if only one suffix is defined */
635 bi
->sql_flags
|= BSQLF_USE_SUBTREE_SHORTCUT
;
638 bi
->sql_flags
|= BSQLF_CHECK_SCHEMA
;
640 Debug( LDAP_DEBUG_TRACE
, "<==backsql_db_open(): "
641 "test succeeded, schema map loaded\n", 0, 0, 0 );
650 backsql_info
*bi
= (backsql_info
*)bd
->be_private
;
652 Debug( LDAP_DEBUG_TRACE
, "==>backsql_db_close()\n", 0, 0, 0 );
654 backsql_conn_destroy( bi
);
656 Debug( LDAP_DEBUG_TRACE
, "<==backsql_db_close()\n", 0, 0, 0 );
661 #if SLAPD_SQL == SLAPD_MOD_DYNAMIC
663 /* conditionally define the init_module() function */
664 SLAP_BACKEND_INIT_MODULE( sql
)
666 #endif /* SLAPD_SQL == SLAPD_MOD_DYNAMIC */