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,
117 AttributeName *attrs,
120 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
121 int rc = LDAP_SUCCESS;
123 bsi->bsi_base_ndn = nbase;
124 bsi->bsi_use_subtree_shortcut = 0;
125 BER_BVZERO( &bsi->bsi_base_id.eid_dn );
126 BER_BVZERO( &bsi->bsi_base_id.eid_ndn );
127 bsi->bsi_scope = scope;
128 bsi->bsi_filter = filter;
132 bsi->bsi_flags = BSQL_SF_NONE;
134 bsi->bsi_attrs = NULL;
136 if ( BACKSQL_FETCH_ALL_ATTRS( bi ) ) {
138 * if requested, simply try to fetch all attributes
140 bsi->bsi_flags |= BSQL_SF_ALL_ATTRS;
143 if ( BACKSQL_FETCH_ALL_USERATTRS( bi ) ) {
144 bsi->bsi_flags |= BSQL_SF_ALL_USER;
146 } else if ( BACKSQL_FETCH_ALL_OPATTRS( bi ) ) {
147 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
150 if ( attrs == NULL ) {
151 /* NULL means all user attributes */
152 bsi->bsi_flags |= BSQL_SF_ALL_USER;
158 bsi->bsi_attrs = (AttributeName *)bsi->bsi_op->o_tmpalloc(
159 sizeof( AttributeName ),
160 bsi->bsi_op->o_tmpmemctx );
161 BER_BVZERO( &bsi->bsi_attrs[ 0 ].an_name );
163 for ( p = attrs; !BER_BVISNULL( &p->an_name ); p++ ) {
164 if ( BACKSQL_NCMP( &p->an_name, &AllUser ) == 0 ) {
166 bsi->bsi_flags |= BSQL_SF_ALL_USER;
168 /* if all attrs are requested, there's
169 * no need to continue */
170 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
171 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
172 bsi->bsi_op->o_tmpmemctx );
173 bsi->bsi_attrs = NULL;
178 } else if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) {
180 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
182 /* if all attrs are requested, there's
183 * no need to continue */
184 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
185 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
186 bsi->bsi_op->o_tmpmemctx );
187 bsi->bsi_attrs = NULL;
192 } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
196 } else if ( p->an_desc == slap_schema.si_ad_objectClass ) {
200 backsql_attrlist_add( bsi, p->an_desc );
203 if ( got_oc == 0 && !( bsi->bsi_flags & BSQL_SF_ALL_USER ) ) {
204 /* add objectClass if not present,
205 * because it is required to understand
206 * if an entry is a referral, an alias
208 backsql_attrlist_add( bsi, slap_schema.si_ad_objectClass );
212 if ( !BSQL_ISF_ALL_ATTRS( bsi ) && bi->sql_anlist ) {
215 /* use hints if available */
216 for ( p = bi->sql_anlist; !BER_BVISNULL( &p->an_name ); p++ ) {
217 if ( BACKSQL_NCMP( &p->an_name, &AllUser ) == 0 ) {
219 bsi->bsi_flags |= BSQL_SF_ALL_USER;
221 /* if all attrs are requested, there's
222 * no need to continue */
223 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
224 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
225 bsi->bsi_op->o_tmpmemctx );
226 bsi->bsi_attrs = NULL;
231 } else if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) {
233 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
235 /* if all attrs are requested, there's
236 * no need to continue */
237 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
238 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
239 bsi->bsi_op->o_tmpmemctx );
240 bsi->bsi_attrs = NULL;
246 backsql_attrlist_add( bsi, p->an_desc );
252 bsi->bsi_id_list = NULL;
253 bsi->bsi_id_listtail = &bsi->bsi_id_list;
254 bsi->bsi_n_candidates = 0;
255 bsi->bsi_stoptime = stoptime;
256 BER_BVZERO( &bsi->bsi_sel.bb_val );
257 bsi->bsi_sel.bb_len = 0;
258 BER_BVZERO( &bsi->bsi_from.bb_val );
259 bsi->bsi_from.bb_len = 0;
260 BER_BVZERO( &bsi->bsi_join_where.bb_val );
261 bsi->bsi_join_where.bb_len = 0;
262 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
263 bsi->bsi_flt_where.bb_len = 0;
264 bsi->bsi_filter_oc = NULL;
266 if ( BACKSQL_IS_GET_ID( flags ) ) {
267 int matched = BACKSQL_IS_MATCHED( flags );
268 int getentry = BACKSQL_IS_GET_ENTRY( flags );
271 assert( op->o_bd->be_private != NULL );
273 rc = backsql_dn2id( op, rs, dbh, nbase, &bsi->bsi_base_id,
276 /* the entry is collected either if requested for by getentry
277 * or if get noSuchObject and requested to climb the tree,
278 * so that a matchedDN or a referral can be returned */
279 if ( ( rc == LDAP_NO_SUCH_OBJECT && matched ) || getentry ) {
280 if ( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ) {
281 assert( bsi->bsi_e != NULL );
283 if ( dn_match( nbase, &bsi->bsi_base_id.eid_ndn ) )
289 * let's see if it is a referral and, in case, get it
291 backsql_attrlist_add( bsi, slap_schema.si_ad_ref );
292 rc = backsql_id2entry( bsi, &bsi->bsi_base_id );
293 if ( rc == LDAP_SUCCESS ) {
294 if ( is_entry_referral( bsi->bsi_e ) )
296 BerVarray erefs = get_entry_referrals( op, bsi->bsi_e );
298 rc = rs->sr_err = LDAP_REFERRAL;
299 rs->sr_ref = referral_rewrite( erefs,
300 &bsi->bsi_e->e_nname,
303 ber_bvarray_free( erefs );
306 rc = rs->sr_err = LDAP_OTHER;
307 rs->sr_text = "bad referral object";
310 } else if ( !gotit ) {
311 rc = rs->sr_err = LDAP_NO_SUCH_OBJECT;
316 rs->sr_ref = referral_rewrite( default_referral,
317 NULL, &op->o_req_dn, scope );
318 rc = rs->sr_err = LDAP_REFERRAL;
323 bsi->bsi_status = rc;
331 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
332 bsi->bsi_op->o_tmpmemctx );
340 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
348 backsql_strfcat_x( &bsi->bsi_flt_where,
349 bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ );
352 res = backsql_process_filter( bsi, f );
355 * TimesTen : If the query has no answers,
356 * don't bother to run the query.
367 case LDAP_FILTER_AND:
368 backsql_strfcat_x( &bsi->bsi_flt_where,
369 bsi->bsi_op->o_tmpmemctx, "l",
370 (ber_len_t)STRLENOF( " AND " ),
375 backsql_strfcat_x( &bsi->bsi_flt_where,
376 bsi->bsi_op->o_tmpmemctx, "l",
377 (ber_len_t)STRLENOF( " OR " ),
383 backsql_strfcat_x( &bsi->bsi_flt_where,
384 bsi->bsi_op->o_tmpmemctx, "c", /* ( */ ')' );
390 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
391 backsql_at_map_rec *at )
393 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
401 /* always uppercase strings by now */
402 #ifdef BACKSQL_UPPERCASE_FILTER
403 if ( f->f_sub_desc->ad_type->sat_substr &&
404 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
405 bi->sql_caseIgnoreMatch ) )
406 #endif /* BACKSQL_UPPERCASE_FILTER */
411 if ( f->f_sub_desc->ad_type->sat_substr &&
412 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
413 bi->sql_telephoneNumberMatch ) )
420 * to check for matching telephone numbers
421 * with intermixed chars, e.g. val='1234'
424 * val LIKE '%1%2%3%4%'
428 if ( f->f_sub_initial.bv_val ) {
429 bv.bv_len += f->f_sub_initial.bv_len;
431 if ( f->f_sub_any != NULL ) {
432 for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) {
433 bv.bv_len += f->f_sub_any[ a ].bv_len;
436 if ( f->f_sub_final.bv_val ) {
437 bv.bv_len += f->f_sub_final.bv_len;
439 bv.bv_len = 2 * bv.bv_len - 1;
440 bv.bv_val = ch_malloc( bv.bv_len + 1 );
443 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
444 bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ];
445 for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) {
446 bv.bv_val[ s + 2 * i - 1 ] = '%';
447 bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ];
449 bv.bv_val[ s + 2 * i - 1 ] = '%';
453 if ( f->f_sub_any != NULL ) {
454 for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
455 bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ];
456 for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) {
457 bv.bv_val[ s + 2 * i - 1 ] = '%';
458 bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ];
460 bv.bv_val[ s + 2 * i - 1 ] = '%';
465 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
466 bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ];
467 for ( i = 1; i < f->f_sub_final.bv_len; i++ ) {
468 bv.bv_val[ s + 2 * i - 1 ] = '%';
469 bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ];
471 bv.bv_val[ s + 2 * i - 1 ] = '%';
475 bv.bv_val[ s - 1 ] = '\0';
477 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
478 ch_free( bv.bv_val );
484 * When dealing with case-sensitive strings
485 * we may omit normalization; however, normalized
486 * SQL filters are more liberal.
489 backsql_strfcat_x( &bsi->bsi_flt_where,
490 bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ );
493 Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n",
494 at->bam_ad->ad_cname.bv_val, 0, 0 );
495 Debug(LDAP_DEBUG_TRACE, " expr: '%s%s%s'\n", at->bam_sel_expr.bv_val,
496 at->bam_sel_expr_u.bv_val ? "' '" : "",
497 at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" );
498 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
500 * If a pre-upper-cased version of the column
501 * or a precompiled upper function exists, use it
503 backsql_strfcat_x( &bsi->bsi_flt_where,
504 bsi->bsi_op->o_tmpmemctx,
507 (ber_len_t)STRLENOF( " LIKE '" ),
511 backsql_strfcat_x( &bsi->bsi_flt_where,
512 bsi->bsi_op->o_tmpmemctx,
515 (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
518 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
522 Debug( LDAP_DEBUG_TRACE,
523 "==>backsql_process_sub_filter(%s): "
524 "sub_initial=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
525 f->f_sub_initial.bv_val, 0 );
526 #endif /* BACKSQL_TRACE */
528 start = bsi->bsi_flt_where.bb_val.bv_len;
529 backsql_strfcat_x( &bsi->bsi_flt_where,
530 bsi->bsi_op->o_tmpmemctx,
533 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
534 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
538 backsql_strfcat_x( &bsi->bsi_flt_where,
539 bsi->bsi_op->o_tmpmemctx,
542 if ( f->f_sub_any != NULL ) {
543 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) {
547 Debug( LDAP_DEBUG_TRACE,
548 "==>backsql_process_sub_filter(%s): "
549 "sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
550 i, f->f_sub_any[ i ].bv_val );
551 #endif /* BACKSQL_TRACE */
553 start = bsi->bsi_flt_where.bb_val.bv_len;
554 backsql_strfcat_x( &bsi->bsi_flt_where,
555 bsi->bsi_op->o_tmpmemctx,
559 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
561 * Note: toupper('%') = '%'
563 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
568 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
572 Debug( LDAP_DEBUG_TRACE,
573 "==>backsql_process_sub_filter(%s): "
574 "sub_final=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
575 f->f_sub_final.bv_val, 0 );
576 #endif /* BACKSQL_TRACE */
578 start = bsi->bsi_flt_where.bb_val.bv_len;
579 backsql_strfcat_x( &bsi->bsi_flt_where,
580 bsi->bsi_op->o_tmpmemctx,
583 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
584 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
588 backsql_strfcat_x( &bsi->bsi_flt_where,
589 bsi->bsi_op->o_tmpmemctx,
591 (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" );
597 backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls )
599 if ( BER_BVISNULL( from_tbls ) ) {
603 if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) {
607 ber_dupbv_x( &tmp, from_tbls, bsi->bsi_op->o_tmpmemctx );
609 for ( start = tmp.bv_val, end = strchr( start, ',' ); start; ) {
614 if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL )
616 backsql_strfcat_x( &bsi->bsi_from,
617 bsi->bsi_op->o_tmpmemctx,
622 /* in case there are spaces after the comma... */
623 for ( start = &end[1]; isspace( start[0] ); start++ );
625 end = strchr( start, ',' );
634 bsi->bsi_op->o_tmpfree( tmp.bv_val, bsi->bsi_op->o_tmpmemctx );
637 backsql_strfcat_x( &bsi->bsi_from,
638 bsi->bsi_op->o_tmpmemctx,
646 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
648 backsql_at_map_rec **vat = NULL;
649 AttributeDescription *ad = NULL;
654 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 );
655 if ( f->f_choice == SLAPD_FILTER_COMPUTED ) {
656 Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
657 "invalid filter\n", 0, 0, 0 );
662 switch( f->f_choice ) {
664 rc = backsql_process_filter_list( bsi, f->f_or,
669 case LDAP_FILTER_AND:
670 rc = backsql_process_filter_list( bsi, f->f_and,
675 case LDAP_FILTER_NOT:
676 backsql_strfcat_x( &bsi->bsi_flt_where,
677 bsi->bsi_op->o_tmpmemctx,
679 (ber_len_t)STRLENOF( "NOT (" /* ) */ ),
681 rc = backsql_process_filter( bsi, f->f_not );
682 backsql_strfcat_x( &bsi->bsi_flt_where,
683 bsi->bsi_op->o_tmpmemctx,
688 case LDAP_FILTER_PRESENT:
692 case LDAP_FILTER_EXT:
693 ad = f->f_mra->ma_desc;
694 if ( f->f_mr_dnattrs ) {
696 * if dn attrs filtering is requested, better return
697 * success and let test_filter() deal with candidate
698 * selection; otherwise we'd need to set conditions
699 * on the contents of the DN, e.g. "SELECT ... FROM
700 * ldap_entries AS attributeName WHERE attributeName.dn
701 * like '%attributeName=value%'"
703 backsql_strfcat_x( &bsi->bsi_flt_where,
704 bsi->bsi_op->o_tmpmemctx,
706 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
707 bsi->bsi_status = LDAP_SUCCESS;
728 * Turn structuralObjectClass into objectClass
730 if ( ad == slap_schema.si_ad_objectClass
731 || ad == slap_schema.si_ad_structuralObjectClass )
734 * If the filter is LDAP_FILTER_PRESENT, then it's done;
735 * otherwise, let's see if we are lucky: filtering
736 * for "structural" objectclass or ancestor...
738 switch ( f->f_choice ) {
739 case LDAP_FILTER_EQUALITY:
741 ObjectClass *oc = oc_bvfind( &f->f_av_value );
744 Debug( LDAP_DEBUG_TRACE,
745 "backsql_process_filter(): "
746 "unknown objectClass \"%s\" "
748 f->f_av_value.bv_val, 0, 0 );
749 bsi->bsi_status = LDAP_OTHER;
755 * "structural" objectClass inheritance:
756 * - a search for "person" will also return
758 * - a search for "top" will return everything
760 if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
761 static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" );
763 backsql_merge_from_tbls( bsi, &ldap_entry_objclasses );
765 backsql_strfcat_x( &bsi->bsi_flt_where,
766 bsi->bsi_op->o_tmpmemctx,
768 (ber_len_t)STRLENOF( "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */ ),
769 "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */,
770 &bsi->bsi_oc->bom_oc->soc_cname,
771 (ber_len_t)STRLENOF( /* ((' */ "'))" ),
773 bsi->bsi_status = LDAP_SUCCESS;
781 case LDAP_FILTER_PRESENT:
782 backsql_strfcat_x( &bsi->bsi_flt_where,
783 bsi->bsi_op->o_tmpmemctx,
785 (ber_len_t)STRLENOF( "3=3" ), "3=3" );
786 bsi->bsi_status = LDAP_SUCCESS;
790 /* FIXME: LDAP_FILTER_EXT? */
793 Debug( LDAP_DEBUG_TRACE,
794 "backsql_process_filter(): "
795 "illegal/unhandled filter "
796 "on objectClass attribute",
798 bsi->bsi_status = LDAP_OTHER;
803 } else if ( ad == slap_schema.si_ad_entryUUID ) {
805 #ifdef BACKSQL_ARBITRARY_KEY
806 struct berval keyval;
807 #else /* ! BACKSQL_ARBITRARY_KEY */
808 unsigned long keyval;
809 char keyvalbuf[] = "18446744073709551615";
810 #endif /* ! BACKSQL_ARBITRARY_KEY */
812 switch ( f->f_choice ) {
813 case LDAP_FILTER_EQUALITY:
814 backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval );
816 if ( oc_id != bsi->bsi_oc->bom_id ) {
817 bsi->bsi_status = LDAP_SUCCESS;
822 #ifdef BACKSQL_ARBITRARY_KEY
823 backsql_strfcat_x( &bsi->bsi_flt_where,
824 bsi->bsi_op->o_tmpmemctx,
826 &bsi->bsi_oc->bom_keytbl, '.',
827 &bsi->bsi_oc->bom_keycol,
828 STRLENOF( " LIKE '" ), " LIKE '",
830 #else /* ! BACKSQL_ARBITRARY_KEY */
831 snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval );
832 backsql_strfcat_x( &bsi->bsi_flt_where,
833 bsi->bsi_op->o_tmpmemctx,
835 &bsi->bsi_oc->bom_keytbl, '.',
836 &bsi->bsi_oc->bom_keycol, '=', keyvalbuf );
837 #endif /* ! BACKSQL_ARBITRARY_KEY */
840 case LDAP_FILTER_PRESENT:
841 backsql_strfcat_x( &bsi->bsi_flt_where,
842 bsi->bsi_op->o_tmpmemctx,
844 (ber_len_t)STRLENOF( "4=4" ), "4=4" );
852 bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID;
856 #ifdef BACKSQL_SYNCPROV
857 } else if ( ad == slap_schema.si_ad_entryCSN ) {
859 * support for syncrepl as producer...
862 if ( !bsi->bsi_op->o_sync ) {
863 /* unsupported at present... */
864 bsi->bsi_status = LDAP_OTHER;
870 bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID);
872 /* if doing a syncrepl, try to return as much as possible,
873 * and always match the filter */
874 backsql_strfcat_x( &bsi->bsi_flt_where,
875 bsi->bsi_op->o_tmpmemctx,
877 (ber_len_t)STRLENOF( "5=5" ), "5=5" );
879 /* save for later use in operational attributes */
880 /* FIXME: saves only the first occurrence, because
881 * the filter during updates is written as
882 * "(&(entryCSN<={contextCSN})(entryCSN>={oldContextCSN})({filter}))"
883 * so we want our fake entryCSN to match the greatest
886 if ( bsi->bsi_op->o_private == NULL ) {
887 bsi->bsi_op->o_private = &f->f_av_value;
889 bsi->bsi_status = LDAP_SUCCESS;
893 #endif /* BACKSQL_SYNCPROV */
895 } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
897 * FIXME: this is not robust; e.g. a filter
898 * '(!(hasSubordinates=TRUE))' fails because
899 * in SQL it would read 'NOT (1=1)' instead
901 * Note however that hasSubordinates is boolean,
902 * so a more appropriate filter would be
903 * '(hasSubordinates=FALSE)'
905 * A more robust search for hasSubordinates
906 * would * require joining the ldap_entries table
907 * selecting if there are descendants of the
910 backsql_strfcat_x( &bsi->bsi_flt_where,
911 bsi->bsi_op->o_tmpmemctx,
913 (ber_len_t)STRLENOF( "6=6" ), "6=6" );
914 if ( ad == slap_schema.si_ad_hasSubordinates ) {
916 * instruct candidate selection algorithm
917 * and attribute list to try to detect
918 * if an entry has subordinates
920 bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
924 * clear attributes to fetch, to require ALL
925 * and try extended match on all attributes
927 backsql_attrlist_add( bsi, NULL );
934 * attribute inheritance:
936 if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) {
937 bsi->bsi_status = LDAP_OTHER;
943 /* search anyway; other parts of the filter
945 backsql_strfcat_x( &bsi->bsi_flt_where,
946 bsi->bsi_op->o_tmpmemctx,
948 (ber_len_t)STRLENOF( "7=7" ), "7=7" );
949 bsi->bsi_status = LDAP_SUCCESS;
954 /* if required, open extra level of parens */
956 if ( vat[0]->bam_next || vat[1] ) {
957 backsql_strfcat_x( &bsi->bsi_flt_where,
958 bsi->bsi_op->o_tmpmemctx,
966 if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) {
970 /* if more definitions of the same attr, apply */
971 if ( vat[i]->bam_next ) {
972 backsql_strfcat_x( &bsi->bsi_flt_where,
973 bsi->bsi_op->o_tmpmemctx,
975 STRLENOF( " OR " ), " OR " );
976 vat[i] = vat[i]->bam_next;
980 /* if more descendants of the same attr, apply */
983 backsql_strfcat_x( &bsi->bsi_flt_where,
984 bsi->bsi_op->o_tmpmemctx,
986 STRLENOF( " OR " ), " OR " );
990 /* if needed, close extra level of parens */
992 backsql_strfcat_x( &bsi->bsi_flt_where,
993 bsi->bsi_op->o_tmpmemctx,
1004 Debug( LDAP_DEBUG_TRACE,
1005 "<==backsql_process_filter() %s\n",
1006 rc == 1 ? "succeeded" : "failed", 0, 0);
1012 backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at,
1013 int casefold, struct berval *filter_value )
1016 * maybe we should check type of at->sel_expr here somehow,
1017 * to know whether upper_func is applicable, but for now
1018 * upper_func stuff is made for Oracle, where UPPER is
1019 * safely applicable to NUMBER etc.
1021 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1024 backsql_strfcat_x( &bsi->bsi_flt_where,
1025 bsi->bsi_op->o_tmpmemctx,
1028 &at->bam_sel_expr_u,
1029 (ber_len_t)STRLENOF( "='" ),
1032 start = bsi->bsi_flt_where.bb_val.bv_len;
1034 backsql_strfcat_x( &bsi->bsi_flt_where,
1035 bsi->bsi_op->o_tmpmemctx,
1038 (ber_len_t)STRLENOF( /* (' */ "')" ),
1041 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1044 backsql_strfcat_x( &bsi->bsi_flt_where,
1045 bsi->bsi_op->o_tmpmemctx,
1049 (ber_len_t)STRLENOF( "='" ), "='",
1051 (ber_len_t)STRLENOF( /* (' */ "')" ),
1059 backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at,
1060 int casefold, struct berval *filter_value )
1063 * maybe we should check type of at->sel_expr here somehow,
1064 * to know whether upper_func is applicable, but for now
1065 * upper_func stuff is made for Oracle, where UPPER is
1066 * safely applicable to NUMBER etc.
1068 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1071 backsql_strfcat_x( &bsi->bsi_flt_where,
1072 bsi->bsi_op->o_tmpmemctx,
1075 &at->bam_sel_expr_u,
1076 (ber_len_t)STRLENOF( " LIKE '%" ),
1079 start = bsi->bsi_flt_where.bb_val.bv_len;
1081 backsql_strfcat_x( &bsi->bsi_flt_where,
1082 bsi->bsi_op->o_tmpmemctx,
1085 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1088 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1091 backsql_strfcat_x( &bsi->bsi_flt_where,
1092 bsi->bsi_op->o_tmpmemctx,
1096 (ber_len_t)STRLENOF( " LIKE '%" ),
1099 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1107 backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at )
1109 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1111 struct berval *filter_value = NULL;
1112 MatchingRule *matching_rule = NULL;
1113 struct berval ordering = BER_BVC("<=");
1115 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n",
1116 at->bam_ad->ad_cname.bv_val, 0, 0 );
1119 * need to add this attribute to list of attrs to load,
1120 * so that we can do test_filter() later
1122 backsql_attrlist_add( bsi, at->bam_ad );
1124 backsql_merge_from_tbls( bsi, &at->bam_from_tbls );
1126 if ( !BER_BVISNULL( &at->bam_join_where )
1127 && strstr( bsi->bsi_join_where.bb_val.bv_val,
1128 at->bam_join_where.bv_val ) == NULL )
1130 backsql_strfcat_x( &bsi->bsi_join_where,
1131 bsi->bsi_op->o_tmpmemctx,
1133 (ber_len_t)STRLENOF( " AND " ), " AND ",
1134 &at->bam_join_where );
1137 switch ( f->f_choice ) {
1138 case LDAP_FILTER_EQUALITY:
1139 filter_value = &f->f_av_value;
1140 matching_rule = at->bam_ad->ad_type->sat_equality;
1142 goto equality_match;
1144 /* fail over into next case */
1146 case LDAP_FILTER_EXT:
1147 filter_value = &f->f_mra->ma_value;
1148 matching_rule = f->f_mr_rule;
1151 /* always uppercase strings by now */
1152 #ifdef BACKSQL_UPPERCASE_FILTER
1153 if ( SLAP_MR_ASSOCIATED( matching_rule,
1154 bi->sql_caseIgnoreMatch ) )
1155 #endif /* BACKSQL_UPPERCASE_FILTER */
1160 /* FIXME: directoryString filtering should use a similar
1161 * approach to deal with non-prettified values like
1162 * " A non prettified value ", by using a LIKE
1163 * filter with all whitespaces collapsed to a single '%' */
1164 if ( SLAP_MR_ASSOCIATED( matching_rule,
1165 bi->sql_telephoneNumberMatch ) )
1171 * to check for matching telephone numbers
1172 * with intermized chars, e.g. val='1234'
1175 * val LIKE '%1%2%3%4%'
1178 bv.bv_len = 2 * filter_value->bv_len - 1;
1179 bv.bv_val = ch_malloc( bv.bv_len + 1 );
1181 bv.bv_val[ 0 ] = filter_value->bv_val[ 0 ];
1182 for ( i = 1; i < filter_value->bv_len; i++ ) {
1183 bv.bv_val[ 2 * i - 1 ] = '%';
1184 bv.bv_val[ 2 * i ] = filter_value->bv_val[ i ];
1186 bv.bv_val[ 2 * i - 1 ] = '\0';
1188 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
1189 ch_free( bv.bv_val );
1194 /* NOTE: this is required by objectClass inheritance
1195 * and auxiliary objectClass use in filters for slightly
1196 * more efficient candidate selection. */
1197 /* FIXME: a bit too many specializations to deal with
1198 * very specific cases... */
1199 if ( at->bam_ad == slap_schema.si_ad_objectClass
1200 || at->bam_ad == slap_schema.si_ad_structuralObjectClass )
1202 backsql_strfcat_x( &bsi->bsi_flt_where,
1203 bsi->bsi_op->o_tmpmemctx,
1205 (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
1206 "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
1208 (ber_len_t)STRLENOF( /* (' */ "')" ),
1214 * maybe we should check type of at->sel_expr here somehow,
1215 * to know whether upper_func is applicable, but for now
1216 * upper_func stuff is made for Oracle, where UPPER is
1217 * safely applicable to NUMBER etc.
1219 (void)backsql_process_filter_eq( bsi, at, casefold, filter_value );
1222 case LDAP_FILTER_GE:
1223 ordering.bv_val = ">=";
1225 /* fall thru to next case */
1227 case LDAP_FILTER_LE:
1228 filter_value = &f->f_av_value;
1230 /* always uppercase strings by now */
1231 #ifdef BACKSQL_UPPERCASE_FILTER
1232 if ( at->bam_ad->ad_type->sat_ordering &&
1233 SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering,
1234 bi->sql_caseIgnoreMatch ) )
1235 #endif /* BACKSQL_UPPERCASE_FILTER */
1241 * FIXME: should we uppercase the operands?
1243 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1246 backsql_strfcat_x( &bsi->bsi_flt_where,
1247 bsi->bsi_op->o_tmpmemctx,
1250 &at->bam_sel_expr_u,
1254 start = bsi->bsi_flt_where.bb_val.bv_len;
1256 backsql_strfcat_x( &bsi->bsi_flt_where,
1257 bsi->bsi_op->o_tmpmemctx,
1260 (ber_len_t)STRLENOF( /* (' */ "')" ),
1263 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1266 backsql_strfcat_x( &bsi->bsi_flt_where,
1267 bsi->bsi_op->o_tmpmemctx,
1274 (ber_len_t)STRLENOF( /* (' */ "')" ),
1279 case LDAP_FILTER_PRESENT:
1280 backsql_strfcat_x( &bsi->bsi_flt_where,
1281 bsi->bsi_op->o_tmpmemctx,
1283 (ber_len_t)STRLENOF( "NOT (" /* ) */),
1286 (ber_len_t)STRLENOF( /* ( */ " IS NULL)" ),
1287 /* ( */ " IS NULL)" );
1290 case LDAP_FILTER_SUBSTRINGS:
1291 backsql_process_sub_filter( bsi, f, at );
1294 case LDAP_FILTER_APPROX:
1295 /* we do our best */
1298 * maybe we should check type of at->sel_expr here somehow,
1299 * to know whether upper_func is applicable, but for now
1300 * upper_func stuff is made for Oracle, where UPPER is
1301 * safely applicable to NUMBER etc.
1303 (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value );
1307 /* unhandled filter type; should not happen */
1309 backsql_strfcat_x( &bsi->bsi_flt_where,
1310 bsi->bsi_op->o_tmpmemctx,
1312 (ber_len_t)STRLENOF( "8=8" ), "8=8" );
1317 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n",
1318 at->bam_ad->ad_cname.bv_val, 0, 0 );
1324 backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
1326 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1329 assert( query != NULL );
1330 BER_BVZERO( query );
1332 bsi->bsi_use_subtree_shortcut = 0;
1334 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n", 0, 0, 0 );
1335 BER_BVZERO( &bsi->bsi_sel.bb_val );
1336 BER_BVZERO( &bsi->bsi_sel.bb_val );
1337 bsi->bsi_sel.bb_len = 0;
1338 BER_BVZERO( &bsi->bsi_from.bb_val );
1339 bsi->bsi_from.bb_len = 0;
1340 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1341 bsi->bsi_join_where.bb_len = 0;
1342 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1343 bsi->bsi_flt_where.bb_len = 0;
1345 backsql_strfcat_x( &bsi->bsi_sel,
1346 bsi->bsi_op->o_tmpmemctx,
1348 (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ),
1349 "SELECT DISTINCT ldap_entries.id,",
1350 &bsi->bsi_oc->bom_keytbl,
1352 &bsi->bsi_oc->bom_keycol,
1355 if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
1356 backsql_strfcat_x( &bsi->bsi_sel,
1357 bsi->bsi_op->o_tmpmemctx,
1359 &bi->sql_strcast_func,
1360 (ber_len_t)STRLENOF( "('" /* ') */ ),
1362 &bsi->bsi_oc->bom_oc->soc_cname,
1363 (ber_len_t)STRLENOF( /* (' */ "')" ),
1366 backsql_strfcat_x( &bsi->bsi_sel,
1367 bsi->bsi_op->o_tmpmemctx,
1370 &bsi->bsi_oc->bom_oc->soc_cname,
1374 backsql_strfcat_x( &bsi->bsi_sel,
1375 bsi->bsi_op->o_tmpmemctx,
1377 &bi->sql_dn_oc_aliasing );
1378 backsql_strfcat_x( &bsi->bsi_from,
1379 bsi->bsi_op->o_tmpmemctx,
1381 (ber_len_t)STRLENOF( " FROM ldap_entries," ),
1382 " FROM ldap_entries,",
1383 &bsi->bsi_oc->bom_keytbl );
1385 backsql_strfcat_x( &bsi->bsi_join_where,
1386 bsi->bsi_op->o_tmpmemctx,
1388 (ber_len_t)STRLENOF( " WHERE " ), " WHERE ",
1389 &bsi->bsi_oc->bom_keytbl,
1391 &bsi->bsi_oc->bom_keycol,
1392 (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ),
1393 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
1395 switch ( bsi->bsi_scope ) {
1396 case LDAP_SCOPE_BASE:
1397 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1398 backsql_strfcat_x( &bsi->bsi_join_where,
1399 bsi->bsi_op->o_tmpmemctx,
1401 &bi->sql_upper_func,
1402 (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ),
1403 "(ldap_entries.dn)=?" );
1405 backsql_strfcat_x( &bsi->bsi_join_where,
1406 bsi->bsi_op->o_tmpmemctx,
1408 (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
1409 "ldap_entries.dn=?" );
1413 case BACKSQL_SCOPE_BASE_LIKE:
1414 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1415 backsql_strfcat_x( &bsi->bsi_join_where,
1416 bsi->bsi_op->o_tmpmemctx,
1418 &bi->sql_upper_func,
1419 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1420 "(ldap_entries.dn) LIKE ?" );
1422 backsql_strfcat_x( &bsi->bsi_join_where,
1423 bsi->bsi_op->o_tmpmemctx,
1425 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1426 "ldap_entries.dn LIKE ?" );
1430 case LDAP_SCOPE_ONELEVEL:
1431 backsql_strfcat_x( &bsi->bsi_join_where,
1432 bsi->bsi_op->o_tmpmemctx,
1434 (ber_len_t)STRLENOF( "ldap_entries.parent=?" ),
1435 "ldap_entries.parent=?" );
1438 #ifdef LDAP_SCOPE_SUBORDINATE
1439 case LDAP_SCOPE_SUBORDINATE:
1440 #endif /* LDAP_SCOPE_SUBORDINATE */
1441 case LDAP_SCOPE_SUBTREE:
1442 if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) {
1444 BackendDB *bd = bsi->bsi_op->o_bd;
1446 assert( bd->be_nsuffix != NULL );
1448 for ( i = 0; !BER_BVISNULL( &bd->be_nsuffix[ i ] ); i++ )
1450 if ( dn_match( &bd->be_nsuffix[ i ],
1451 bsi->bsi_base_ndn ) )
1453 /* pass this to the candidate selection
1454 * routine so that the DN is not bound
1455 * to the select statement */
1456 bsi->bsi_use_subtree_shortcut = 1;
1462 if ( bsi->bsi_use_subtree_shortcut ) {
1463 /* Skip the base DN filter, as every entry will match it */
1464 backsql_strfcat_x( &bsi->bsi_join_where,
1465 bsi->bsi_op->o_tmpmemctx,
1467 (ber_len_t)STRLENOF( "9=9"), "9=9");
1469 } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
1470 backsql_strfcat_x( &bsi->bsi_join_where,
1471 bsi->bsi_op->o_tmpmemctx,
1473 &bi->sql_subtree_cond );
1475 } else if ( BACKSQL_CANUPPERCASE( bi ) ) {
1476 backsql_strfcat_x( &bsi->bsi_join_where,
1477 bsi->bsi_op->o_tmpmemctx,
1479 &bi->sql_upper_func,
1480 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1481 "(ldap_entries.dn) LIKE ?" );
1484 backsql_strfcat_x( &bsi->bsi_join_where,
1485 bsi->bsi_op->o_tmpmemctx,
1487 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1488 "ldap_entries.dn LIKE ?" );
1497 rc = backsql_process_filter( bsi, bsi->bsi_filter );
1499 struct berbuf bb = BB_NULL;
1501 backsql_strfcat_x( &bb,
1502 bsi->bsi_op->o_tmpmemctx,
1504 &bsi->bsi_sel.bb_val,
1505 &bsi->bsi_from.bb_val,
1506 &bsi->bsi_join_where.bb_val,
1507 (ber_len_t)STRLENOF( " AND " ), " AND ",
1508 &bsi->bsi_flt_where.bb_val );
1512 } else if ( rc < 0 ) {
1514 * Indicates that there's no possible way the filter matches
1515 * anything. No need to issue the query
1517 free( query->bv_val );
1518 BER_BVZERO( query );
1521 free( bsi->bsi_sel.bb_val.bv_val );
1522 BER_BVZERO( &bsi->bsi_sel.bb_val );
1523 bsi->bsi_sel.bb_len = 0;
1524 free( bsi->bsi_from.bb_val.bv_val );
1525 BER_BVZERO( &bsi->bsi_from.bb_val );
1526 bsi->bsi_from.bb_len = 0;
1527 free( bsi->bsi_join_where.bb_val.bv_val );
1528 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1529 bsi->bsi_join_where.bb_len = 0;
1530 free( bsi->bsi_flt_where.bb_val.bv_val );
1531 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1532 bsi->bsi_flt_where.bb_len = 0;
1534 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n",
1535 query->bv_val ? query->bv_val : "NULL", 0, 0 );
1537 return ( rc <= 0 ? 1 : 0 );
1541 backsql_oc_get_candidates( void *v_oc, void *v_bsi )
1543 backsql_oc_map_rec *oc = v_oc;
1544 backsql_srch_info *bsi = v_bsi;
1545 Operation *op = bsi->bsi_op;
1546 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1547 struct berval query;
1548 SQLHSTMT sth = SQL_NULL_HSTMT;
1551 BACKSQL_ROW_NTS row;
1554 int n_candidates = bsi->bsi_n_candidates;
1557 * + 1 because we need room for '%';
1558 * + 1 because we need room for ',' for LDAP_SCOPE_SUBORDINATE;
1559 * this makes a subtree
1560 * search for a DN BACKSQL_MAX_DN_LEN long legal
1561 * if it returns that DN only
1563 char tmp_base_ndn[ BACKSQL_MAX_DN_LEN + 1 + 1 ];
1565 bsi->bsi_status = LDAP_SUCCESS;
1567 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n",
1568 BACKSQL_OC_NAME( oc ), 0, 0 );
1570 /* check for abandon */
1571 if ( op->o_abandon ) {
1572 bsi->bsi_status = SLAPD_ABANDON;
1573 return BACKSQL_AVL_STOP;
1576 if ( bsi->bsi_n_candidates == -1 ) {
1577 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1578 "unchecked limit has been overcome\n", 0, 0, 0 );
1579 /* should never get here */
1581 bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED;
1582 return BACKSQL_AVL_STOP;
1586 res = backsql_srch_query( bsi, &query );
1588 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1589 "error while constructing query for objectclass \"%s\"\n",
1590 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1592 * FIXME: need to separate errors from legally
1593 * impossible filters
1595 switch ( bsi->bsi_status ) {
1597 case LDAP_UNDEFINED_TYPE:
1598 case LDAP_NO_SUCH_OBJECT:
1599 /* we are conservative... */
1601 bsi->bsi_status = LDAP_SUCCESS;
1603 return BACKSQL_AVL_CONTINUE;
1605 case LDAP_ADMINLIMIT_EXCEEDED:
1607 /* don't try any more */
1608 return BACKSQL_AVL_STOP;
1612 if ( BER_BVISNULL( &query ) ) {
1613 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1614 "could not construct query for objectclass \"%s\"\n",
1615 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1616 bsi->bsi_status = LDAP_SUCCESS;
1617 return BACKSQL_AVL_CONTINUE;
1620 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n",
1621 query.bv_val, 0, 0 );
1623 rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 );
1624 free( query.bv_val );
1625 BER_BVZERO( &query );
1626 if ( rc != SQL_SUCCESS ) {
1627 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1628 "error preparing query\n", 0, 0, 0 );
1629 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1630 bsi->bsi_status = LDAP_OTHER;
1631 return BACKSQL_AVL_CONTINUE;
1634 Debug( LDAP_DEBUG_TRACE, "id: '%ld'\n", bsi->bsi_oc->bom_id, 0, 0 );
1636 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_INPUT,
1637 &bsi->bsi_oc->bom_id );
1638 if ( rc != SQL_SUCCESS ) {
1639 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1640 "error binding objectclass id parameter\n", 0, 0, 0 );
1641 bsi->bsi_status = LDAP_OTHER;
1642 return BACKSQL_AVL_CONTINUE;
1645 switch ( bsi->bsi_scope ) {
1646 case LDAP_SCOPE_BASE:
1647 case BACKSQL_SCOPE_BASE_LIKE:
1649 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1650 * however this should be handled earlier
1652 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1653 bsi->bsi_status = LDAP_OTHER;
1654 return BACKSQL_AVL_CONTINUE;
1657 AC_MEMCPY( tmp_base_ndn, bsi->bsi_base_ndn->bv_val,
1658 bsi->bsi_base_ndn->bv_len + 1 );
1660 /* uppercase DN only if the stored DN can be uppercased
1662 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1663 ldap_pvt_str2upper( tmp_base_ndn );
1666 Debug( LDAP_DEBUG_TRACE, "(base)dn: \"%s\"\n",
1667 tmp_base_ndn, 0, 0 );
1669 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1670 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1671 if ( rc != SQL_SUCCESS ) {
1672 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1673 "error binding base_ndn parameter\n", 0, 0, 0 );
1674 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1676 bsi->bsi_status = LDAP_OTHER;
1677 return BACKSQL_AVL_CONTINUE;
1681 #ifdef LDAP_SCOPE_SUBORDINATE
1682 case LDAP_SCOPE_SUBORDINATE:
1683 #endif /* LDAP_SCOPE_SUBORDINATE */
1684 case LDAP_SCOPE_SUBTREE:
1686 /* if short-cutting the search base,
1687 * don't bind any parameter */
1688 if ( bsi->bsi_use_subtree_shortcut ) {
1693 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1694 * however this should be handled earlier
1696 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1697 bsi->bsi_status = LDAP_OTHER;
1698 return BACKSQL_AVL_CONTINUE;
1702 * Sets the parameters for the SQL built earlier
1703 * NOTE that all the databases could actually use
1704 * the TimesTen version, which would be cleaner
1705 * and would also eliminate the need for the
1706 * subtree_cond line in the configuration file.
1707 * For now, I'm leaving it the way it is,
1708 * so non-TimesTen databases use the original code.
1709 * But at some point this should get cleaned up.
1711 * If "dn" is being used, do a suffix search.
1712 * If "dn_ru" is being used, do a prefix search.
1714 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
1715 tmp_base_ndn[ 0 ] = '\0';
1717 for ( i = 0, j = bsi->bsi_base_ndn->bv_len - 1;
1719 tmp_base_ndn[ i ] = bsi->bsi_base_ndn->bv_val[ j ];
1722 #ifdef LDAP_SCOPE_SUBORDINATE
1723 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1724 tmp_base_ndn[ i++ ] = ',';
1726 #endif /* LDAP_SCOPE_SUBORDINATE */
1728 tmp_base_ndn[ i ] = '%';
1729 tmp_base_ndn[ i + 1 ] = '\0';
1734 tmp_base_ndn[ i++ ] = '%';
1736 #ifdef LDAP_SCOPE_SUBORDINATE
1737 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1738 tmp_base_ndn[ i++ ] = ',';
1740 #endif /* LDAP_SCOPE_SUBORDINATE */
1742 AC_MEMCPY( &tmp_base_ndn[ i ], bsi->bsi_base_ndn->bv_val,
1743 bsi->bsi_base_ndn->bv_len + 1 );
1746 /* uppercase DN only if the stored DN can be uppercased
1748 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1749 ldap_pvt_str2upper( tmp_base_ndn );
1752 #ifdef LDAP_SCOPE_SUBORDINATE
1753 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1754 Debug( LDAP_DEBUG_TRACE, "(children)dn: \"%s\"\n",
1755 tmp_base_ndn, 0, 0 );
1757 #endif /* LDAP_SCOPE_SUBORDINATE */
1759 Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n",
1760 tmp_base_ndn, 0, 0 );
1763 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1764 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1765 if ( rc != SQL_SUCCESS ) {
1766 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1767 "error binding base_ndn parameter (2)\n",
1769 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1771 bsi->bsi_status = LDAP_OTHER;
1772 return BACKSQL_AVL_CONTINUE;
1777 case LDAP_SCOPE_ONELEVEL:
1778 assert( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) );
1780 #ifdef BACKSQL_ARBITRARY_KEY
1781 Debug( LDAP_DEBUG_TRACE, "(one)id: \"%s\"\n",
1782 bsi->bsi_base_id.eid_id.bv_val, 0, 0 );
1783 #else /* ! BACKSQL_ARBITRARY_KEY */
1784 Debug( LDAP_DEBUG_TRACE, "(one)id: '%lu'\n",
1785 bsi->bsi_base_id.eid_id, 0, 0 );
1786 #endif /* ! BACKSQL_ARBITRARY_KEY */
1787 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT,
1788 &bsi->bsi_base_id.eid_id );
1789 if ( rc != SQL_SUCCESS ) {
1790 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1791 "error binding base id parameter\n", 0, 0, 0 );
1792 bsi->bsi_status = LDAP_OTHER;
1793 return BACKSQL_AVL_CONTINUE;
1798 rc = SQLExecute( sth );
1799 if ( !BACKSQL_SUCCESS( rc ) ) {
1800 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1801 "error executing query\n", 0, 0, 0 );
1802 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1803 SQLFreeStmt( sth, SQL_DROP );
1804 bsi->bsi_status = LDAP_OTHER;
1805 return BACKSQL_AVL_CONTINUE;
1808 backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx );
1809 rc = SQLFetch( sth );
1810 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
1811 struct berval dn, pdn, ndn;
1812 backsql_entryID *c_id = NULL;
1815 ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
1817 if ( backsql_api_odbc2dn( bsi->bsi_op, bsi->bsi_rs, &dn ) ) {
1821 ret = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
1822 if ( dn.bv_val != row.cols[ 3 ] ) {
1826 if ( ret != LDAP_SUCCESS ) {
1830 if ( bi->sql_baseObject && dn_match( &ndn, &bi->sql_baseObject->e_nname ) ) {
1831 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
1832 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
1836 c_id = (backsql_entryID *)ch_calloc( 1,
1837 sizeof( backsql_entryID ) );
1838 #ifdef BACKSQL_ARBITRARY_KEY
1839 ber_str2bv_x( row.cols[ 0 ], 0, 1, &c_id->eid_id,
1841 ber_str2bv_x( row.cols[ 1 ], 0, 1, &c_id->eid_keyval,
1843 #else /* ! BACKSQL_ARBITRARY_KEY */
1844 c_id->eid_id = strtol( row.cols[ 0 ], NULL, 0 );
1845 c_id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 );
1846 #endif /* ! BACKSQL_ARBITRARY_KEY */
1847 c_id->eid_oc_id = bsi->bsi_oc->bom_id;
1850 c_id->eid_ndn = ndn;
1852 /* append at end of list ... */
1853 c_id->eid_next = NULL;
1854 *bsi->bsi_id_listtail = c_id;
1855 bsi->bsi_id_listtail = &c_id->eid_next;
1857 #ifdef BACKSQL_ARBITRARY_KEY
1858 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1859 "added entry id=%s, keyval=%s dn=\"%s\"\n",
1860 c_id->eid_id.bv_val, c_id->eid_keyval.bv_val,
1862 #else /* ! BACKSQL_ARBITRARY_KEY */
1863 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1864 "added entry id=%ld, keyval=%ld dn=\"%s\"\n",
1865 c_id->eid_id, c_id->eid_keyval, row.cols[ 3 ] );
1866 #endif /* ! BACKSQL_ARBITRARY_KEY */
1868 /* count candidates, for unchecked limit */
1869 bsi->bsi_n_candidates--;
1870 if ( bsi->bsi_n_candidates == -1 ) {
1874 backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );
1875 SQLFreeStmt( sth, SQL_DROP );
1877 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n",
1878 n_candidates - bsi->bsi_n_candidates, 0, 0 );
1880 return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE );
1884 backsql_search( Operation *op, SlapReply *rs )
1886 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
1887 SQLHDBC dbh = SQL_NULL_HDBC;
1889 Entry user_entry = { 0 },
1891 int manageDSAit = get_manageDSAit( op );
1892 time_t stoptime = 0;
1893 backsql_srch_info bsi = { 0 };
1894 backsql_entryID *eid = NULL;
1895 struct berval nbase = BER_BVNULL;
1897 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): "
1898 "base=\"%s\", filter=\"%s\", scope=%d,",
1899 op->o_req_ndn.bv_val,
1900 op->ors_filterstr.bv_val ? op->ors_filterstr.bv_val : "(no filter)",
1902 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, "
1903 "attributes to load: %s\n",
1906 op->ors_attrs == NULL ? "all" : "custom list" );
1908 if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) {
1909 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1910 "search base length (%ld) exceeds max length (%d)\n",
1911 op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN, 0 );
1913 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
1914 * since it is impossible that such a long DN exists
1917 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
1918 send_ldap_result( op, rs );
1922 sres = backsql_get_db_conn( op, &dbh );
1923 if ( sres != LDAP_SUCCESS ) {
1924 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1925 "could not get connection handle - exiting\n",
1928 rs->sr_text = sres == LDAP_OTHER ? "SQL-backend error" : NULL;
1929 send_ldap_result( op, rs );
1933 /* compute it anyway; root does not use it */
1934 stoptime = op->o_time + op->ors_tlimit;
1937 bsi.bsi_e = &base_entry;
1938 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
1940 stoptime, op->ors_filter,
1941 dbh, op, rs, op->ors_attrs,
1942 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
1943 switch ( rs->sr_err ) {
1948 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
1949 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
1951 rs->sr_err = LDAP_SUCCESS;
1953 rs->sr_matched = NULL;
1955 ber_bvarray_free( rs->sr_ref );
1961 /* an entry was created; free it */
1962 entry_clean( bsi.bsi_e );
1967 #ifdef SLAP_ACL_HONOR_DISCLOSE
1968 if ( !BER_BVISNULL( &base_entry.e_nname )
1969 && ! access_allowed( op, &base_entry,
1970 slap_schema.si_ad_entry, NULL,
1971 ACL_DISCLOSE, NULL ) )
1973 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1975 ber_bvarray_free( rs->sr_ref );
1978 rs->sr_matched = NULL;
1981 #endif /* SLAP_ACL_HONOR_DISCLOSE */
1983 send_ldap_result( op, rs );
1986 ber_bvarray_free( rs->sr_ref );
1992 #ifdef SLAP_ACL_HONOR_DISCLOSE
1993 /* NOTE: __NEW__ "search" access is required
1994 * on searchBase object */
1998 if ( get_assert( op ) &&
1999 ( test_filter( op, &base_entry, get_assertion( op ) )
2000 != LDAP_COMPARE_TRUE ) )
2002 rs->sr_err = LDAP_ASSERTION_FAILED;
2005 if ( ! access_allowed_mask( op, &base_entry,
2006 slap_schema.si_ad_entry,
2007 NULL, ACL_SEARCH, NULL, &mask ) )
2009 if ( rs->sr_err == LDAP_SUCCESS ) {
2010 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
2014 if ( rs->sr_err != LDAP_SUCCESS ) {
2015 if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
2016 rs->sr_err = LDAP_NO_SUCH_OBJECT;
2019 send_ldap_result( op, rs );
2023 #endif /* SLAP_ACL_HONOR_DISCLOSE */
2027 bsi.bsi_n_candidates =
2028 ( op->ors_limit == NULL /* isroot == TRUE */ ? -2 :
2029 ( op->ors_limit->lms_s_unchecked == -1 ? -2 :
2030 ( op->ors_limit->lms_s_unchecked ) ) );
2032 switch ( bsi.bsi_scope ) {
2033 case LDAP_SCOPE_BASE:
2034 case BACKSQL_SCOPE_BASE_LIKE:
2036 * probably already found...
2038 bsi.bsi_id_list = &bsi.bsi_base_id;
2039 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
2042 case LDAP_SCOPE_SUBTREE:
2044 * if baseObject is defined, and if it is the root
2045 * of the search, add it to the candidate list
2047 if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &bsi.bsi_base_id.eid_id ) )
2049 bsi.bsi_id_list = &bsi.bsi_base_id;
2050 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
2057 * for each objectclass we try to construct query which gets IDs
2058 * of entries matching LDAP query filter and scope (or at least
2059 * candidates), and get the IDs
2061 avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates,
2062 &bsi, BACKSQL_AVL_STOP, AVL_INORDER );
2064 /* check for abandon */
2065 if ( op->o_abandon ) {
2066 eid = bsi.bsi_id_list;
2067 rs->sr_err = SLAPD_ABANDON;
2072 if ( op->ors_limit != NULL /* isroot == FALSE */
2073 && op->ors_limit->lms_s_unchecked != -1
2074 && bsi.bsi_n_candidates == -1 )
2076 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
2077 send_ldap_result( op, rs );
2082 * now we load candidate entries (only those attributes
2083 * mentioned in attrs and filter), test it against full filter
2084 * and then send to client; don't free entry_id if baseObject...
2086 for ( eid = bsi.bsi_id_list;
2088 eid = backsql_free_entryID( op,
2089 eid, eid == &bsi.bsi_base_id ? 0 : 1 ) )
2092 Attribute *a_hasSubordinate = NULL,
2093 *a_entryUUID = NULL,
2098 /* check for abandon */
2099 if ( op->o_abandon ) {
2100 rs->sr_err = SLAPD_ABANDON;
2104 /* check time limit */
2105 if ( op->ors_tlimit != SLAP_NO_LIMIT
2106 && slap_get_time() > stoptime )
2108 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
2109 rs->sr_ctrls = NULL;
2110 rs->sr_ref = rs->sr_v2ref;
2114 #ifdef BACKSQL_ARBITRARY_KEY
2115 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
2116 "for entry id=%s, oc_id=%ld, keyval=%s\n",
2117 eid->eid_id.bv_val, eid->eid_oc_id,
2118 eid->eid_keyval.bv_val );
2119 #else /* ! BACKSQL_ARBITRARY_KEY */
2120 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
2121 "for entry id=%ld, oc_id=%ld, keyval=%ld\n",
2122 eid->eid_id, eid->eid_oc_id, eid->eid_keyval );
2123 #endif /* ! BACKSQL_ARBITRARY_KEY */
2126 switch ( op->ors_scope ) {
2127 case LDAP_SCOPE_BASE:
2128 case BACKSQL_SCOPE_BASE_LIKE:
2129 if ( !dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
2134 case LDAP_SCOPE_ONE:
2136 struct berval rdn = eid->eid_ndn;
2138 rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
2139 if ( !dnIsOneLevelRDN( &rdn ) ) {
2145 #ifdef LDAP_SCOPE_SUBORDINATE
2146 case LDAP_SCOPE_SUBORDINATE:
2147 /* discard the baseObject entry */
2148 if ( dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
2152 #endif /* LDAP_SCOPE_SUBORDINATE */
2154 case LDAP_SCOPE_SUBTREE:
2155 /* FIXME: this should never fail... */
2156 if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) {
2163 if ( BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
2164 /* don't recollect baseObject... */
2165 e = bi->sql_baseObject;
2167 } else if ( eid == &bsi.bsi_base_id ) {
2168 /* don't recollect searchBase object... */
2172 bsi.bsi_e = &user_entry;
2173 rc = backsql_id2entry( &bsi, eid );
2174 if ( rc != LDAP_SUCCESS ) {
2175 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2176 "error %d in backsql_id2entry() "
2177 "- skipping\n", rc, 0, 0 );
2183 if ( !manageDSAit &&
2184 op->ors_scope != LDAP_SCOPE_BASE &&
2185 op->ors_scope != BACKSQL_SCOPE_BASE_LIKE &&
2186 is_entry_referral( e ) )
2190 refs = get_entry_referrals( op, e );
2192 backsql_srch_info bsi2 = { 0 };
2193 Entry user_entry2 = { 0 };
2195 /* retry with the full entry... */
2196 bsi2.bsi_e = &user_entry2;
2197 rc = backsql_init_search( &bsi2,
2202 BACKSQL_ISF_GET_ENTRY );
2203 if ( rc == LDAP_SUCCESS ) {
2204 if ( is_entry_referral( &user_entry2 ) )
2206 refs = get_entry_referrals( op,
2209 rs->sr_err = LDAP_OTHER;
2211 backsql_entry_clean( op, &user_entry2 );
2213 if ( bsi2.bsi_attrs != NULL ) {
2214 op->o_tmpfree( bsi2.bsi_attrs,
2220 rs->sr_ref = referral_rewrite( refs,
2224 ber_bvarray_free( refs );
2228 rs->sr_err = LDAP_REFERRAL;
2231 rs->sr_text = "bad referral object";
2235 rs->sr_matched = user_entry.e_name.bv_val;
2236 send_search_reference( op, rs );
2238 ber_bvarray_free( rs->sr_ref );
2240 rs->sr_matched = NULL;
2241 rs->sr_entry = NULL;
2247 * We use this flag since we need to parse the filter
2248 * anyway; we should have used the frontend API function
2249 * filter_has_subordinates()
2251 if ( bsi.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
2252 rc = backsql_has_children( op, dbh, &e->e_nname );
2255 case LDAP_COMPARE_TRUE:
2256 case LDAP_COMPARE_FALSE:
2257 a_hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
2258 if ( a_hasSubordinate != NULL ) {
2259 for ( ap = &user_entry.e_attrs;
2261 ap = &(*ap)->a_next );
2263 *ap = a_hasSubordinate;
2269 Debug(LDAP_DEBUG_TRACE,
2270 "backsql_search(): "
2271 "has_children failed( %d)\n",
2278 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYUUID ) {
2279 a_entryUUID = backsql_operational_entryUUID( bi, eid );
2280 if ( a_entryUUID != NULL ) {
2282 ap = &user_entry.e_attrs;
2285 for ( ; *ap; ap = &(*ap)->a_next );
2291 #ifdef BACKSQL_SYNCPROV
2292 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYCSN ) {
2293 a_entryCSN = backsql_operational_entryCSN( op );
2294 if ( a_entryCSN != NULL ) {
2296 ap = &user_entry.e_attrs;
2299 for ( ; *ap; ap = &(*ap)->a_next );
2304 #endif /* BACKSQL_SYNCPROV */
2306 if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE )
2308 rs->sr_attrs = op->ors_attrs;
2309 rs->sr_operational_attrs = NULL;
2311 if ( e == &user_entry ) {
2312 rs->sr_flags = REP_ENTRY_MODIFIABLE;
2314 /* FIXME: need the whole entry (ITS#3480) */
2315 sres = send_search_entry( op, rs );
2316 rs->sr_entry = NULL;
2317 rs->sr_attrs = NULL;
2318 rs->sr_operational_attrs = NULL;
2322 * FIXME: send_search_entry failed;
2325 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2326 "connection lost\n", 0, 0, 0 );
2332 if ( e == &user_entry ) {
2333 backsql_entry_clean( op, &user_entry );
2337 if ( --op->ors_slimit == -1 ) {
2338 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
2344 if ( rs->sr_nentries > 0 ) {
2345 rs->sr_ref = rs->sr_v2ref;
2346 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
2350 rs->sr_err = bsi.bsi_status;
2354 if ( rs->sr_err != SLAPD_ABANDON ) {
2355 send_ldap_result( op, rs );
2358 /* cleanup in case of abandon */
2359 for ( ; eid != NULL;
2360 eid = backsql_free_entryID( op,
2361 eid, eid == &bsi.bsi_base_id ? 0 : 1 ) )
2364 backsql_entry_clean( op, &base_entry );
2366 /* in case we got here accidentally */
2367 backsql_entry_clean( op, &user_entry );
2369 if ( rs->sr_v2ref ) {
2370 ber_bvarray_free( rs->sr_v2ref );
2371 rs->sr_v2ref = NULL;
2374 #ifdef BACKSQL_SYNCPROV
2376 Operation op2 = *op;
2377 SlapReply rs2 = { 0 };
2379 slap_callback cb = { 0 };
2381 op2.o_tag = LDAP_REQ_ADD;
2382 op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0, 0 );
2384 op2.o_callback = &cb;
2386 e.e_name = op->o_bd->be_suffix[0];
2387 e.e_nname = op->o_bd->be_nsuffix[0];
2389 cb.sc_response = slap_null_cb;
2391 op2.o_bd->be_add( &op2, &rs2 );
2393 #endif /* BACKSQL_SYNCPROV */
2396 (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
2398 if ( bsi.bsi_attrs != NULL ) {
2399 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2402 if ( !BER_BVISNULL( &nbase )
2403 && nbase.bv_val != op->o_req_ndn.bv_val )
2405 ch_free( nbase.bv_val );
2408 /* restore scope ... FIXME: this should be done before ANY
2409 * frontend call that uses op */
2410 if ( op->ors_scope == BACKSQL_SCOPE_BASE_LIKE ) {
2411 op->ors_scope = LDAP_SCOPE_BASE;
2414 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
2419 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
2426 AttributeDescription *at,
2430 backsql_srch_info bsi = { 0 };
2431 SQLHDBC dbh = SQL_NULL_HDBC;
2433 SlapReply rs = { 0 };
2434 AttributeName anlist[ 2 ];
2438 rc = backsql_get_db_conn( op, &dbh );
2444 anlist[ 0 ].an_name = at->ad_cname;
2445 anlist[ 0 ].an_desc = at;
2446 BER_BVZERO( &anlist[ 1 ].an_name );
2449 bsi.bsi_e = ch_malloc( sizeof( Entry ) );
2450 rc = backsql_init_search( &bsi,
2454 dbh, op, &rs, at ? anlist : NULL,
2455 BACKSQL_ISF_GET_ENTRY );
2457 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) {
2458 (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
2461 if ( rc == LDAP_SUCCESS ) {
2463 #if 0 /* not supported at present */
2464 /* find attribute values */
2465 if ( is_entry_alias( bsi.bsi_e ) ) {
2466 Debug( LDAP_DEBUG_ACL,
2467 "<= backsql_entry_get: entry is an alias\n",
2469 rc = LDAP_ALIAS_PROBLEM;
2470 goto return_results;
2474 if ( is_entry_referral( bsi.bsi_e ) ) {
2475 Debug( LDAP_DEBUG_ACL,
2476 "<= backsql_entry_get: entry is a referral\n",
2479 goto return_results;
2482 if ( oc && !is_entry_objectclass( bsi.bsi_e, oc, 0 ) ) {
2483 Debug( LDAP_DEBUG_ACL,
2484 "<= backsql_entry_get: "
2485 "failed to find objectClass\n",
2487 rc = LDAP_NO_SUCH_ATTRIBUTE;
2488 goto return_results;
2495 if ( bsi.bsi_attrs != NULL ) {
2496 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2499 if ( rc != LDAP_SUCCESS ) {
2501 entry_free( bsi.bsi_e );
2509 backsql_entry_clean(
2515 ctx = ldap_pvt_thread_pool_context();
2517 if ( ctx == NULL || ctx != op->o_tmpmemctx ) {
2518 if ( !BER_BVISNULL( &e->e_name ) ) {
2519 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx );
2520 BER_BVZERO( &e->e_name );
2523 if ( !BER_BVISNULL( &e->e_nname ) ) {
2524 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx );
2525 BER_BVZERO( &e->e_nname );
2533 backsql_entry_release(
2538 backsql_entry_clean( op, e );