2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2004 The OpenLDAP Foundation.
5 * Portions Copyright 1999 Dmitry Kovalev.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was initially developed by Dmitry Kovalev for inclusion
18 * by OpenLDAP Software.
26 #include <sys/types.h>
27 #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 ch_free( bsi->bsi_attrs );
59 bsi->bsi_attrs = NULL;
63 for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) {
64 an = &bsi->bsi_attrs[ n_attrs ];
66 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
67 "attribute \"%s\" is in list\n",
68 an->an_name.bv_val, 0, 0 );
70 * We can live with strcmp because the attribute
71 * list has been normalized before calling be_search
73 if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) {
78 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
79 "adding \"%s\" to list\n", ad->ad_cname.bv_val, 0, 0 );
81 an = (AttributeName *)ch_realloc( bsi->bsi_attrs,
82 sizeof( AttributeName ) * ( n_attrs + 2 ) );
87 an[ n_attrs ].an_name = ad->ad_cname;
88 an[ n_attrs ].an_desc = ad;
89 BER_BVZERO( &an[ n_attrs + 1 ].an_name );
98 backsql_srch_info *bsi,
108 AttributeName *attrs )
112 bsi->bsi_base_dn = base;
113 bsi->bsi_scope = scope;
114 bsi->bsi_slimit = slimit;
115 bsi->bsi_tlimit = tlimit;
116 bsi->bsi_filter = filter;
125 if ( attrs == NULL || an_find( attrs, &AllUser ) ) {
126 bsi->bsi_attrs = NULL;
131 bsi->bsi_attrs = (AttributeName *)ch_calloc( 1,
132 sizeof( AttributeName ) );
133 BER_BVZERO( &bsi->bsi_attrs[ 0 ].an_name );
135 for ( p = attrs; !BER_BVISNULL( &p->an_name ); p++ ) {
137 * ignore "1.1"; handle "+"
139 if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) {
140 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
143 } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
145 } else if ( p->an_desc == slap_schema.si_ad_objectClass ) {
149 backsql_attrlist_add( bsi, p->an_desc );
153 /* add objectClass if not present,
154 * because it is required to understand
155 * if an entry is a referral, an alias
157 backsql_attrlist_add( bsi, slap_schema.si_ad_objectClass );
161 bsi->bsi_abandon = 0;
162 bsi->bsi_id_list = NULL;
163 bsi->bsi_id_listtail = &bsi->bsi_id_list;
164 bsi->bsi_n_candidates = 0;
165 bsi->bsi_stoptime = stoptime;
166 BER_BVZERO( &bsi->bsi_sel.bb_val );
167 bsi->bsi_sel.bb_len = 0;
168 BER_BVZERO( &bsi->bsi_from.bb_val );
169 bsi->bsi_from.bb_len = 0;
170 BER_BVZERO( &bsi->bsi_join_where.bb_val );
171 bsi->bsi_join_where.bb_len = 0;
172 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
173 bsi->bsi_flt_where.bb_len = 0;
174 bsi->bsi_filter_oc = NULL;
176 bsi->bsi_status = LDAP_SUCCESS;
180 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
188 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' /* ) */ );
191 res = backsql_process_filter( bsi, f );
194 * TimesTen : If the query has no answers,
195 * don't bother to run the query.
206 case LDAP_FILTER_AND:
207 backsql_strfcat( &bsi->bsi_flt_where, "l",
208 (ber_len_t)STRLENOF( " AND " ),
213 backsql_strfcat( &bsi->bsi_flt_where, "l",
214 (ber_len_t)STRLENOF( " OR " ),
220 backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' );
226 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
227 backsql_at_map_rec *at )
229 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
237 /* always uppercase strings by now */
238 #ifdef BACKSQL_UPPERCASE_FILTER
239 if ( SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
240 bi->bi_caseIgnoreMatch ) )
241 #endif /* BACKSQL_UPPERCASE_FILTER */
246 if ( SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
247 bi->bi_telephoneNumberMatch ) )
254 * to check for matching telephone numbers
255 * with intermixed chars, e.g. val='1234'
258 * val LIKE '%1%2%3%4%'
262 if ( f->f_sub_initial.bv_val ) {
263 bv.bv_len += f->f_sub_initial.bv_len;
265 if ( f->f_sub_any != NULL ) {
266 for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) {
267 bv.bv_len += f->f_sub_any[ a ].bv_len;
270 if ( f->f_sub_final.bv_val ) {
271 bv.bv_len += f->f_sub_final.bv_len;
273 bv.bv_len = 2 * bv.bv_len - 1;
274 bv.bv_val = ch_malloc( bv.bv_len + 1 );
277 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
278 bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ];
279 for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) {
280 bv.bv_val[ s + 2 * i - 1 ] = '%';
281 bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ];
283 bv.bv_val[ s + 2 * i - 1 ] = '%';
287 if ( f->f_sub_any != NULL ) {
288 for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
289 bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ];
290 for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) {
291 bv.bv_val[ s + 2 * i - 1 ] = '%';
292 bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ];
294 bv.bv_val[ s + 2 * i - 1 ] = '%';
299 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
300 bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ];
301 for ( i = 1; i < f->f_sub_final.bv_len; i++ ) {
302 bv.bv_val[ s + 2 * i - 1 ] = '%';
303 bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ];
305 bv.bv_val[ s + 2 * i - 1 ] = '%';
309 bv.bv_val[ s - 1 ] = '\0';
311 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
312 ch_free( bv.bv_val );
318 * When dealing with case-sensitive strings
319 * we may omit normalization; however, normalized
320 * SQL filters are more liberal.
323 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' /* ) */ );
326 Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n",
327 at->bam_ad->ad_cname.bv_val, 0, 0 );
328 Debug(LDAP_DEBUG_TRACE, " expr: '%s%s%s'\n", at->bam_sel_expr.bv_val,
329 at->bam_sel_expr_u.bv_val ? "' '" : "",
330 at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" );
331 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
333 * If a pre-upper-cased version of the column
334 * or a precompiled upper function exists, use it
336 backsql_strfcat( &bsi->bsi_flt_where,
339 (ber_len_t)STRLENOF( " LIKE '" ),
343 backsql_strfcat( &bsi->bsi_flt_where, "bl",
345 (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
348 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
352 Debug( LDAP_DEBUG_TRACE,
353 "==>backsql_process_sub_filter(%s): "
354 "sub_initial=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
355 f->f_sub_initial.bv_val, 0 );
356 #endif /* BACKSQL_TRACE */
358 start = bsi->bsi_flt_where.bb_val.bv_len;
359 backsql_strfcat( &bsi->bsi_flt_where, "b",
361 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
362 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
366 backsql_strfcat( &bsi->bsi_flt_where, "c", '%' );
368 if ( f->f_sub_any != NULL ) {
369 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) {
373 Debug( LDAP_DEBUG_TRACE,
374 "==>backsql_process_sub_filter(%s): "
375 "sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
376 i, f->f_sub_any[ i ].bv_val );
377 #endif /* BACKSQL_TRACE */
379 start = bsi->bsi_flt_where.bb_val.bv_len;
380 backsql_strfcat( &bsi->bsi_flt_where,
384 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
386 * Note: toupper('%') = '%'
388 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
393 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
397 Debug( LDAP_DEBUG_TRACE,
398 "==>backsql_process_sub_filter(%s): "
399 "sub_final=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
400 f->f_sub_final.bv_val, 0 );
401 #endif /* BACKSQL_TRACE */
403 start = bsi->bsi_flt_where.bb_val.bv_len;
404 backsql_strfcat( &bsi->bsi_flt_where, "b",
406 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
407 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
411 backsql_strfcat( &bsi->bsi_flt_where, "l",
412 (ber_len_t)sizeof( /* (' */ "')" ) - 1, /* ( */ "')" );
418 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
420 backsql_at_map_rec **vat = NULL;
421 AttributeDescription *ad = NULL;
426 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 );
427 if ( f->f_choice == SLAPD_FILTER_COMPUTED ) {
428 Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
429 "invalid filter\n", 0, 0, 0 );
434 switch( f->f_choice ) {
436 rc = backsql_process_filter_list( bsi, f->f_or,
441 case LDAP_FILTER_AND:
442 rc = backsql_process_filter_list( bsi, f->f_and,
447 case LDAP_FILTER_NOT:
448 backsql_strfcat( &bsi->bsi_flt_where, "l",
449 (ber_len_t)sizeof( "NOT (" /* ) */ ) - 1,
451 rc = backsql_process_filter( bsi, f->f_not );
452 backsql_strfcat( &bsi->bsi_flt_where, "c", /* ( */ ')' );
456 case LDAP_FILTER_PRESENT:
460 case LDAP_FILTER_EXT:
461 ad = f->f_mra->ma_desc;
462 if ( f->f_mr_dnattrs ) {
464 * if dn attrs filtering is requested, better return
465 * success and let test_filter() deal with candidate
466 * selection; otherwise we'd need to set conditions
467 * on the contents of the DN, e.g. "SELECT ... FROM
468 * ldap_entries AS attributeName WHERE attributeName.dn
469 * like '%attributeName=value%'"
471 backsql_strfcat( &bsi->bsi_flt_where, "l",
472 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
473 bsi->bsi_status = LDAP_SUCCESS;
494 * Turn structuralObjectClass into objectClass
496 if ( ad == slap_schema.si_ad_objectClass
497 || ad == slap_schema.si_ad_structuralObjectClass ) {
499 * If the filter is LDAP_FILTER_PRESENT, then it's done;
500 * otherwise, let's see if we are lucky: filtering
501 * for "structural" objectclass or ancestor...
503 switch ( f->f_choice ) {
504 case LDAP_FILTER_EQUALITY:
506 ObjectClass *oc = oc_bvfind( &f->f_av_value );
509 Debug( LDAP_DEBUG_TRACE,
510 "backsql_process_filter(): "
511 "unknown objectClass \"%s\" "
513 f->f_av_value.bv_val, 0, 0 );
514 bsi->bsi_status = LDAP_OTHER;
520 * "structural" objectClass inheritance:
521 * - a search for "person" will also return
523 * - a search for "top" will return everything
525 if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
526 goto filter_oc_success;
532 case LDAP_FILTER_PRESENT:
534 backsql_strfcat( &bsi->bsi_flt_where, "l",
535 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
536 bsi->bsi_status = LDAP_SUCCESS;
541 Debug( LDAP_DEBUG_TRACE,
542 "backsql_process_filter(): "
543 "illegal/unhandled filter "
544 "on objectClass attribute",
546 bsi->bsi_status = LDAP_OTHER;
551 } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
553 * FIXME: this is not robust; e.g. a filter
554 * '(!(hasSubordinates=TRUE))' fails because
555 * in SQL it would read 'NOT (1=1)' instead
557 * Note however that hasSubordinates is boolean,
558 * so a more appropriate filter would be
559 * '(hasSubordinates=FALSE)'
561 * A more robust search for hasSubordinates
562 * would * require joining the ldap_entries table
563 * selecting if there are descendants of the
566 backsql_strfcat( &bsi->bsi_flt_where, "l",
567 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
568 if ( ad == slap_schema.si_ad_hasSubordinates ) {
570 * instruct candidate selection algorithm
571 * and attribute list to try to detect
572 * if an entry has subordinates
574 bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
578 * clear attributes to fetch, to require ALL
579 * and try extended match on all attributes
581 backsql_attrlist_add( bsi, NULL );
588 * attribute inheritance:
590 if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) {
591 bsi->bsi_status = LDAP_OTHER;
597 /* search anyway; other parts of the filter
599 backsql_strfcat( &bsi->bsi_flt_where, "l",
600 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
601 bsi->bsi_status = LDAP_SUCCESS;
606 /* if required, open extra level of parens */
608 if ( vat[0]->bam_next || vat[1] ) {
609 backsql_strfcat( &bsi->bsi_flt_where, "c", '(' );
616 if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) {
620 /* if more definitions of the same attr, apply */
621 if ( vat[i]->bam_next ) {
622 backsql_strfcat( &bsi->bsi_flt_where, "l",
623 STRLENOF( " OR " ), " OR " );
624 vat[i] = vat[i]->bam_next;
628 /* if more descendants of the same attr, apply */
631 backsql_strfcat( &bsi->bsi_flt_where, "l",
632 STRLENOF( " OR " ), " OR " );
636 /* if needed, close extra level of parens */
638 backsql_strfcat( &bsi->bsi_flt_where, "c", ')' );
648 Debug( LDAP_DEBUG_TRACE,
649 "<==backsql_process_filter() %s\n",
650 rc == 1 ? "succeeded" : "failed", 0, 0);
656 backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at,
657 int casefold, struct berval *filter_value )
660 * maybe we should check type of at->sel_expr here somehow,
661 * to know whether upper_func is applicable, but for now
662 * upper_func stuff is made for Oracle, where UPPER is
663 * safely applicable to NUMBER etc.
665 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
668 backsql_strfcat( &bsi->bsi_flt_where, "cbl",
671 (ber_len_t)STRLENOF( "='" ),
674 start = bsi->bsi_flt_where.bb_val.bv_len;
676 backsql_strfcat( &bsi->bsi_flt_where, "bl",
678 (ber_len_t)sizeof( /* (' */ "')" ) - 1,
681 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
684 backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
687 (ber_len_t)STRLENOF( "='" ), "='",
689 (ber_len_t)sizeof( /* (' */ "')" ) - 1,
697 backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at,
698 int casefold, struct berval *filter_value )
701 * maybe we should check type of at->sel_expr here somehow,
702 * to know whether upper_func is applicable, but for now
703 * upper_func stuff is made for Oracle, where UPPER is
704 * safely applicable to NUMBER etc.
706 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
709 backsql_strfcat( &bsi->bsi_flt_where, "cbl",
712 (ber_len_t)STRLENOF( " LIKE '%" ),
715 start = bsi->bsi_flt_where.bb_val.bv_len;
717 backsql_strfcat( &bsi->bsi_flt_where, "bl",
719 (ber_len_t)sizeof( /* (' */ "%')" ) - 1,
722 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
725 backsql_strfcat( &bsi->bsi_flt_where, "cblbl",
728 (ber_len_t)STRLENOF( " LIKE '%" ),
731 (ber_len_t)sizeof( /* (' */ "%')" ) - 1,
739 backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at )
741 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
743 struct berval *filter_value = NULL;
744 MatchingRule *matching_rule = NULL;
745 struct berval ordering = BER_BVC("<=");
747 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n",
748 at->bam_ad->ad_cname.bv_val, 0, 0 );
750 backsql_merge_from_clause( &bsi->bsi_from, &at->bam_from_tbls );
753 * need to add this attribute to list of attrs to load,
754 * so that we can do test_filter() later
756 backsql_attrlist_add( bsi, at->bam_ad );
758 if ( !BER_BVISNULL( &at->bam_join_where )
759 && strstr( bsi->bsi_join_where.bb_val.bv_val, at->bam_join_where.bv_val ) == NULL ) {
760 backsql_strfcat( &bsi->bsi_join_where, "lb",
761 (ber_len_t)STRLENOF( " AND " ), " AND ",
762 &at->bam_join_where );
765 switch ( f->f_choice ) {
766 case LDAP_FILTER_EQUALITY:
767 filter_value = &f->f_av_value;
768 matching_rule = at->bam_ad->ad_type->sat_equality;
772 /* fail over into next case */
774 case LDAP_FILTER_EXT:
775 filter_value = &f->f_mra->ma_value;
776 matching_rule = f->f_mr_rule;
779 /* always uppercase strings by now */
780 #ifdef BACKSQL_UPPERCASE_FILTER
781 if ( SLAP_MR_ASSOCIATED( matching_rule,
782 bi->bi_caseIgnoreMatch ) )
783 #endif /* BACKSQL_UPPERCASE_FILTER */
788 if ( SLAP_MR_ASSOCIATED( matching_rule,
789 bi->bi_telephoneNumberMatch ) )
795 * to check for matching telephone numbers
796 * with intermized chars, e.g. val='1234'
799 * val LIKE '%1%2%3%4%'
802 bv.bv_len = 2 * filter_value->bv_len - 1;
803 bv.bv_val = ch_malloc( bv.bv_len + 1 );
805 bv.bv_val[ 0 ] = filter_value->bv_val[ 0 ];
806 for ( i = 1; i < filter_value->bv_len; i++ ) {
807 bv.bv_val[ 2 * i - 1 ] = '%';
808 bv.bv_val[ 2 * i ] = filter_value->bv_val[ i ];
810 bv.bv_val[ 2 * i - 1 ] = '\0';
812 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
813 ch_free( bv.bv_val );
819 * maybe we should check type of at->sel_expr here somehow,
820 * to know whether upper_func is applicable, but for now
821 * upper_func stuff is made for Oracle, where UPPER is
822 * safely applicable to NUMBER etc.
824 (void)backsql_process_filter_eq( bsi, at, casefold, filter_value );
828 ordering.bv_val = ">=";
830 /* fall thru to next case */
833 /* always uppercase strings by now */
834 #ifdef BACKSQL_UPPERCASE_FILTER
835 if ( SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering,
836 bi->bi_caseIgnoreMatch ) )
837 #endif /* BACKSQL_UPPERCASE_FILTER */
843 * FIXME: should we uppercase the operands?
845 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
848 backsql_strfcat( &bsi->bsi_flt_where, "cbbc",
854 start = bsi->bsi_flt_where.bb_val.bv_len;
856 backsql_strfcat( &bsi->bsi_flt_where, "bl",
858 (ber_len_t)sizeof( /* (' */ "')" ) - 1,
861 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
864 backsql_strfcat( &bsi->bsi_flt_where, "cbbcbl",
870 (ber_len_t)sizeof( /* (' */ "')" ) - 1,
875 case LDAP_FILTER_PRESENT:
876 backsql_strfcat( &bsi->bsi_flt_where, "lbl",
877 (ber_len_t)sizeof( "NOT (" /* ) */) - 1,
880 (ber_len_t)sizeof( /* ( */ " IS NULL)" ) - 1,
881 /* ( */ " IS NULL)" );
884 case LDAP_FILTER_SUBSTRINGS:
885 backsql_process_sub_filter( bsi, f, at );
888 case LDAP_FILTER_APPROX:
892 * maybe we should check type of at->sel_expr here somehow,
893 * to know whether upper_func is applicable, but for now
894 * upper_func stuff is made for Oracle, where UPPER is
895 * safely applicable to NUMBER etc.
897 (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value );
901 /* unhandled filter type; should not happen */
903 backsql_strfcat( &bsi->bsi_flt_where, "l",
904 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
909 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n",
910 at->bam_ad->ad_cname.bv_val, 0, 0 );
916 backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
918 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
924 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n", 0, 0, 0 );
925 BER_BVZERO( &bsi->bsi_sel.bb_val );
926 BER_BVZERO( &bsi->bsi_sel.bb_val );
927 bsi->bsi_sel.bb_len = 0;
928 BER_BVZERO( &bsi->bsi_from.bb_val );
929 bsi->bsi_from.bb_len = 0;
930 BER_BVZERO( &bsi->bsi_join_where.bb_val );
931 bsi->bsi_join_where.bb_len = 0;
932 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
933 bsi->bsi_flt_where.bb_len = 0;
935 backsql_strfcat( &bsi->bsi_sel, "lbcbc",
936 (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ),
937 "SELECT DISTINCT ldap_entries.id,",
938 &bsi->bsi_oc->bom_keytbl,
940 &bsi->bsi_oc->bom_keycol,
943 if ( !BER_BVISNULL( &bi->strcast_func ) ) {
944 backsql_strfcat( &bsi->bsi_sel, "blbl",
946 (ber_len_t)sizeof( "('" /* ') */ ) - 1,
948 &bsi->bsi_oc->bom_oc->soc_cname,
949 (ber_len_t)sizeof( /* (' */ "')" ) - 1,
952 backsql_strfcat( &bsi->bsi_sel, "cbc",
954 &bsi->bsi_oc->bom_oc->soc_cname,
957 backsql_strfcat( &bsi->bsi_sel, "l",
958 (ber_len_t)STRLENOF( " AS objectClass,ldap_entries.dn AS dn" ),
959 " AS objectClass,ldap_entries.dn AS dn" );
961 backsql_strfcat( &bsi->bsi_from, "lb",
962 (ber_len_t)STRLENOF( " FROM ldap_entries," ),
963 " FROM ldap_entries,",
964 &bsi->bsi_oc->bom_keytbl );
966 backsql_strfcat( &bsi->bsi_join_where, "lbcbl",
967 (ber_len_t)STRLENOF( " WHERE " ), " WHERE ",
968 &bsi->bsi_oc->bom_keytbl,
970 &bsi->bsi_oc->bom_keycol,
971 (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ),
972 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
974 switch ( bsi->bsi_scope ) {
975 case LDAP_SCOPE_BASE:
976 if ( BACKSQL_CANUPPERCASE( bi ) ) {
977 backsql_strfcat( &bsi->bsi_join_where, "bl",
979 (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ),
980 "(ldap_entries.dn)=?" );
982 backsql_strfcat( &bsi->bsi_join_where, "l",
983 (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
984 "ldap_entries.dn=?" );
988 case BACKSQL_SCOPE_BASE_LIKE:
989 if ( BACKSQL_CANUPPERCASE( bi ) ) {
990 backsql_strfcat( &bsi->bsi_join_where, "bl",
992 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
993 "(ldap_entries.dn) LIKE ?" );
995 backsql_strfcat( &bsi->bsi_join_where, "l",
996 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
997 "ldap_entries.dn LIKE ?" );
1001 case LDAP_SCOPE_ONELEVEL:
1002 backsql_strfcat( &bsi->bsi_join_where, "l",
1003 (ber_len_t)STRLENOF( "ldap_entries.parent=?" ),
1004 "ldap_entries.parent=?" );
1007 case LDAP_SCOPE_SUBTREE:
1008 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1009 backsql_strfcat( &bsi->bsi_join_where, "bl",
1011 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1012 "(ldap_entries.dn) LIKE ?" );
1014 backsql_strfcat( &bsi->bsi_join_where, "l",
1015 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1016 "ldap_entries.dn LIKE ?" );
1025 rc = backsql_process_filter( bsi, bsi->bsi_filter );
1027 struct berbuf bb = BB_NULL;
1029 backsql_strfcat( &bb, "bbblb",
1030 &bsi->bsi_sel.bb_val,
1031 &bsi->bsi_from.bb_val,
1032 &bsi->bsi_join_where.bb_val,
1033 (ber_len_t)STRLENOF( " AND " ), " AND ",
1034 &bsi->bsi_flt_where.bb_val );
1038 } else if ( rc < 0 ) {
1040 * Indicates that there's no possible way the filter matches
1041 * anything. No need to issue the query
1043 free( query->bv_val );
1044 BER_BVZERO( query );
1047 free( bsi->bsi_sel.bb_val.bv_val );
1048 BER_BVZERO( &bsi->bsi_sel.bb_val );
1049 bsi->bsi_sel.bb_len = 0;
1050 free( bsi->bsi_from.bb_val.bv_val );
1051 BER_BVZERO( &bsi->bsi_from.bb_val );
1052 bsi->bsi_from.bb_len = 0;
1053 free( bsi->bsi_join_where.bb_val.bv_val );
1054 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1055 bsi->bsi_join_where.bb_len = 0;
1056 free( bsi->bsi_flt_where.bb_val.bv_val );
1057 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1058 bsi->bsi_flt_where.bb_len = 0;
1060 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n",
1061 query->bv_val ? query->bv_val : "NULL", 0, 0 );
1063 return ( rc <= 0 ? 1 : 0 );
1067 backsql_oc_get_candidates( void *v_oc, void *v_bsi )
1069 backsql_oc_map_rec *oc = v_oc;
1070 backsql_srch_info *bsi = v_bsi;
1071 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1072 struct berval query;
1075 backsql_entryID base_id = BACKSQL_ENTRYID_INIT;
1077 BACKSQL_ROW_NTS row;
1080 int n_candidates = bsi->bsi_n_candidates;
1083 * + 1 because we need room for '%'; this makes a subtree
1084 * search for a DN BACKSQL_MAX_DN_LEN long legal
1085 * if it returns that DN only
1087 char temp_base_dn[ BACKSQL_MAX_DN_LEN + 1 + 1 ];
1089 bsi->bsi_status = LDAP_SUCCESS;
1091 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n",
1092 BACKSQL_OC_NAME( oc ), 0, 0 );
1094 if ( bsi->bsi_n_candidates == -1 ) {
1095 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1096 "unchecked limit has been overcome\n", 0, 0, 0 );
1097 /* should never get here */
1099 bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED;
1100 return BACKSQL_AVL_STOP;
1104 res = backsql_srch_query( bsi, &query );
1106 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1107 "error while constructing query for objectclass \"%s\"\n",
1108 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1110 * FIXME: need to separate errors from legally
1111 * impossible filters
1113 switch ( bsi->bsi_status ) {
1115 case LDAP_UNDEFINED_TYPE:
1116 case LDAP_NO_SUCH_OBJECT:
1117 /* we are conservative... */
1119 bsi->bsi_status = LDAP_SUCCESS;
1121 return BACKSQL_AVL_CONTINUE;
1123 case LDAP_ADMINLIMIT_EXCEEDED:
1125 /* don't try any more */
1126 return BACKSQL_AVL_STOP;
1130 if ( BER_BVISNULL( &query ) ) {
1131 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1132 "could not construct query for objectclass \"%s\"\n",
1133 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1134 bsi->bsi_status = LDAP_SUCCESS;
1135 return BACKSQL_AVL_CONTINUE;
1138 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n",
1139 query.bv_val, 0, 0 );
1141 rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 );
1142 free( query.bv_val );
1143 BER_BVZERO( &query );
1144 if ( rc != SQL_SUCCESS ) {
1145 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1146 "error preparing query\n", 0, 0, 0 );
1147 backsql_PrintErrors( bi->db_env, bsi->bsi_dbh, sth, rc );
1148 bsi->bsi_status = LDAP_OTHER;
1149 return BACKSQL_AVL_CONTINUE;
1152 Debug( LDAP_DEBUG_TRACE, "id: '%ld'\n", bsi->bsi_oc->bom_id, 0, 0 );
1154 if ( backsql_BindParamID( sth, 1, &bsi->bsi_oc->bom_id ) != SQL_SUCCESS ) {
1155 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1156 "error binding objectclass id parameter\n", 0, 0, 0 );
1157 bsi->bsi_status = LDAP_OTHER;
1158 return BACKSQL_AVL_CONTINUE;
1161 switch ( bsi->bsi_scope ) {
1162 case LDAP_SCOPE_BASE:
1163 case BACKSQL_SCOPE_BASE_LIKE:
1165 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1166 * however this should be handled earlier
1168 if ( bsi->bsi_base_dn->bv_len > BACKSQL_MAX_DN_LEN ) {
1169 bsi->bsi_status = LDAP_OTHER;
1170 return BACKSQL_AVL_CONTINUE;
1173 AC_MEMCPY( temp_base_dn, bsi->bsi_base_dn->bv_val,
1174 bsi->bsi_base_dn->bv_len + 1 );
1176 /* uppercase DN only if the stored DN can be uppercased
1178 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1179 ldap_pvt_str2upper( temp_base_dn );
1182 Debug( LDAP_DEBUG_TRACE, "(base)dn: \"%s\"\n",
1183 temp_base_dn, 0, 0 );
1185 rc = backsql_BindParamStr( sth, 2, temp_base_dn,
1186 BACKSQL_MAX_DN_LEN );
1187 if ( rc != SQL_SUCCESS ) {
1188 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1189 "error binding base_dn parameter\n", 0, 0, 0 );
1190 backsql_PrintErrors( bi->db_env, bsi->bsi_dbh,
1192 bsi->bsi_status = LDAP_OTHER;
1193 return BACKSQL_AVL_CONTINUE;
1197 case LDAP_SCOPE_SUBTREE: {
1199 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1200 * however this should be handled earlier
1202 if ( bsi->bsi_base_dn->bv_len > BACKSQL_MAX_DN_LEN ) {
1203 bsi->bsi_status = LDAP_OTHER;
1204 return BACKSQL_AVL_CONTINUE;
1208 * Sets the parameters for the SQL built earlier
1209 * NOTE that all the databases could actually use
1210 * the TimesTen version, which would be cleaner
1211 * and would also eliminate the need for the
1212 * subtree_cond line in the configuration file.
1213 * For now, I'm leaving it the way it is,
1214 * so non-TimesTen databases use the original code.
1215 * But at some point this should get cleaned up.
1217 * If "dn" is being used, do a suffix search.
1218 * If "dn_ru" is being used, do a prefix search.
1220 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
1221 temp_base_dn[ 0 ] = '\0';
1222 for ( i = 0, j = bsi->bsi_base_dn->bv_len - 1;
1224 temp_base_dn[ i ] = bsi->bsi_base_dn->bv_val[ j ];
1226 temp_base_dn[ i ] = '%';
1227 temp_base_dn[ i + 1 ] = '\0';
1230 temp_base_dn[ 0 ] = '%';
1231 AC_MEMCPY( &temp_base_dn[ 1 ], bsi->bsi_base_dn->bv_val,
1232 bsi->bsi_base_dn->bv_len + 1 );
1235 /* uppercase DN only if the stored DN can be uppercased
1237 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1238 ldap_pvt_str2upper( temp_base_dn );
1241 Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n", temp_base_dn,
1244 rc = backsql_BindParamStr( sth, 2, temp_base_dn,
1245 BACKSQL_MAX_DN_LEN );
1246 if ( rc != SQL_SUCCESS ) {
1247 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1248 "error binding base_dn parameter (2)\n",
1250 backsql_PrintErrors( bi->db_env, bsi->bsi_dbh,
1252 bsi->bsi_status = LDAP_OTHER;
1253 return BACKSQL_AVL_CONTINUE;
1258 case LDAP_SCOPE_ONELEVEL:
1259 res = backsql_dn2id( bi, &base_id,
1260 bsi->bsi_dbh, bsi->bsi_base_dn );
1261 if ( res != LDAP_SUCCESS ) {
1262 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1263 "could not retrieve base_dn id%s\n",
1264 res == LDAP_NO_SUCH_OBJECT ? ": no such entry"
1266 bsi->bsi_status = res;
1267 return BACKSQL_AVL_CONTINUE;
1270 #ifdef BACKSQL_ARBITRARY_KEY
1271 Debug( LDAP_DEBUG_TRACE, "(one)id: \"%s\"\n",
1272 base_id.eid_id.bv_val, 0, 0 );
1274 rc = backsql_BindParamStr( sth, 2, base_id.eid_id.bv_val,
1275 BACKSQL_MAX_KEY_LEN );
1276 #else /* ! BACKSQL_ARBITRARY_KEY */
1277 Debug( LDAP_DEBUG_TRACE, "(one)id: '%lu'\n", base_id.eid_id,
1280 rc = backsql_BindParamID( sth, 2, &base_id.eid_id );
1281 #endif /* ! BACKSQL_ARBITRARY_KEY */
1282 backsql_free_entryID( &base_id, 0 );
1283 if ( rc != SQL_SUCCESS ) {
1284 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1285 "error binding base id parameter\n", 0, 0, 0 );
1286 bsi->bsi_status = LDAP_OTHER;
1287 return BACKSQL_AVL_CONTINUE;
1292 rc = SQLExecute( sth );
1293 if ( !BACKSQL_SUCCESS( rc ) ) {
1294 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1295 "error executing query\n", 0, 0, 0 );
1296 backsql_PrintErrors( bi->db_env, bsi->bsi_dbh, sth, rc );
1297 SQLFreeStmt( sth, SQL_DROP );
1298 bsi->bsi_status = LDAP_OTHER;
1299 return BACKSQL_AVL_CONTINUE;
1302 backsql_BindRowAsStrings( sth, &row );
1303 rc = SQLFetch( sth );
1304 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
1306 backsql_entryID *c_id = NULL;
1308 ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
1310 if ( backsql_api_odbc2dn( bsi->bsi_op, bsi->bsi_rs, &dn ) ) {
1314 c_id = (backsql_entryID *)ch_calloc( 1,
1315 sizeof( backsql_entryID ) );
1316 #ifdef BACKSQL_ARBITRARY_KEY
1317 ber_str2bv( row.cols[ 0 ], 0, 1, &c_id->eid_id );
1318 ber_str2bv( row.cols[ 1 ], 0, 1, &c_id->eid_keyval );
1319 #else /* ! BACKSQL_ARBITRARY_KEY */
1320 c_id->eid_id = strtol( row.cols[ 0 ], NULL, 0 );
1321 c_id->eid_keyval = strtol( row.cols[ 1 ], NULL, 0 );
1322 #endif /* ! BACKSQL_ARBITRARY_KEY */
1323 c_id->eid_oc_id = bsi->bsi_oc->bom_id;
1325 if ( dn.bv_val == row.cols[ 3 ] ) {
1326 ber_dupbv( &c_id->eid_dn, &dn );
1331 /* append at end of list ... */
1332 c_id->eid_next = NULL;
1333 *bsi->bsi_id_listtail = c_id;
1334 bsi->bsi_id_listtail = &c_id->eid_next;
1336 #ifdef BACKSQL_ARBITRARY_KEY
1337 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1338 "added entry id=%s, keyval=%s dn=\"%s\"\n",
1339 c_id->eid_id.bv_val, c_id->eid_keyval.bv_val,
1341 #else /* ! BACKSQL_ARBITRARY_KEY */
1342 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1343 "added entry id=%ld, keyval=%ld dn=\"%s\"\n",
1344 c_id->eid_id, c_id->eid_keyval, row.cols[ 3 ] );
1345 #endif /* ! BACKSQL_ARBITRARY_KEY */
1347 /* count candidates, for unchecked limit */
1348 bsi->bsi_n_candidates--;
1349 if ( bsi->bsi_n_candidates == -1 ) {
1353 backsql_FreeRow( &row );
1354 SQLFreeStmt( sth, SQL_DROP );
1356 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n",
1357 n_candidates - bsi->bsi_n_candidates, 0, 0 );
1359 return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE );
1363 backsql_search( Operation *op, SlapReply *rs )
1365 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
1368 Entry user_entry = { 0 };
1370 time_t stoptime = 0;
1371 backsql_srch_info srch_info;
1372 backsql_entryID *eid = NULL;
1375 manageDSAit = get_manageDSAit( op );
1377 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): "
1378 "base=\"%s\", filter=\"%s\", scope=%d,",
1379 op->o_req_ndn.bv_val,
1380 op->ors_filterstr.bv_val,
1382 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, "
1383 "attributes to load: %s\n",
1386 op->ors_attrs == NULL ? "all" : "custom list" );
1388 if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) {
1389 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1390 "search base length (%ld) exceeds max length (%ld)\n",
1391 op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN, 0 );
1393 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
1394 * since it is impossible that such a long DN exists
1397 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
1398 send_ldap_result( op, rs );
1402 sres = backsql_get_db_conn( op, &dbh );
1403 if ( sres != LDAP_SUCCESS ) {
1404 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1405 "could not get connection handle - exiting\n",
1408 rs->sr_text = sres == LDAP_OTHER ? "SQL-backend error" : NULL;
1409 send_ldap_result( op, rs );
1413 /* compute it anyway; root does not use it */
1414 stoptime = op->o_time + op->ors_tlimit;
1416 base = op->o_req_dn;
1417 if ( backsql_api_dn2odbc( op, rs, &base ) ) {
1418 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1419 "backsql_api_dn2odbc failed\n",
1421 rs->sr_err = LDAP_OTHER;
1422 rs->sr_text = "SQL-backend error";
1423 send_ldap_result( op, rs );
1427 backsql_init_search( &srch_info, &base,
1429 op->ors_slimit, op->ors_tlimit,
1430 stoptime, op->ors_filter,
1431 dbh, op, rs, op->ors_attrs );
1434 * for each objectclass we try to construct query which gets IDs
1435 * of entries matching LDAP query filter and scope (or at least
1436 * candidates), and get the IDs
1438 srch_info.bsi_n_candidates =
1439 ( op->ors_limit == NULL /* isroot == FALSE */ ? -2 :
1440 ( op->ors_limit->lms_s_unchecked == -1 ? -2 :
1441 ( op->ors_limit->lms_s_unchecked ) ) );
1442 avl_apply( bi->oc_by_oc, backsql_oc_get_candidates,
1443 &srch_info, BACKSQL_AVL_STOP, AVL_INORDER );
1444 if ( op->ors_limit != NULL /* isroot == TRUE */
1445 && op->ors_limit->lms_s_unchecked != -1
1446 && srch_info.bsi_n_candidates == -1 )
1448 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
1449 send_ldap_result( op, rs );
1454 * now we load candidate entries (only those attributes
1455 * mentioned in attrs and filter), test it against full filter
1456 * and then send to client
1458 for ( eid = srch_info.bsi_id_list;
1460 eid = backsql_free_entryID( eid, 1 ) )
1463 Attribute *hasSubordinate = NULL,
1466 /* check for abandon */
1467 if ( op->o_abandon ) {
1471 /* check time limit */
1472 if ( op->ors_tlimit != SLAP_NO_LIMIT
1473 && slap_get_time() > stoptime )
1475 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
1476 rs->sr_ctrls = NULL;
1477 rs->sr_ref = rs->sr_v2ref;
1478 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
1480 send_ldap_result( op, rs );
1484 #ifdef BACKSQL_ARBITRARY_KEY
1485 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
1486 "for entry id=%s, oc_id=%ld, keyval=%s\n",
1487 eid->eid_id.bv_val, eid->eid_oc_id,
1488 eid->eid_keyval.bv_val );
1489 #else /* ! BACKSQL_ARBITRARY_KEY */
1490 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
1491 "for entry id=%ld, oc_id=%ld, keyval=%ld\n",
1492 eid->eid_id, eid->eid_oc_id, eid->eid_keyval );
1493 #endif /* ! BACKSQL_ARBITRARY_KEY */
1495 srch_info.bsi_e = &user_entry;
1496 rc = backsql_id2entry( &srch_info, eid );
1497 if ( rc != LDAP_SUCCESS ) {
1498 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1499 "error %d in backsql_id2entry() "
1500 "- skipping\n", rc, 0, 0 );
1504 if ( !manageDSAit &&
1505 op->ors_scope != LDAP_SCOPE_BASE &&
1506 op->ors_scope != BACKSQL_SCOPE_BASE_LIKE &&
1507 is_entry_referral( &user_entry ) )
1510 struct berval matched_dn;
1512 ber_dupbv( &matched_dn, &user_entry.e_name );
1513 refs = get_entry_referrals( op, &user_entry );
1515 backsql_srch_info srch_info2 = { 0 };
1516 Entry user_entry2 = { 0 };
1518 /* retry with the full entry... */
1519 backsql_init_search( &srch_info2,
1523 dbh, op, rs, NULL );
1524 srch_info2.bsi_e = &user_entry2;
1525 rc = backsql_id2entry( &srch_info2, eid );
1526 if ( rc == LDAP_SUCCESS ) {
1527 if ( is_entry_referral( &user_entry2 ) )
1529 refs = get_entry_referrals( op,
1531 } /* else: FIXME: inconsistency! */
1532 entry_clean( &user_entry2 );
1537 rs->sr_ref = referral_rewrite( refs,
1538 &matched_dn, &op->o_req_dn,
1540 ber_bvarray_free( refs );
1543 if ( !rs->sr_ref ) {
1544 rs->sr_text = "bad_referral object";
1547 rs->sr_err = LDAP_REFERRAL;
1548 rs->sr_matched = matched_dn.bv_val;
1549 send_search_reference( op, rs );
1551 ber_bvarray_free( rs->sr_ref );
1553 ber_memfree( matched_dn.bv_val );
1554 rs->sr_matched = NULL;
1560 * We use this flag since we need to parse the filter
1561 * anyway; we should have used the frontend API function
1562 * filter_has_subordinates()
1564 if ( srch_info.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
1565 rc = backsql_has_children( bi, dbh, &user_entry.e_nname );
1568 case LDAP_COMPARE_TRUE:
1569 case LDAP_COMPARE_FALSE:
1570 hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
1571 if ( hasSubordinate != NULL ) {
1572 for ( a = user_entry.e_attrs;
1576 a->a_next = hasSubordinate;
1582 Debug(LDAP_DEBUG_TRACE,
1583 "backsql_search(): "
1584 "has_children failed( %d)\n",
1591 if ( test_filter( op, &user_entry, op->ors_filter )
1592 == LDAP_COMPARE_TRUE ) {
1593 if ( hasSubordinate && !( srch_info.bsi_flags & BSQL_SF_ALL_OPER )
1594 && !ad_inlist( slap_schema.si_ad_hasSubordinates, op->ors_attrs ) ) {
1596 attr_free( hasSubordinate );
1597 hasSubordinate = NULL;
1600 rs->sr_attrs = op->ors_attrs;
1601 rs->sr_operational_attrs = NULL;
1602 rs->sr_entry = &user_entry;
1603 rs->sr_flags = REP_ENTRY_MODIFIABLE;
1604 sres = send_search_entry( op, rs );
1605 rs->sr_entry = NULL;
1606 rs->sr_attrs = NULL;
1607 rs->sr_operational_attrs = NULL;
1615 * FIXME: send_search_entry failed;
1619 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1620 "connection lost\n", 0, 0, 0 );
1626 entry_clean( &user_entry );
1628 if ( op->ors_slimit != SLAP_NO_LIMIT
1629 && rs->sr_nentries >= op->ors_slimit )
1631 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
1632 send_ldap_result( op, rs );
1638 /* in case we got here accidentally */
1639 entry_clean( &user_entry );
1641 if ( rs->sr_nentries > 0 ) {
1642 rs->sr_ref = rs->sr_v2ref;
1643 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
1647 rs->sr_err = srch_info.bsi_status;
1649 send_ldap_result( op, rs );
1651 if ( rs->sr_v2ref ) {
1652 ber_bvarray_free( rs->sr_v2ref );
1653 rs->sr_v2ref = NULL;
1657 ch_free( srch_info.bsi_attrs );
1658 if ( base.bv_val != op->o_req_ndn.bv_val ) {
1659 ch_free( base.bv_val );
1662 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
1666 #endif /* SLAPD_SQL */