2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2004 The OpenLDAP Foundation.
5 * Portions Copyright 1999 Dmitry Kovalev.
6 * Portions Copyright 2004 Mark Adamson.
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.
25 #include <sys/types.h>
26 #include "ac/string.h"
29 #include "proto-sql.h"
31 #ifdef BACKSQL_ARBITRARY_KEY
32 struct berval backsql_baseObject_bv = BER_BVC( BACKSQL_BASEOBJECT_IDSTR );
33 #endif /* BACKSQL_ARBITRARY_KEY */
36 backsql_free_entryID( backsql_entryID *id, int freeit )
38 backsql_entryID *next;
44 if ( !BER_BVISNULL( &id->eid_ndn ) ) {
45 if ( !BER_BVISNULL( &id->eid_dn )
46 && id->eid_dn.bv_val != id->eid_ndn.bv_val )
48 free( id->eid_dn.bv_val );
49 BER_BVZERO( &id->eid_dn );
52 free( id->eid_ndn.bv_val );
53 BER_BVZERO( &id->eid_ndn );
56 #ifdef BACKSQL_ARBITRARY_KEY
57 if ( id->eid_id.bv_val ) {
58 free( id->eid_id.bv_val );
59 BER_BVZERO( &id->eid_id );
62 if ( id->eid_keyval.bv_val ) {
63 free( id->eid_keyval.bv_val );
64 BER_BVZERO( &id->eid_keyval );
66 #endif /* BACKSQL_ARBITRARY_KEY */
76 * NOTE: the dn must be normalized
87 backsql_info *bi = op->o_bd->be_private;
88 SQLHSTMT sth = SQL_NULL_HSTMT;
92 struct berval realndn = BER_BVNULL;
95 char upperdn[ BACKSQL_MAX_DN_LEN + 1 ];
100 * NOTE: id can be NULL; in this case, the function
101 * simply checks whether the DN can be successfully
102 * turned into an ID, returning LDAP_SUCCESS for
103 * positive cases, or the most appropriate error
106 Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(): dn=\"%s\"%s\n",
107 ndn->bv_val, id == NULL ? " (no ID)" : "", 0 );
109 if ( ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
110 Debug( LDAP_DEBUG_TRACE,
111 "backsql_dn2id(): DN \"%s\" (%ld bytes) "
112 "exceeds max DN length (%d):\n",
113 ndn->bv_val, ndn->bv_len, BACKSQL_MAX_DN_LEN );
117 /* return baseObject if available and matches */
118 /* FIXME: if ndn is already mucked, we cannot check this */
119 if ( bi->sql_baseObject != NULL &&
120 dn_match( ndn, &bi->sql_baseObject->e_nname ) )
123 #ifdef BACKSQL_ARBITRARY_KEY
124 ber_dupbv( &id->eid_id, &backsql_baseObject_bv );
125 ber_dupbv( &id->eid_keyval, &backsql_baseObject_bv );
126 #else /* ! BACKSQL_ARBITRARY_KEY */
127 id->eid_id = BACKSQL_BASEOBJECT_ID;
128 id->eid_keyval = BACKSQL_BASEOBJECT_KEYVAL;
129 #endif /* ! BACKSQL_ARBITRARY_KEY */
130 id->eid_oc_id = BACKSQL_BASEOBJECT_OC;
132 ber_dupbv( &id->eid_ndn, &bi->sql_baseObject->e_nname );
133 ber_dupbv( &id->eid_dn, &bi->sql_baseObject->e_name );
142 Debug( LDAP_DEBUG_TRACE, "id_query \"%s\"\n", bi->sql_id_query, 0, 0 );
143 assert( bi->sql_id_query );
144 rc = backsql_Prepare( dbh, &sth, bi->sql_id_query, 0 );
145 if ( rc != SQL_SUCCESS ) {
146 Debug( LDAP_DEBUG_TRACE,
147 "backsql_dn2id(): error preparing SQL:\n%s",
148 bi->sql_id_query, 0, 0);
149 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
156 if ( backsql_api_dn2odbc( op, rs, &realndn ) ) {
157 Debug( LDAP_DEBUG_TRACE, " backsql_dn2id(\"%s\"): "
158 "backsql_api_dn2odbc(\"%s\") failed\n",
159 ndn->bv_val, realndn.bv_val, 0 );
165 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
167 * Prepare an upper cased, byte reversed version
168 * that can be searched using indexes
171 for ( i = 0, j = realndn.bv_len - 1; realndn.bv_val[ i ]; i++, j--)
173 upperdn[ i ] = realndn.bv_val[ j ];
176 ldap_pvt_str2upper( upperdn );
178 Debug( LDAP_DEBUG_TRACE, "==>backsql_dn2id(): upperdn=\"%s\"\n",
180 ber_str2bv( upperdn, 0, 0, &tbbDN );
183 if ( BACKSQL_USE_REVERSE_DN( bi ) ) {
184 AC_MEMCPY( upperdn, realndn.bv_val, realndn.bv_len + 1 );
185 ldap_pvt_str2upper( upperdn );
186 Debug( LDAP_DEBUG_TRACE,
187 "==>backsql_dn2id(): upperdn=\"%s\"\n",
189 ber_str2bv( upperdn, 0, 0, &tbbDN );
196 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, &tbbDN );
197 if ( rc != SQL_SUCCESS) {
199 Debug( LDAP_DEBUG_TRACE, "backsql_dn2id(): "
200 "error binding dn=\"%s\" parameter:\n",
201 tbbDN.bv_val, 0, 0 );
202 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
207 rc = SQLExecute( sth );
208 if ( rc != SQL_SUCCESS ) {
209 Debug( LDAP_DEBUG_TRACE, "backsql_dn2id(): "
210 "error executing query (\"%s\", \"%s\"):\n",
211 bi->sql_id_query, tbbDN.bv_val, 0 );
212 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
217 backsql_BindRowAsStrings( sth, &row );
218 rc = SQLFetch( sth );
219 if ( BACKSQL_SUCCESS( rc ) ) {
223 snprintf( buf, sizeof(buf),
224 "id=%s keyval=%s oc_id=%s dn=%s",
225 row.cols[ 0 ], row.cols[ 1 ],
226 row.cols[ 2 ], row.cols[ 3 ] );
227 Debug( LDAP_DEBUG_TRACE,
228 "<==backsql_dn2id(): %s\n", buf, 0, 0 );
229 #endif /* LDAP_DEBUG */
235 #ifdef BACKSQL_ARBITRARY_KEY
236 ber_str2bv( row.cols[ 0 ], 0, 1, &id->eid_id );
237 ber_str2bv( row.cols[ 1 ], 0, 1, &id->eid_keyval );
238 #else /* ! BACKSQL_ARBITRARY_KEY */
239 id->eid_id = strtol( row.cols[ 0 ], NULL, 0 );
240 id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 );
241 #endif /* ! BACKSQL_ARBITRARY_KEY */
242 id->eid_oc_id = strtol( row.cols[ 2 ], NULL, 0 );
244 ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
246 if ( backsql_api_odbc2dn( op, rs, &dn ) ) {
250 res = dnPrettyNormal( NULL, &dn, &id->eid_dn, &id->eid_ndn, NULL );
251 if ( res != LDAP_SUCCESS ) {
252 Debug( LDAP_DEBUG_TRACE,
253 "<==backsql_dn2id(\"%s\"): "
254 "dnPrettyNormal failed (%d: %s)\n",
256 ldap_err2string( res ) );
259 (void)backsql_free_entryID( id, 0 );
262 if ( dn.bv_val != row.cols[ 3 ] ) {
271 res = LDAP_NO_SUCH_OBJECT;
272 Debug( LDAP_DEBUG_TRACE, "<==backsql_dn2id(): no match\n",
275 backsql_FreeRow( &row );
278 if ( sth != SQL_NULL_HSTMT ) {
279 SQLFreeStmt( sth, SQL_DROP );
282 if ( !BER_BVISNULL( &realndn ) && realndn.bv_val != ndn->bv_val ) {
283 ch_free( realndn.bv_val );
290 backsql_count_children(
294 unsigned long *nchildren )
296 SQLHSTMT sth = SQL_NULL_HSTMT;
299 int res = LDAP_SUCCESS;
301 Debug( LDAP_DEBUG_TRACE, "==>backsql_count_children(): dn=\"%s\"\n",
304 if ( dn->bv_len > BACKSQL_MAX_DN_LEN ) {
305 Debug( LDAP_DEBUG_TRACE,
306 "backsql_count_children(): DN \"%s\" (%ld bytes) "
307 "exceeds max DN length (%d):\n",
308 dn->bv_val, dn->bv_len, BACKSQL_MAX_DN_LEN );
313 Debug(LDAP_DEBUG_TRACE, "children id query \"%s\"\n",
314 bi->sql_has_children_query, 0, 0);
315 assert( bi->sql_has_children_query );
316 rc = backsql_Prepare( dbh, &sth, bi->sql_has_children_query, 0 );
317 if ( rc != SQL_SUCCESS ) {
318 Debug( LDAP_DEBUG_TRACE,
319 "backsql_count_children(): error preparing SQL:\n%s",
320 bi->sql_has_children_query, 0, 0);
321 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
322 SQLFreeStmt( sth, SQL_DROP );
326 rc = backsql_BindParamBerVal( sth, 1, SQL_PARAM_INPUT, dn );
327 if ( rc != SQL_SUCCESS) {
329 Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): "
330 "error binding dn=\"%s\" parameter:\n",
332 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
333 SQLFreeStmt( sth, SQL_DROP );
337 rc = SQLExecute( sth );
338 if ( rc != SQL_SUCCESS ) {
339 Debug( LDAP_DEBUG_TRACE, "backsql_count_children(): "
340 "error executing query (\"%s\", \"%s\"):\n",
341 bi->sql_has_children_query, dn->bv_val, 0 );
342 backsql_PrintErrors( bi->sql_db_env, dbh, sth, rc );
343 SQLFreeStmt( sth, SQL_DROP );
347 backsql_BindRowAsStrings( sth, &row );
349 rc = SQLFetch( sth );
350 if ( BACKSQL_SUCCESS( rc ) ) {
353 *nchildren = strtol( row.cols[ 0 ], &end, 0 );
354 if ( end[ 0 ] != '\0' && end[0] != '.' ) {
355 /* FIXME: braindead RDBMSes return
356 * a fractional number from COUNT!
364 backsql_FreeRow( &row );
366 SQLFreeStmt( sth, SQL_DROP );
368 Debug( LDAP_DEBUG_TRACE, "<==backsql_count_children(): %lu\n",
375 backsql_has_children(
380 unsigned long nchildren;
383 rc = backsql_count_children( bi, dbh, dn, &nchildren );
385 if ( rc == LDAP_SUCCESS ) {
386 return nchildren > 0 ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE;
393 backsql_get_attr_vals( void *v_at, void *v_bsi )
395 backsql_at_map_rec *at = v_at;
396 backsql_srch_info *bsi = v_bsi;
397 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
399 SQLHSTMT sth = SQL_NULL_HSTMT;
406 #ifdef BACKSQL_ARBITRARY_KEY
407 Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
408 "oc=\"%s\" attr=\"%s\" keyval=%s\n",
409 BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val,
410 bsi->bsi_c_eid->eid_keyval.bv_val );
411 #else /* ! BACKSQL_ARBITRARY_KEY */
412 Debug( LDAP_DEBUG_TRACE, "==>backsql_get_attr_vals(): "
413 "oc=\"%s\" attr=\"%s\" keyval=%ld\n",
414 BACKSQL_OC_NAME( bsi->bsi_oc ), at->bam_ad->ad_cname.bv_val,
415 bsi->bsi_c_eid->eid_keyval );
416 #endif /* ! BACKSQL_ARBITRARY_KEY */
418 rc = backsql_Prepare( bsi->bsi_dbh, &sth, at->bam_query, 0 );
419 if ( rc != SQL_SUCCESS ) {
420 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): "
421 "error preparing query: %s\n", at->bam_query, 0, 0 );
422 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
426 rc = backsql_BindParamID( sth, 1, SQL_PARAM_INPUT,
427 &bsi->bsi_c_eid->eid_keyval );
428 if ( rc != SQL_SUCCESS ) {
429 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): "
430 "error binding key value parameter\n", 0, 0, 0 );
435 #ifdef BACKSQL_ARBITRARY_KEY
436 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): "
437 "query=\"%s\" keyval=%s\n", at->bam_query,
438 bsi->bsi_c_eid->eid_keyval.bv_val, 0 );
439 #else /* !BACKSQL_ARBITRARY_KEY */
440 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): "
441 "query=\"%s\" keyval=%d\n", at->bam_query,
442 bsi->bsi_c_eid->eid_keyval, 0 );
443 #endif /* ! BACKSQL_ARBITRARY_KEY */
444 #endif /* BACKSQL_TRACE */
446 rc = SQLExecute( sth );
447 if ( ! BACKSQL_SUCCESS( rc ) ) {
448 Debug( LDAP_DEBUG_TRACE, "backsql_get_attr_values(): "
449 "error executing attribute query \"%s\"\n",
450 at->bam_query, 0, 0 );
451 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
452 SQLFreeStmt( sth, SQL_DROP );
456 backsql_BindRowAsStrings( sth, &row );
458 rc = SQLFetch( sth );
459 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
460 for ( i = 0; i < row.ncols; i++ ) {
461 if ( row.value_len[ i ] > 0 ) {
464 bv.bv_val = row.cols[ i ];
466 bv.bv_len = row.col_prec[ i ];
469 * FIXME: what if a binary
472 bv.bv_len = strlen( row.cols[ i ] );
474 backsql_entry_addattr( bsi->bsi_e,
475 &row.col_names[ i ], &bv,
476 bsi->bsi_op->o_tmpmemctx );
479 Debug( LDAP_DEBUG_TRACE, "prec=%d\n",
480 (int)row.col_prec[ i ], 0, 0 );
482 Debug( LDAP_DEBUG_TRACE, "NULL value "
483 "in this row for attribute \"%s\"\n",
484 row.col_names[ i ].bv_val, 0, 0 );
485 #endif /* BACKSQL_TRACE */
490 backsql_FreeRow( &row );
491 SQLFreeStmt( sth, SQL_DROP );
492 Debug( LDAP_DEBUG_TRACE, "<==backsql_get_attr_vals()\n", 0, 0, 0 );
494 if ( at->bam_next ) {
495 return backsql_get_attr_vals( at->bam_next, v_bsi );
502 backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid )
504 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
507 AttributeDescription *ad_oc = slap_schema.si_ad_objectClass;
509 Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 );
511 assert( bsi->bsi_e );
513 memset( bsi->bsi_e, 0, sizeof( Entry ) );
515 if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
518 e = entry_dup( bi->sql_baseObject );
520 return LDAP_NO_MEMORY;
528 ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, bsi->bsi_op->o_tmpmemctx );
529 ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, bsi->bsi_op->o_tmpmemctx );
531 bsi->bsi_e->e_attrs = NULL;
532 bsi->bsi_e->e_private = NULL;
534 bsi->bsi_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private,
536 bsi->bsi_c_eid = eid;
538 #ifndef BACKSQL_ARBITRARY_KEY
539 bsi->bsi_e->e_id = eid->eid_id;
540 #endif /* ! BACKSQL_ARBITRARY_KEY */
542 rc = attr_merge_normalize_one( bsi->bsi_e, ad_oc,
543 &bsi->bsi_oc->bom_oc->soc_cname,
544 bsi->bsi_op->o_tmpmemctx );
545 if ( rc != LDAP_SUCCESS ) {
546 entry_clean( bsi->bsi_e );
550 if ( bsi->bsi_attrs == NULL || ( bsi->bsi_flags & BSQL_SF_ALL_USER ) )
552 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
553 "retrieving all attributes\n", 0, 0, 0 );
554 avl_apply( bsi->bsi_oc->bom_attrs, backsql_get_attr_vals,
555 bsi, 0, AVL_INORDER );
558 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
559 "custom attribute list\n", 0, 0, 0 );
560 for ( i = 0; bsi->bsi_attrs[ i ].an_name.bv_val; i++ ) {
561 backsql_at_map_rec **vat;
562 AttributeName *an = &bsi->bsi_attrs[ i ];
565 /* if one of the attributes listed here is
566 * a subtype of another, it must be ignored,
567 * because subtypes are already dealt with
568 * by backsql_supad2at()
570 for ( j = 0; bsi->bsi_attrs[ j ].an_name.bv_val; j++ ) {
577 if ( is_at_subtype( an->an_desc->ad_type,
578 bsi->bsi_attrs[ j ].an_desc->ad_type ) )
584 rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat );
585 if ( rc != 0 || vat == NULL ) {
586 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): "
587 "attribute \"%s\" is not defined "
588 "for objectlass \"%s\"\n",
590 BACKSQL_OC_NAME( bsi->bsi_oc ), 0 );
594 for ( j = 0; vat[j]; j++ ) {
595 backsql_get_attr_vals( vat[j], bsi );
604 if ( bsi->bsi_flags & BSQL_SF_RETURN_ENTRYUUID ) {
605 Attribute *a_entryUUID,
608 a_entryUUID = backsql_operational_entryUUID( bi, eid );
609 if ( a_entryUUID != NULL ) {
610 for ( ap = &bsi->bsi_e->e_attrs;
612 ap = &(*ap)->a_next );
618 if ( global_schemacheck ) {
619 const char *text = NULL;
620 char textbuf[ 1024 ];
621 size_t textlen = sizeof( textbuf );
622 struct berval bv[ 2 ];
626 bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname;
627 bv[ 1 ].bv_val = NULL;
629 rc = structural_class( bv, &soc, NULL,
630 &text, textbuf, textlen );
631 if ( rc != LDAP_SUCCESS ) {
632 Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): "
633 "structural_class() failed %d (%s)\n",
634 bsi->bsi_e->e_name.bv_val,
635 rc, text ? text : "" );
636 entry_clean( bsi->bsi_e );
640 if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER )
641 || an_find( bsi->bsi_attrs, &AllOper )
642 || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) )
644 rc = attr_merge_normalize_one( bsi->bsi_e,
645 slap_schema.si_ad_structuralObjectClass,
646 &soc, bsi->bsi_op->o_tmpmemctx );
647 if ( rc != LDAP_SUCCESS ) {
648 entry_clean( bsi->bsi_e );
655 Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 );