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 int matched = BACKSQL_IS_MATCHED( flags );
273 int getentry = BACKSQL_IS_GET_ENTRY( flags );
275 assert( op->o_bd->be_private );
277 rc = backsql_dn2id( op, rs, dbh, nbase, &bsi->bsi_base_id,
280 if ( ( rc == LDAP_NO_SUCH_OBJECT && matched ) || getentry ) {
281 if ( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ) {
282 assert( bsi->bsi_e != NULL );
285 * let's see if it is a referral and, in case, get it
287 backsql_attrlist_add( bsi, slap_schema.si_ad_ref );
288 rc = backsql_id2entry( bsi, &bsi->bsi_base_id );
289 if ( rc == LDAP_SUCCESS && is_entry_referral( bsi->bsi_e ) )
291 BerVarray erefs = get_entry_referrals( op, bsi->bsi_e );
293 rc = rs->sr_err = LDAP_REFERRAL;
294 rs->sr_ref = referral_rewrite( erefs,
295 &bsi->bsi_e->e_nname,
298 ber_bvarray_free( erefs );
301 rc = rs->sr_err = LDAP_OTHER;
302 rs->sr_text = "bad referral object";
306 rc = rs->sr_err = getentry ?
307 LDAP_SUCCESS : LDAP_NO_SUCH_OBJECT;
311 rs->sr_ref = referral_rewrite( default_referral,
312 NULL, &op->o_req_dn, scope );
313 rc = rs->sr_err = LDAP_REFERRAL;
318 bsi->bsi_status = rc;
326 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
327 bsi->bsi_op->o_tmpmemctx );
335 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
343 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' /* ) */ );
346 res = backsql_process_filter( bsi, f );
349 * TimesTen : If the query has no answers,
350 * don't bother to run the query.
361 case LDAP_FILTER_AND:
362 backsql_strfcat( &bsi->bsi_flt_where, "l",
363 (ber_len_t)STRLENOF( " AND " ),
368 backsql_strfcat( &bsi->bsi_flt_where, "l",
369 (ber_len_t)STRLENOF( " OR " ),
375 backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' );
381 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
382 backsql_at_map_rec *at )
384 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
392 /* always uppercase strings by now */
393 #ifdef BACKSQL_UPPERCASE_FILTER
394 if ( f->f_sub_desc->ad_type->sat_substr &&
395 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
396 bi->sql_caseIgnoreMatch ) )
397 #endif /* BACKSQL_UPPERCASE_FILTER */
402 if ( f->f_sub_desc->ad_type->sat_substr &&
403 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
404 bi->sql_telephoneNumberMatch ) )
411 * to check for matching telephone numbers
412 * with intermixed chars, e.g. val='1234'
415 * val LIKE '%1%2%3%4%'
419 if ( f->f_sub_initial.bv_val ) {
420 bv.bv_len += f->f_sub_initial.bv_len;
422 if ( f->f_sub_any != NULL ) {
423 for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) {
424 bv.bv_len += f->f_sub_any[ a ].bv_len;
427 if ( f->f_sub_final.bv_val ) {
428 bv.bv_len += f->f_sub_final.bv_len;
430 bv.bv_len = 2 * bv.bv_len - 1;
431 bv.bv_val = ch_malloc( bv.bv_len + 1 );
434 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
435 bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ];
436 for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) {
437 bv.bv_val[ s + 2 * i - 1 ] = '%';
438 bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ];
440 bv.bv_val[ s + 2 * i - 1 ] = '%';
444 if ( f->f_sub_any != NULL ) {
445 for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
446 bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ];
447 for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) {
448 bv.bv_val[ s + 2 * i - 1 ] = '%';
449 bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ];
451 bv.bv_val[ s + 2 * i - 1 ] = '%';
456 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
457 bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ];
458 for ( i = 1; i < f->f_sub_final.bv_len; i++ ) {
459 bv.bv_val[ s + 2 * i - 1 ] = '%';
460 bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ];
462 bv.bv_val[ s + 2 * i - 1 ] = '%';
466 bv.bv_val[ s - 1 ] = '\0';
468 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
469 ch_free( bv.bv_val );
475 * When dealing with case-sensitive strings
476 * we may omit normalization; however, normalized
477 * SQL filters are more liberal.
480 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' /* ) */ );
483 Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n",
484 at->bam_ad->ad_cname.bv_val, 0, 0 );
485 Debug(LDAP_DEBUG_TRACE, " expr: '%s%s%s'\n", at->bam_sel_expr.bv_val,
486 at->bam_sel_expr_u.bv_val ? "' '" : "",
487 at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" );
488 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
490 * If a pre-upper-cased version of the column
491 * or a precompiled upper function exists, use it
493 backsql_strfcat( &bsi->bsi_flt_where,
496 (ber_len_t)STRLENOF( " LIKE '" ),
500 backsql_strfcat( &bsi->bsi_flt_where, "bl",
502 (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
505 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
509 Debug( LDAP_DEBUG_TRACE,
510 "==>backsql_process_sub_filter(%s): "
511 "sub_initial=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
512 f->f_sub_initial.bv_val, 0 );
513 #endif /* BACKSQL_TRACE */
515 start = bsi->bsi_flt_where.bb_val.bv_len;
516 backsql_strfcat( &bsi->bsi_flt_where, "b",
518 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
519 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
523 backsql_strfcat( &bsi->bsi_flt_where, "c", '%' );
525 if ( f->f_sub_any != NULL ) {
526 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) {
530 Debug( LDAP_DEBUG_TRACE,
531 "==>backsql_process_sub_filter(%s): "
532 "sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
533 i, f->f_sub_any[ i ].bv_val );
534 #endif /* BACKSQL_TRACE */
536 start = bsi->bsi_flt_where.bb_val.bv_len;
537 backsql_strfcat( &bsi->bsi_flt_where,
541 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
543 * Note: toupper('%') = '%'
545 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
550 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
554 Debug( LDAP_DEBUG_TRACE,
555 "==>backsql_process_sub_filter(%s): "
556 "sub_final=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
557 f->f_sub_final.bv_val, 0 );
558 #endif /* BACKSQL_TRACE */
560 start = bsi->bsi_flt_where.bb_val.bv_len;
561 backsql_strfcat( &bsi->bsi_flt_where, "b",
563 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
564 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
568 backsql_strfcat( &bsi->bsi_flt_where, "l",
569 (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" );
575 backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls )
577 if ( BER_BVISNULL( from_tbls ) ) {
581 if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) {
582 char *start, *end, *tmp;
584 tmp = ch_strdup( from_tbls->bv_val );
586 for ( start = tmp, end = strchr( start, ',' ); start; ) {
591 if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL )
593 backsql_strfcat( &bsi->bsi_from, "cs", ',', start );
597 /* in case there are spaces after the comma... */
598 for ( start = &end[1]; isspace( start[0] ); start++ );
600 end = strchr( start, ',' );
612 backsql_strfcat( &bsi->bsi_from, "b", from_tbls );
619 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
621 backsql_at_map_rec **vat = NULL;
622 AttributeDescription *ad = NULL;
627 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 );
628 if ( f->f_choice == SLAPD_FILTER_COMPUTED ) {
629 Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
630 "invalid filter\n", 0, 0, 0 );
635 switch( f->f_choice ) {
637 rc = backsql_process_filter_list( bsi, f->f_or,
642 case LDAP_FILTER_AND:
643 rc = backsql_process_filter_list( bsi, f->f_and,
648 case LDAP_FILTER_NOT:
649 backsql_strfcat( &bsi->bsi_flt_where, "l",
650 (ber_len_t)STRLENOF( "NOT (" /* ) */ ),
652 rc = backsql_process_filter( bsi, f->f_not );
653 backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' );
657 case LDAP_FILTER_PRESENT:
661 case LDAP_FILTER_EXT:
662 ad = f->f_mra->ma_desc;
663 if ( f->f_mr_dnattrs ) {
665 * if dn attrs filtering is requested, better return
666 * success and let test_filter() deal with candidate
667 * selection; otherwise we'd need to set conditions
668 * on the contents of the DN, e.g. "SELECT ... FROM
669 * ldap_entries AS attributeName WHERE attributeName.dn
670 * like '%attributeName=value%'"
672 backsql_strfcat( &bsi->bsi_flt_where, "l",
673 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
674 bsi->bsi_status = LDAP_SUCCESS;
695 * Turn structuralObjectClass into objectClass
697 if ( ad == slap_schema.si_ad_objectClass
698 || ad == slap_schema.si_ad_structuralObjectClass )
701 * If the filter is LDAP_FILTER_PRESENT, then it's done;
702 * otherwise, let's see if we are lucky: filtering
703 * for "structural" objectclass or ancestor...
705 switch ( f->f_choice ) {
706 case LDAP_FILTER_EQUALITY:
708 ObjectClass *oc = oc_bvfind( &f->f_av_value );
711 Debug( LDAP_DEBUG_TRACE,
712 "backsql_process_filter(): "
713 "unknown objectClass \"%s\" "
715 f->f_av_value.bv_val, 0, 0 );
716 bsi->bsi_status = LDAP_OTHER;
722 * "structural" objectClass inheritance:
723 * - a search for "person" will also return
725 * - a search for "top" will return everything
727 if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
728 static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" );
730 backsql_merge_from_tbls( bsi, &ldap_entry_objclasses );
732 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
733 (ber_len_t)STRLENOF( "2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
734 "2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
735 &bsi->bsi_oc->bom_oc->soc_cname,
736 (ber_len_t)STRLENOF( /* (' */ "')" ),
738 bsi->bsi_status = LDAP_SUCCESS;
746 case LDAP_FILTER_PRESENT:
747 backsql_strfcat( &bsi->bsi_flt_where, "l",
748 (ber_len_t)STRLENOF( "3=3" ), "3=3" );
749 bsi->bsi_status = LDAP_SUCCESS;
753 /* FIXME: LDAP_FILTER_EXT? */
756 Debug( LDAP_DEBUG_TRACE,
757 "backsql_process_filter(): "
758 "illegal/unhandled filter "
759 "on objectClass attribute",
761 bsi->bsi_status = LDAP_OTHER;
766 } else if ( ad == slap_schema.si_ad_entryUUID ) {
768 #ifdef BACKSQL_ARBITRARY_KEY
769 struct berval keyval;
770 #else /* ! BACKSQL_ARBITRARY_KEY */
771 unsigned long keyval;
772 char keyvalbuf[] = "18446744073709551615";
773 #endif /* ! BACKSQL_ARBITRARY_KEY */
775 switch ( f->f_choice ) {
776 case LDAP_FILTER_EQUALITY:
777 backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval );
779 if ( oc_id != bsi->bsi_oc->bom_id ) {
780 bsi->bsi_status = LDAP_SUCCESS;
785 #ifdef BACKSQL_ARBITRARY_KEY
786 backsql_strfcat( &bsi->bsi_flt_where, "bcblbc",
787 &bsi->bsi_oc->bom_keytbl, '.',
788 &bsi->bsi_oc->bom_keycol,
789 STRLENOF( " LIKE '" ), " LIKE '",
791 #else /* ! BACKSQL_ARBITRARY_KEY */
792 snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval );
793 backsql_strfcat( &bsi->bsi_flt_where, "bcbcs",
794 &bsi->bsi_oc->bom_keytbl, '.',
795 &bsi->bsi_oc->bom_keycol, '=', keyvalbuf );
796 #endif /* ! BACKSQL_ARBITRARY_KEY */
799 case LDAP_FILTER_PRESENT:
800 backsql_strfcat( &bsi->bsi_flt_where, "l",
801 (ber_len_t)STRLENOF( "4=4" ), "4=4" );
809 bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID;
813 #ifdef BACKSQL_SYNCPROV
814 } else if ( ad == slap_schema.si_ad_entryCSN ) {
816 * support for syncrepl as producer...
818 if ( !bsi->bsi_op->o_sync ) {
819 /* unsupported at present... */
820 bsi->bsi_status = LDAP_OTHER;
825 bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID);
827 /* if doing a syncrepl, try to return as much as possible,
828 * and always match the filter */
829 backsql_strfcat( &bsi->bsi_flt_where, "l",
830 (ber_len_t)STRLENOF( "5=5" ), "5=5" );
832 /* save for later use in operational attributes */
833 /* FIXME: saves only the first occurrence, because
834 * the filter during updates is written as
835 * "(&(entryCSN<={contextCSN})(entryCSN>={oldContextCSN})({filter}))"
836 * so we want our fake entryCSN to match the greatest
839 if ( bsi->bsi_op->o_private == NULL ) {
840 bsi->bsi_op->o_private = &f->f_av_value;
842 bsi->bsi_status = LDAP_SUCCESS;
846 #endif /* BACKSQL_SYNCPROV */
848 } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
850 * FIXME: this is not robust; e.g. a filter
851 * '(!(hasSubordinates=TRUE))' fails because
852 * in SQL it would read 'NOT (1=1)' instead
854 * Note however that hasSubordinates is boolean,
855 * so a more appropriate filter would be
856 * '(hasSubordinates=FALSE)'
858 * A more robust search for hasSubordinates
859 * would * require joining the ldap_entries table
860 * selecting if there are descendants of the
863 backsql_strfcat( &bsi->bsi_flt_where, "l",
864 (ber_len_t)STRLENOF( "6=6" ), "6=6" );
865 if ( ad == slap_schema.si_ad_hasSubordinates ) {
867 * instruct candidate selection algorithm
868 * and attribute list to try to detect
869 * if an entry has subordinates
871 bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
875 * clear attributes to fetch, to require ALL
876 * and try extended match on all attributes
878 backsql_attrlist_add( bsi, NULL );
885 * attribute inheritance:
887 if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) {
888 bsi->bsi_status = LDAP_OTHER;
894 /* search anyway; other parts of the filter
896 backsql_strfcat( &bsi->bsi_flt_where, "l",
897 (ber_len_t)STRLENOF( "7=7" ), "7=7" );
898 bsi->bsi_status = LDAP_SUCCESS;
903 /* if required, open extra level of parens */
905 if ( vat[0]->bam_next || vat[1] ) {
906 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' );
913 if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) {
917 /* if more definitions of the same attr, apply */
918 if ( vat[i]->bam_next ) {
919 backsql_strfcat( &bsi->bsi_flt_where, "l",
920 STRLENOF( " OR " ), " OR " );
921 vat[i] = vat[i]->bam_next;
925 /* if more descendants of the same attr, apply */
928 backsql_strfcat( &bsi->bsi_flt_where, "l",
929 STRLENOF( " OR " ), " OR " );
933 /* if needed, close extra level of parens */
935 backsql_strfcat( &bsi->bsi_flt_where, "c", ')' );
945 Debug( LDAP_DEBUG_TRACE,
946 "<==backsql_process_filter() %s\n",
947 rc == 1 ? "succeeded" : "failed", 0, 0);
953 backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at,
954 int casefold, struct berval *filter_value )
957 * maybe we should check type of at->sel_expr here somehow,
958 * to know whether upper_func is applicable, but for now
959 * upper_func stuff is made for Oracle, where UPPER is
960 * safely applicable to NUMBER etc.
962 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
965 backsql_strfcat( &bsi->bsi_flt_where, "cbl",
968 (ber_len_t)STRLENOF( "='" ),
971 start = bsi->bsi_flt_where.bb_val.bv_len;
973 backsql_strfcat( &bsi->bsi_flt_where, "bl",
975 (ber_len_t)STRLENOF( /* (' */ "')" ),
978 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
981 backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
984 (ber_len_t)STRLENOF( "='" ), "='",
986 (ber_len_t)STRLENOF( /* (' */ "')" ),
994 backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at,
995 int casefold, struct berval *filter_value )
998 * maybe we should check type of at->sel_expr here somehow,
999 * to know whether upper_func is applicable, but for now
1000 * upper_func stuff is made for Oracle, where UPPER is
1001 * safely applicable to NUMBER etc.
1003 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1006 backsql_strfcat( &bsi->bsi_flt_where, "cbl",
1008 &at->bam_sel_expr_u,
1009 (ber_len_t)STRLENOF( " LIKE '%" ),
1012 start = bsi->bsi_flt_where.bb_val.bv_len;
1014 backsql_strfcat( &bsi->bsi_flt_where, "bl",
1016 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1019 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1022 backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
1025 (ber_len_t)STRLENOF( " LIKE '%" ),
1028 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1036 backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at )
1038 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1040 struct berval *filter_value = NULL;
1041 MatchingRule *matching_rule = NULL;
1042 struct berval ordering = BER_BVC("<=");
1044 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n",
1045 at->bam_ad->ad_cname.bv_val, 0, 0 );
1048 * need to add this attribute to list of attrs to load,
1049 * so that we can do test_filter() later
1051 backsql_attrlist_add( bsi, at->bam_ad );
1053 backsql_merge_from_tbls( bsi, &at->bam_from_tbls );
1055 if ( !BER_BVISNULL( &at->bam_join_where )
1056 && strstr( bsi->bsi_join_where.bb_val.bv_val,
1057 at->bam_join_where.bv_val ) == NULL )
1059 backsql_strfcat( &bsi->bsi_join_where, "lb",
1060 (ber_len_t)STRLENOF( " AND " ), " AND ",
1061 &at->bam_join_where );
1064 switch ( f->f_choice ) {
1065 case LDAP_FILTER_EQUALITY:
1066 filter_value = &f->f_av_value;
1067 matching_rule = at->bam_ad->ad_type->sat_equality;
1069 goto equality_match;
1071 /* fail over into next case */
1073 case LDAP_FILTER_EXT:
1074 filter_value = &f->f_mra->ma_value;
1075 matching_rule = f->f_mr_rule;
1078 /* always uppercase strings by now */
1079 #ifdef BACKSQL_UPPERCASE_FILTER
1080 if ( SLAP_MR_ASSOCIATED( matching_rule,
1081 bi->sql_caseIgnoreMatch ) )
1082 #endif /* BACKSQL_UPPERCASE_FILTER */
1087 /* FIXME: directoryString filtering should use a similar
1088 * approach to deal with non-prettified values like
1089 * " A non prettified value ", by using a LIKE
1090 * filter with all whitespaces collapsed to a single '%' */
1091 if ( SLAP_MR_ASSOCIATED( matching_rule,
1092 bi->sql_telephoneNumberMatch ) )
1098 * to check for matching telephone numbers
1099 * with intermized chars, e.g. val='1234'
1102 * val LIKE '%1%2%3%4%'
1105 bv.bv_len = 2 * filter_value->bv_len - 1;
1106 bv.bv_val = ch_malloc( bv.bv_len + 1 );
1108 bv.bv_val[ 0 ] = filter_value->bv_val[ 0 ];
1109 for ( i = 1; i < filter_value->bv_len; i++ ) {
1110 bv.bv_val[ 2 * i - 1 ] = '%';
1111 bv.bv_val[ 2 * i ] = filter_value->bv_val[ i ];
1113 bv.bv_val[ 2 * i - 1 ] = '\0';
1115 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
1116 ch_free( bv.bv_val );
1121 /* NOTE: this is required by objectClass inheritance
1122 * and auxiliary objectClass use in filters for slightly
1123 * more efficient candidate selection. */
1124 /* FIXME: a bit too many specializations to deal with
1125 * very specific cases... */
1126 if ( at->bam_ad == slap_schema.si_ad_objectClass
1127 || at->bam_ad == slap_schema.si_ad_structuralObjectClass )
1129 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
1130 (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
1131 "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
1133 (ber_len_t)STRLENOF( /* (' */ "')" ),
1139 * maybe we should check type of at->sel_expr here somehow,
1140 * to know whether upper_func is applicable, but for now
1141 * upper_func stuff is made for Oracle, where UPPER is
1142 * safely applicable to NUMBER etc.
1144 (void)backsql_process_filter_eq( bsi, at, casefold, filter_value );
1147 case LDAP_FILTER_GE:
1148 ordering.bv_val = ">=";
1150 /* fall thru to next case */
1152 case LDAP_FILTER_LE:
1153 filter_value = &f->f_av_value;
1155 /* always uppercase strings by now */
1156 #ifdef BACKSQL_UPPERCASE_FILTER
1157 if ( at->bam_ad->ad_type->sat_ordering &&
1158 SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering,
1159 bi->sql_caseIgnoreMatch ) )
1160 #endif /* BACKSQL_UPPERCASE_FILTER */
1166 * FIXME: should we uppercase the operands?
1168 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1171 backsql_strfcat( &bsi->bsi_flt_where, "cbbc",
1173 &at->bam_sel_expr_u,
1177 start = bsi->bsi_flt_where.bb_val.bv_len;
1179 backsql_strfcat( &bsi->bsi_flt_where, "bl",
1181 (ber_len_t)STRLENOF( /* (' */ "')" ),
1184 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1187 backsql_strfcat( &bsi->bsi_flt_where, "cbbcbl",
1193 (ber_len_t)STRLENOF( /* (' */ "')" ),
1198 case LDAP_FILTER_PRESENT:
1199 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
1200 (ber_len_t)STRLENOF( "NOT (" /* ) */),
1203 (ber_len_t)STRLENOF( /* ( */ " IS NULL)" ),
1204 /* ( */ " IS NULL)" );
1207 case LDAP_FILTER_SUBSTRINGS:
1208 backsql_process_sub_filter( bsi, f, at );
1211 case LDAP_FILTER_APPROX:
1212 /* we do our best */
1215 * maybe we should check type of at->sel_expr here somehow,
1216 * to know whether upper_func is applicable, but for now
1217 * upper_func stuff is made for Oracle, where UPPER is
1218 * safely applicable to NUMBER etc.
1220 (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value );
1224 /* unhandled filter type; should not happen */
1226 backsql_strfcat( &bsi->bsi_flt_where, "l",
1227 (ber_len_t)STRLENOF( "8=8" ), "8=8" );
1232 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n",
1233 at->bam_ad->ad_cname.bv_val, 0, 0 );
1239 backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
1241 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1245 BER_BVZERO( query );
1247 bsi->bsi_use_subtree_shortcut = 0;
1249 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n", 0, 0, 0 );
1250 BER_BVZERO( &bsi->bsi_sel.bb_val );
1251 BER_BVZERO( &bsi->bsi_sel.bb_val );
1252 bsi->bsi_sel.bb_len = 0;
1253 BER_BVZERO( &bsi->bsi_from.bb_val );
1254 bsi->bsi_from.bb_len = 0;
1255 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1256 bsi->bsi_join_where.bb_len = 0;
1257 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1258 bsi->bsi_flt_where.bb_len = 0;
1260 backsql_strfcat( &bsi->bsi_sel, "lbcbc",
1261 (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ),
1262 "SELECT DISTINCT ldap_entries.id,",
1263 &bsi->bsi_oc->bom_keytbl,
1265 &bsi->bsi_oc->bom_keycol,
1268 if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
1269 backsql_strfcat( &bsi->bsi_sel, "blbl",
1270 &bi->sql_strcast_func,
1271 (ber_len_t)STRLENOF( "('" /* ') */ ),
1273 &bsi->bsi_oc->bom_oc->soc_cname,
1274 (ber_len_t)STRLENOF( /* (' */ "')" ),
1277 backsql_strfcat( &bsi->bsi_sel, "cbc",
1279 &bsi->bsi_oc->bom_oc->soc_cname,
1282 #ifdef BACKSQL_ALIASING_QUOTE
1283 backsql_strfcat( &bsi->bsi_sel, "lclcl",
1284 (ber_len_t)STRLENOF( " " BACKSQL_ALIASING ),
1285 " " BACKSQL_ALIASING,
1286 BACKSQL_ALIASING_QUOTE,
1287 (ber_len_t)STRLENOF( "objectClass" ),
1289 BACKSQL_ALIASING_QUOTE,
1290 (ber_len_t)STRLENOF( ",ldap_entries.dn " BACKSQL_ALIASING "dn" ),
1291 ",ldap_entries.dn " BACKSQL_ALIASING "dn" );
1292 #else /* ! BACKSQL_ALIASING_QUOTE */
1293 backsql_strfcat( &bsi->bsi_sel, "l",
1294 (ber_len_t)STRLENOF( " " BACKSQL_ALIASING "objectClass,ldap_entries.dn " BACKSQL_ALIASING "dn" ),
1295 " " BACKSQL_ALIASING "objectClass,ldap_entries.dn " BACKSQL_ALIASING "dn" );
1296 #endif /* ! BACKSQL_ALIASING_QUOTE */
1298 backsql_strfcat( &bsi->bsi_from, "lb",
1299 (ber_len_t)STRLENOF( " FROM ldap_entries," ),
1300 " FROM ldap_entries,",
1301 &bsi->bsi_oc->bom_keytbl );
1303 backsql_strfcat( &bsi->bsi_join_where, "lbcbl",
1304 (ber_len_t)STRLENOF( " WHERE " ), " WHERE ",
1305 &bsi->bsi_oc->bom_keytbl,
1307 &bsi->bsi_oc->bom_keycol,
1308 (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ),
1309 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
1311 switch ( bsi->bsi_scope ) {
1312 case LDAP_SCOPE_BASE:
1313 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1314 backsql_strfcat( &bsi->bsi_join_where, "bl",
1315 &bi->sql_upper_func,
1316 (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ),
1317 "(ldap_entries.dn)=?" );
1319 backsql_strfcat( &bsi->bsi_join_where, "l",
1320 (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
1321 "ldap_entries.dn=?" );
1325 case BACKSQL_SCOPE_BASE_LIKE:
1326 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1327 backsql_strfcat( &bsi->bsi_join_where, "bl",
1328 &bi->sql_upper_func,
1329 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1330 "(ldap_entries.dn) LIKE ?" );
1332 backsql_strfcat( &bsi->bsi_join_where, "l",
1333 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1334 "ldap_entries.dn LIKE ?" );
1338 case LDAP_SCOPE_ONELEVEL:
1339 backsql_strfcat( &bsi->bsi_join_where, "l",
1340 (ber_len_t)STRLENOF( "ldap_entries.parent=?" ),
1341 "ldap_entries.parent=?" );
1344 #ifdef LDAP_SCOPE_SUBORDINATE
1345 case LDAP_SCOPE_SUBORDINATE:
1346 #endif /* LDAP_SCOPE_SUBORDINATE */
1347 case LDAP_SCOPE_SUBTREE:
1348 if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) {
1350 BackendDB *bd = bsi->bsi_op->o_bd;
1352 assert( bd->be_nsuffix );
1354 for ( i = 0; !BER_BVISNULL( &bd->be_nsuffix[ i ] ); i++ )
1356 if ( dn_match( &bd->be_nsuffix[ i ],
1357 bsi->bsi_base_ndn ) )
1359 /* pass this to the candidate selection
1360 * routine so that the DN is not bound
1361 * to the select statement */
1362 bsi->bsi_use_subtree_shortcut = 1;
1368 if ( bsi->bsi_use_subtree_shortcut ) {
1369 /* Skip the base DN filter, as every entry will match it */
1370 backsql_strfcat( &bsi->bsi_join_where, "l",
1371 (ber_len_t)STRLENOF( "9=9"), "9=9");
1373 } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
1374 backsql_strfcat( &bsi->bsi_join_where, "b", &bi->sql_subtree_cond );
1376 } else if ( BACKSQL_CANUPPERCASE( bi ) ) {
1377 backsql_strfcat( &bsi->bsi_join_where, "bl",
1378 &bi->sql_upper_func,
1379 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1380 "(ldap_entries.dn) LIKE ?" );
1383 backsql_strfcat( &bsi->bsi_join_where, "l",
1384 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1385 "ldap_entries.dn LIKE ?" );
1394 rc = backsql_process_filter( bsi, bsi->bsi_filter );
1396 struct berbuf bb = BB_NULL;
1398 backsql_strfcat( &bb, "bbblb",
1399 &bsi->bsi_sel.bb_val,
1400 &bsi->bsi_from.bb_val,
1401 &bsi->bsi_join_where.bb_val,
1402 (ber_len_t)STRLENOF( " AND " ), " AND ",
1403 &bsi->bsi_flt_where.bb_val );
1407 } else if ( rc < 0 ) {
1409 * Indicates that there's no possible way the filter matches
1410 * anything. No need to issue the query
1412 free( query->bv_val );
1413 BER_BVZERO( query );
1416 free( bsi->bsi_sel.bb_val.bv_val );
1417 BER_BVZERO( &bsi->bsi_sel.bb_val );
1418 bsi->bsi_sel.bb_len = 0;
1419 free( bsi->bsi_from.bb_val.bv_val );
1420 BER_BVZERO( &bsi->bsi_from.bb_val );
1421 bsi->bsi_from.bb_len = 0;
1422 free( bsi->bsi_join_where.bb_val.bv_val );
1423 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1424 bsi->bsi_join_where.bb_len = 0;
1425 free( bsi->bsi_flt_where.bb_val.bv_val );
1426 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1427 bsi->bsi_flt_where.bb_len = 0;
1429 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n",
1430 query->bv_val ? query->bv_val : "NULL", 0, 0 );
1432 return ( rc <= 0 ? 1 : 0 );
1436 backsql_oc_get_candidates( void *v_oc, void *v_bsi )
1438 backsql_oc_map_rec *oc = v_oc;
1439 backsql_srch_info *bsi = v_bsi;
1440 Operation *op = bsi->bsi_op;
1441 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1442 struct berval query;
1443 SQLHSTMT sth = SQL_NULL_HSTMT;
1446 BACKSQL_ROW_NTS row;
1449 int n_candidates = bsi->bsi_n_candidates;
1452 * + 1 because we need room for '%';
1453 * + 1 because we need room for ',' for LDAP_SCOPE_SUBORDINATE;
1454 * this makes a subtree
1455 * search for a DN BACKSQL_MAX_DN_LEN long legal
1456 * if it returns that DN only
1458 char tmp_base_ndn[ BACKSQL_MAX_DN_LEN + 1 + 1 ];
1460 bsi->bsi_status = LDAP_SUCCESS;
1462 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n",
1463 BACKSQL_OC_NAME( oc ), 0, 0 );
1465 if ( bsi->bsi_n_candidates == -1 ) {
1466 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1467 "unchecked limit has been overcome\n", 0, 0, 0 );
1468 /* should never get here */
1470 bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED;
1471 return BACKSQL_AVL_STOP;
1475 res = backsql_srch_query( bsi, &query );
1477 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1478 "error while constructing query for objectclass \"%s\"\n",
1479 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1481 * FIXME: need to separate errors from legally
1482 * impossible filters
1484 switch ( bsi->bsi_status ) {
1486 case LDAP_UNDEFINED_TYPE:
1487 case LDAP_NO_SUCH_OBJECT:
1488 /* we are conservative... */
1490 bsi->bsi_status = LDAP_SUCCESS;
1492 return BACKSQL_AVL_CONTINUE;
1494 case LDAP_ADMINLIMIT_EXCEEDED:
1496 /* don't try any more */
1497 return BACKSQL_AVL_STOP;
1501 if ( BER_BVISNULL( &query ) ) {
1502 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1503 "could not construct query for objectclass \"%s\"\n",
1504 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1505 bsi->bsi_status = LDAP_SUCCESS;
1506 return BACKSQL_AVL_CONTINUE;
1509 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n",
1510 query.bv_val, 0, 0 );
1512 rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 );
1513 free( query.bv_val );
1514 BER_BVZERO( &query );
1515 if ( rc != SQL_SUCCESS ) {
1516 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1517 "error preparing query\n", 0, 0, 0 );
1518 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1519 bsi->bsi_status = LDAP_OTHER;
1520 return BACKSQL_AVL_CONTINUE;
1523 Debug( LDAP_DEBUG_TRACE, "id: '%ld'\n", bsi->bsi_oc->bom_id, 0, 0 );
1525 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_INPUT,
1526 &bsi->bsi_oc->bom_id );
1527 if ( rc != SQL_SUCCESS ) {
1528 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1529 "error binding objectclass id parameter\n", 0, 0, 0 );
1530 bsi->bsi_status = LDAP_OTHER;
1531 return BACKSQL_AVL_CONTINUE;
1534 switch ( bsi->bsi_scope ) {
1535 case LDAP_SCOPE_BASE:
1536 case BACKSQL_SCOPE_BASE_LIKE:
1538 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1539 * however this should be handled earlier
1541 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1542 bsi->bsi_status = LDAP_OTHER;
1543 return BACKSQL_AVL_CONTINUE;
1546 AC_MEMCPY( tmp_base_ndn, bsi->bsi_base_ndn->bv_val,
1547 bsi->bsi_base_ndn->bv_len + 1 );
1549 /* uppercase DN only if the stored DN can be uppercased
1551 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1552 ldap_pvt_str2upper( tmp_base_ndn );
1555 Debug( LDAP_DEBUG_TRACE, "(base)dn: \"%s\"\n",
1556 tmp_base_ndn, 0, 0 );
1558 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1559 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1560 if ( rc != SQL_SUCCESS ) {
1561 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1562 "error binding base_ndn parameter\n", 0, 0, 0 );
1563 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1565 bsi->bsi_status = LDAP_OTHER;
1566 return BACKSQL_AVL_CONTINUE;
1570 #ifdef LDAP_SCOPE_SUBORDINATE
1571 case LDAP_SCOPE_SUBORDINATE:
1572 #endif /* LDAP_SCOPE_SUBORDINATE */
1573 case LDAP_SCOPE_SUBTREE:
1575 /* if short-cutting the search base,
1576 * don't bind any parameter */
1577 if ( bsi->bsi_use_subtree_shortcut ) {
1582 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1583 * however this should be handled earlier
1585 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1586 bsi->bsi_status = LDAP_OTHER;
1587 return BACKSQL_AVL_CONTINUE;
1591 * Sets the parameters for the SQL built earlier
1592 * NOTE that all the databases could actually use
1593 * the TimesTen version, which would be cleaner
1594 * and would also eliminate the need for the
1595 * subtree_cond line in the configuration file.
1596 * For now, I'm leaving it the way it is,
1597 * so non-TimesTen databases use the original code.
1598 * But at some point this should get cleaned up.
1600 * If "dn" is being used, do a suffix search.
1601 * If "dn_ru" is being used, do a prefix search.
1603 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
1604 tmp_base_ndn[ 0 ] = '\0';
1606 for ( i = 0, j = bsi->bsi_base_ndn->bv_len - 1;
1608 tmp_base_ndn[ i ] = bsi->bsi_base_ndn->bv_val[ j ];
1611 #ifdef LDAP_SCOPE_SUBORDINATE
1612 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1613 tmp_base_ndn[ i++ ] = ',';
1615 #endif /* LDAP_SCOPE_SUBORDINATE */
1617 tmp_base_ndn[ i ] = '%';
1618 tmp_base_ndn[ i + 1 ] = '\0';
1623 tmp_base_ndn[ i++ ] = '%';
1625 #ifdef LDAP_SCOPE_SUBORDINATE
1626 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1627 tmp_base_ndn[ i++ ] = ',';
1629 #endif /* LDAP_SCOPE_SUBORDINATE */
1631 AC_MEMCPY( &tmp_base_ndn[ i ], bsi->bsi_base_ndn->bv_val,
1632 bsi->bsi_base_ndn->bv_len + 1 );
1635 /* uppercase DN only if the stored DN can be uppercased
1637 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1638 ldap_pvt_str2upper( tmp_base_ndn );
1641 #ifdef LDAP_SCOPE_SUBORDINATE
1642 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1643 Debug( LDAP_DEBUG_TRACE, "(children)dn: \"%s\"\n",
1644 tmp_base_ndn, 0, 0 );
1646 #endif /* LDAP_SCOPE_SUBORDINATE */
1648 Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n",
1649 tmp_base_ndn, 0, 0 );
1652 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1653 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1654 if ( rc != SQL_SUCCESS ) {
1655 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1656 "error binding base_ndn parameter (2)\n",
1658 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1660 bsi->bsi_status = LDAP_OTHER;
1661 return BACKSQL_AVL_CONTINUE;
1666 case LDAP_SCOPE_ONELEVEL:
1667 assert( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) );
1669 #ifdef BACKSQL_ARBITRARY_KEY
1670 Debug( LDAP_DEBUG_TRACE, "(one)id: \"%s\"\n",
1671 bsi->bsi_base_id.eid_id.bv_val, 0, 0 );
1672 #else /* ! BACKSQL_ARBITRARY_KEY */
1673 Debug( LDAP_DEBUG_TRACE, "(one)id: '%lu'\n",
1674 bsi->bsi_base_id.eid_id, 0, 0 );
1675 #endif /* ! BACKSQL_ARBITRARY_KEY */
1676 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT,
1677 &bsi->bsi_base_id.eid_id );
1678 if ( rc != SQL_SUCCESS ) {
1679 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1680 "error binding base id parameter\n", 0, 0, 0 );
1681 bsi->bsi_status = LDAP_OTHER;
1682 return BACKSQL_AVL_CONTINUE;
1687 rc = SQLExecute( sth );
1688 if ( !BACKSQL_SUCCESS( rc ) ) {
1689 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1690 "error executing query\n", 0, 0, 0 );
1691 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1692 SQLFreeStmt( sth, SQL_DROP );
1693 bsi->bsi_status = LDAP_OTHER;
1694 return BACKSQL_AVL_CONTINUE;
1697 backsql_BindRowAsStrings( sth, &row );
1698 rc = SQLFetch( sth );
1699 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
1700 struct berval dn, pdn, ndn;
1701 backsql_entryID *c_id = NULL;
1704 ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
1706 if ( backsql_api_odbc2dn( bsi->bsi_op, bsi->bsi_rs, &dn ) ) {
1710 ret = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
1711 if ( dn.bv_val != row.cols[ 3 ] ) {
1715 if ( ret != LDAP_SUCCESS ) {
1719 if ( bi->sql_baseObject && dn_match( &ndn, &bi->sql_baseObject->e_nname ) ) {
1720 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
1721 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
1725 c_id = (backsql_entryID *)ch_calloc( 1,
1726 sizeof( backsql_entryID ) );
1727 #ifdef BACKSQL_ARBITRARY_KEY
1728 ber_str2bv_x( row.cols[ 0 ], 0, 1, &c_id->eid_id,
1730 ber_str2bv_x( row.cols[ 1 ], 0, 1, &c_id->eid_keyval,
1732 #else /* ! BACKSQL_ARBITRARY_KEY */
1733 c_id->eid_id = strtol( row.cols[ 0 ], NULL, 0 );
1734 c_id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 );
1735 #endif /* ! BACKSQL_ARBITRARY_KEY */
1736 c_id->eid_oc_id = bsi->bsi_oc->bom_id;
1739 c_id->eid_ndn = ndn;
1741 /* append at end of list ... */
1742 c_id->eid_next = NULL;
1743 *bsi->bsi_id_listtail = c_id;
1744 bsi->bsi_id_listtail = &c_id->eid_next;
1746 #ifdef BACKSQL_ARBITRARY_KEY
1747 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1748 "added entry id=%s, keyval=%s dn=\"%s\"\n",
1749 c_id->eid_id.bv_val, c_id->eid_keyval.bv_val,
1751 #else /* ! BACKSQL_ARBITRARY_KEY */
1752 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1753 "added entry id=%ld, keyval=%ld dn=\"%s\"\n",
1754 c_id->eid_id, c_id->eid_keyval, row.cols[ 3 ] );
1755 #endif /* ! BACKSQL_ARBITRARY_KEY */
1757 /* count candidates, for unchecked limit */
1758 bsi->bsi_n_candidates--;
1759 if ( bsi->bsi_n_candidates == -1 ) {
1763 backsql_FreeRow( &row );
1764 SQLFreeStmt( sth, SQL_DROP );
1766 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n",
1767 n_candidates - bsi->bsi_n_candidates, 0, 0 );
1769 return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE );
1773 backsql_search( Operation *op, SlapReply *rs )
1775 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
1776 SQLHDBC dbh = SQL_NULL_HDBC;
1778 Entry user_entry = { 0 },
1781 time_t stoptime = 0;
1782 backsql_srch_info bsi;
1783 backsql_entryID *eid = NULL;
1784 struct berval nbase = BER_BVNULL,
1785 realndn = BER_BVNULL;
1787 manageDSAit = get_manageDSAit( op );
1789 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): "
1790 "base=\"%s\", filter=\"%s\", scope=%d,",
1791 op->o_req_ndn.bv_val,
1792 op->ors_filterstr.bv_val ? op->ors_filterstr.bv_val : "(no filter)",
1794 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, "
1795 "attributes to load: %s\n",
1798 op->ors_attrs == NULL ? "all" : "custom list" );
1800 if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) {
1801 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1802 "search base length (%ld) exceeds max length (%d)\n",
1803 op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN, 0 );
1805 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
1806 * since it is impossible that such a long DN exists
1809 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
1810 send_ldap_result( op, rs );
1814 sres = backsql_get_db_conn( op, &dbh );
1815 if ( sres != LDAP_SUCCESS ) {
1816 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1817 "could not get connection handle - exiting\n",
1820 rs->sr_text = sres == LDAP_OTHER ? "SQL-backend error" : NULL;
1821 send_ldap_result( op, rs );
1825 /* compute it anyway; root does not use it */
1826 stoptime = op->o_time + op->ors_tlimit;
1828 realndn = op->o_req_ndn;
1829 if ( backsql_api_dn2odbc( op, rs, &realndn ) ) {
1830 Debug( LDAP_DEBUG_TRACE, " backsql_search(\"%s\"): "
1831 "backsql_api_dn2odbc(\"%s\") failed\n",
1832 op->o_req_ndn.bv_val, realndn.bv_val, 0 );
1833 rs->sr_err = LDAP_OTHER;
1834 rs->sr_text = "SQL-backend error";
1835 send_ldap_result( op, rs );
1840 bsi.bsi_e = &base_entry;
1841 rs->sr_err = backsql_init_search( &bsi, &realndn,
1843 op->ors_slimit, op->ors_tlimit,
1844 stoptime, op->ors_filter,
1845 dbh, op, rs, op->ors_attrs,
1846 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
1847 if ( rs->sr_err != LDAP_SUCCESS ) {
1848 #ifdef SLAP_ACL_HONOR_DISCLOSE
1849 if ( !BER_BVISNULL( &base_entry.e_nname )
1850 && ! access_allowed( op, &base_entry,
1851 slap_schema.si_ad_entry, NULL,
1852 ACL_DISCLOSE, NULL ) )
1854 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1856 ber_bvarray_free( rs->sr_ref );
1858 rs->sr_matched = NULL;
1861 #endif /* SLAP_ACL_HONOR_DISCLOSE */
1862 send_ldap_result( op, rs );
1866 #ifdef SLAP_ACL_HONOR_DISCLOSE
1867 /* NOTE: __NEW__ "search" access is required
1868 * on searchBase object */
1872 /* FIXME: need the whole entry (ITS#3480) */
1873 if ( ! access_allowed_mask( op, &base_entry,
1874 slap_schema.si_ad_entry,
1875 NULL, ACL_SEARCH, NULL, &mask ) )
1877 if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
1878 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1882 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1884 send_ldap_result( op, rs );
1888 #endif /* SLAP_ACL_HONOR_DISCLOSE */
1892 bsi.bsi_n_candidates =
1893 ( op->ors_limit == NULL /* isroot == TRUE */ ? -2 :
1894 ( op->ors_limit->lms_s_unchecked == -1 ? -2 :
1895 ( op->ors_limit->lms_s_unchecked ) ) );
1897 switch ( bsi.bsi_scope ) {
1898 case LDAP_SCOPE_BASE:
1899 case BACKSQL_SCOPE_BASE_LIKE:
1901 * probably already found...
1903 bsi.bsi_id_list = &bsi.bsi_base_id;
1904 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
1907 case LDAP_SCOPE_SUBTREE:
1909 * if baseObject is defined, and if it is the root
1910 * of the search, add it to the candidate list
1912 if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &bsi.bsi_base_id.eid_id ) )
1914 bsi.bsi_id_list = &bsi.bsi_base_id;
1915 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
1922 * for each objectclass we try to construct query which gets IDs
1923 * of entries matching LDAP query filter and scope (or at least
1924 * candidates), and get the IDs
1926 avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates,
1927 &bsi, BACKSQL_AVL_STOP, AVL_INORDER );
1930 if ( op->ors_limit != NULL /* isroot == FALSE */
1931 && op->ors_limit->lms_s_unchecked != -1
1932 && bsi.bsi_n_candidates == -1 )
1934 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
1935 send_ldap_result( op, rs );
1940 * now we load candidate entries (only those attributes
1941 * mentioned in attrs and filter), test it against full filter
1942 * and then send to client; don't free entry_id if baseObject...
1944 for ( eid = bsi.bsi_id_list;
1946 eid = backsql_free_entryID( op,
1947 eid, eid == &bsi.bsi_base_id ? 0 : 1 ) )
1950 Attribute *a_hasSubordinate = NULL,
1951 *a_entryUUID = NULL,
1956 /* check for abandon */
1957 if ( op->o_abandon ) {
1961 /* check time limit */
1962 if ( op->ors_tlimit != SLAP_NO_LIMIT
1963 && slap_get_time() > stoptime )
1965 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
1966 rs->sr_ctrls = NULL;
1967 rs->sr_ref = rs->sr_v2ref;
1968 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
1970 send_ldap_result( op, rs );
1974 #ifdef BACKSQL_ARBITRARY_KEY
1975 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
1976 "for entry id=%s, oc_id=%ld, keyval=%s\n",
1977 eid->eid_id.bv_val, eid->eid_oc_id,
1978 eid->eid_keyval.bv_val );
1979 #else /* ! BACKSQL_ARBITRARY_KEY */
1980 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
1981 "for entry id=%ld, oc_id=%ld, keyval=%ld\n",
1982 eid->eid_id, eid->eid_oc_id, eid->eid_keyval );
1983 #endif /* ! BACKSQL_ARBITRARY_KEY */
1986 switch ( op->ors_scope ) {
1987 case LDAP_SCOPE_BASE:
1988 case BACKSQL_SCOPE_BASE_LIKE:
1989 if ( !dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
1994 case LDAP_SCOPE_ONE:
1996 struct berval rdn = eid->eid_ndn;
1998 rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
1999 if ( !dnIsOneLevelRDN( &rdn ) ) {
2005 #ifdef LDAP_SCOPE_SUBORDINATE
2006 case LDAP_SCOPE_SUBORDINATE:
2007 /* discard the baseObject entry */
2008 if ( dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
2012 #endif /* LDAP_SCOPE_SUBORDINATE */
2014 case LDAP_SCOPE_SUBTREE:
2015 /* FIXME: this should never fail... */
2016 if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) {
2023 if ( BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
2024 /* don't recollect baseObject... */
2025 e = bi->sql_baseObject;
2027 } else if ( eid == &bsi.bsi_base_id ) {
2028 /* don't recollect searchBase object... */
2032 bsi.bsi_e = &user_entry;
2033 rc = backsql_id2entry( &bsi, eid );
2034 if ( rc != LDAP_SUCCESS ) {
2035 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2036 "error %d in backsql_id2entry() "
2037 "- skipping\n", rc, 0, 0 );
2043 if ( !manageDSAit &&
2044 op->ors_scope != LDAP_SCOPE_BASE &&
2045 op->ors_scope != BACKSQL_SCOPE_BASE_LIKE &&
2046 is_entry_referral( e ) )
2050 refs = get_entry_referrals( op, e );
2052 backsql_srch_info bsi2 = { 0 };
2053 Entry user_entry2 = { 0 };
2055 /* retry with the full entry... */
2056 bsi2.bsi_e = &user_entry2;
2057 rc = backsql_init_search( &bsi2,
2060 SLAP_NO_LIMIT, SLAP_NO_LIMIT,
2063 BACKSQL_ISF_GET_ENTRY );
2064 if ( rc == LDAP_SUCCESS ) {
2065 if ( is_entry_referral( &user_entry2 ) )
2067 refs = get_entry_referrals( op,
2070 rs->sr_err = LDAP_OTHER;
2072 entry_clean( &user_entry2 );
2074 if ( bsi2.bsi_attrs != NULL ) {
2075 op->o_tmpfree( bsi2.bsi_attrs,
2081 rs->sr_ref = referral_rewrite( refs,
2085 ber_bvarray_free( refs );
2089 rs->sr_err = LDAP_REFERRAL;
2092 rs->sr_text = "bad referral object";
2096 rs->sr_matched = user_entry.e_name.bv_val;
2097 send_search_reference( op, rs );
2099 ber_bvarray_free( rs->sr_ref );
2101 rs->sr_matched = NULL;
2102 rs->sr_entry = NULL;
2108 * We use this flag since we need to parse the filter
2109 * anyway; we should have used the frontend API function
2110 * filter_has_subordinates()
2112 if ( bsi.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
2113 rc = backsql_has_children( bi, dbh, &e->e_nname );
2116 case LDAP_COMPARE_TRUE:
2117 case LDAP_COMPARE_FALSE:
2118 a_hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
2119 if ( a_hasSubordinate != NULL ) {
2120 for ( ap = &user_entry.e_attrs;
2122 ap = &(*ap)->a_next );
2124 *ap = a_hasSubordinate;
2130 Debug(LDAP_DEBUG_TRACE,
2131 "backsql_search(): "
2132 "has_children failed( %d)\n",
2139 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYUUID ) {
2140 a_entryUUID = backsql_operational_entryUUID( bi, eid );
2141 if ( a_entryUUID != NULL ) {
2143 ap = &user_entry.e_attrs;
2146 for ( ; *ap; ap = &(*ap)->a_next );
2152 #ifdef BACKSQL_SYNCPROV
2153 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYCSN ) {
2154 a_entryCSN = backsql_operational_entryCSN( op );
2155 if ( a_entryCSN != NULL ) {
2157 ap = &user_entry.e_attrs;
2160 for ( ; *ap; ap = &(*ap)->a_next );
2165 #endif /* BACKSQL_SYNCPROV */
2167 if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE )
2169 rs->sr_attrs = op->ors_attrs;
2170 rs->sr_operational_attrs = NULL;
2172 if ( e == &user_entry ) {
2173 rs->sr_flags = REP_ENTRY_MODIFIABLE;
2175 /* FIXME: need the whole entry (ITS#3480) */
2176 sres = send_search_entry( op, rs );
2177 rs->sr_entry = NULL;
2178 rs->sr_attrs = NULL;
2179 rs->sr_operational_attrs = NULL;
2183 * FIXME: send_search_entry failed;
2186 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2187 "connection lost\n", 0, 0, 0 );
2193 if ( e == &user_entry ) {
2194 entry_clean( &user_entry );
2198 if ( op->ors_slimit != SLAP_NO_LIMIT
2199 && rs->sr_nentries >= op->ors_slimit )
2201 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
2202 send_ldap_result( op, rs );
2208 entry_clean( &base_entry );
2210 /* in case we got here accidentally */
2211 entry_clean( &user_entry );
2213 if ( rs->sr_nentries > 0 ) {
2214 rs->sr_ref = rs->sr_v2ref;
2215 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
2219 rs->sr_err = bsi.bsi_status;
2221 send_ldap_result( op, rs );
2223 if ( rs->sr_v2ref ) {
2224 ber_bvarray_free( rs->sr_v2ref );
2225 rs->sr_v2ref = NULL;
2228 #ifdef BACKSQL_SYNCPROV
2230 Operation op2 = *op;
2231 SlapReply rs2 = { 0 };
2233 slap_callback cb = { 0 };
2235 op2.o_tag = LDAP_REQ_ADD;
2236 op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0, 0 );
2238 op2.o_callback = &cb;
2240 e.e_name = op->o_bd->be_suffix[0];
2241 e.e_nname = op->o_bd->be_nsuffix[0];
2243 cb.sc_response = slap_null_cb;
2245 op2.o_bd->be_add( &op2, &rs2 );
2247 #endif /* BACKSQL_SYNCPROV */
2250 if ( !BER_BVISNULL( &realndn ) && realndn.bv_val != op->o_req_ndn.bv_val ) {
2251 ch_free( realndn.bv_val );
2254 (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
2256 if ( bsi.bsi_attrs != NULL ) {
2257 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2260 if ( !BER_BVISNULL( &nbase )
2261 && nbase.bv_val != op->o_req_ndn.bv_val )
2263 ch_free( nbase.bv_val );
2266 /* restore scope ... FIXME: this should be done before ANY
2267 * frontend call that uses op */
2268 if ( op->ors_scope == BACKSQL_SCOPE_BASE_LIKE ) {
2269 op->ors_scope = LDAP_SCOPE_BASE;
2272 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
2276 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
2283 AttributeDescription *at,
2287 backsql_srch_info bsi;
2288 SQLHDBC dbh = SQL_NULL_HDBC;
2290 SlapReply rs = { 0 };
2291 AttributeName anlist[ 2 ];
2295 rc = backsql_get_db_conn( op, &dbh );
2301 anlist[ 0 ].an_name = at->ad_cname;
2302 anlist[ 0 ].an_desc = at;
2303 BER_BVZERO( &anlist[ 1 ].an_name );
2306 bsi.bsi_e = ch_malloc( sizeof( Entry ) );
2307 rc = backsql_init_search( &bsi,
2310 SLAP_NO_LIMIT, SLAP_NO_LIMIT,
2312 dbh, op, &rs, at ? anlist : NULL,
2313 BACKSQL_ISF_GET_ENTRY );
2315 (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
2317 if ( rc == LDAP_SUCCESS ) {
2319 #if 0 /* not supported at present */
2320 /* find attribute values */
2321 if ( is_entry_alias( bsi.bsi_e ) ) {
2322 Debug( LDAP_DEBUG_ACL,
2323 "<= backsql_entry_get: entry is an alias\n",
2325 rc = LDAP_ALIAS_PROBLEM;
2326 goto return_results;
2330 if ( is_entry_referral( bsi.bsi_e ) ) {
2331 Debug( LDAP_DEBUG_ACL,
2332 "<= backsql_entry_get: entry is a referral\n",
2335 goto return_results;
2338 if ( oc && !is_entry_objectclass( bsi.bsi_e, oc, 0 ) ) {
2339 Debug( LDAP_DEBUG_ACL,
2340 "<= backsql_entry_get: "
2341 "failed to find objectClass\n",
2343 rc = LDAP_NO_SUCH_ATTRIBUTE;
2344 goto return_results;
2351 if ( bsi.bsi_attrs != NULL ) {
2352 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2355 if ( rc != LDAP_SUCCESS ) {
2357 entry_free( bsi.bsi_e );