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( &bsi->bsi_flt_where, "c", '(' /* ) */ );
351 res = backsql_process_filter( bsi, f );
354 * TimesTen : If the query has no answers,
355 * don't bother to run the query.
366 case LDAP_FILTER_AND:
367 backsql_strfcat( &bsi->bsi_flt_where, "l",
368 (ber_len_t)STRLENOF( " AND " ),
373 backsql_strfcat( &bsi->bsi_flt_where, "l",
374 (ber_len_t)STRLENOF( " OR " ),
380 backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' );
386 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
387 backsql_at_map_rec *at )
389 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
397 /* always uppercase strings by now */
398 #ifdef BACKSQL_UPPERCASE_FILTER
399 if ( f->f_sub_desc->ad_type->sat_substr &&
400 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
401 bi->sql_caseIgnoreMatch ) )
402 #endif /* BACKSQL_UPPERCASE_FILTER */
407 if ( f->f_sub_desc->ad_type->sat_substr &&
408 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
409 bi->sql_telephoneNumberMatch ) )
416 * to check for matching telephone numbers
417 * with intermixed chars, e.g. val='1234'
420 * val LIKE '%1%2%3%4%'
424 if ( f->f_sub_initial.bv_val ) {
425 bv.bv_len += f->f_sub_initial.bv_len;
427 if ( f->f_sub_any != NULL ) {
428 for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) {
429 bv.bv_len += f->f_sub_any[ a ].bv_len;
432 if ( f->f_sub_final.bv_val ) {
433 bv.bv_len += f->f_sub_final.bv_len;
435 bv.bv_len = 2 * bv.bv_len - 1;
436 bv.bv_val = ch_malloc( bv.bv_len + 1 );
439 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
440 bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ];
441 for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) {
442 bv.bv_val[ s + 2 * i - 1 ] = '%';
443 bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ];
445 bv.bv_val[ s + 2 * i - 1 ] = '%';
449 if ( f->f_sub_any != NULL ) {
450 for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
451 bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ];
452 for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) {
453 bv.bv_val[ s + 2 * i - 1 ] = '%';
454 bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ];
456 bv.bv_val[ s + 2 * i - 1 ] = '%';
461 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
462 bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ];
463 for ( i = 1; i < f->f_sub_final.bv_len; i++ ) {
464 bv.bv_val[ s + 2 * i - 1 ] = '%';
465 bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ];
467 bv.bv_val[ s + 2 * i - 1 ] = '%';
471 bv.bv_val[ s - 1 ] = '\0';
473 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
474 ch_free( bv.bv_val );
480 * When dealing with case-sensitive strings
481 * we may omit normalization; however, normalized
482 * SQL filters are more liberal.
485 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' /* ) */ );
488 Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n",
489 at->bam_ad->ad_cname.bv_val, 0, 0 );
490 Debug(LDAP_DEBUG_TRACE, " expr: '%s%s%s'\n", at->bam_sel_expr.bv_val,
491 at->bam_sel_expr_u.bv_val ? "' '" : "",
492 at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" );
493 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
495 * If a pre-upper-cased version of the column
496 * or a precompiled upper function exists, use it
498 backsql_strfcat( &bsi->bsi_flt_where,
501 (ber_len_t)STRLENOF( " LIKE '" ),
505 backsql_strfcat( &bsi->bsi_flt_where, "bl",
507 (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
510 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
514 Debug( LDAP_DEBUG_TRACE,
515 "==>backsql_process_sub_filter(%s): "
516 "sub_initial=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
517 f->f_sub_initial.bv_val, 0 );
518 #endif /* BACKSQL_TRACE */
520 start = bsi->bsi_flt_where.bb_val.bv_len;
521 backsql_strfcat( &bsi->bsi_flt_where, "b",
523 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
524 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
528 backsql_strfcat( &bsi->bsi_flt_where, "c", '%' );
530 if ( f->f_sub_any != NULL ) {
531 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) {
535 Debug( LDAP_DEBUG_TRACE,
536 "==>backsql_process_sub_filter(%s): "
537 "sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
538 i, f->f_sub_any[ i ].bv_val );
539 #endif /* BACKSQL_TRACE */
541 start = bsi->bsi_flt_where.bb_val.bv_len;
542 backsql_strfcat( &bsi->bsi_flt_where,
546 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
548 * Note: toupper('%') = '%'
550 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
555 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
559 Debug( LDAP_DEBUG_TRACE,
560 "==>backsql_process_sub_filter(%s): "
561 "sub_final=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
562 f->f_sub_final.bv_val, 0 );
563 #endif /* BACKSQL_TRACE */
565 start = bsi->bsi_flt_where.bb_val.bv_len;
566 backsql_strfcat( &bsi->bsi_flt_where, "b",
568 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
569 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
573 backsql_strfcat( &bsi->bsi_flt_where, "l",
574 (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" );
580 backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls )
582 if ( BER_BVISNULL( from_tbls ) ) {
586 if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) {
587 char *start, *end, *tmp;
589 tmp = ch_strdup( from_tbls->bv_val );
591 for ( start = tmp, end = strchr( start, ',' ); start; ) {
596 if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL )
598 backsql_strfcat( &bsi->bsi_from, "cs", ',', start );
602 /* in case there are spaces after the comma... */
603 for ( start = &end[1]; isspace( start[0] ); start++ );
605 end = strchr( start, ',' );
617 backsql_strfcat( &bsi->bsi_from, "b", from_tbls );
624 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
626 backsql_at_map_rec **vat = NULL;
627 AttributeDescription *ad = NULL;
632 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 );
633 if ( f->f_choice == SLAPD_FILTER_COMPUTED ) {
634 Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
635 "invalid filter\n", 0, 0, 0 );
640 switch( f->f_choice ) {
642 rc = backsql_process_filter_list( bsi, f->f_or,
647 case LDAP_FILTER_AND:
648 rc = backsql_process_filter_list( bsi, f->f_and,
653 case LDAP_FILTER_NOT:
654 backsql_strfcat( &bsi->bsi_flt_where, "l",
655 (ber_len_t)STRLENOF( "NOT (" /* ) */ ),
657 rc = backsql_process_filter( bsi, f->f_not );
658 backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' );
662 case LDAP_FILTER_PRESENT:
666 case LDAP_FILTER_EXT:
667 ad = f->f_mra->ma_desc;
668 if ( f->f_mr_dnattrs ) {
670 * if dn attrs filtering is requested, better return
671 * success and let test_filter() deal with candidate
672 * selection; otherwise we'd need to set conditions
673 * on the contents of the DN, e.g. "SELECT ... FROM
674 * ldap_entries AS attributeName WHERE attributeName.dn
675 * like '%attributeName=value%'"
677 backsql_strfcat( &bsi->bsi_flt_where, "l",
678 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
679 bsi->bsi_status = LDAP_SUCCESS;
700 * Turn structuralObjectClass into objectClass
702 if ( ad == slap_schema.si_ad_objectClass
703 || ad == slap_schema.si_ad_structuralObjectClass )
706 * If the filter is LDAP_FILTER_PRESENT, then it's done;
707 * otherwise, let's see if we are lucky: filtering
708 * for "structural" objectclass or ancestor...
710 switch ( f->f_choice ) {
711 case LDAP_FILTER_EQUALITY:
713 ObjectClass *oc = oc_bvfind( &f->f_av_value );
716 Debug( LDAP_DEBUG_TRACE,
717 "backsql_process_filter(): "
718 "unknown objectClass \"%s\" "
720 f->f_av_value.bv_val, 0, 0 );
721 bsi->bsi_status = LDAP_OTHER;
727 * "structural" objectClass inheritance:
728 * - a search for "person" will also return
730 * - a search for "top" will return everything
732 if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
733 static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" );
735 backsql_merge_from_tbls( bsi, &ldap_entry_objclasses );
737 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
738 (ber_len_t)STRLENOF( "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */ ),
739 "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */,
740 &bsi->bsi_oc->bom_oc->soc_cname,
741 (ber_len_t)STRLENOF( /* ((' */ "'))" ),
743 bsi->bsi_status = LDAP_SUCCESS;
751 case LDAP_FILTER_PRESENT:
752 backsql_strfcat( &bsi->bsi_flt_where, "l",
753 (ber_len_t)STRLENOF( "3=3" ), "3=3" );
754 bsi->bsi_status = LDAP_SUCCESS;
758 /* FIXME: LDAP_FILTER_EXT? */
761 Debug( LDAP_DEBUG_TRACE,
762 "backsql_process_filter(): "
763 "illegal/unhandled filter "
764 "on objectClass attribute",
766 bsi->bsi_status = LDAP_OTHER;
771 } else if ( ad == slap_schema.si_ad_entryUUID ) {
773 #ifdef BACKSQL_ARBITRARY_KEY
774 struct berval keyval;
775 #else /* ! BACKSQL_ARBITRARY_KEY */
776 unsigned long keyval;
777 char keyvalbuf[] = "18446744073709551615";
778 #endif /* ! BACKSQL_ARBITRARY_KEY */
780 switch ( f->f_choice ) {
781 case LDAP_FILTER_EQUALITY:
782 backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval );
784 if ( oc_id != bsi->bsi_oc->bom_id ) {
785 bsi->bsi_status = LDAP_SUCCESS;
790 #ifdef BACKSQL_ARBITRARY_KEY
791 backsql_strfcat( &bsi->bsi_flt_where, "bcblbc",
792 &bsi->bsi_oc->bom_keytbl, '.',
793 &bsi->bsi_oc->bom_keycol,
794 STRLENOF( " LIKE '" ), " LIKE '",
796 #else /* ! BACKSQL_ARBITRARY_KEY */
797 snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval );
798 backsql_strfcat( &bsi->bsi_flt_where, "bcbcs",
799 &bsi->bsi_oc->bom_keytbl, '.',
800 &bsi->bsi_oc->bom_keycol, '=', keyvalbuf );
801 #endif /* ! BACKSQL_ARBITRARY_KEY */
804 case LDAP_FILTER_PRESENT:
805 backsql_strfcat( &bsi->bsi_flt_where, "l",
806 (ber_len_t)STRLENOF( "4=4" ), "4=4" );
814 bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID;
818 #ifdef BACKSQL_SYNCPROV
819 } else if ( ad == slap_schema.si_ad_entryCSN ) {
821 * support for syncrepl as producer...
823 if ( !bsi->bsi_op->o_sync ) {
824 /* unsupported at present... */
825 bsi->bsi_status = LDAP_OTHER;
830 bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID);
832 /* if doing a syncrepl, try to return as much as possible,
833 * and always match the filter */
834 backsql_strfcat( &bsi->bsi_flt_where, "l",
835 (ber_len_t)STRLENOF( "5=5" ), "5=5" );
837 /* save for later use in operational attributes */
838 /* FIXME: saves only the first occurrence, because
839 * the filter during updates is written as
840 * "(&(entryCSN<={contextCSN})(entryCSN>={oldContextCSN})({filter}))"
841 * so we want our fake entryCSN to match the greatest
844 if ( bsi->bsi_op->o_private == NULL ) {
845 bsi->bsi_op->o_private = &f->f_av_value;
847 bsi->bsi_status = LDAP_SUCCESS;
851 #endif /* BACKSQL_SYNCPROV */
853 } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
855 * FIXME: this is not robust; e.g. a filter
856 * '(!(hasSubordinates=TRUE))' fails because
857 * in SQL it would read 'NOT (1=1)' instead
859 * Note however that hasSubordinates is boolean,
860 * so a more appropriate filter would be
861 * '(hasSubordinates=FALSE)'
863 * A more robust search for hasSubordinates
864 * would * require joining the ldap_entries table
865 * selecting if there are descendants of the
868 backsql_strfcat( &bsi->bsi_flt_where, "l",
869 (ber_len_t)STRLENOF( "6=6" ), "6=6" );
870 if ( ad == slap_schema.si_ad_hasSubordinates ) {
872 * instruct candidate selection algorithm
873 * and attribute list to try to detect
874 * if an entry has subordinates
876 bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
880 * clear attributes to fetch, to require ALL
881 * and try extended match on all attributes
883 backsql_attrlist_add( bsi, NULL );
890 * attribute inheritance:
892 if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) {
893 bsi->bsi_status = LDAP_OTHER;
899 /* search anyway; other parts of the filter
901 backsql_strfcat( &bsi->bsi_flt_where, "l",
902 (ber_len_t)STRLENOF( "7=7" ), "7=7" );
903 bsi->bsi_status = LDAP_SUCCESS;
908 /* if required, open extra level of parens */
910 if ( vat[0]->bam_next || vat[1] ) {
911 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' );
918 if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) {
922 /* if more definitions of the same attr, apply */
923 if ( vat[i]->bam_next ) {
924 backsql_strfcat( &bsi->bsi_flt_where, "l",
925 STRLENOF( " OR " ), " OR " );
926 vat[i] = vat[i]->bam_next;
930 /* if more descendants of the same attr, apply */
933 backsql_strfcat( &bsi->bsi_flt_where, "l",
934 STRLENOF( " OR " ), " OR " );
938 /* if needed, close extra level of parens */
940 backsql_strfcat( &bsi->bsi_flt_where, "c", ')' );
950 Debug( LDAP_DEBUG_TRACE,
951 "<==backsql_process_filter() %s\n",
952 rc == 1 ? "succeeded" : "failed", 0, 0);
958 backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at,
959 int casefold, struct berval *filter_value )
962 * maybe we should check type of at->sel_expr here somehow,
963 * to know whether upper_func is applicable, but for now
964 * upper_func stuff is made for Oracle, where UPPER is
965 * safely applicable to NUMBER etc.
967 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
970 backsql_strfcat( &bsi->bsi_flt_where, "cbl",
973 (ber_len_t)STRLENOF( "='" ),
976 start = bsi->bsi_flt_where.bb_val.bv_len;
978 backsql_strfcat( &bsi->bsi_flt_where, "bl",
980 (ber_len_t)STRLENOF( /* (' */ "')" ),
983 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
986 backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
989 (ber_len_t)STRLENOF( "='" ), "='",
991 (ber_len_t)STRLENOF( /* (' */ "')" ),
999 backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at,
1000 int casefold, struct berval *filter_value )
1003 * maybe we should check type of at->sel_expr here somehow,
1004 * to know whether upper_func is applicable, but for now
1005 * upper_func stuff is made for Oracle, where UPPER is
1006 * safely applicable to NUMBER etc.
1008 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1011 backsql_strfcat( &bsi->bsi_flt_where, "cbl",
1013 &at->bam_sel_expr_u,
1014 (ber_len_t)STRLENOF( " LIKE '%" ),
1017 start = bsi->bsi_flt_where.bb_val.bv_len;
1019 backsql_strfcat( &bsi->bsi_flt_where, "bl",
1021 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1024 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1027 backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
1030 (ber_len_t)STRLENOF( " LIKE '%" ),
1033 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1041 backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at )
1043 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1045 struct berval *filter_value = NULL;
1046 MatchingRule *matching_rule = NULL;
1047 struct berval ordering = BER_BVC("<=");
1049 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n",
1050 at->bam_ad->ad_cname.bv_val, 0, 0 );
1053 * need to add this attribute to list of attrs to load,
1054 * so that we can do test_filter() later
1056 backsql_attrlist_add( bsi, at->bam_ad );
1058 backsql_merge_from_tbls( bsi, &at->bam_from_tbls );
1060 if ( !BER_BVISNULL( &at->bam_join_where )
1061 && strstr( bsi->bsi_join_where.bb_val.bv_val,
1062 at->bam_join_where.bv_val ) == NULL )
1064 backsql_strfcat( &bsi->bsi_join_where, "lb",
1065 (ber_len_t)STRLENOF( " AND " ), " AND ",
1066 &at->bam_join_where );
1069 switch ( f->f_choice ) {
1070 case LDAP_FILTER_EQUALITY:
1071 filter_value = &f->f_av_value;
1072 matching_rule = at->bam_ad->ad_type->sat_equality;
1074 goto equality_match;
1076 /* fail over into next case */
1078 case LDAP_FILTER_EXT:
1079 filter_value = &f->f_mra->ma_value;
1080 matching_rule = f->f_mr_rule;
1083 /* always uppercase strings by now */
1084 #ifdef BACKSQL_UPPERCASE_FILTER
1085 if ( SLAP_MR_ASSOCIATED( matching_rule,
1086 bi->sql_caseIgnoreMatch ) )
1087 #endif /* BACKSQL_UPPERCASE_FILTER */
1092 /* FIXME: directoryString filtering should use a similar
1093 * approach to deal with non-prettified values like
1094 * " A non prettified value ", by using a LIKE
1095 * filter with all whitespaces collapsed to a single '%' */
1096 if ( SLAP_MR_ASSOCIATED( matching_rule,
1097 bi->sql_telephoneNumberMatch ) )
1103 * to check for matching telephone numbers
1104 * with intermized chars, e.g. val='1234'
1107 * val LIKE '%1%2%3%4%'
1110 bv.bv_len = 2 * filter_value->bv_len - 1;
1111 bv.bv_val = ch_malloc( bv.bv_len + 1 );
1113 bv.bv_val[ 0 ] = filter_value->bv_val[ 0 ];
1114 for ( i = 1; i < filter_value->bv_len; i++ ) {
1115 bv.bv_val[ 2 * i - 1 ] = '%';
1116 bv.bv_val[ 2 * i ] = filter_value->bv_val[ i ];
1118 bv.bv_val[ 2 * i - 1 ] = '\0';
1120 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
1121 ch_free( bv.bv_val );
1126 /* NOTE: this is required by objectClass inheritance
1127 * and auxiliary objectClass use in filters for slightly
1128 * more efficient candidate selection. */
1129 /* FIXME: a bit too many specializations to deal with
1130 * very specific cases... */
1131 if ( at->bam_ad == slap_schema.si_ad_objectClass
1132 || at->bam_ad == slap_schema.si_ad_structuralObjectClass )
1134 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
1135 (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
1136 "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
1138 (ber_len_t)STRLENOF( /* (' */ "')" ),
1144 * maybe we should check type of at->sel_expr here somehow,
1145 * to know whether upper_func is applicable, but for now
1146 * upper_func stuff is made for Oracle, where UPPER is
1147 * safely applicable to NUMBER etc.
1149 (void)backsql_process_filter_eq( bsi, at, casefold, filter_value );
1152 case LDAP_FILTER_GE:
1153 ordering.bv_val = ">=";
1155 /* fall thru to next case */
1157 case LDAP_FILTER_LE:
1158 filter_value = &f->f_av_value;
1160 /* always uppercase strings by now */
1161 #ifdef BACKSQL_UPPERCASE_FILTER
1162 if ( at->bam_ad->ad_type->sat_ordering &&
1163 SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering,
1164 bi->sql_caseIgnoreMatch ) )
1165 #endif /* BACKSQL_UPPERCASE_FILTER */
1171 * FIXME: should we uppercase the operands?
1173 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1176 backsql_strfcat( &bsi->bsi_flt_where, "cbbc",
1178 &at->bam_sel_expr_u,
1182 start = bsi->bsi_flt_where.bb_val.bv_len;
1184 backsql_strfcat( &bsi->bsi_flt_where, "bl",
1186 (ber_len_t)STRLENOF( /* (' */ "')" ),
1189 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1192 backsql_strfcat( &bsi->bsi_flt_where, "cbbcbl",
1198 (ber_len_t)STRLENOF( /* (' */ "')" ),
1203 case LDAP_FILTER_PRESENT:
1204 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
1205 (ber_len_t)STRLENOF( "NOT (" /* ) */),
1208 (ber_len_t)STRLENOF( /* ( */ " IS NULL)" ),
1209 /* ( */ " IS NULL)" );
1212 case LDAP_FILTER_SUBSTRINGS:
1213 backsql_process_sub_filter( bsi, f, at );
1216 case LDAP_FILTER_APPROX:
1217 /* we do our best */
1220 * maybe we should check type of at->sel_expr here somehow,
1221 * to know whether upper_func is applicable, but for now
1222 * upper_func stuff is made for Oracle, where UPPER is
1223 * safely applicable to NUMBER etc.
1225 (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value );
1229 /* unhandled filter type; should not happen */
1231 backsql_strfcat( &bsi->bsi_flt_where, "l",
1232 (ber_len_t)STRLENOF( "8=8" ), "8=8" );
1237 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n",
1238 at->bam_ad->ad_cname.bv_val, 0, 0 );
1244 backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
1246 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1249 assert( query != NULL );
1250 BER_BVZERO( query );
1252 bsi->bsi_use_subtree_shortcut = 0;
1254 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n", 0, 0, 0 );
1255 BER_BVZERO( &bsi->bsi_sel.bb_val );
1256 BER_BVZERO( &bsi->bsi_sel.bb_val );
1257 bsi->bsi_sel.bb_len = 0;
1258 BER_BVZERO( &bsi->bsi_from.bb_val );
1259 bsi->bsi_from.bb_len = 0;
1260 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1261 bsi->bsi_join_where.bb_len = 0;
1262 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1263 bsi->bsi_flt_where.bb_len = 0;
1265 backsql_strfcat( &bsi->bsi_sel, "lbcbc",
1266 (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ),
1267 "SELECT DISTINCT ldap_entries.id,",
1268 &bsi->bsi_oc->bom_keytbl,
1270 &bsi->bsi_oc->bom_keycol,
1273 if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
1274 backsql_strfcat( &bsi->bsi_sel, "blbl",
1275 &bi->sql_strcast_func,
1276 (ber_len_t)STRLENOF( "('" /* ') */ ),
1278 &bsi->bsi_oc->bom_oc->soc_cname,
1279 (ber_len_t)STRLENOF( /* (' */ "')" ),
1282 backsql_strfcat( &bsi->bsi_sel, "cbc",
1284 &bsi->bsi_oc->bom_oc->soc_cname,
1288 backsql_strfcat( &bsi->bsi_sel, "b", &bi->sql_dn_oc_aliasing );
1289 backsql_strfcat( &bsi->bsi_from, "lb",
1290 (ber_len_t)STRLENOF( " FROM ldap_entries," ),
1291 " FROM ldap_entries,",
1292 &bsi->bsi_oc->bom_keytbl );
1294 backsql_strfcat( &bsi->bsi_join_where, "lbcbl",
1295 (ber_len_t)STRLENOF( " WHERE " ), " WHERE ",
1296 &bsi->bsi_oc->bom_keytbl,
1298 &bsi->bsi_oc->bom_keycol,
1299 (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ),
1300 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
1302 switch ( bsi->bsi_scope ) {
1303 case LDAP_SCOPE_BASE:
1304 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1305 backsql_strfcat( &bsi->bsi_join_where, "bl",
1306 &bi->sql_upper_func,
1307 (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ),
1308 "(ldap_entries.dn)=?" );
1310 backsql_strfcat( &bsi->bsi_join_where, "l",
1311 (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
1312 "ldap_entries.dn=?" );
1316 case BACKSQL_SCOPE_BASE_LIKE:
1317 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1318 backsql_strfcat( &bsi->bsi_join_where, "bl",
1319 &bi->sql_upper_func,
1320 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1321 "(ldap_entries.dn) LIKE ?" );
1323 backsql_strfcat( &bsi->bsi_join_where, "l",
1324 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1325 "ldap_entries.dn LIKE ?" );
1329 case LDAP_SCOPE_ONELEVEL:
1330 backsql_strfcat( &bsi->bsi_join_where, "l",
1331 (ber_len_t)STRLENOF( "ldap_entries.parent=?" ),
1332 "ldap_entries.parent=?" );
1335 #ifdef LDAP_SCOPE_SUBORDINATE
1336 case LDAP_SCOPE_SUBORDINATE:
1337 #endif /* LDAP_SCOPE_SUBORDINATE */
1338 case LDAP_SCOPE_SUBTREE:
1339 if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) {
1341 BackendDB *bd = bsi->bsi_op->o_bd;
1343 assert( bd->be_nsuffix != NULL );
1345 for ( i = 0; !BER_BVISNULL( &bd->be_nsuffix[ i ] ); i++ )
1347 if ( dn_match( &bd->be_nsuffix[ i ],
1348 bsi->bsi_base_ndn ) )
1350 /* pass this to the candidate selection
1351 * routine so that the DN is not bound
1352 * to the select statement */
1353 bsi->bsi_use_subtree_shortcut = 1;
1359 if ( bsi->bsi_use_subtree_shortcut ) {
1360 /* Skip the base DN filter, as every entry will match it */
1361 backsql_strfcat( &bsi->bsi_join_where, "l",
1362 (ber_len_t)STRLENOF( "9=9"), "9=9");
1364 } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
1365 backsql_strfcat( &bsi->bsi_join_where, "b", &bi->sql_subtree_cond );
1367 } else if ( BACKSQL_CANUPPERCASE( bi ) ) {
1368 backsql_strfcat( &bsi->bsi_join_where, "bl",
1369 &bi->sql_upper_func,
1370 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1371 "(ldap_entries.dn) LIKE ?" );
1374 backsql_strfcat( &bsi->bsi_join_where, "l",
1375 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1376 "ldap_entries.dn LIKE ?" );
1385 rc = backsql_process_filter( bsi, bsi->bsi_filter );
1387 struct berbuf bb = BB_NULL;
1389 backsql_strfcat( &bb, "bbblb",
1390 &bsi->bsi_sel.bb_val,
1391 &bsi->bsi_from.bb_val,
1392 &bsi->bsi_join_where.bb_val,
1393 (ber_len_t)STRLENOF( " AND " ), " AND ",
1394 &bsi->bsi_flt_where.bb_val );
1398 } else if ( rc < 0 ) {
1400 * Indicates that there's no possible way the filter matches
1401 * anything. No need to issue the query
1403 free( query->bv_val );
1404 BER_BVZERO( query );
1407 free( bsi->bsi_sel.bb_val.bv_val );
1408 BER_BVZERO( &bsi->bsi_sel.bb_val );
1409 bsi->bsi_sel.bb_len = 0;
1410 free( bsi->bsi_from.bb_val.bv_val );
1411 BER_BVZERO( &bsi->bsi_from.bb_val );
1412 bsi->bsi_from.bb_len = 0;
1413 free( bsi->bsi_join_where.bb_val.bv_val );
1414 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1415 bsi->bsi_join_where.bb_len = 0;
1416 free( bsi->bsi_flt_where.bb_val.bv_val );
1417 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1418 bsi->bsi_flt_where.bb_len = 0;
1420 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n",
1421 query->bv_val ? query->bv_val : "NULL", 0, 0 );
1423 return ( rc <= 0 ? 1 : 0 );
1427 backsql_oc_get_candidates( void *v_oc, void *v_bsi )
1429 backsql_oc_map_rec *oc = v_oc;
1430 backsql_srch_info *bsi = v_bsi;
1431 Operation *op = bsi->bsi_op;
1432 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1433 struct berval query;
1434 SQLHSTMT sth = SQL_NULL_HSTMT;
1437 BACKSQL_ROW_NTS row;
1440 int n_candidates = bsi->bsi_n_candidates;
1443 * + 1 because we need room for '%';
1444 * + 1 because we need room for ',' for LDAP_SCOPE_SUBORDINATE;
1445 * this makes a subtree
1446 * search for a DN BACKSQL_MAX_DN_LEN long legal
1447 * if it returns that DN only
1449 char tmp_base_ndn[ BACKSQL_MAX_DN_LEN + 1 + 1 ];
1451 bsi->bsi_status = LDAP_SUCCESS;
1453 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n",
1454 BACKSQL_OC_NAME( oc ), 0, 0 );
1456 /* check for abandon */
1457 if ( op->o_abandon ) {
1458 bsi->bsi_status = SLAPD_ABANDON;
1459 return BACKSQL_AVL_STOP;
1462 if ( bsi->bsi_n_candidates == -1 ) {
1463 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1464 "unchecked limit has been overcome\n", 0, 0, 0 );
1465 /* should never get here */
1467 bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED;
1468 return BACKSQL_AVL_STOP;
1472 res = backsql_srch_query( bsi, &query );
1474 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1475 "error while constructing query for objectclass \"%s\"\n",
1476 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1478 * FIXME: need to separate errors from legally
1479 * impossible filters
1481 switch ( bsi->bsi_status ) {
1483 case LDAP_UNDEFINED_TYPE:
1484 case LDAP_NO_SUCH_OBJECT:
1485 /* we are conservative... */
1487 bsi->bsi_status = LDAP_SUCCESS;
1489 return BACKSQL_AVL_CONTINUE;
1491 case LDAP_ADMINLIMIT_EXCEEDED:
1493 /* don't try any more */
1494 return BACKSQL_AVL_STOP;
1498 if ( BER_BVISNULL( &query ) ) {
1499 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1500 "could not construct query for objectclass \"%s\"\n",
1501 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1502 bsi->bsi_status = LDAP_SUCCESS;
1503 return BACKSQL_AVL_CONTINUE;
1506 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n",
1507 query.bv_val, 0, 0 );
1509 rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 );
1510 free( query.bv_val );
1511 BER_BVZERO( &query );
1512 if ( rc != SQL_SUCCESS ) {
1513 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1514 "error preparing query\n", 0, 0, 0 );
1515 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1516 bsi->bsi_status = LDAP_OTHER;
1517 return BACKSQL_AVL_CONTINUE;
1520 Debug( LDAP_DEBUG_TRACE, "id: '%ld'\n", bsi->bsi_oc->bom_id, 0, 0 );
1522 rc = backsql_BindParamInt( sth, 1, SQL_PARAM_INPUT,
1523 &bsi->bsi_oc->bom_id );
1524 if ( rc != SQL_SUCCESS ) {
1525 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1526 "error binding objectclass id parameter\n", 0, 0, 0 );
1527 bsi->bsi_status = LDAP_OTHER;
1528 return BACKSQL_AVL_CONTINUE;
1531 switch ( bsi->bsi_scope ) {
1532 case LDAP_SCOPE_BASE:
1533 case BACKSQL_SCOPE_BASE_LIKE:
1535 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1536 * however this should be handled earlier
1538 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1539 bsi->bsi_status = LDAP_OTHER;
1540 return BACKSQL_AVL_CONTINUE;
1543 AC_MEMCPY( tmp_base_ndn, bsi->bsi_base_ndn->bv_val,
1544 bsi->bsi_base_ndn->bv_len + 1 );
1546 /* uppercase DN only if the stored DN can be uppercased
1548 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1549 ldap_pvt_str2upper( tmp_base_ndn );
1552 Debug( LDAP_DEBUG_TRACE, "(base)dn: \"%s\"\n",
1553 tmp_base_ndn, 0, 0 );
1555 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1556 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1557 if ( rc != SQL_SUCCESS ) {
1558 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1559 "error binding base_ndn parameter\n", 0, 0, 0 );
1560 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1562 bsi->bsi_status = LDAP_OTHER;
1563 return BACKSQL_AVL_CONTINUE;
1567 #ifdef LDAP_SCOPE_SUBORDINATE
1568 case LDAP_SCOPE_SUBORDINATE:
1569 #endif /* LDAP_SCOPE_SUBORDINATE */
1570 case LDAP_SCOPE_SUBTREE:
1572 /* if short-cutting the search base,
1573 * don't bind any parameter */
1574 if ( bsi->bsi_use_subtree_shortcut ) {
1579 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1580 * however this should be handled earlier
1582 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1583 bsi->bsi_status = LDAP_OTHER;
1584 return BACKSQL_AVL_CONTINUE;
1588 * Sets the parameters for the SQL built earlier
1589 * NOTE that all the databases could actually use
1590 * the TimesTen version, which would be cleaner
1591 * and would also eliminate the need for the
1592 * subtree_cond line in the configuration file.
1593 * For now, I'm leaving it the way it is,
1594 * so non-TimesTen databases use the original code.
1595 * But at some point this should get cleaned up.
1597 * If "dn" is being used, do a suffix search.
1598 * If "dn_ru" is being used, do a prefix search.
1600 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
1601 tmp_base_ndn[ 0 ] = '\0';
1603 for ( i = 0, j = bsi->bsi_base_ndn->bv_len - 1;
1605 tmp_base_ndn[ i ] = bsi->bsi_base_ndn->bv_val[ j ];
1608 #ifdef LDAP_SCOPE_SUBORDINATE
1609 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1610 tmp_base_ndn[ i++ ] = ',';
1612 #endif /* LDAP_SCOPE_SUBORDINATE */
1614 tmp_base_ndn[ i ] = '%';
1615 tmp_base_ndn[ i + 1 ] = '\0';
1620 tmp_base_ndn[ i++ ] = '%';
1622 #ifdef LDAP_SCOPE_SUBORDINATE
1623 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1624 tmp_base_ndn[ i++ ] = ',';
1626 #endif /* LDAP_SCOPE_SUBORDINATE */
1628 AC_MEMCPY( &tmp_base_ndn[ i ], bsi->bsi_base_ndn->bv_val,
1629 bsi->bsi_base_ndn->bv_len + 1 );
1632 /* uppercase DN only if the stored DN can be uppercased
1634 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1635 ldap_pvt_str2upper( tmp_base_ndn );
1638 #ifdef LDAP_SCOPE_SUBORDINATE
1639 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1640 Debug( LDAP_DEBUG_TRACE, "(children)dn: \"%s\"\n",
1641 tmp_base_ndn, 0, 0 );
1643 #endif /* LDAP_SCOPE_SUBORDINATE */
1645 Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n",
1646 tmp_base_ndn, 0, 0 );
1649 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1650 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1651 if ( rc != SQL_SUCCESS ) {
1652 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1653 "error binding base_ndn parameter (2)\n",
1655 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1657 bsi->bsi_status = LDAP_OTHER;
1658 return BACKSQL_AVL_CONTINUE;
1663 case LDAP_SCOPE_ONELEVEL:
1664 assert( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) );
1666 #ifdef BACKSQL_ARBITRARY_KEY
1667 Debug( LDAP_DEBUG_TRACE, "(one)id: \"%s\"\n",
1668 bsi->bsi_base_id.eid_id.bv_val, 0, 0 );
1669 #else /* ! BACKSQL_ARBITRARY_KEY */
1670 Debug( LDAP_DEBUG_TRACE, "(one)id: '%lu'\n",
1671 bsi->bsi_base_id.eid_id, 0, 0 );
1672 #endif /* ! BACKSQL_ARBITRARY_KEY */
1673 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT,
1674 &bsi->bsi_base_id.eid_id );
1675 if ( rc != SQL_SUCCESS ) {
1676 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1677 "error binding base id parameter\n", 0, 0, 0 );
1678 bsi->bsi_status = LDAP_OTHER;
1679 return BACKSQL_AVL_CONTINUE;
1684 rc = SQLExecute( sth );
1685 if ( !BACKSQL_SUCCESS( rc ) ) {
1686 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1687 "error executing query\n", 0, 0, 0 );
1688 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1689 SQLFreeStmt( sth, SQL_DROP );
1690 bsi->bsi_status = LDAP_OTHER;
1691 return BACKSQL_AVL_CONTINUE;
1694 backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx );
1695 rc = SQLFetch( sth );
1696 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
1697 struct berval dn, pdn, ndn;
1698 backsql_entryID *c_id = NULL;
1701 ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
1703 if ( backsql_api_odbc2dn( bsi->bsi_op, bsi->bsi_rs, &dn ) ) {
1707 ret = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
1708 if ( dn.bv_val != row.cols[ 3 ] ) {
1712 if ( ret != LDAP_SUCCESS ) {
1716 if ( bi->sql_baseObject && dn_match( &ndn, &bi->sql_baseObject->e_nname ) ) {
1717 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
1718 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
1722 c_id = (backsql_entryID *)ch_calloc( 1,
1723 sizeof( backsql_entryID ) );
1724 #ifdef BACKSQL_ARBITRARY_KEY
1725 ber_str2bv_x( row.cols[ 0 ], 0, 1, &c_id->eid_id,
1727 ber_str2bv_x( row.cols[ 1 ], 0, 1, &c_id->eid_keyval,
1729 #else /* ! BACKSQL_ARBITRARY_KEY */
1730 c_id->eid_id = strtol( row.cols[ 0 ], NULL, 0 );
1731 c_id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 );
1732 #endif /* ! BACKSQL_ARBITRARY_KEY */
1733 c_id->eid_oc_id = bsi->bsi_oc->bom_id;
1736 c_id->eid_ndn = ndn;
1738 /* append at end of list ... */
1739 c_id->eid_next = NULL;
1740 *bsi->bsi_id_listtail = c_id;
1741 bsi->bsi_id_listtail = &c_id->eid_next;
1743 #ifdef BACKSQL_ARBITRARY_KEY
1744 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1745 "added entry id=%s, keyval=%s dn=\"%s\"\n",
1746 c_id->eid_id.bv_val, c_id->eid_keyval.bv_val,
1748 #else /* ! BACKSQL_ARBITRARY_KEY */
1749 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1750 "added entry id=%ld, keyval=%ld dn=\"%s\"\n",
1751 c_id->eid_id, c_id->eid_keyval, row.cols[ 3 ] );
1752 #endif /* ! BACKSQL_ARBITRARY_KEY */
1754 /* count candidates, for unchecked limit */
1755 bsi->bsi_n_candidates--;
1756 if ( bsi->bsi_n_candidates == -1 ) {
1760 backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );
1761 SQLFreeStmt( sth, SQL_DROP );
1763 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n",
1764 n_candidates - bsi->bsi_n_candidates, 0, 0 );
1766 return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE );
1770 backsql_search( Operation *op, SlapReply *rs )
1772 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
1773 SQLHDBC dbh = SQL_NULL_HDBC;
1775 Entry user_entry = { 0 },
1777 int manageDSAit = get_manageDSAit( op );
1778 time_t stoptime = 0;
1779 backsql_srch_info bsi = { 0 };
1780 backsql_entryID *eid = NULL;
1781 struct berval nbase = BER_BVNULL;
1783 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): "
1784 "base=\"%s\", filter=\"%s\", scope=%d,",
1785 op->o_req_ndn.bv_val,
1786 op->ors_filterstr.bv_val ? op->ors_filterstr.bv_val : "(no filter)",
1788 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, "
1789 "attributes to load: %s\n",
1792 op->ors_attrs == NULL ? "all" : "custom list" );
1794 if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) {
1795 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1796 "search base length (%ld) exceeds max length (%d)\n",
1797 op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN, 0 );
1799 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
1800 * since it is impossible that such a long DN exists
1803 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
1804 send_ldap_result( op, rs );
1808 sres = backsql_get_db_conn( op, &dbh );
1809 if ( sres != LDAP_SUCCESS ) {
1810 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1811 "could not get connection handle - exiting\n",
1814 rs->sr_text = sres == LDAP_OTHER ? "SQL-backend error" : NULL;
1815 send_ldap_result( op, rs );
1819 /* compute it anyway; root does not use it */
1820 stoptime = op->o_time + op->ors_tlimit;
1823 bsi.bsi_e = &base_entry;
1824 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
1826 stoptime, op->ors_filter,
1827 dbh, op, rs, op->ors_attrs,
1828 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
1829 switch ( rs->sr_err ) {
1834 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
1835 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
1837 rs->sr_err = LDAP_SUCCESS;
1839 rs->sr_matched = NULL;
1841 ber_bvarray_free( rs->sr_ref );
1847 /* an entry was created; free it */
1848 entry_clean( bsi.bsi_e );
1853 #ifdef SLAP_ACL_HONOR_DISCLOSE
1854 if ( !BER_BVISNULL( &base_entry.e_nname )
1855 && ! access_allowed( op, &base_entry,
1856 slap_schema.si_ad_entry, NULL,
1857 ACL_DISCLOSE, NULL ) )
1859 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1861 ber_bvarray_free( rs->sr_ref );
1864 rs->sr_matched = NULL;
1867 #endif /* SLAP_ACL_HONOR_DISCLOSE */
1869 send_ldap_result( op, rs );
1872 ber_bvarray_free( rs->sr_ref );
1878 #ifdef SLAP_ACL_HONOR_DISCLOSE
1879 /* NOTE: __NEW__ "search" access is required
1880 * on searchBase object */
1884 if ( get_assert( op ) &&
1885 ( test_filter( op, &base_entry, get_assertion( op ) )
1886 != LDAP_COMPARE_TRUE ) )
1888 rs->sr_err = LDAP_ASSERTION_FAILED;
1891 if ( ! access_allowed_mask( op, &base_entry,
1892 slap_schema.si_ad_entry,
1893 NULL, ACL_SEARCH, NULL, &mask ) )
1895 if ( rs->sr_err == LDAP_SUCCESS ) {
1896 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
1900 if ( rs->sr_err != LDAP_SUCCESS ) {
1901 if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
1902 rs->sr_err = LDAP_NO_SUCH_OBJECT;
1905 send_ldap_result( op, rs );
1909 #endif /* SLAP_ACL_HONOR_DISCLOSE */
1913 bsi.bsi_n_candidates =
1914 ( op->ors_limit == NULL /* isroot == TRUE */ ? -2 :
1915 ( op->ors_limit->lms_s_unchecked == -1 ? -2 :
1916 ( op->ors_limit->lms_s_unchecked ) ) );
1918 switch ( bsi.bsi_scope ) {
1919 case LDAP_SCOPE_BASE:
1920 case BACKSQL_SCOPE_BASE_LIKE:
1922 * probably already found...
1924 bsi.bsi_id_list = &bsi.bsi_base_id;
1925 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
1928 case LDAP_SCOPE_SUBTREE:
1930 * if baseObject is defined, and if it is the root
1931 * of the search, add it to the candidate list
1933 if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &bsi.bsi_base_id.eid_id ) )
1935 bsi.bsi_id_list = &bsi.bsi_base_id;
1936 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
1943 * for each objectclass we try to construct query which gets IDs
1944 * of entries matching LDAP query filter and scope (or at least
1945 * candidates), and get the IDs
1947 avl_apply( bi->sql_oc_by_oc, backsql_oc_get_candidates,
1948 &bsi, BACKSQL_AVL_STOP, AVL_INORDER );
1950 /* check for abandon */
1951 if ( op->o_abandon ) {
1952 eid = bsi.bsi_id_list;
1953 rs->sr_err = SLAPD_ABANDON;
1958 if ( op->ors_limit != NULL /* isroot == FALSE */
1959 && op->ors_limit->lms_s_unchecked != -1
1960 && bsi.bsi_n_candidates == -1 )
1962 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
1963 send_ldap_result( op, rs );
1968 * now we load candidate entries (only those attributes
1969 * mentioned in attrs and filter), test it against full filter
1970 * and then send to client; don't free entry_id if baseObject...
1972 for ( eid = bsi.bsi_id_list;
1974 eid = backsql_free_entryID( op,
1975 eid, eid == &bsi.bsi_base_id ? 0 : 1 ) )
1978 Attribute *a_hasSubordinate = NULL,
1979 *a_entryUUID = NULL,
1984 /* check for abandon */
1985 if ( op->o_abandon ) {
1986 rs->sr_err = SLAPD_ABANDON;
1990 /* check time limit */
1991 if ( op->ors_tlimit != SLAP_NO_LIMIT
1992 && slap_get_time() > stoptime )
1994 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
1995 rs->sr_ctrls = NULL;
1996 rs->sr_ref = rs->sr_v2ref;
2000 #ifdef BACKSQL_ARBITRARY_KEY
2001 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
2002 "for entry id=%s, oc_id=%ld, keyval=%s\n",
2003 eid->eid_id.bv_val, eid->eid_oc_id,
2004 eid->eid_keyval.bv_val );
2005 #else /* ! BACKSQL_ARBITRARY_KEY */
2006 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
2007 "for entry id=%ld, oc_id=%ld, keyval=%ld\n",
2008 eid->eid_id, eid->eid_oc_id, eid->eid_keyval );
2009 #endif /* ! BACKSQL_ARBITRARY_KEY */
2012 switch ( op->ors_scope ) {
2013 case LDAP_SCOPE_BASE:
2014 case BACKSQL_SCOPE_BASE_LIKE:
2015 if ( !dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
2020 case LDAP_SCOPE_ONE:
2022 struct berval rdn = eid->eid_ndn;
2024 rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
2025 if ( !dnIsOneLevelRDN( &rdn ) ) {
2031 #ifdef LDAP_SCOPE_SUBORDINATE
2032 case LDAP_SCOPE_SUBORDINATE:
2033 /* discard the baseObject entry */
2034 if ( dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
2038 #endif /* LDAP_SCOPE_SUBORDINATE */
2040 case LDAP_SCOPE_SUBTREE:
2041 /* FIXME: this should never fail... */
2042 if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) {
2049 if ( BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
2050 /* don't recollect baseObject... */
2051 e = bi->sql_baseObject;
2053 } else if ( eid == &bsi.bsi_base_id ) {
2054 /* don't recollect searchBase object... */
2058 bsi.bsi_e = &user_entry;
2059 rc = backsql_id2entry( &bsi, eid );
2060 if ( rc != LDAP_SUCCESS ) {
2061 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2062 "error %d in backsql_id2entry() "
2063 "- skipping\n", rc, 0, 0 );
2069 if ( !manageDSAit &&
2070 op->ors_scope != LDAP_SCOPE_BASE &&
2071 op->ors_scope != BACKSQL_SCOPE_BASE_LIKE &&
2072 is_entry_referral( e ) )
2076 refs = get_entry_referrals( op, e );
2078 backsql_srch_info bsi2 = { 0 };
2079 Entry user_entry2 = { 0 };
2081 /* retry with the full entry... */
2082 bsi2.bsi_e = &user_entry2;
2083 rc = backsql_init_search( &bsi2,
2088 BACKSQL_ISF_GET_ENTRY );
2089 if ( rc == LDAP_SUCCESS ) {
2090 if ( is_entry_referral( &user_entry2 ) )
2092 refs = get_entry_referrals( op,
2095 rs->sr_err = LDAP_OTHER;
2097 backsql_entry_clean( op, &user_entry2 );
2099 if ( bsi2.bsi_attrs != NULL ) {
2100 op->o_tmpfree( bsi2.bsi_attrs,
2106 rs->sr_ref = referral_rewrite( refs,
2110 ber_bvarray_free( refs );
2114 rs->sr_err = LDAP_REFERRAL;
2117 rs->sr_text = "bad referral object";
2121 rs->sr_matched = user_entry.e_name.bv_val;
2122 send_search_reference( op, rs );
2124 ber_bvarray_free( rs->sr_ref );
2126 rs->sr_matched = NULL;
2127 rs->sr_entry = NULL;
2133 * We use this flag since we need to parse the filter
2134 * anyway; we should have used the frontend API function
2135 * filter_has_subordinates()
2137 if ( bsi.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
2138 rc = backsql_has_children( op, dbh, &e->e_nname );
2141 case LDAP_COMPARE_TRUE:
2142 case LDAP_COMPARE_FALSE:
2143 a_hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
2144 if ( a_hasSubordinate != NULL ) {
2145 for ( ap = &user_entry.e_attrs;
2147 ap = &(*ap)->a_next );
2149 *ap = a_hasSubordinate;
2155 Debug(LDAP_DEBUG_TRACE,
2156 "backsql_search(): "
2157 "has_children failed( %d)\n",
2164 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYUUID ) {
2165 a_entryUUID = backsql_operational_entryUUID( bi, eid );
2166 if ( a_entryUUID != NULL ) {
2168 ap = &user_entry.e_attrs;
2171 for ( ; *ap; ap = &(*ap)->a_next );
2177 #ifdef BACKSQL_SYNCPROV
2178 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYCSN ) {
2179 a_entryCSN = backsql_operational_entryCSN( op );
2180 if ( a_entryCSN != NULL ) {
2182 ap = &user_entry.e_attrs;
2185 for ( ; *ap; ap = &(*ap)->a_next );
2190 #endif /* BACKSQL_SYNCPROV */
2192 if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE )
2194 rs->sr_attrs = op->ors_attrs;
2195 rs->sr_operational_attrs = NULL;
2197 if ( e == &user_entry ) {
2198 rs->sr_flags = REP_ENTRY_MODIFIABLE;
2200 /* FIXME: need the whole entry (ITS#3480) */
2201 sres = send_search_entry( op, rs );
2202 rs->sr_entry = NULL;
2203 rs->sr_attrs = NULL;
2204 rs->sr_operational_attrs = NULL;
2208 * FIXME: send_search_entry failed;
2211 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2212 "connection lost\n", 0, 0, 0 );
2218 if ( e == &user_entry ) {
2219 backsql_entry_clean( op, &user_entry );
2223 if ( --op->ors_slimit == -1 ) {
2224 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
2230 if ( rs->sr_nentries > 0 ) {
2231 rs->sr_ref = rs->sr_v2ref;
2232 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
2236 rs->sr_err = bsi.bsi_status;
2240 if ( rs->sr_err != SLAPD_ABANDON ) {
2241 send_ldap_result( op, rs );
2244 /* cleanup in case of abandon */
2245 for ( ; eid != NULL;
2246 eid = backsql_free_entryID( op,
2247 eid, eid == &bsi.bsi_base_id ? 0 : 1 ) )
2250 backsql_entry_clean( op, &base_entry );
2252 /* in case we got here accidentally */
2253 backsql_entry_clean( op, &user_entry );
2255 if ( rs->sr_v2ref ) {
2256 ber_bvarray_free( rs->sr_v2ref );
2257 rs->sr_v2ref = NULL;
2260 #ifdef BACKSQL_SYNCPROV
2262 Operation op2 = *op;
2263 SlapReply rs2 = { 0 };
2265 slap_callback cb = { 0 };
2267 op2.o_tag = LDAP_REQ_ADD;
2268 op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0, 0 );
2270 op2.o_callback = &cb;
2272 e.e_name = op->o_bd->be_suffix[0];
2273 e.e_nname = op->o_bd->be_nsuffix[0];
2275 cb.sc_response = slap_null_cb;
2277 op2.o_bd->be_add( &op2, &rs2 );
2279 #endif /* BACKSQL_SYNCPROV */
2282 (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
2284 if ( bsi.bsi_attrs != NULL ) {
2285 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2288 if ( !BER_BVISNULL( &nbase )
2289 && nbase.bv_val != op->o_req_ndn.bv_val )
2291 ch_free( nbase.bv_val );
2294 /* restore scope ... FIXME: this should be done before ANY
2295 * frontend call that uses op */
2296 if ( op->ors_scope == BACKSQL_SCOPE_BASE_LIKE ) {
2297 op->ors_scope = LDAP_SCOPE_BASE;
2300 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
2305 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
2312 AttributeDescription *at,
2316 backsql_srch_info bsi = { 0 };
2317 SQLHDBC dbh = SQL_NULL_HDBC;
2319 SlapReply rs = { 0 };
2320 AttributeName anlist[ 2 ];
2324 rc = backsql_get_db_conn( op, &dbh );
2330 anlist[ 0 ].an_name = at->ad_cname;
2331 anlist[ 0 ].an_desc = at;
2332 BER_BVZERO( &anlist[ 1 ].an_name );
2335 bsi.bsi_e = ch_malloc( sizeof( Entry ) );
2336 rc = backsql_init_search( &bsi,
2340 dbh, op, &rs, at ? anlist : NULL,
2341 BACKSQL_ISF_GET_ENTRY );
2343 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) {
2344 (void)backsql_free_entryID( op, &bsi.bsi_base_id, 0 );
2347 if ( rc == LDAP_SUCCESS ) {
2349 #if 0 /* not supported at present */
2350 /* find attribute values */
2351 if ( is_entry_alias( bsi.bsi_e ) ) {
2352 Debug( LDAP_DEBUG_ACL,
2353 "<= backsql_entry_get: entry is an alias\n",
2355 rc = LDAP_ALIAS_PROBLEM;
2356 goto return_results;
2360 if ( is_entry_referral( bsi.bsi_e ) ) {
2361 Debug( LDAP_DEBUG_ACL,
2362 "<= backsql_entry_get: entry is a referral\n",
2365 goto return_results;
2368 if ( oc && !is_entry_objectclass( bsi.bsi_e, oc, 0 ) ) {
2369 Debug( LDAP_DEBUG_ACL,
2370 "<= backsql_entry_get: "
2371 "failed to find objectClass\n",
2373 rc = LDAP_NO_SUCH_ATTRIBUTE;
2374 goto return_results;
2381 if ( bsi.bsi_attrs != NULL ) {
2382 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2385 if ( rc != LDAP_SUCCESS ) {
2387 entry_free( bsi.bsi_e );
2395 backsql_entry_clean(
2401 ctx = ldap_pvt_thread_pool_context();
2403 if ( ctx == NULL || ctx != op->o_tmpmemctx ) {
2404 if ( !BER_BVISNULL( &e->e_name ) ) {
2405 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx );
2406 BER_BVZERO( &e->e_name );
2409 if ( !BER_BVISNULL( &e->e_nname ) ) {
2410 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx );
2411 BER_BVZERO( &e->e_nname );
2419 backsql_entry_release(
2424 backsql_entry_clean( op, e );