2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2005 The OpenLDAP Foundation.
5 * Portions Copyright 1999 Dmitry Kovalev.
6 * Portions Copyright 2002 Pierangelo Masarati.
7 * Portions Copyright 2004 Mark Adamson.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
19 * This work was initially developed by Dmitry Kovalev for inclusion
20 * by OpenLDAP Software. Additional significant contributors include
21 * Pierangelo Masarati and Mark Adamson.
27 #include <sys/types.h>
28 #include "ac/string.h"
32 #include "proto-sql.h"
34 static int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
35 static int backsql_process_filter_eq( backsql_srch_info *bsi,
36 backsql_at_map_rec *at,
37 int casefold, struct berval *filter_value );
38 static int backsql_process_filter_like( backsql_srch_info *bsi,
39 backsql_at_map_rec *at,
40 int casefold, struct berval *filter_value );
41 static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f,
42 backsql_at_map_rec *at );
45 backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
48 AttributeName *an = NULL;
50 if ( bsi->bsi_attrs == NULL ) {
55 * clear the list (retrieve all attrs)
58 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx );
59 bsi->bsi_attrs = NULL;
60 bsi->bsi_flags |= BSQL_SF_ALL_ATTRS;
64 for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) {
65 an = &bsi->bsi_attrs[ n_attrs ];
67 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
68 "attribute \"%s\" is in list\n",
69 an->an_name.bv_val, 0, 0 );
71 * We can live with strcmp because the attribute
72 * list has been normalized before calling be_search
74 if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) {
79 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
80 "adding \"%s\" to list\n", ad->ad_cname.bv_val, 0, 0 );
82 an = (AttributeName *)bsi->bsi_op->o_tmprealloc( bsi->bsi_attrs,
83 sizeof( AttributeName ) * ( n_attrs + 2 ),
84 bsi->bsi_op->o_tmpmemctx );
89 an[ n_attrs ].an_name = ad->ad_cname;
90 an[ n_attrs ].an_desc = ad;
91 BER_BVZERO( &an[ n_attrs + 1 ].an_name );
99 * Initializes the search structure.
101 * If get_base_id != 0, the field bsi_base_id is filled
102 * with the entryID of bsi_base_ndn; it must be freed
103 * by backsql_free_entryID() when no longer required.
105 * NOTE: base must be normalized
109 backsql_srch_info *bsi,
110 struct berval *nbase,
119 AttributeName *attrs,
122 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
123 int rc = LDAP_SUCCESS;
125 bsi->bsi_base_ndn = nbase;
126 bsi->bsi_use_subtree_shortcut = 0;
127 BER_BVZERO( &bsi->bsi_base_id.eid_dn );
128 BER_BVZERO( &bsi->bsi_base_id.eid_ndn );
129 bsi->bsi_scope = scope;
130 bsi->bsi_slimit = slimit;
131 bsi->bsi_tlimit = tlimit;
132 bsi->bsi_filter = filter;
136 bsi->bsi_flags = BSQL_SF_NONE;
138 bsi->bsi_attrs = NULL;
140 if ( BACKSQL_FETCH_ALL_ATTRS( bi ) ) {
142 * if requested, simply try to fetch all attributes
144 bsi->bsi_flags |= BSQL_SF_ALL_ATTRS;
147 if ( BACKSQL_FETCH_ALL_USERATTRS( bi ) ) {
148 bsi->bsi_flags |= BSQL_SF_ALL_USER;
150 } else if ( BACKSQL_FETCH_ALL_OPATTRS( bi ) ) {
151 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
154 if ( attrs == NULL ) {
155 /* NULL means all user attributes */
156 bsi->bsi_flags |= BSQL_SF_ALL_USER;
162 bsi->bsi_attrs = (AttributeName *)bsi->bsi_op->o_tmpalloc(
163 sizeof( AttributeName ),
164 bsi->bsi_op->o_tmpmemctx );
165 BER_BVZERO( &bsi->bsi_attrs[ 0 ].an_name );
167 for ( p = attrs; !BER_BVISNULL( &p->an_name ); p++ ) {
168 if ( BACKSQL_NCMP( &p->an_name, &AllUser ) == 0 ) {
170 bsi->bsi_flags |= BSQL_SF_ALL_USER;
172 /* if all attrs are requested, there's
173 * no need to continue */
174 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
175 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
176 bsi->bsi_op->o_tmpmemctx );
177 bsi->bsi_attrs = NULL;
182 } else if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) {
184 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
186 /* if all attrs are requested, there's
187 * no need to continue */
188 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
189 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
190 bsi->bsi_op->o_tmpmemctx );
191 bsi->bsi_attrs = NULL;
196 } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
200 } else if ( p->an_desc == slap_schema.si_ad_objectClass ) {
204 backsql_attrlist_add( bsi, p->an_desc );
207 if ( got_oc == 0 && !( bsi->bsi_flags & BSQL_SF_ALL_USER ) ) {
208 /* add objectClass if not present,
209 * because it is required to understand
210 * if an entry is a referral, an alias
212 backsql_attrlist_add( bsi, slap_schema.si_ad_objectClass );
216 if ( !BSQL_ISF_ALL_ATTRS( bsi ) && bi->sql_anlist ) {
219 /* use hints if available */
220 for ( p = bi->sql_anlist; !BER_BVISNULL( &p->an_name ); p++ ) {
221 if ( BACKSQL_NCMP( &p->an_name, &AllUser ) == 0 ) {
223 bsi->bsi_flags |= BSQL_SF_ALL_USER;
225 /* if all attrs are requested, there's
226 * no need to continue */
227 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
228 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
229 bsi->bsi_op->o_tmpmemctx );
230 bsi->bsi_attrs = NULL;
235 } else if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) {
237 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
239 /* if all attrs are requested, there's
240 * no need to continue */
241 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
242 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
243 bsi->bsi_op->o_tmpmemctx );
244 bsi->bsi_attrs = NULL;
250 backsql_attrlist_add( bsi, p->an_desc );
256 bsi->bsi_abandon = 0;
257 bsi->bsi_id_list = NULL;
258 bsi->bsi_id_listtail = &bsi->bsi_id_list;
259 bsi->bsi_n_candidates = 0;
260 bsi->bsi_stoptime = stoptime;
261 BER_BVZERO( &bsi->bsi_sel.bb_val );
262 bsi->bsi_sel.bb_len = 0;
263 BER_BVZERO( &bsi->bsi_from.bb_val );
264 bsi->bsi_from.bb_len = 0;
265 BER_BVZERO( &bsi->bsi_join_where.bb_val );
266 bsi->bsi_join_where.bb_len = 0;
267 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
268 bsi->bsi_flt_where.bb_len = 0;
269 bsi->bsi_filter_oc = NULL;
271 if ( BACKSQL_IS_GET_ID( flags ) ) {
272 assert( op->o_bd->be_private );
274 rc = backsql_dn2id( op, rs, dbh, nbase, &bsi->bsi_base_id,
275 BACKSQL_IS_MATCHED( flags ), 1 );
278 bsi->bsi_status = rc;
286 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
287 bsi->bsi_op->o_tmpmemctx );
295 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
303 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' /* ) */ );
306 res = backsql_process_filter( bsi, f );
309 * TimesTen : If the query has no answers,
310 * don't bother to run the query.
321 case LDAP_FILTER_AND:
322 backsql_strfcat( &bsi->bsi_flt_where, "l",
323 (ber_len_t)STRLENOF( " AND " ),
328 backsql_strfcat( &bsi->bsi_flt_where, "l",
329 (ber_len_t)STRLENOF( " OR " ),
335 backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' );
341 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
342 backsql_at_map_rec *at )
344 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
352 /* always uppercase strings by now */
353 #ifdef BACKSQL_UPPERCASE_FILTER
354 if ( f->f_sub_desc->ad_type->sat_substr &&
355 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
356 bi->sql_caseIgnoreMatch ) )
357 #endif /* BACKSQL_UPPERCASE_FILTER */
362 if ( f->f_sub_desc->ad_type->sat_substr &&
363 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
364 bi->sql_telephoneNumberMatch ) )
371 * to check for matching telephone numbers
372 * with intermixed chars, e.g. val='1234'
375 * val LIKE '%1%2%3%4%'
379 if ( f->f_sub_initial.bv_val ) {
380 bv.bv_len += f->f_sub_initial.bv_len;
382 if ( f->f_sub_any != NULL ) {
383 for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) {
384 bv.bv_len += f->f_sub_any[ a ].bv_len;
387 if ( f->f_sub_final.bv_val ) {
388 bv.bv_len += f->f_sub_final.bv_len;
390 bv.bv_len = 2 * bv.bv_len - 1;
391 bv.bv_val = ch_malloc( bv.bv_len + 1 );
394 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
395 bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ];
396 for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) {
397 bv.bv_val[ s + 2 * i - 1 ] = '%';
398 bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ];
400 bv.bv_val[ s + 2 * i - 1 ] = '%';
404 if ( f->f_sub_any != NULL ) {
405 for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
406 bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ];
407 for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) {
408 bv.bv_val[ s + 2 * i - 1 ] = '%';
409 bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ];
411 bv.bv_val[ s + 2 * i - 1 ] = '%';
416 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
417 bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ];
418 for ( i = 1; i < f->f_sub_final.bv_len; i++ ) {
419 bv.bv_val[ s + 2 * i - 1 ] = '%';
420 bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ];
422 bv.bv_val[ s + 2 * i - 1 ] = '%';
426 bv.bv_val[ s - 1 ] = '\0';
428 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
429 ch_free( bv.bv_val );
435 * When dealing with case-sensitive strings
436 * we may omit normalization; however, normalized
437 * SQL filters are more liberal.
440 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' /* ) */ );
443 Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n",
444 at->bam_ad->ad_cname.bv_val, 0, 0 );
445 Debug(LDAP_DEBUG_TRACE, " expr: '%s%s%s'\n", at->bam_sel_expr.bv_val,
446 at->bam_sel_expr_u.bv_val ? "' '" : "",
447 at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" );
448 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
450 * If a pre-upper-cased version of the column
451 * or a precompiled upper function exists, use it
453 backsql_strfcat( &bsi->bsi_flt_where,
456 (ber_len_t)STRLENOF( " LIKE '" ),
460 backsql_strfcat( &bsi->bsi_flt_where, "bl",
462 (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
465 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
469 Debug( LDAP_DEBUG_TRACE,
470 "==>backsql_process_sub_filter(%s): "
471 "sub_initial=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
472 f->f_sub_initial.bv_val, 0 );
473 #endif /* BACKSQL_TRACE */
475 start = bsi->bsi_flt_where.bb_val.bv_len;
476 backsql_strfcat( &bsi->bsi_flt_where, "b",
478 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
479 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
483 backsql_strfcat( &bsi->bsi_flt_where, "c", '%' );
485 if ( f->f_sub_any != NULL ) {
486 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) {
490 Debug( LDAP_DEBUG_TRACE,
491 "==>backsql_process_sub_filter(%s): "
492 "sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
493 i, f->f_sub_any[ i ].bv_val );
494 #endif /* BACKSQL_TRACE */
496 start = bsi->bsi_flt_where.bb_val.bv_len;
497 backsql_strfcat( &bsi->bsi_flt_where,
501 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
503 * Note: toupper('%') = '%'
505 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
510 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
514 Debug( LDAP_DEBUG_TRACE,
515 "==>backsql_process_sub_filter(%s): "
516 "sub_final=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
517 f->f_sub_final.bv_val, 0 );
518 #endif /* BACKSQL_TRACE */
520 start = bsi->bsi_flt_where.bb_val.bv_len;
521 backsql_strfcat( &bsi->bsi_flt_where, "b",
523 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
524 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
528 backsql_strfcat( &bsi->bsi_flt_where, "l",
529 (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" );
535 backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls )
537 if ( BER_BVISNULL( from_tbls ) ) {
541 if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) {
542 char *start, *end, *tmp;
544 tmp = ch_strdup( from_tbls->bv_val );
546 for ( start = tmp, end = strchr( start, ',' ); start; ) {
551 if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL )
553 backsql_strfcat( &bsi->bsi_from, "cs", ',', start );
557 /* in case there are spaces after the comma... */
558 for ( start = &end[1]; isspace( start[0] ); start++ );
560 end = strchr( start, ',' );
572 backsql_strfcat( &bsi->bsi_from, "b", from_tbls );
579 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
581 backsql_at_map_rec **vat = NULL;
582 AttributeDescription *ad = NULL;
587 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 );
588 if ( f->f_choice == SLAPD_FILTER_COMPUTED ) {
589 Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
590 "invalid filter\n", 0, 0, 0 );
595 switch( f->f_choice ) {
597 rc = backsql_process_filter_list( bsi, f->f_or,
602 case LDAP_FILTER_AND:
603 rc = backsql_process_filter_list( bsi, f->f_and,
608 case LDAP_FILTER_NOT:
609 backsql_strfcat( &bsi->bsi_flt_where, "l",
610 (ber_len_t)STRLENOF( "NOT (" /* ) */ ),
612 rc = backsql_process_filter( bsi, f->f_not );
613 backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' );
617 case LDAP_FILTER_PRESENT:
621 case LDAP_FILTER_EXT:
622 ad = f->f_mra->ma_desc;
623 if ( f->f_mr_dnattrs ) {
625 * if dn attrs filtering is requested, better return
626 * success and let test_filter() deal with candidate
627 * selection; otherwise we'd need to set conditions
628 * on the contents of the DN, e.g. "SELECT ... FROM
629 * ldap_entries AS attributeName WHERE attributeName.dn
630 * like '%attributeName=value%'"
632 backsql_strfcat( &bsi->bsi_flt_where, "l",
633 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
634 bsi->bsi_status = LDAP_SUCCESS;
655 * Turn structuralObjectClass into objectClass
657 if ( ad == slap_schema.si_ad_objectClass
658 || ad == slap_schema.si_ad_structuralObjectClass )
661 * If the filter is LDAP_FILTER_PRESENT, then it's done;
662 * otherwise, let's see if we are lucky: filtering
663 * for "structural" objectclass or ancestor...
665 switch ( f->f_choice ) {
666 case LDAP_FILTER_EQUALITY:
668 ObjectClass *oc = oc_bvfind( &f->f_av_value );
671 Debug( LDAP_DEBUG_TRACE,
672 "backsql_process_filter(): "
673 "unknown objectClass \"%s\" "
675 f->f_av_value.bv_val, 0, 0 );
676 bsi->bsi_status = LDAP_OTHER;
682 * "structural" objectClass inheritance:
683 * - a search for "person" will also return
685 * - a search for "top" will return everything
687 if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
688 static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" );
690 backsql_merge_from_tbls( bsi, &ldap_entry_objclasses );
692 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
693 (ber_len_t)STRLENOF( "2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
694 "2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
695 &bsi->bsi_oc->bom_oc->soc_cname,
696 (ber_len_t)STRLENOF( /* (' */ "')" ),
698 bsi->bsi_status = LDAP_SUCCESS;
706 case LDAP_FILTER_PRESENT:
707 backsql_strfcat( &bsi->bsi_flt_where, "l",
708 (ber_len_t)STRLENOF( "3=3" ), "3=3" );
709 bsi->bsi_status = LDAP_SUCCESS;
713 /* FIXME: LDAP_FILTER_EXT? */
716 Debug( LDAP_DEBUG_TRACE,
717 "backsql_process_filter(): "
718 "illegal/unhandled filter "
719 "on objectClass attribute",
721 bsi->bsi_status = LDAP_OTHER;
726 } else if ( ad == slap_schema.si_ad_entryUUID ) {
728 #ifdef BACKSQL_ARBITRARY_KEY
729 struct berval keyval;
730 #else /* ! BACKSQL_ARBITRARY_KEY */
731 unsigned long keyval;
732 char keyvalbuf[] = "18446744073709551615";
733 #endif /* ! BACKSQL_ARBITRARY_KEY */
735 switch ( f->f_choice ) {
736 case LDAP_FILTER_EQUALITY:
737 backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval );
739 if ( oc_id != bsi->bsi_oc->bom_id ) {
740 bsi->bsi_status = LDAP_SUCCESS;
745 #ifdef BACKSQL_ARBITRARY_KEY
746 backsql_strfcat( &bsi->bsi_flt_where, "bcblbc",
747 &bsi->bsi_oc->bom_keytbl, '.',
748 &bsi->bsi_oc->bom_keycol,
749 STRLENOF( " LIKE '" ), " LIKE '",
751 #else /* ! BACKSQL_ARBITRARY_KEY */
752 snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval );
753 backsql_strfcat( &bsi->bsi_flt_where, "bcbcs",
754 &bsi->bsi_oc->bom_keytbl, '.',
755 &bsi->bsi_oc->bom_keycol, '=', keyvalbuf );
756 #endif /* ! BACKSQL_ARBITRARY_KEY */
759 case LDAP_FILTER_PRESENT:
760 backsql_strfcat( &bsi->bsi_flt_where, "l",
761 (ber_len_t)STRLENOF( "4=4" ), "4=4" );
769 bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID;
773 #ifdef BACKSQL_SYNCPROV
774 } else if ( ad == slap_schema.si_ad_entryCSN ) {
776 * support for syncrepl as producer...
778 if ( !bsi->bsi_op->o_sync ) {
779 /* unsupported at present... */
780 bsi->bsi_status = LDAP_OTHER;
785 bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID);
787 /* if doing a syncrepl, try to return as much as possible,
788 * and always match the filter */
789 backsql_strfcat( &bsi->bsi_flt_where, "l",
790 (ber_len_t)STRLENOF( "5=5" ), "5=5" );
792 /* save for later use in operational attributes */
793 /* FIXME: saves only the first occurrence, because
794 * the filter during updates is written as
795 * "(&(entryCSN<={contextCSN})(entryCSN>={oldContextCSN})({filter}))"
796 * so we want our fake entryCSN to match the greatest
799 if ( bsi->bsi_op->o_private == NULL ) {
800 bsi->bsi_op->o_private = &f->f_av_value;
802 bsi->bsi_status = LDAP_SUCCESS;
806 #endif /* BACKSQL_SYNCPROV */
808 } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
810 * FIXME: this is not robust; e.g. a filter
811 * '(!(hasSubordinates=TRUE))' fails because
812 * in SQL it would read 'NOT (1=1)' instead
814 * Note however that hasSubordinates is boolean,
815 * so a more appropriate filter would be
816 * '(hasSubordinates=FALSE)'
818 * A more robust search for hasSubordinates
819 * would * require joining the ldap_entries table
820 * selecting if there are descendants of the
823 backsql_strfcat( &bsi->bsi_flt_where, "l",
824 (ber_len_t)STRLENOF( "6=6" ), "6=6" );
825 if ( ad == slap_schema.si_ad_hasSubordinates ) {
827 * instruct candidate selection algorithm
828 * and attribute list to try to detect
829 * if an entry has subordinates
831 bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
835 * clear attributes to fetch, to require ALL
836 * and try extended match on all attributes
838 backsql_attrlist_add( bsi, NULL );
845 * attribute inheritance:
847 if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) {
848 bsi->bsi_status = LDAP_OTHER;
854 /* search anyway; other parts of the filter
856 backsql_strfcat( &bsi->bsi_flt_where, "l",
857 (ber_len_t)STRLENOF( "7=7" ), "7=7" );
858 bsi->bsi_status = LDAP_SUCCESS;
863 /* if required, open extra level of parens */
865 if ( vat[0]->bam_next || vat[1] ) {
866 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' );
873 if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) {
877 /* if more definitions of the same attr, apply */
878 if ( vat[i]->bam_next ) {
879 backsql_strfcat( &bsi->bsi_flt_where, "l",
880 STRLENOF( " OR " ), " OR " );
881 vat[i] = vat[i]->bam_next;
885 /* if more descendants of the same attr, apply */
888 backsql_strfcat( &bsi->bsi_flt_where, "l",
889 STRLENOF( " OR " ), " OR " );
893 /* if needed, close extra level of parens */
895 backsql_strfcat( &bsi->bsi_flt_where, "c", ')' );
905 Debug( LDAP_DEBUG_TRACE,
906 "<==backsql_process_filter() %s\n",
907 rc == 1 ? "succeeded" : "failed", 0, 0);
913 backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at,
914 int casefold, struct berval *filter_value )
917 * maybe we should check type of at->sel_expr here somehow,
918 * to know whether upper_func is applicable, but for now
919 * upper_func stuff is made for Oracle, where UPPER is
920 * safely applicable to NUMBER etc.
922 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
925 backsql_strfcat( &bsi->bsi_flt_where, "cbl",
928 (ber_len_t)STRLENOF( "='" ),
931 start = bsi->bsi_flt_where.bb_val.bv_len;
933 backsql_strfcat( &bsi->bsi_flt_where, "bl",
935 (ber_len_t)STRLENOF( /* (' */ "')" ),
938 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
941 backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
944 (ber_len_t)STRLENOF( "='" ), "='",
946 (ber_len_t)STRLENOF( /* (' */ "')" ),
954 backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at,
955 int casefold, struct berval *filter_value )
958 * maybe we should check type of at->sel_expr here somehow,
959 * to know whether upper_func is applicable, but for now
960 * upper_func stuff is made for Oracle, where UPPER is
961 * safely applicable to NUMBER etc.
963 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
966 backsql_strfcat( &bsi->bsi_flt_where, "cbl",
969 (ber_len_t)STRLENOF( " LIKE '%" ),
972 start = bsi->bsi_flt_where.bb_val.bv_len;
974 backsql_strfcat( &bsi->bsi_flt_where, "bl",
976 (ber_len_t)STRLENOF( /* (' */ "%')" ),
979 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
982 backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
985 (ber_len_t)STRLENOF( " LIKE '%" ),
988 (ber_len_t)STRLENOF( /* (' */ "%')" ),
996 backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at )
998 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1000 struct berval *filter_value = NULL;
1001 MatchingRule *matching_rule = NULL;
1002 struct berval ordering = BER_BVC("<=");
1004 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n",
1005 at->bam_ad->ad_cname.bv_val, 0, 0 );
1008 * need to add this attribute to list of attrs to load,
1009 * so that we can do test_filter() later
1011 backsql_attrlist_add( bsi, at->bam_ad );
1013 backsql_merge_from_tbls( bsi, &at->bam_from_tbls );
1015 if ( !BER_BVISNULL( &at->bam_join_where )
1016 && strstr( bsi->bsi_join_where.bb_val.bv_val,
1017 at->bam_join_where.bv_val ) == NULL )
1019 backsql_strfcat( &bsi->bsi_join_where, "lb",
1020 (ber_len_t)STRLENOF( " AND " ), " AND ",
1021 &at->bam_join_where );
1024 switch ( f->f_choice ) {
1025 case LDAP_FILTER_EQUALITY:
1026 filter_value = &f->f_av_value;
1027 matching_rule = at->bam_ad->ad_type->sat_equality;
1029 goto equality_match;
1031 /* fail over into next case */
1033 case LDAP_FILTER_EXT:
1034 filter_value = &f->f_mra->ma_value;
1035 matching_rule = f->f_mr_rule;
1038 /* always uppercase strings by now */
1039 #ifdef BACKSQL_UPPERCASE_FILTER
1040 if ( SLAP_MR_ASSOCIATED( matching_rule,
1041 bi->sql_caseIgnoreMatch ) )
1042 #endif /* BACKSQL_UPPERCASE_FILTER */
1047 /* FIXME: directoryString filtering should use a similar
1048 * approach to deal with non-prettified values like
1049 * " A non prettified value ", by using a LIKE
1050 * filter with all whitespaces collapsed to a single '%' */
1051 if ( SLAP_MR_ASSOCIATED( matching_rule,
1052 bi->sql_telephoneNumberMatch ) )
1058 * to check for matching telephone numbers
1059 * with intermized chars, e.g. val='1234'
1062 * val LIKE '%1%2%3%4%'
1065 bv.bv_len = 2 * filter_value->bv_len - 1;
1066 bv.bv_val = ch_malloc( bv.bv_len + 1 );
1068 bv.bv_val[ 0 ] = filter_value->bv_val[ 0 ];
1069 for ( i = 1; i < filter_value->bv_len; i++ ) {
1070 bv.bv_val[ 2 * i - 1 ] = '%';
1071 bv.bv_val[ 2 * i ] = filter_value->bv_val[ i ];
1073 bv.bv_val[ 2 * i - 1 ] = '\0';
1075 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
1076 ch_free( bv.bv_val );
1081 /* NOTE: this is required by objectClass inheritance
1082 * and auxiliary objectClass use in filters for slightly
1083 * more efficient candidate selection. */
1084 /* FIXME: a bit too many specializations to deal with
1085 * very specific cases... */
1086 if ( at->bam_ad == slap_schema.si_ad_objectClass
1087 || at->bam_ad == slap_schema.si_ad_structuralObjectClass )
1089 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
1090 (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
1091 "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
1093 (ber_len_t)STRLENOF( /* (' */ "')" ),
1099 * maybe we should check type of at->sel_expr here somehow,
1100 * to know whether upper_func is applicable, but for now
1101 * upper_func stuff is made for Oracle, where UPPER is
1102 * safely applicable to NUMBER etc.
1104 (void)backsql_process_filter_eq( bsi, at, casefold, filter_value );
1107 case LDAP_FILTER_GE:
1108 ordering.bv_val = ">=";
1110 /* fall thru to next case */
1112 case LDAP_FILTER_LE:
1113 filter_value = &f->f_av_value;
1115 /* always uppercase strings by now */
1116 #ifdef BACKSQL_UPPERCASE_FILTER
1117 if ( at->bam_ad->ad_type->sat_ordering &&
1118 SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering,
1119 bi->sql_caseIgnoreMatch ) )
1120 #endif /* BACKSQL_UPPERCASE_FILTER */
1126 * FIXME: should we uppercase the operands?
1128 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1131 backsql_strfcat( &bsi->bsi_flt_where, "cbbc",
1133 &at->bam_sel_expr_u,
1137 start = bsi->bsi_flt_where.bb_val.bv_len;
1139 backsql_strfcat( &bsi->bsi_flt_where, "bl",
1141 (ber_len_t)STRLENOF( /* (' */ "')" ),
1144 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1147 backsql_strfcat( &bsi->bsi_flt_where, "cbbcbl",
1153 (ber_len_t)STRLENOF( /* (' */ "')" ),
1158 case LDAP_FILTER_PRESENT:
1159 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
1160 (ber_len_t)STRLENOF( "NOT (" /* ) */),
1163 (ber_len_t)STRLENOF( /* ( */ " IS NULL)" ),
1164 /* ( */ " IS NULL)" );
1167 case LDAP_FILTER_SUBSTRINGS:
1168 backsql_process_sub_filter( bsi, f, at );
1171 case LDAP_FILTER_APPROX:
1172 /* we do our best */
1175 * maybe we should check type of at->sel_expr here somehow,
1176 * to know whether upper_func is applicable, but for now
1177 * upper_func stuff is made for Oracle, where UPPER is
1178 * safely applicable to NUMBER etc.
1180 (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value );
1184 /* unhandled filter type; should not happen */
1186 backsql_strfcat( &bsi->bsi_flt_where, "l",
1187 (ber_len_t)STRLENOF( "8=8" ), "8=8" );
1192 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n",
1193 at->bam_ad->ad_cname.bv_val, 0, 0 );
1199 backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
1201 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1205 BER_BVZERO( query );
1207 bsi->bsi_use_subtree_shortcut = 0;
1209 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n", 0, 0, 0 );
1210 BER_BVZERO( &bsi->bsi_sel.bb_val );
1211 BER_BVZERO( &bsi->bsi_sel.bb_val );
1212 bsi->bsi_sel.bb_len = 0;
1213 BER_BVZERO( &bsi->bsi_from.bb_val );
1214 bsi->bsi_from.bb_len = 0;
1215 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1216 bsi->bsi_join_where.bb_len = 0;
1217 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1218 bsi->bsi_flt_where.bb_len = 0;
1220 backsql_strfcat( &bsi->bsi_sel, "lbcbc",
1221 (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ),
1222 "SELECT DISTINCT ldap_entries.id,",
1223 &bsi->bsi_oc->bom_keytbl,
1225 &bsi->bsi_oc->bom_keycol,
1228 if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
1229 backsql_strfcat( &bsi->bsi_sel, "blbl",
1230 &bi->sql_strcast_func,
1231 (ber_len_t)STRLENOF( "('" /* ') */ ),
1233 &bsi->bsi_oc->bom_oc->soc_cname,
1234 (ber_len_t)STRLENOF( /* (' */ "')" ),
1237 backsql_strfcat( &bsi->bsi_sel, "cbc",
1239 &bsi->bsi_oc->bom_oc->soc_cname,
1242 #ifdef BACKSQL_ALIASING_QUOTE
1243 backsql_strfcat( &bsi->bsi_sel, "lclcl",
1244 (ber_len_t)STRLENOF( " " BACKSQL_ALIASING ),
1245 " " BACKSQL_ALIASING,
1246 BACKSQL_ALIASING_QUOTE,
1247 (ber_len_t)STRLENOF( "objectClass" ),
1249 BACKSQL_ALIASING_QUOTE,
1250 (ber_len_t)STRLENOF( ",ldap_entries.dn " BACKSQL_ALIASING "dn" ),
1251 ",ldap_entries.dn " BACKSQL_ALIASING "dn" );
1252 #else /* ! BACKSQL_ALIASING_QUOTE */
1253 backsql_strfcat( &bsi->bsi_sel, "l",
1254 (ber_len_t)STRLENOF( " " BACKSQL_ALIASING "objectClass,ldap_entries.dn " BACKSQL_ALIASING "dn" ),
1255 " " BACKSQL_ALIASING "objectClass,ldap_entries.dn " BACKSQL_ALIASING "dn" );
1256 #endif /* ! BACKSQL_ALIASING_QUOTE */
1258 backsql_strfcat( &bsi->bsi_from, "lb",
1259 (ber_len_t)STRLENOF( " FROM ldap_entries," ),
1260 " FROM ldap_entries,",
1261 &bsi->bsi_oc->bom_keytbl );
1263 backsql_strfcat( &bsi->bsi_join_where, "lbcbl",
1264 (ber_len_t)STRLENOF( " WHERE " ), " WHERE ",
1265 &bsi->bsi_oc->bom_keytbl,
1267 &bsi->bsi_oc->bom_keycol,
1268 (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ),
1269 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
1271 switch ( bsi->bsi_scope ) {
1272 case LDAP_SCOPE_BASE:
1273 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1274 backsql_strfcat( &bsi->bsi_join_where, "bl",
1275 &bi->sql_upper_func,
1276 (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ),
1277 "(ldap_entries.dn)=?" );
1279 backsql_strfcat( &bsi->bsi_join_where, "l",
1280 (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
1281 "ldap_entries.dn=?" );
1285 case BACKSQL_SCOPE_BASE_LIKE:
1286 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1287 backsql_strfcat( &bsi->bsi_join_where, "bl",
1288 &bi->sql_upper_func,
1289 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1290 "(ldap_entries.dn) LIKE ?" );
1292 backsql_strfcat( &bsi->bsi_join_where, "l",
1293 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1294 "ldap_entries.dn LIKE ?" );
1298 case LDAP_SCOPE_ONELEVEL:
1299 backsql_strfcat( &bsi->bsi_join_where, "l",
1300 (ber_len_t)STRLENOF( "ldap_entries.parent=?" ),
1301 "ldap_entries.parent=?" );
1304 #ifdef LDAP_SCOPE_SUBORDINATE
1305 case LDAP_SCOPE_SUBORDINATE:
1306 #endif /* LDAP_SCOPE_SUBORDINATE */
1307 case LDAP_SCOPE_SUBTREE:
1308 if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) {
1310 BackendDB *bd = bsi->bsi_op->o_bd;
1312 assert( bd->be_nsuffix );
1314 for ( i = 0; !BER_BVISNULL( &bd->be_nsuffix[ i ] ); i++ )
1316 if ( dn_match( &bd->be_nsuffix[ i ],
1317 bsi->bsi_base_ndn ) )
1319 /* pass this to the candidate selection
1320 * routine so that the DN is not bound
1321 * to the select statement */
1322 bsi->bsi_use_subtree_shortcut = 1;
1328 if ( bsi->bsi_use_subtree_shortcut ) {
1329 /* Skip the base DN filter, as every entry will match it */
1330 backsql_strfcat( &bsi->bsi_join_where, "l",
1331 (ber_len_t)STRLENOF( "9=9"), "9=9");
1333 } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
1334 backsql_strfcat( &bsi->bsi_join_where, "b", &bi->sql_subtree_cond );
1336 } else if ( BACKSQL_CANUPPERCASE( bi ) ) {
1337 backsql_strfcat( &bsi->bsi_join_where, "bl",
1338 &bi->sql_upper_func,
1339 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1340 "(ldap_entries.dn) LIKE ?" );
1343 backsql_strfcat( &bsi->bsi_join_where, "l",
1344 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1345 "ldap_entries.dn LIKE ?" );
1354 rc = backsql_process_filter( bsi, bsi->bsi_filter );
1356 struct berbuf bb = BB_NULL;
1358 backsql_strfcat( &bb, "bbblb",
1359 &bsi->bsi_sel.bb_val,
1360 &bsi->bsi_from.bb_val,
1361 &bsi->bsi_join_where.bb_val,
1362 (ber_len_t)STRLENOF( " AND " ), " AND ",
1363 &bsi->bsi_flt_where.bb_val );
1367 } else if ( rc < 0 ) {
1369 * Indicates that there's no possible way the filter matches
1370 * anything. No need to issue the query
1372 free( query->bv_val );
1373 BER_BVZERO( query );
1376 free( bsi->bsi_sel.bb_val.bv_val );
1377 BER_BVZERO( &bsi->bsi_sel.bb_val );
1378 bsi->bsi_sel.bb_len = 0;
1379 free( bsi->bsi_from.bb_val.bv_val );
1380 BER_BVZERO( &bsi->bsi_from.bb_val );
1381 bsi->bsi_from.bb_len = 0;
1382 free( bsi->bsi_join_where.bb_val.bv_val );
1383 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1384 bsi->bsi_join_where.bb_len = 0;
1385 free( bsi->bsi_flt_where.bb_val.bv_val );
1386 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1387 bsi->bsi_flt_where.bb_len = 0;
1389 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n",
1390 query->bv_val ? query->bv_val : "NULL", 0, 0 );
1392 return ( rc <= 0 ? 1 : 0 );
1396 backsql_oc_get_candidates( void *v_oc, void *v_bsi )
1398 backsql_oc_map_rec *oc = v_oc;
1399 backsql_srch_info *bsi = v_bsi;
1400 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1401 struct berval query;
1402 SQLHSTMT sth = SQL_NULL_HSTMT;
1405 BACKSQL_ROW_NTS row;
1408 int n_candidates = bsi->bsi_n_candidates;
1411 * + 1 because we need room for '%';
1412 * + 1 because we need room for ',' for LDAP_SCOPE_SUBORDINATE;
1413 * this makes a subtree
1414 * search for a DN BACKSQL_MAX_DN_LEN long legal
1415 * if it returns that DN only
1417 char tmp_base_ndn[ BACKSQL_MAX_DN_LEN + 1 + 1 ];
1419 bsi->bsi_status = LDAP_SUCCESS;
1421 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n",
1422 BACKSQL_OC_NAME( oc ), 0, 0 );
1424 if ( bsi->bsi_n_candidates == -1 ) {
1425 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1426 "unchecked limit has been overcome\n", 0, 0, 0 );
1427 /* should never get here */
1429 bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED;
1430 return BACKSQL_AVL_STOP;
1434 res = backsql_srch_query( bsi, &query );
1436 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1437 "error while constructing query for objectclass \"%s\"\n",
1438 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1440 * FIXME: need to separate errors from legally
1441 * impossible filters
1443 switch ( bsi->bsi_status ) {
1445 case LDAP_UNDEFINED_TYPE:
1446 case LDAP_NO_SUCH_OBJECT:
1447 /* we are conservative... */
1449 bsi->bsi_status = LDAP_SUCCESS;
1451 return BACKSQL_AVL_CONTINUE;
1453 case LDAP_ADMINLIMIT_EXCEEDED:
1455 /* don't try any more */
1456 return BACKSQL_AVL_STOP;
1460 if ( BER_BVISNULL( &query ) ) {
1461 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1462 "could not construct query for objectclass \"%s\"\n",
1463 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1464 bsi->bsi_status = LDAP_SUCCESS;
1465 return BACKSQL_AVL_CONTINUE;
1468 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n",
1469 query.bv_val, 0, 0 );
1471 rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 );
1472 free( query.bv_val );
1473 BER_BVZERO( &query );
1474 if ( rc != SQL_SUCCESS ) {
1475 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1476 "error preparing query\n", 0, 0, 0 );
1477 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1478 bsi->bsi_status = LDAP_OTHER;
1479 return BACKSQL_AVL_CONTINUE;
1482 Debug( LDAP_DEBUG_TRACE, "id: '%ld'\n", bsi->bsi_oc->bom_id, 0, 0 );
1484 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_INPUT,
1485 &bsi->bsi_oc->bom_id );
1486 if ( rc != SQL_SUCCESS ) {
1487 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1488 "error binding objectclass id parameter\n", 0, 0, 0 );
1489 bsi->bsi_status = LDAP_OTHER;
1490 return BACKSQL_AVL_CONTINUE;
1493 switch ( bsi->bsi_scope ) {
1494 case LDAP_SCOPE_BASE:
1495 case BACKSQL_SCOPE_BASE_LIKE:
1497 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1498 * however this should be handled earlier
1500 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1501 bsi->bsi_status = LDAP_OTHER;
1502 return BACKSQL_AVL_CONTINUE;
1505 AC_MEMCPY( tmp_base_ndn, bsi->bsi_base_ndn->bv_val,
1506 bsi->bsi_base_ndn->bv_len + 1 );
1508 /* uppercase DN only if the stored DN can be uppercased
1510 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1511 ldap_pvt_str2upper( tmp_base_ndn );
1514 Debug( LDAP_DEBUG_TRACE, "(base)dn: \"%s\"\n",
1515 tmp_base_ndn, 0, 0 );
1517 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1518 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1519 if ( rc != SQL_SUCCESS ) {
1520 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1521 "error binding base_ndn parameter\n", 0, 0, 0 );
1522 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1524 bsi->bsi_status = LDAP_OTHER;
1525 return BACKSQL_AVL_CONTINUE;
1529 #ifdef LDAP_SCOPE_SUBORDINATE
1530 case LDAP_SCOPE_SUBORDINATE:
1531 #endif /* LDAP_SCOPE_SUBORDINATE */
1532 case LDAP_SCOPE_SUBTREE:
1534 /* if short-cutting the search base,
1535 * don't bind any parameter */
1536 if ( bsi->bsi_use_subtree_shortcut ) {
1541 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1542 * however this should be handled earlier
1544 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1545 bsi->bsi_status = LDAP_OTHER;
1546 return BACKSQL_AVL_CONTINUE;
1550 * Sets the parameters for the SQL built earlier
1551 * NOTE that all the databases could actually use
1552 * the TimesTen version, which would be cleaner
1553 * and would also eliminate the need for the
1554 * subtree_cond line in the configuration file.
1555 * For now, I'm leaving it the way it is,
1556 * so non-TimesTen databases use the original code.
1557 * But at some point this should get cleaned up.
1559 * If "dn" is being used, do a suffix search.
1560 * If "dn_ru" is being used, do a prefix search.
1562 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
1563 tmp_base_ndn[ 0 ] = '\0';
1565 for ( i = 0, j = bsi->bsi_base_ndn->bv_len - 1;
1567 tmp_base_ndn[ i ] = bsi->bsi_base_ndn->bv_val[ j ];
1570 #ifdef LDAP_SCOPE_SUBORDINATE
1571 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1572 tmp_base_ndn[ i++ ] = ',';
1574 #endif /* LDAP_SCOPE_SUBORDINATE */
1576 tmp_base_ndn[ i ] = '%';
1577 tmp_base_ndn[ i + 1 ] = '\0';
1582 tmp_base_ndn[ i++ ] = '%';
1584 #ifdef LDAP_SCOPE_SUBORDINATE
1585 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1586 tmp_base_ndn[ i++ ] = ',';
1588 #endif /* LDAP_SCOPE_SUBORDINATE */
1590 AC_MEMCPY( &tmp_base_ndn[ i ], bsi->bsi_base_ndn->bv_val,
1591 bsi->bsi_base_ndn->bv_len + 1 );
1594 /* uppercase DN only if the stored DN can be uppercased
1596 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1597 ldap_pvt_str2upper( tmp_base_ndn );
1600 #ifdef LDAP_SCOPE_SUBORDINATE
1601 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1602 Debug( LDAP_DEBUG_TRACE, "(children)dn: \"%s\"\n",
1603 tmp_base_ndn, 0, 0 );
1605 #endif /* LDAP_SCOPE_SUBORDINATE */
1607 Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n",
1608 tmp_base_ndn, 0, 0 );
1611 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1612 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1613 if ( rc != SQL_SUCCESS ) {
1614 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1615 "error binding base_ndn parameter (2)\n",
1617 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1619 bsi->bsi_status = LDAP_OTHER;
1620 return BACKSQL_AVL_CONTINUE;
1625 case LDAP_SCOPE_ONELEVEL:
1626 assert( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) );
1628 #ifdef BACKSQL_ARBITRARY_KEY
1629 Debug( LDAP_DEBUG_TRACE, "(one)id: \"%s\"\n",
1630 bsi->bsi_base_id.eid_id.bv_val, 0, 0 );
1631 #else /* ! BACKSQL_ARBITRARY_KEY */
1632 Debug( LDAP_DEBUG_TRACE, "(one)id: '%lu'\n",
1633 bsi->bsi_base_id.eid_id, 0, 0 );
1634 #endif /* ! BACKSQL_ARBITRARY_KEY */
1635 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT,
1636 &bsi->bsi_base_id.eid_id );
1637 if ( rc != SQL_SUCCESS ) {
1638 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1639 "error binding base id parameter\n", 0, 0, 0 );
1640 bsi->bsi_status = LDAP_OTHER;
1641 return BACKSQL_AVL_CONTINUE;
1646 rc = SQLExecute( sth );
1647 if ( !BACKSQL_SUCCESS( rc ) ) {
1648 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1649 "error executing query\n", 0, 0, 0 );
1650 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1651 SQLFreeStmt( sth, SQL_DROP );
1652 bsi->bsi_status = LDAP_OTHER;
1653 return BACKSQL_AVL_CONTINUE;
1656 backsql_BindRowAsStrings( sth, &row );
1657 rc = SQLFetch( sth );
1658 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
1659 struct berval dn, pdn, ndn;
1660 backsql_entryID *c_id = NULL;
1663 ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
1665 if ( backsql_api_odbc2dn( bsi->bsi_op, bsi->bsi_rs, &dn ) ) {
1669 ret = dnPrettyNormal( NULL, &dn, &pdn, &ndn, NULL );
1670 if ( dn.bv_val != row.cols[ 3 ] ) {
1674 if ( ret != LDAP_SUCCESS ) {
1678 if ( bi->sql_baseObject && dn_match( &ndn, &bi->sql_baseObject->e_nname ) ) {
1684 c_id = (backsql_entryID *)ch_calloc( 1,
1685 sizeof( backsql_entryID ) );
1686 #ifdef BACKSQL_ARBITRARY_KEY
1687 ber_str2bv( row.cols[ 0 ], 0, 1, &c_id->eid_id );
1688 ber_str2bv( row.cols[ 1 ], 0, 1, &c_id->eid_keyval );
1689 #else /* ! BACKSQL_ARBITRARY_KEY */
1690 c_id->eid_id = strtol( row.cols[ 0 ], NULL, 0 );
1691 c_id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 );
1692 #endif /* ! BACKSQL_ARBITRARY_KEY */
1693 c_id->eid_oc_id = bsi->bsi_oc->bom_id;
1696 c_id->eid_ndn = ndn;
1698 /* append at end of list ... */
1699 c_id->eid_next = NULL;
1700 *bsi->bsi_id_listtail = c_id;
1701 bsi->bsi_id_listtail = &c_id->eid_next;
1703 #ifdef BACKSQL_ARBITRARY_KEY
1704 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1705 "added entry id=%s, keyval=%s dn=\"%s\"\n",
1706 c_id->eid_id.bv_val, c_id->eid_keyval.bv_val,
1708 #else /* ! BACKSQL_ARBITRARY_KEY */
1709 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1710 "added entry id=%ld, keyval=%ld dn=\"%s\"\n",
1711 c_id->eid_id, c_id->eid_keyval, row.cols[ 3 ] );
1712 #endif /* ! BACKSQL_ARBITRARY_KEY */
1714 /* count candidates, for unchecked limit */
1715 bsi->bsi_n_candidates--;
1716 if ( bsi->bsi_n_candidates == -1 ) {
1720 backsql_FreeRow( &row );
1721 SQLFreeStmt( sth, SQL_DROP );
1723 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n",
1724 n_candidates - bsi->bsi_n_candidates, 0, 0 );
1726 return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE );
1730 backsql_search( Operation *op, SlapReply *rs )
1732 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
1733 SQLHDBC dbh = SQL_NULL_HDBC;
1735 Entry user_entry = { 0 };
1737 time_t stoptime = 0;
1738 backsql_srch_info bsi;
1739 backsql_entryID *eid = NULL;
1740 struct berval nbase = BER_BVNULL,
1741 realndn = BER_BVNULL;
1743 manageDSAit = get_manageDSAit( op );
1745 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): "
1746 "base=\"%s\", filter=\"%s\", scope=%d,",
1747 op->o_req_ndn.bv_val,
1748 op->ors_filterstr.bv_val ? op->ors_filterstr.bv_val : "(no filter)",
1750 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, "
1751 "attributes to load: %s\n",
1754 op->ors_attrs == NULL ? "all" : "custom list" );
1756 if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) {
1757 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1758 "search base length (%ld) exceeds max length (%d)\n",
1759 op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN, 0 );
1761 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
1762 * since it is impossible that such a long DN exists
1765 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
1766 send_ldap_result( op, rs );
1770 sres = backsql_get_db_conn( op, &dbh );
1771 if ( sres != LDAP_SUCCESS ) {
1772 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1773 "could not get connection handle - exiting\n",
1776 rs->sr_text = sres == LDAP_OTHER ? "SQL-backend error" : NULL;
1777 send_ldap_result( op, rs );
1781 /* compute it anyway; root does not use it */
1782 stoptime = op->o_time + op->ors_tlimit;
1784 realndn = op->o_req_ndn;
1785 if ( backsql_api_dn2odbc( op, rs, &realndn ) ) {
1786 Debug( LDAP_DEBUG_TRACE, " backsql_search(\"%s\"): "
1787 "backsql_api_dn2odbc(\"%s\") failed\n",
1788 op->o_req_ndn.bv_val, realndn.bv_val, 0 );
1789 rs->sr_err = LDAP_OTHER;
1790 rs->sr_text = "SQL-backend error";
1791 send_ldap_result( op, rs );
1796 rs->sr_err = backsql_init_search( &bsi, &realndn,
1798 op->ors_slimit, op->ors_tlimit,
1799 stoptime, op->ors_filter,
1800 dbh, op, rs, op->ors_attrs,
1801 BACKSQL_ISF_GET_ID );
1802 if ( rs->sr_err != LDAP_SUCCESS ) {
1803 send_ldap_result( op, rs );
1809 e.e_name = bsi.bsi_base_id.eid_dn;
1810 e.e_nname = bsi.bsi_base_id.eid_ndn;
1811 /* FIXME: need the whole entry (ITS#3480) */
1812 if ( ! access_allowed( op, &e, slap_schema.si_ad_entry,
1813 NULL, ACL_DISCLOSE, NULL ) )
1815 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1816 send_ldap_result( op, rs );
1821 bsi.bsi_n_candidates =
1822 ( op->ors_limit == NULL /* isroot == TRUE */ ? -2 :
1823 ( op->ors_limit->lms_s_unchecked == -1 ? -2 :
1824 ( op->ors_limit->lms_s_unchecked ) ) );
1826 switch ( bsi.bsi_scope ) {
1827 case LDAP_SCOPE_BASE:
1828 case BACKSQL_SCOPE_BASE_LIKE:
1830 * probably already found...
1832 bsi.bsi_id_list = &bsi.bsi_base_id;
1833 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
1836 case LDAP_SCOPE_SUBTREE:
1838 * if baseObject is defined, and if it is the root
1839 * of the search, add it to the candidate list
1841 if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &bsi.bsi_base_id.eid_id ) )
1843 bsi.bsi_id_list = &bsi.bsi_base_id;
1844 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
1851 * for each objectclass we try to construct query which gets IDs
1852 * of entries matching LDAP query filter and scope (or at least
1853 * candidates), and get the IDs
1855 avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates,
1856 &bsi, BACKSQL_AVL_STOP, AVL_INORDER );
1859 if ( op->ors_limit != NULL /* isroot == FALSE */
1860 && op->ors_limit->lms_s_unchecked != -1
1861 && bsi.bsi_n_candidates == -1 )
1863 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
1864 send_ldap_result( op, rs );
1869 * now we load candidate entries (only those attributes
1870 * mentioned in attrs and filter), test it against full filter
1871 * and then send to client; don't free entry_id if baseObject...
1873 for ( eid = bsi.bsi_id_list;
1875 eid = backsql_free_entryID( eid, eid == &bsi.bsi_base_id ? 0 : 1 ) )
1878 Attribute *a_hasSubordinate = NULL,
1879 *a_entryUUID = NULL,
1884 /* check for abandon */
1885 if ( op->o_abandon ) {
1889 /* check time limit */
1890 if ( op->ors_tlimit != SLAP_NO_LIMIT
1891 && slap_get_time() > stoptime )
1893 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
1894 rs->sr_ctrls = NULL;
1895 rs->sr_ref = rs->sr_v2ref;
1896 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
1898 send_ldap_result( op, rs );
1902 #ifdef BACKSQL_ARBITRARY_KEY
1903 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
1904 "for entry id=%s, oc_id=%ld, keyval=%s\n",
1905 eid->eid_id.bv_val, eid->eid_oc_id,
1906 eid->eid_keyval.bv_val );
1907 #else /* ! BACKSQL_ARBITRARY_KEY */
1908 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
1909 "for entry id=%ld, oc_id=%ld, keyval=%ld\n",
1910 eid->eid_id, eid->eid_oc_id, eid->eid_keyval );
1911 #endif /* ! BACKSQL_ARBITRARY_KEY */
1914 switch ( op->ors_scope ) {
1915 case LDAP_SCOPE_BASE:
1916 case BACKSQL_SCOPE_BASE_LIKE:
1917 if ( !dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
1922 case LDAP_SCOPE_ONE:
1924 struct berval rdn = eid->eid_ndn;
1926 rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
1927 if ( !dnIsOneLevelRDN( &rdn ) ) {
1933 #ifdef LDAP_SCOPE_SUBORDINATE
1934 case LDAP_SCOPE_SUBORDINATE:
1935 /* discard the baseObject entry */
1936 if ( dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
1940 #endif /* LDAP_SCOPE_SUBORDINATE */
1942 case LDAP_SCOPE_SUBTREE:
1943 /* FIXME: this should never fail... */
1944 if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) {
1950 /* don't recollect baseObject ... */
1951 if ( BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
1952 e = bi->sql_baseObject;
1955 bsi.bsi_e = &user_entry;
1956 rc = backsql_id2entry( &bsi, eid );
1957 if ( rc != LDAP_SUCCESS ) {
1958 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1959 "error %d in backsql_id2entry() "
1960 "- skipping\n", rc, 0, 0 );
1967 if ( !manageDSAit &&
1968 op->ors_scope != LDAP_SCOPE_BASE &&
1969 op->ors_scope != BACKSQL_SCOPE_BASE_LIKE &&
1970 is_entry_referral( e ) )
1974 refs = get_entry_referrals( op, e );
1976 backsql_srch_info bsi2 = { 0 };
1977 Entry user_entry2 = { 0 };
1979 /* retry with the full entry... */
1980 (void)backsql_init_search( &bsi2,
1983 SLAP_NO_LIMIT, SLAP_NO_LIMIT,
1985 dbh, op, rs, NULL, 0 );
1986 bsi2.bsi_e = &user_entry2;
1987 rc = backsql_id2entry( &bsi2, eid );
1988 if ( rc == LDAP_SUCCESS ) {
1989 if ( is_entry_referral( &user_entry2 ) )
1991 refs = get_entry_referrals( op,
1993 } /* else: FIXME: inconsistency! */
1994 entry_clean( &user_entry2 );
1996 if ( bsi2.bsi_attrs != NULL ) {
1997 op->o_tmpfree( bsi2.bsi_attrs,
2003 rs->sr_ref = referral_rewrite( refs,
2007 ber_bvarray_free( refs );
2010 if ( !rs->sr_ref ) {
2011 rs->sr_text = "bad referral object";
2015 rs->sr_err = LDAP_REFERRAL;
2016 rs->sr_matched = user_entry.e_name.bv_val;
2017 send_search_reference( op, rs );
2019 ber_bvarray_free( rs->sr_ref );
2021 rs->sr_matched = NULL;
2022 rs->sr_entry = NULL;
2028 * We use this flag since we need to parse the filter
2029 * anyway; we should have used the frontend API function
2030 * filter_has_subordinates()
2032 if ( bsi.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
2033 rc = backsql_has_children( bi, dbh, &e->e_nname );
2036 case LDAP_COMPARE_TRUE:
2037 case LDAP_COMPARE_FALSE:
2038 a_hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
2039 if ( a_hasSubordinate != NULL ) {
2040 for ( ap = &user_entry.e_attrs;
2042 ap = &(*ap)->a_next );
2044 *ap = a_hasSubordinate;
2050 Debug(LDAP_DEBUG_TRACE,
2051 "backsql_search(): "
2052 "has_children failed( %d)\n",
2059 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYUUID ) {
2060 a_entryUUID = backsql_operational_entryUUID( bi, eid );
2061 if ( a_entryUUID != NULL ) {
2063 ap = &user_entry.e_attrs;
2066 for ( ; *ap; ap = &(*ap)->a_next );
2072 #ifdef BACKSQL_SYNCPROV
2073 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYCSN ) {
2074 a_entryCSN = backsql_operational_entryCSN( op );
2075 if ( a_entryCSN != NULL ) {
2077 ap = &user_entry.e_attrs;
2080 for ( ; *ap; ap = &(*ap)->a_next );
2085 #endif /* BACKSQL_SYNCPROV */
2087 if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE )
2089 rs->sr_attrs = op->ors_attrs;
2090 rs->sr_operational_attrs = NULL;
2092 if ( e == &user_entry ) {
2093 rs->sr_flags = REP_ENTRY_MODIFIABLE;
2095 /* FIXME: need the whole entry (ITS#3480) */
2096 sres = send_search_entry( op, rs );
2097 rs->sr_entry = NULL;
2098 rs->sr_attrs = NULL;
2099 rs->sr_operational_attrs = NULL;
2107 * FIXME: send_search_entry failed;
2111 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2112 "connection lost\n", 0, 0, 0 );
2118 entry_clean( &user_entry );
2121 if ( op->ors_slimit != SLAP_NO_LIMIT
2122 && rs->sr_nentries >= op->ors_slimit )
2124 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
2125 send_ldap_result( op, rs );
2131 /* in case we got here accidentally */
2132 entry_clean( &user_entry );
2134 if ( rs->sr_nentries > 0 ) {
2135 rs->sr_ref = rs->sr_v2ref;
2136 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
2140 rs->sr_err = bsi.bsi_status;
2142 send_ldap_result( op, rs );
2144 if ( rs->sr_v2ref ) {
2145 ber_bvarray_free( rs->sr_v2ref );
2146 rs->sr_v2ref = NULL;
2149 #ifdef BACKSQL_SYNCPROV
2151 Operation op2 = *op;
2152 SlapReply rs2 = { 0 };
2154 slap_callback cb = { 0 };
2156 op2.o_tag = LDAP_REQ_ADD;
2157 op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0, 0 );
2159 op2.o_callback = &cb;
2161 e.e_name = op->o_bd->be_suffix[0];
2162 e.e_nname = op->o_bd->be_nsuffix[0];
2164 cb.sc_response = slap_null_cb;
2166 op2.o_bd->be_add( &op2, &rs2 );
2168 #endif /* BACKSQL_SYNCPROV */
2171 if ( !BER_BVISNULL( &realndn ) && realndn.bv_val != op->o_req_ndn.bv_val ) {
2172 ch_free( realndn.bv_val );
2175 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) {
2176 (void)backsql_free_entryID( &bsi.bsi_base_id, 0 );
2179 if ( bsi.bsi_attrs != NULL ) {
2180 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2183 if ( !BER_BVISNULL( &nbase )
2184 && nbase.bv_val != op->o_req_ndn.bv_val )
2186 ch_free( nbase.bv_val );
2189 /* restore scope ... FIXME: this should be done before ANY
2190 * frontend call that uses op */
2191 if ( op->ors_scope == BACKSQL_SCOPE_BASE_LIKE ) {
2192 op->ors_scope = LDAP_SCOPE_BASE;
2195 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
2199 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
2206 AttributeDescription *at,
2210 backsql_srch_info bsi;
2211 SQLHDBC dbh = SQL_NULL_HDBC;
2213 SlapReply rs = { 0 };
2214 AttributeName anlist[ 2 ];
2216 rc = backsql_get_db_conn( op, &dbh );
2222 anlist[ 0 ].an_name = at->ad_cname;
2223 anlist[ 0 ].an_desc = at;
2224 BER_BVZERO( &anlist[ 1 ].an_name );
2227 rc = backsql_init_search( &bsi,
2230 SLAP_NO_LIMIT, SLAP_NO_LIMIT,
2232 dbh, op, &rs, at ? anlist : NULL,
2233 BACKSQL_ISF_GET_ID );
2234 if ( rc != LDAP_SUCCESS ) {
2238 bsi.bsi_e = ch_malloc( sizeof( Entry ) );
2239 rc = backsql_id2entry( &bsi, &bsi.bsi_base_id );
2241 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) {
2242 (void)backsql_free_entryID( &bsi.bsi_base_id, 0 );
2245 if ( rc == LDAP_SUCCESS ) {
2247 #if 0 /* not supported at present */
2248 /* find attribute values */
2249 if ( is_entry_alias( bsi.bsi_e ) ) {
2250 Debug( LDAP_DEBUG_ACL,
2251 "<= backsql_entry_get: entry is an alias\n",
2253 rc = LDAP_ALIAS_PROBLEM;
2254 goto return_results;
2258 if ( is_entry_referral( bsi.bsi_e ) ) {
2259 Debug( LDAP_DEBUG_ACL,
2260 "<= backsql_entry_get: entry is a referral\n",
2263 goto return_results;
2266 if ( oc && !is_entry_objectclass( bsi.bsi_e, oc, 0 ) ) {
2267 Debug( LDAP_DEBUG_ACL,
2268 "<= backsql_entry_get: "
2269 "failed to find objectClass\n",
2271 rc = LDAP_NO_SUCH_ATTRIBUTE;
2272 goto return_results;
2279 if ( bsi.bsi_attrs != NULL ) {
2280 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2283 if ( rc != LDAP_SUCCESS ) {
2285 entry_free( bsi.bsi_e );