2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1999-2013 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"
33 #include "proto-sql.h"
35 static int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
36 static int backsql_process_filter_eq( backsql_srch_info *bsi,
37 backsql_at_map_rec *at,
38 int casefold, struct berval *filter_value );
39 static int backsql_process_filter_like( backsql_srch_info *bsi,
40 backsql_at_map_rec *at,
41 int casefold, struct berval *filter_value );
42 static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f,
43 backsql_at_map_rec *at );
45 /* For LDAP_CONTROL_PAGEDRESULTS, a 32 bit cookie is available to keep track of
46 the state of paged results. The ldap_entries.id and oc_map_id values of the
47 last entry returned are used as the cookie, so 6 bits are used for the OC id
48 and the other 26 for ldap_entries ID number. If your max(oc_map_id) is more
49 than 63, you will need to steal more bits from ldap_entries ID number and
50 put them into the OC ID part of the cookie. */
52 /* NOTE: not supported when BACKSQL_ARBITRARY_KEY is defined */
53 #ifndef BACKSQL_ARBITRARY_KEY
54 #define SQL_TO_PAGECOOKIE(id, oc) (((id) << 6 ) | ((oc) & 0x3F))
55 #define PAGECOOKIE_TO_SQL_ID(pc) ((pc) >> 6)
56 #define PAGECOOKIE_TO_SQL_OC(pc) ((pc) & 0x3F)
58 static int parse_paged_cookie( Operation *op, SlapReply *rs );
60 static void send_paged_response(
64 #endif /* ! BACKSQL_ARBITRARY_KEY */
67 backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
70 AttributeName *an = NULL;
72 if ( bsi->bsi_attrs == NULL ) {
77 * clear the list (retrieve all attrs)
80 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx );
81 bsi->bsi_attrs = NULL;
82 bsi->bsi_flags |= BSQL_SF_ALL_ATTRS;
87 if ( slap_ad_is_binary( ad ) ) {
88 ad = ad->ad_type->sat_ad;
91 for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) {
92 an = &bsi->bsi_attrs[ n_attrs ];
94 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
95 "attribute \"%s\" is in list\n",
96 an->an_name.bv_val, 0, 0 );
98 * We can live with strcmp because the attribute
99 * list has been normalized before calling be_search
101 if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) {
106 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
107 "adding \"%s\" to list\n", ad->ad_cname.bv_val, 0, 0 );
109 an = (AttributeName *)bsi->bsi_op->o_tmprealloc( bsi->bsi_attrs,
110 sizeof( AttributeName ) * ( n_attrs + 2 ),
111 bsi->bsi_op->o_tmpmemctx );
116 an[ n_attrs ].an_name = ad->ad_cname;
117 an[ n_attrs ].an_desc = ad;
118 BER_BVZERO( &an[ n_attrs + 1 ].an_name );
126 * Initializes the search structure.
128 * If get_base_id != 0, the field bsi_base_id is filled
129 * with the entryID of bsi_base_ndn; it must be freed
130 * by backsql_free_entryID() when no longer required.
132 * NOTE: base must be normalized
136 backsql_srch_info *bsi,
137 struct berval *nbase,
144 AttributeName *attrs,
147 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
148 int rc = LDAP_SUCCESS;
150 bsi->bsi_base_ndn = nbase;
151 bsi->bsi_use_subtree_shortcut = 0;
152 BER_BVZERO( &bsi->bsi_base_id.eid_dn );
153 BER_BVZERO( &bsi->bsi_base_id.eid_ndn );
154 bsi->bsi_scope = scope;
155 bsi->bsi_filter = filter;
159 bsi->bsi_flags = BSQL_SF_NONE;
161 bsi->bsi_attrs = NULL;
163 if ( BACKSQL_FETCH_ALL_ATTRS( bi ) ) {
165 * if requested, simply try to fetch all attributes
167 bsi->bsi_flags |= BSQL_SF_ALL_ATTRS;
170 if ( BACKSQL_FETCH_ALL_USERATTRS( bi ) ) {
171 bsi->bsi_flags |= BSQL_SF_ALL_USER;
173 } else if ( BACKSQL_FETCH_ALL_OPATTRS( bi ) ) {
174 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
177 if ( attrs == NULL ) {
178 /* NULL means all user attributes */
179 bsi->bsi_flags |= BSQL_SF_ALL_USER;
185 bsi->bsi_attrs = (AttributeName *)bsi->bsi_op->o_tmpalloc(
186 sizeof( AttributeName ),
187 bsi->bsi_op->o_tmpmemctx );
188 BER_BVZERO( &bsi->bsi_attrs[ 0 ].an_name );
190 for ( p = attrs; !BER_BVISNULL( &p->an_name ); p++ ) {
191 if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) {
193 bsi->bsi_flags |= BSQL_SF_ALL_USER;
195 /* if all attrs are requested, there's
196 * no need to continue */
197 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
198 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
199 bsi->bsi_op->o_tmpmemctx );
200 bsi->bsi_attrs = NULL;
205 } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) {
207 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
209 /* if all attrs are requested, there's
210 * no need to continue */
211 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
212 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
213 bsi->bsi_op->o_tmpmemctx );
214 bsi->bsi_attrs = NULL;
219 } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_no_attrs ) == 0 ) {
223 } else if ( p->an_desc == slap_schema.si_ad_objectClass ) {
227 backsql_attrlist_add( bsi, p->an_desc );
230 if ( got_oc == 0 && !( bsi->bsi_flags & BSQL_SF_ALL_USER ) ) {
231 /* add objectClass if not present,
232 * because it is required to understand
233 * if an entry is a referral, an alias
235 backsql_attrlist_add( bsi, slap_schema.si_ad_objectClass );
239 if ( !BSQL_ISF_ALL_ATTRS( bsi ) && bi->sql_anlist ) {
242 /* use hints if available */
243 for ( p = bi->sql_anlist; !BER_BVISNULL( &p->an_name ); p++ ) {
244 if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) {
246 bsi->bsi_flags |= BSQL_SF_ALL_USER;
248 /* if all attrs are requested, there's
249 * no need to continue */
250 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
251 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
252 bsi->bsi_op->o_tmpmemctx );
253 bsi->bsi_attrs = NULL;
258 } else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) {
260 bsi->bsi_flags |= BSQL_SF_ALL_OPER;
262 /* if all attrs are requested, there's
263 * no need to continue */
264 if ( BSQL_ISF_ALL_ATTRS( bsi ) ) {
265 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
266 bsi->bsi_op->o_tmpmemctx );
267 bsi->bsi_attrs = NULL;
273 backsql_attrlist_add( bsi, p->an_desc );
279 bsi->bsi_id_list = NULL;
280 bsi->bsi_id_listtail = &bsi->bsi_id_list;
281 bsi->bsi_n_candidates = 0;
282 bsi->bsi_stoptime = stoptime;
283 BER_BVZERO( &bsi->bsi_sel.bb_val );
284 bsi->bsi_sel.bb_len = 0;
285 BER_BVZERO( &bsi->bsi_from.bb_val );
286 bsi->bsi_from.bb_len = 0;
287 BER_BVZERO( &bsi->bsi_join_where.bb_val );
288 bsi->bsi_join_where.bb_len = 0;
289 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
290 bsi->bsi_flt_where.bb_len = 0;
291 bsi->bsi_filter_oc = NULL;
293 if ( BACKSQL_IS_GET_ID( flags ) ) {
294 int matched = BACKSQL_IS_MATCHED( flags );
295 int getentry = BACKSQL_IS_GET_ENTRY( flags );
298 assert( op->o_bd->be_private != NULL );
300 rc = backsql_dn2id( op, rs, dbh, nbase, &bsi->bsi_base_id,
303 /* the entry is collected either if requested for by getentry
304 * or if get noSuchObject and requested to climb the tree,
305 * so that a matchedDN or a referral can be returned */
306 if ( ( rc == LDAP_NO_SUCH_OBJECT && matched ) || getentry ) {
307 if ( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ) {
308 assert( bsi->bsi_e != NULL );
310 if ( dn_match( nbase, &bsi->bsi_base_id.eid_ndn ) )
316 * let's see if it is a referral and, in case, get it
318 backsql_attrlist_add( bsi, slap_schema.si_ad_ref );
319 rc = backsql_id2entry( bsi, &bsi->bsi_base_id );
320 if ( rc == LDAP_SUCCESS ) {
321 if ( is_entry_referral( bsi->bsi_e ) )
323 BerVarray erefs = get_entry_referrals( op, bsi->bsi_e );
325 rc = rs->sr_err = LDAP_REFERRAL;
326 rs->sr_ref = referral_rewrite( erefs,
327 &bsi->bsi_e->e_nname,
330 ber_bvarray_free( erefs );
333 rc = rs->sr_err = LDAP_OTHER;
334 rs->sr_text = "bad referral object";
337 } else if ( !gotit ) {
338 rc = rs->sr_err = LDAP_NO_SUCH_OBJECT;
347 if ( gotit && BACKSQL_IS_GET_OC( flags ) ) {
348 bsi->bsi_base_id.eid_oc = backsql_id2oc( bi,
349 bsi->bsi_base_id.eid_oc_id );
350 if ( bsi->bsi_base_id.eid_oc == NULL ) {
352 backsql_free_entryID( &bsi->bsi_base_id, 1,
354 rc = rs->sr_err = LDAP_OTHER;
359 bsi->bsi_status = rc;
367 bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
368 bsi->bsi_op->o_tmpmemctx );
376 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
384 backsql_strfcat_x( &bsi->bsi_flt_where,
385 bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ );
388 res = backsql_process_filter( bsi, f );
391 * TimesTen : If the query has no answers,
392 * don't bother to run the query.
403 case LDAP_FILTER_AND:
404 backsql_strfcat_x( &bsi->bsi_flt_where,
405 bsi->bsi_op->o_tmpmemctx, "l",
406 (ber_len_t)STRLENOF( " AND " ),
411 backsql_strfcat_x( &bsi->bsi_flt_where,
412 bsi->bsi_op->o_tmpmemctx, "l",
413 (ber_len_t)STRLENOF( " OR " ),
419 backsql_strfcat_x( &bsi->bsi_flt_where,
420 bsi->bsi_op->o_tmpmemctx, "c", /* ( */ ')' );
426 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
427 backsql_at_map_rec *at )
429 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
437 /* always uppercase strings by now */
438 #ifdef BACKSQL_UPPERCASE_FILTER
439 if ( f->f_sub_desc->ad_type->sat_substr &&
440 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
441 bi->sql_caseIgnoreMatch ) )
442 #endif /* BACKSQL_UPPERCASE_FILTER */
447 if ( f->f_sub_desc->ad_type->sat_substr &&
448 SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
449 bi->sql_telephoneNumberMatch ) )
456 * to check for matching telephone numbers
457 * with intermixed chars, e.g. val='1234'
460 * val LIKE '%1%2%3%4%'
464 if ( f->f_sub_initial.bv_val ) {
465 bv.bv_len += f->f_sub_initial.bv_len;
467 if ( f->f_sub_any != NULL ) {
468 for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) {
469 bv.bv_len += f->f_sub_any[ a ].bv_len;
472 if ( f->f_sub_final.bv_val ) {
473 bv.bv_len += f->f_sub_final.bv_len;
475 bv.bv_len = 2 * bv.bv_len - 1;
476 bv.bv_val = ch_malloc( bv.bv_len + 1 );
479 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
480 bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ];
481 for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) {
482 bv.bv_val[ s + 2 * i - 1 ] = '%';
483 bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ];
485 bv.bv_val[ s + 2 * i - 1 ] = '%';
489 if ( f->f_sub_any != NULL ) {
490 for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
491 bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ];
492 for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) {
493 bv.bv_val[ s + 2 * i - 1 ] = '%';
494 bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ];
496 bv.bv_val[ s + 2 * i - 1 ] = '%';
501 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
502 bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ];
503 for ( i = 1; i < f->f_sub_final.bv_len; i++ ) {
504 bv.bv_val[ s + 2 * i - 1 ] = '%';
505 bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ];
507 bv.bv_val[ s + 2 * i - 1 ] = '%';
511 bv.bv_val[ s - 1 ] = '\0';
513 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
514 ch_free( bv.bv_val );
520 * When dealing with case-sensitive strings
521 * we may omit normalization; however, normalized
522 * SQL filters are more liberal.
525 backsql_strfcat_x( &bsi->bsi_flt_where,
526 bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ );
529 Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n",
530 at->bam_ad->ad_cname.bv_val, 0, 0 );
531 Debug(LDAP_DEBUG_TRACE, " expr: '%s%s%s'\n", at->bam_sel_expr.bv_val,
532 at->bam_sel_expr_u.bv_val ? "' '" : "",
533 at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" );
534 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
536 * If a pre-upper-cased version of the column
537 * or a precompiled upper function exists, use it
539 backsql_strfcat_x( &bsi->bsi_flt_where,
540 bsi->bsi_op->o_tmpmemctx,
543 (ber_len_t)STRLENOF( " LIKE '" ),
547 backsql_strfcat_x( &bsi->bsi_flt_where,
548 bsi->bsi_op->o_tmpmemctx,
551 (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
554 if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
558 Debug( LDAP_DEBUG_TRACE,
559 "==>backsql_process_sub_filter(%s): "
560 "sub_initial=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
561 f->f_sub_initial.bv_val, 0 );
562 #endif /* BACKSQL_TRACE */
564 start = bsi->bsi_flt_where.bb_val.bv_len;
565 backsql_strfcat_x( &bsi->bsi_flt_where,
566 bsi->bsi_op->o_tmpmemctx,
569 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
570 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
574 backsql_strfcat_x( &bsi->bsi_flt_where,
575 bsi->bsi_op->o_tmpmemctx,
578 if ( f->f_sub_any != NULL ) {
579 for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) {
583 Debug( LDAP_DEBUG_TRACE,
584 "==>backsql_process_sub_filter(%s): "
585 "sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
586 i, f->f_sub_any[ i ].bv_val );
587 #endif /* BACKSQL_TRACE */
589 start = bsi->bsi_flt_where.bb_val.bv_len;
590 backsql_strfcat_x( &bsi->bsi_flt_where,
591 bsi->bsi_op->o_tmpmemctx,
595 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
597 * Note: toupper('%') = '%'
599 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
604 if ( !BER_BVISNULL( &f->f_sub_final ) ) {
608 Debug( LDAP_DEBUG_TRACE,
609 "==>backsql_process_sub_filter(%s): "
610 "sub_final=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
611 f->f_sub_final.bv_val, 0 );
612 #endif /* BACKSQL_TRACE */
614 start = bsi->bsi_flt_where.bb_val.bv_len;
615 backsql_strfcat_x( &bsi->bsi_flt_where,
616 bsi->bsi_op->o_tmpmemctx,
619 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
620 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
624 backsql_strfcat_x( &bsi->bsi_flt_where,
625 bsi->bsi_op->o_tmpmemctx,
627 (ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" );
633 backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls )
635 if ( BER_BVISNULL( from_tbls ) ) {
639 if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) {
643 ber_dupbv_x( &tmp, from_tbls, bsi->bsi_op->o_tmpmemctx );
645 for ( start = tmp.bv_val, end = strchr( start, ',' ); start; ) {
650 if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL )
652 backsql_strfcat_x( &bsi->bsi_from,
653 bsi->bsi_op->o_tmpmemctx,
658 /* in case there are spaces after the comma... */
659 for ( start = &end[1]; isspace( start[0] ); start++ );
661 end = strchr( start, ',' );
670 bsi->bsi_op->o_tmpfree( tmp.bv_val, bsi->bsi_op->o_tmpmemctx );
673 backsql_strfcat_x( &bsi->bsi_from,
674 bsi->bsi_op->o_tmpmemctx,
682 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
684 backsql_at_map_rec **vat = NULL;
685 AttributeDescription *ad = NULL;
690 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 );
691 if ( f->f_choice == SLAPD_FILTER_COMPUTED ) {
695 switch ( f->f_result ) {
696 case LDAP_COMPARE_TRUE:
697 BER_BVSTR( &flt, "10=10" );
701 case LDAP_COMPARE_FALSE:
702 BER_BVSTR( &flt, "11=0" );
706 case SLAPD_COMPARE_UNDEFINED:
707 BER_BVSTR( &flt, "12=0" );
716 Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
717 "filter computed (%s)\n", msg, 0, 0 );
718 backsql_strfcat_x( &bsi->bsi_flt_where,
719 bsi->bsi_op->o_tmpmemctx, "b", &flt );
724 if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
725 backsql_strfcat_x( &bsi->bsi_flt_where,
726 bsi->bsi_op->o_tmpmemctx,
728 (ber_len_t)STRLENOF( "1=0" ), "1=0" );
734 switch( f->f_choice ) {
736 rc = backsql_process_filter_list( bsi, f->f_or,
741 case LDAP_FILTER_AND:
742 rc = backsql_process_filter_list( bsi, f->f_and,
747 case LDAP_FILTER_NOT:
748 backsql_strfcat_x( &bsi->bsi_flt_where,
749 bsi->bsi_op->o_tmpmemctx,
751 (ber_len_t)STRLENOF( "NOT (" /* ) */ ),
753 rc = backsql_process_filter( bsi, f->f_not );
754 backsql_strfcat_x( &bsi->bsi_flt_where,
755 bsi->bsi_op->o_tmpmemctx,
760 case LDAP_FILTER_PRESENT:
764 case LDAP_FILTER_EXT:
765 ad = f->f_mra->ma_desc;
766 if ( f->f_mr_dnattrs ) {
768 * if dn attrs filtering is requested, better return
769 * success and let test_filter() deal with candidate
770 * selection; otherwise we'd need to set conditions
771 * on the contents of the DN, e.g. "SELECT ... FROM
772 * ldap_entries AS attributeName WHERE attributeName.dn
773 * like '%attributeName=value%'"
775 backsql_strfcat_x( &bsi->bsi_flt_where,
776 bsi->bsi_op->o_tmpmemctx,
778 (ber_len_t)STRLENOF( "1=1" ), "1=1" );
779 bsi->bsi_status = LDAP_SUCCESS;
800 * Turn structuralObjectClass into objectClass
802 if ( ad == slap_schema.si_ad_objectClass
803 || ad == slap_schema.si_ad_structuralObjectClass )
806 * If the filter is LDAP_FILTER_PRESENT, then it's done;
807 * otherwise, let's see if we are lucky: filtering
808 * for "structural" objectclass or ancestor...
810 switch ( f->f_choice ) {
811 case LDAP_FILTER_EQUALITY:
813 ObjectClass *oc = oc_bvfind( &f->f_av_value );
816 Debug( LDAP_DEBUG_TRACE,
817 "backsql_process_filter(): "
818 "unknown objectClass \"%s\" "
820 f->f_av_value.bv_val, 0, 0 );
821 bsi->bsi_status = LDAP_OTHER;
827 * "structural" objectClass inheritance:
828 * - a search for "person" will also return
830 * - a search for "top" will return everything
832 if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
833 static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" );
835 backsql_merge_from_tbls( bsi, &ldap_entry_objclasses );
837 backsql_strfcat_x( &bsi->bsi_flt_where,
838 bsi->bsi_op->o_tmpmemctx,
840 (ber_len_t)STRLENOF( "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */ ),
841 "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */,
842 &bsi->bsi_oc->bom_oc->soc_cname,
843 (ber_len_t)STRLENOF( /* ((' */ "'))" ),
845 bsi->bsi_status = LDAP_SUCCESS;
853 case LDAP_FILTER_PRESENT:
854 backsql_strfcat_x( &bsi->bsi_flt_where,
855 bsi->bsi_op->o_tmpmemctx,
857 (ber_len_t)STRLENOF( "3=3" ), "3=3" );
858 bsi->bsi_status = LDAP_SUCCESS;
862 /* FIXME: LDAP_FILTER_EXT? */
865 Debug( LDAP_DEBUG_TRACE,
866 "backsql_process_filter(): "
867 "illegal/unhandled filter "
868 "on objectClass attribute",
870 bsi->bsi_status = LDAP_OTHER;
875 } else if ( ad == slap_schema.si_ad_entryUUID ) {
877 #ifdef BACKSQL_ARBITRARY_KEY
878 struct berval keyval;
879 #else /* ! BACKSQL_ARBITRARY_KEY */
880 unsigned long keyval;
881 char keyvalbuf[LDAP_PVT_INTTYPE_CHARS(unsigned long)];
882 #endif /* ! BACKSQL_ARBITRARY_KEY */
884 switch ( f->f_choice ) {
885 case LDAP_FILTER_EQUALITY:
886 backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval );
888 if ( oc_id != bsi->bsi_oc->bom_id ) {
889 bsi->bsi_status = LDAP_SUCCESS;
894 #ifdef BACKSQL_ARBITRARY_KEY
895 backsql_strfcat_x( &bsi->bsi_flt_where,
896 bsi->bsi_op->o_tmpmemctx,
898 &bsi->bsi_oc->bom_keytbl, '.',
899 &bsi->bsi_oc->bom_keycol,
900 STRLENOF( " LIKE '" ), " LIKE '",
902 #else /* ! BACKSQL_ARBITRARY_KEY */
903 snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval );
904 backsql_strfcat_x( &bsi->bsi_flt_where,
905 bsi->bsi_op->o_tmpmemctx,
907 &bsi->bsi_oc->bom_keytbl, '.',
908 &bsi->bsi_oc->bom_keycol, '=', keyvalbuf );
909 #endif /* ! BACKSQL_ARBITRARY_KEY */
912 case LDAP_FILTER_PRESENT:
913 backsql_strfcat_x( &bsi->bsi_flt_where,
914 bsi->bsi_op->o_tmpmemctx,
916 (ber_len_t)STRLENOF( "4=4" ), "4=4" );
924 bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID;
928 #ifdef BACKSQL_SYNCPROV
929 } else if ( ad == slap_schema.si_ad_entryCSN ) {
931 * support for syncrepl as provider...
934 if ( !bsi->bsi_op->o_sync ) {
935 /* unsupported at present... */
936 bsi->bsi_status = LDAP_OTHER;
942 bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID);
944 /* if doing a syncrepl, try to return as much as possible,
945 * and always match the filter */
946 backsql_strfcat_x( &bsi->bsi_flt_where,
947 bsi->bsi_op->o_tmpmemctx,
949 (ber_len_t)STRLENOF( "5=5" ), "5=5" );
951 /* save for later use in operational attributes */
952 /* FIXME: saves only the first occurrence, because
953 * the filter during updates is written as
954 * "(&(entryCSN<={contextCSN})(entryCSN>={oldContextCSN})({filter}))"
955 * so we want our fake entryCSN to match the greatest
958 if ( bsi->bsi_op->o_private == NULL ) {
959 bsi->bsi_op->o_private = &f->f_av_value;
961 bsi->bsi_status = LDAP_SUCCESS;
965 #endif /* BACKSQL_SYNCPROV */
967 } else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
969 * FIXME: this is not robust; e.g. a filter
970 * '(!(hasSubordinates=TRUE))' fails because
971 * in SQL it would read 'NOT (1=1)' instead
973 * Note however that hasSubordinates is boolean,
974 * so a more appropriate filter would be
975 * '(hasSubordinates=FALSE)'
977 * A more robust search for hasSubordinates
978 * would * require joining the ldap_entries table
979 * selecting if there are descendants of the
982 backsql_strfcat_x( &bsi->bsi_flt_where,
983 bsi->bsi_op->o_tmpmemctx,
985 (ber_len_t)STRLENOF( "6=6" ), "6=6" );
986 if ( ad == slap_schema.si_ad_hasSubordinates ) {
988 * instruct candidate selection algorithm
989 * and attribute list to try to detect
990 * if an entry has subordinates
992 bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
996 * clear attributes to fetch, to require ALL
997 * and try extended match on all attributes
999 backsql_attrlist_add( bsi, NULL );
1006 * attribute inheritance:
1008 if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) {
1009 bsi->bsi_status = LDAP_OTHER;
1014 if ( vat == NULL ) {
1015 /* search anyway; other parts of the filter
1017 backsql_strfcat_x( &bsi->bsi_flt_where,
1018 bsi->bsi_op->o_tmpmemctx,
1020 (ber_len_t)STRLENOF( "7=7" ), "7=7" );
1021 bsi->bsi_status = LDAP_SUCCESS;
1026 /* if required, open extra level of parens */
1028 if ( vat[0]->bam_next || vat[1] ) {
1029 backsql_strfcat_x( &bsi->bsi_flt_where,
1030 bsi->bsi_op->o_tmpmemctx,
1038 if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) {
1042 /* if more definitions of the same attr, apply */
1043 if ( vat[i]->bam_next ) {
1044 backsql_strfcat_x( &bsi->bsi_flt_where,
1045 bsi->bsi_op->o_tmpmemctx,
1047 STRLENOF( " OR " ), " OR " );
1048 vat[i] = vat[i]->bam_next;
1052 /* if more descendants of the same attr, apply */
1055 backsql_strfcat_x( &bsi->bsi_flt_where,
1056 bsi->bsi_op->o_tmpmemctx,
1058 STRLENOF( " OR " ), " OR " );
1062 /* if needed, close extra level of parens */
1064 backsql_strfcat_x( &bsi->bsi_flt_where,
1065 bsi->bsi_op->o_tmpmemctx,
1076 Debug( LDAP_DEBUG_TRACE,
1077 "<==backsql_process_filter() %s\n",
1078 rc == 1 ? "succeeded" : "failed", 0, 0);
1084 backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at,
1085 int casefold, struct berval *filter_value )
1088 * maybe we should check type of at->sel_expr here somehow,
1089 * to know whether upper_func is applicable, but for now
1090 * upper_func stuff is made for Oracle, where UPPER is
1091 * safely applicable to NUMBER etc.
1093 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1096 backsql_strfcat_x( &bsi->bsi_flt_where,
1097 bsi->bsi_op->o_tmpmemctx,
1100 &at->bam_sel_expr_u,
1101 (ber_len_t)STRLENOF( "='" ),
1104 start = bsi->bsi_flt_where.bb_val.bv_len;
1106 backsql_strfcat_x( &bsi->bsi_flt_where,
1107 bsi->bsi_op->o_tmpmemctx,
1110 (ber_len_t)STRLENOF( /* (' */ "')" ),
1113 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1116 backsql_strfcat_x( &bsi->bsi_flt_where,
1117 bsi->bsi_op->o_tmpmemctx,
1121 (ber_len_t)STRLENOF( "='" ), "='",
1123 (ber_len_t)STRLENOF( /* (' */ "')" ),
1131 backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at,
1132 int casefold, struct berval *filter_value )
1135 * maybe we should check type of at->sel_expr here somehow,
1136 * to know whether upper_func is applicable, but for now
1137 * upper_func stuff is made for Oracle, where UPPER is
1138 * safely applicable to NUMBER etc.
1140 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1143 backsql_strfcat_x( &bsi->bsi_flt_where,
1144 bsi->bsi_op->o_tmpmemctx,
1147 &at->bam_sel_expr_u,
1148 (ber_len_t)STRLENOF( " LIKE '%" ),
1151 start = bsi->bsi_flt_where.bb_val.bv_len;
1153 backsql_strfcat_x( &bsi->bsi_flt_where,
1154 bsi->bsi_op->o_tmpmemctx,
1157 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1160 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1163 backsql_strfcat_x( &bsi->bsi_flt_where,
1164 bsi->bsi_op->o_tmpmemctx,
1168 (ber_len_t)STRLENOF( " LIKE '%" ),
1171 (ber_len_t)STRLENOF( /* (' */ "%')" ),
1179 backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at )
1181 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1183 struct berval *filter_value = NULL;
1184 MatchingRule *matching_rule = NULL;
1185 struct berval ordering = BER_BVC("<=");
1187 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter_attr(%s)\n",
1188 at->bam_ad->ad_cname.bv_val, 0, 0 );
1191 * need to add this attribute to list of attrs to load,
1192 * so that we can do test_filter() later
1194 backsql_attrlist_add( bsi, at->bam_ad );
1196 backsql_merge_from_tbls( bsi, &at->bam_from_tbls );
1198 if ( !BER_BVISNULL( &at->bam_join_where )
1199 && strstr( bsi->bsi_join_where.bb_val.bv_val,
1200 at->bam_join_where.bv_val ) == NULL )
1202 backsql_strfcat_x( &bsi->bsi_join_where,
1203 bsi->bsi_op->o_tmpmemctx,
1205 (ber_len_t)STRLENOF( " AND " ), " AND ",
1206 &at->bam_join_where );
1209 if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
1210 backsql_strfcat_x( &bsi->bsi_flt_where,
1211 bsi->bsi_op->o_tmpmemctx,
1213 (ber_len_t)STRLENOF( "1=0" ), "1=0" );
1217 switch ( f->f_choice ) {
1218 case LDAP_FILTER_EQUALITY:
1219 filter_value = &f->f_av_value;
1220 matching_rule = at->bam_ad->ad_type->sat_equality;
1222 goto equality_match;
1224 /* fail over into next case */
1226 case LDAP_FILTER_EXT:
1227 filter_value = &f->f_mra->ma_value;
1228 matching_rule = f->f_mr_rule;
1231 /* always uppercase strings by now */
1232 #ifdef BACKSQL_UPPERCASE_FILTER
1233 if ( SLAP_MR_ASSOCIATED( matching_rule,
1234 bi->sql_caseIgnoreMatch ) )
1235 #endif /* BACKSQL_UPPERCASE_FILTER */
1240 /* FIXME: directoryString filtering should use a similar
1241 * approach to deal with non-prettified values like
1242 * " A non prettified value ", by using a LIKE
1243 * filter with all whitespaces collapsed to a single '%' */
1244 if ( SLAP_MR_ASSOCIATED( matching_rule,
1245 bi->sql_telephoneNumberMatch ) )
1251 * to check for matching telephone numbers
1252 * with intermized chars, e.g. val='1234'
1255 * val LIKE '%1%2%3%4%'
1258 bv.bv_len = 2 * filter_value->bv_len - 1;
1259 bv.bv_val = ch_malloc( bv.bv_len + 1 );
1261 bv.bv_val[ 0 ] = filter_value->bv_val[ 0 ];
1262 for ( i = 1; i < filter_value->bv_len; i++ ) {
1263 bv.bv_val[ 2 * i - 1 ] = '%';
1264 bv.bv_val[ 2 * i ] = filter_value->bv_val[ i ];
1266 bv.bv_val[ 2 * i - 1 ] = '\0';
1268 (void)backsql_process_filter_like( bsi, at, casefold, &bv );
1269 ch_free( bv.bv_val );
1274 /* NOTE: this is required by objectClass inheritance
1275 * and auxiliary objectClass use in filters for slightly
1276 * more efficient candidate selection. */
1277 /* FIXME: a bit too many specializations to deal with
1278 * very specific cases... */
1279 if ( at->bam_ad == slap_schema.si_ad_objectClass
1280 || at->bam_ad == slap_schema.si_ad_structuralObjectClass )
1282 backsql_strfcat_x( &bsi->bsi_flt_where,
1283 bsi->bsi_op->o_tmpmemctx,
1285 (ber_len_t)STRLENOF( "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */ ),
1286 "(ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ') */,
1288 (ber_len_t)STRLENOF( /* (' */ "')" ),
1294 * maybe we should check type of at->sel_expr here somehow,
1295 * to know whether upper_func is applicable, but for now
1296 * upper_func stuff is made for Oracle, where UPPER is
1297 * safely applicable to NUMBER etc.
1299 (void)backsql_process_filter_eq( bsi, at, casefold, filter_value );
1302 case LDAP_FILTER_GE:
1303 ordering.bv_val = ">=";
1305 /* fall thru to next case */
1307 case LDAP_FILTER_LE:
1308 filter_value = &f->f_av_value;
1310 /* always uppercase strings by now */
1311 #ifdef BACKSQL_UPPERCASE_FILTER
1312 if ( at->bam_ad->ad_type->sat_ordering &&
1313 SLAP_MR_ASSOCIATED( at->bam_ad->ad_type->sat_ordering,
1314 bi->sql_caseIgnoreMatch ) )
1315 #endif /* BACKSQL_UPPERCASE_FILTER */
1321 * FIXME: should we uppercase the operands?
1323 if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
1326 backsql_strfcat_x( &bsi->bsi_flt_where,
1327 bsi->bsi_op->o_tmpmemctx,
1330 &at->bam_sel_expr_u,
1334 start = bsi->bsi_flt_where.bb_val.bv_len;
1336 backsql_strfcat_x( &bsi->bsi_flt_where,
1337 bsi->bsi_op->o_tmpmemctx,
1340 (ber_len_t)STRLENOF( /* (' */ "')" ),
1343 ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
1346 backsql_strfcat_x( &bsi->bsi_flt_where,
1347 bsi->bsi_op->o_tmpmemctx,
1354 (ber_len_t)STRLENOF( /* (' */ "')" ),
1359 case LDAP_FILTER_PRESENT:
1360 backsql_strfcat_x( &bsi->bsi_flt_where,
1361 bsi->bsi_op->o_tmpmemctx,
1363 (ber_len_t)STRLENOF( "NOT (" /* ) */),
1366 (ber_len_t)STRLENOF( /* ( */ " IS NULL)" ),
1367 /* ( */ " IS NULL)" );
1370 case LDAP_FILTER_SUBSTRINGS:
1371 backsql_process_sub_filter( bsi, f, at );
1374 case LDAP_FILTER_APPROX:
1375 /* we do our best */
1378 * maybe we should check type of at->sel_expr here somehow,
1379 * to know whether upper_func is applicable, but for now
1380 * upper_func stuff is made for Oracle, where UPPER is
1381 * safely applicable to NUMBER etc.
1383 (void)backsql_process_filter_like( bsi, at, 1, &f->f_av_value );
1387 /* unhandled filter type; should not happen */
1389 backsql_strfcat_x( &bsi->bsi_flt_where,
1390 bsi->bsi_op->o_tmpmemctx,
1392 (ber_len_t)STRLENOF( "8=8" ), "8=8" );
1397 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter_attr(%s)\n",
1398 at->bam_ad->ad_cname.bv_val, 0, 0 );
1404 backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
1406 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1409 assert( query != NULL );
1410 BER_BVZERO( query );
1412 bsi->bsi_use_subtree_shortcut = 0;
1414 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n", 0, 0, 0 );
1415 BER_BVZERO( &bsi->bsi_sel.bb_val );
1416 BER_BVZERO( &bsi->bsi_sel.bb_val );
1417 bsi->bsi_sel.bb_len = 0;
1418 BER_BVZERO( &bsi->bsi_from.bb_val );
1419 bsi->bsi_from.bb_len = 0;
1420 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1421 bsi->bsi_join_where.bb_len = 0;
1422 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1423 bsi->bsi_flt_where.bb_len = 0;
1425 backsql_strfcat_x( &bsi->bsi_sel,
1426 bsi->bsi_op->o_tmpmemctx,
1428 (ber_len_t)STRLENOF( "SELECT DISTINCT ldap_entries.id," ),
1429 "SELECT DISTINCT ldap_entries.id,",
1430 &bsi->bsi_oc->bom_keytbl,
1432 &bsi->bsi_oc->bom_keycol,
1435 if ( !BER_BVISNULL( &bi->sql_strcast_func ) ) {
1436 backsql_strfcat_x( &bsi->bsi_sel,
1437 bsi->bsi_op->o_tmpmemctx,
1439 &bi->sql_strcast_func,
1440 (ber_len_t)STRLENOF( "('" /* ') */ ),
1442 &bsi->bsi_oc->bom_oc->soc_cname,
1443 (ber_len_t)STRLENOF( /* (' */ "')" ),
1446 backsql_strfcat_x( &bsi->bsi_sel,
1447 bsi->bsi_op->o_tmpmemctx,
1450 &bsi->bsi_oc->bom_oc->soc_cname,
1454 backsql_strfcat_x( &bsi->bsi_sel,
1455 bsi->bsi_op->o_tmpmemctx,
1457 &bi->sql_dn_oc_aliasing );
1458 backsql_strfcat_x( &bsi->bsi_from,
1459 bsi->bsi_op->o_tmpmemctx,
1461 (ber_len_t)STRLENOF( " FROM ldap_entries," ),
1462 " FROM ldap_entries,",
1463 &bsi->bsi_oc->bom_keytbl );
1465 backsql_strfcat_x( &bsi->bsi_join_where,
1466 bsi->bsi_op->o_tmpmemctx,
1468 (ber_len_t)STRLENOF( " WHERE " ), " WHERE ",
1469 &bsi->bsi_oc->bom_keytbl,
1471 &bsi->bsi_oc->bom_keycol,
1472 (ber_len_t)STRLENOF( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ),
1473 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
1475 switch ( bsi->bsi_scope ) {
1476 case LDAP_SCOPE_BASE:
1477 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1478 backsql_strfcat_x( &bsi->bsi_join_where,
1479 bsi->bsi_op->o_tmpmemctx,
1481 &bi->sql_upper_func,
1482 (ber_len_t)STRLENOF( "(ldap_entries.dn)=?" ),
1483 "(ldap_entries.dn)=?" );
1485 backsql_strfcat_x( &bsi->bsi_join_where,
1486 bsi->bsi_op->o_tmpmemctx,
1488 (ber_len_t)STRLENOF( "ldap_entries.dn=?" ),
1489 "ldap_entries.dn=?" );
1493 case BACKSQL_SCOPE_BASE_LIKE:
1494 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1495 backsql_strfcat_x( &bsi->bsi_join_where,
1496 bsi->bsi_op->o_tmpmemctx,
1498 &bi->sql_upper_func,
1499 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1500 "(ldap_entries.dn) LIKE ?" );
1502 backsql_strfcat_x( &bsi->bsi_join_where,
1503 bsi->bsi_op->o_tmpmemctx,
1505 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1506 "ldap_entries.dn LIKE ?" );
1510 case LDAP_SCOPE_ONELEVEL:
1511 backsql_strfcat_x( &bsi->bsi_join_where,
1512 bsi->bsi_op->o_tmpmemctx,
1514 (ber_len_t)STRLENOF( "ldap_entries.parent=?" ),
1515 "ldap_entries.parent=?" );
1518 case LDAP_SCOPE_SUBORDINATE:
1519 case LDAP_SCOPE_SUBTREE:
1520 if ( BACKSQL_USE_SUBTREE_SHORTCUT( bi ) ) {
1522 BackendDB *bd = bsi->bsi_op->o_bd;
1524 assert( bd->be_nsuffix != NULL );
1526 for ( i = 0; !BER_BVISNULL( &bd->be_nsuffix[ i ] ); i++ )
1528 if ( dn_match( &bd->be_nsuffix[ i ],
1529 bsi->bsi_base_ndn ) )
1531 /* pass this to the candidate selection
1532 * routine so that the DN is not bound
1533 * to the select statement */
1534 bsi->bsi_use_subtree_shortcut = 1;
1540 if ( bsi->bsi_use_subtree_shortcut ) {
1541 /* Skip the base DN filter, as every entry will match it */
1542 backsql_strfcat_x( &bsi->bsi_join_where,
1543 bsi->bsi_op->o_tmpmemctx,
1545 (ber_len_t)STRLENOF( "9=9"), "9=9");
1547 } else if ( !BER_BVISNULL( &bi->sql_subtree_cond ) ) {
1548 /* This should always be true... */
1549 backsql_strfcat_x( &bsi->bsi_join_where,
1550 bsi->bsi_op->o_tmpmemctx,
1552 &bi->sql_subtree_cond );
1554 } else if ( BACKSQL_CANUPPERCASE( bi ) ) {
1555 backsql_strfcat_x( &bsi->bsi_join_where,
1556 bsi->bsi_op->o_tmpmemctx,
1558 &bi->sql_upper_func,
1559 (ber_len_t)STRLENOF( "(ldap_entries.dn) LIKE ?" ),
1560 "(ldap_entries.dn) LIKE ?" );
1563 backsql_strfcat_x( &bsi->bsi_join_where,
1564 bsi->bsi_op->o_tmpmemctx,
1566 (ber_len_t)STRLENOF( "ldap_entries.dn LIKE ?" ),
1567 "ldap_entries.dn LIKE ?" );
1576 #ifndef BACKSQL_ARBITRARY_KEY
1577 /* If paged results are in effect, ignore low ldap_entries.id numbers */
1578 if ( get_pagedresults(bsi->bsi_op) > SLAP_CONTROL_IGNORED ) {
1579 unsigned long lowid = 0;
1581 /* Pick up the previous ldap_entries.id if the previous page ended in this objectClass */
1582 if ( bsi->bsi_oc->bom_id == PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie ) )
1584 lowid = PAGECOOKIE_TO_SQL_ID( ((PagedResultsState *)bsi->bsi_op->o_pagedresults_state)->ps_cookie );
1588 char lowidstring[48];
1591 lowidlen = snprintf( lowidstring, sizeof( lowidstring ),
1592 " AND ldap_entries.id>%lu", lowid );
1593 backsql_strfcat_x( &bsi->bsi_join_where,
1594 bsi->bsi_op->o_tmpmemctx,
1596 (ber_len_t)lowidlen,
1600 #endif /* ! BACKSQL_ARBITRARY_KEY */
1602 rc = backsql_process_filter( bsi, bsi->bsi_filter );
1604 struct berbuf bb = BB_NULL;
1606 backsql_strfcat_x( &bb,
1607 bsi->bsi_op->o_tmpmemctx,
1609 &bsi->bsi_sel.bb_val,
1610 &bsi->bsi_from.bb_val,
1611 &bsi->bsi_join_where.bb_val,
1612 (ber_len_t)STRLENOF( " AND " ), " AND ",
1613 &bsi->bsi_flt_where.bb_val );
1617 } else if ( rc < 0 ) {
1619 * Indicates that there's no possible way the filter matches
1620 * anything. No need to issue the query
1622 free( query->bv_val );
1623 BER_BVZERO( query );
1626 bsi->bsi_op->o_tmpfree( bsi->bsi_sel.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
1627 BER_BVZERO( &bsi->bsi_sel.bb_val );
1628 bsi->bsi_sel.bb_len = 0;
1629 bsi->bsi_op->o_tmpfree( bsi->bsi_from.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
1630 BER_BVZERO( &bsi->bsi_from.bb_val );
1631 bsi->bsi_from.bb_len = 0;
1632 bsi->bsi_op->o_tmpfree( bsi->bsi_join_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
1633 BER_BVZERO( &bsi->bsi_join_where.bb_val );
1634 bsi->bsi_join_where.bb_len = 0;
1635 bsi->bsi_op->o_tmpfree( bsi->bsi_flt_where.bb_val.bv_val, bsi->bsi_op->o_tmpmemctx );
1636 BER_BVZERO( &bsi->bsi_flt_where.bb_val );
1637 bsi->bsi_flt_where.bb_len = 0;
1639 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query() returns %s\n",
1640 query->bv_val ? query->bv_val : "NULL", 0, 0 );
1642 return ( rc <= 0 ? 1 : 0 );
1646 backsql_oc_get_candidates( void *v_oc, void *v_bsi )
1648 backsql_oc_map_rec *oc = v_oc;
1649 backsql_srch_info *bsi = v_bsi;
1650 Operation *op = bsi->bsi_op;
1651 backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
1652 struct berval query;
1653 SQLHSTMT sth = SQL_NULL_HSTMT;
1656 BACKSQL_ROW_NTS row;
1659 int n_candidates = bsi->bsi_n_candidates;
1662 * + 1 because we need room for '%';
1663 * + 1 because we need room for ',' for LDAP_SCOPE_SUBORDINATE;
1664 * this makes a subtree
1665 * search for a DN BACKSQL_MAX_DN_LEN long legal
1666 * if it returns that DN only
1668 char tmp_base_ndn[ BACKSQL_MAX_DN_LEN + 1 + 1 ];
1670 bsi->bsi_status = LDAP_SUCCESS;
1672 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc=\"%s\"\n",
1673 BACKSQL_OC_NAME( oc ), 0, 0 );
1675 /* check for abandon */
1676 if ( op->o_abandon ) {
1677 bsi->bsi_status = SLAPD_ABANDON;
1678 return BACKSQL_AVL_STOP;
1681 #ifndef BACKSQL_ARBITRARY_KEY
1682 /* If paged results have already completed this objectClass, skip it */
1683 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
1684 if ( oc->bom_id < PAGECOOKIE_TO_SQL_OC( ((PagedResultsState *)op->o_pagedresults_state)->ps_cookie ) )
1686 return BACKSQL_AVL_CONTINUE;
1689 #endif /* ! BACKSQL_ARBITRARY_KEY */
1691 if ( bsi->bsi_n_candidates == -1 ) {
1692 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1693 "unchecked limit has been overcome\n", 0, 0, 0 );
1694 /* should never get here */
1696 bsi->bsi_status = LDAP_ADMINLIMIT_EXCEEDED;
1697 return BACKSQL_AVL_STOP;
1701 res = backsql_srch_query( bsi, &query );
1703 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1704 "error while constructing query for objectclass \"%s\"\n",
1705 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1707 * FIXME: need to separate errors from legally
1708 * impossible filters
1710 switch ( bsi->bsi_status ) {
1712 case LDAP_UNDEFINED_TYPE:
1713 case LDAP_NO_SUCH_OBJECT:
1714 /* we are conservative... */
1716 bsi->bsi_status = LDAP_SUCCESS;
1718 return BACKSQL_AVL_CONTINUE;
1720 case LDAP_ADMINLIMIT_EXCEEDED:
1722 /* don't try any more */
1723 return BACKSQL_AVL_STOP;
1727 if ( BER_BVISNULL( &query ) ) {
1728 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1729 "could not construct query for objectclass \"%s\"\n",
1730 oc->bom_oc->soc_cname.bv_val, 0, 0 );
1731 bsi->bsi_status = LDAP_SUCCESS;
1732 return BACKSQL_AVL_CONTINUE;
1735 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n",
1736 query.bv_val, 0, 0 );
1738 rc = backsql_Prepare( bsi->bsi_dbh, &sth, query.bv_val, 0 );
1739 bsi->bsi_op->o_tmpfree( query.bv_val, bsi->bsi_op->o_tmpmemctx );
1740 BER_BVZERO( &query );
1741 if ( rc != SQL_SUCCESS ) {
1742 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1743 "error preparing query\n", 0, 0, 0 );
1744 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1745 bsi->bsi_status = LDAP_OTHER;
1746 return BACKSQL_AVL_CONTINUE;
1749 Debug( LDAP_DEBUG_TRACE, "id: '" BACKSQL_IDNUMFMT "'\n",
1750 bsi->bsi_oc->bom_id, 0, 0 );
1752 rc = backsql_BindParamNumID( sth, 1, SQL_PARAM_INPUT,
1753 &bsi->bsi_oc->bom_id );
1754 if ( rc != SQL_SUCCESS ) {
1755 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1756 "error binding objectclass id parameter\n", 0, 0, 0 );
1757 bsi->bsi_status = LDAP_OTHER;
1758 return BACKSQL_AVL_CONTINUE;
1761 switch ( bsi->bsi_scope ) {
1762 case LDAP_SCOPE_BASE:
1763 case BACKSQL_SCOPE_BASE_LIKE:
1765 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1766 * however this should be handled earlier
1768 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1769 bsi->bsi_status = LDAP_OTHER;
1770 return BACKSQL_AVL_CONTINUE;
1773 AC_MEMCPY( tmp_base_ndn, bsi->bsi_base_ndn->bv_val,
1774 bsi->bsi_base_ndn->bv_len + 1 );
1776 /* uppercase DN only if the stored DN can be uppercased
1778 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1779 ldap_pvt_str2upper( tmp_base_ndn );
1782 Debug( LDAP_DEBUG_TRACE, "(base)dn: \"%s\"\n",
1783 tmp_base_ndn, 0, 0 );
1785 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1786 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1787 if ( rc != SQL_SUCCESS ) {
1788 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1789 "error binding base_ndn parameter\n", 0, 0, 0 );
1790 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1792 bsi->bsi_status = LDAP_OTHER;
1793 return BACKSQL_AVL_CONTINUE;
1797 case LDAP_SCOPE_SUBORDINATE:
1798 case LDAP_SCOPE_SUBTREE:
1800 /* if short-cutting the search base,
1801 * don't bind any parameter */
1802 if ( bsi->bsi_use_subtree_shortcut ) {
1807 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
1808 * however this should be handled earlier
1810 if ( bsi->bsi_base_ndn->bv_len > BACKSQL_MAX_DN_LEN ) {
1811 bsi->bsi_status = LDAP_OTHER;
1812 return BACKSQL_AVL_CONTINUE;
1816 * Sets the parameters for the SQL built earlier
1817 * NOTE that all the databases could actually use
1818 * the TimesTen version, which would be cleaner
1819 * and would also eliminate the need for the
1820 * subtree_cond line in the configuration file.
1821 * For now, I'm leaving it the way it is,
1822 * so non-TimesTen databases use the original code.
1823 * But at some point this should get cleaned up.
1825 * If "dn" is being used, do a suffix search.
1826 * If "dn_ru" is being used, do a prefix search.
1828 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bi ) ) {
1829 tmp_base_ndn[ 0 ] = '\0';
1831 for ( i = 0, j = bsi->bsi_base_ndn->bv_len - 1;
1833 tmp_base_ndn[ i ] = bsi->bsi_base_ndn->bv_val[ j ];
1836 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1837 tmp_base_ndn[ i++ ] = ',';
1840 tmp_base_ndn[ i ] = '%';
1841 tmp_base_ndn[ i + 1 ] = '\0';
1846 tmp_base_ndn[ i++ ] = '%';
1848 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1849 tmp_base_ndn[ i++ ] = ',';
1852 AC_MEMCPY( &tmp_base_ndn[ i ], bsi->bsi_base_ndn->bv_val,
1853 bsi->bsi_base_ndn->bv_len + 1 );
1856 /* uppercase DN only if the stored DN can be uppercased
1858 if ( BACKSQL_CANUPPERCASE( bi ) ) {
1859 ldap_pvt_str2upper( tmp_base_ndn );
1862 if ( bsi->bsi_scope == LDAP_SCOPE_SUBORDINATE ) {
1863 Debug( LDAP_DEBUG_TRACE, "(children)dn: \"%s\"\n",
1864 tmp_base_ndn, 0, 0 );
1866 Debug( LDAP_DEBUG_TRACE, "(sub)dn: \"%s\"\n",
1867 tmp_base_ndn, 0, 0 );
1870 rc = backsql_BindParamStr( sth, 2, SQL_PARAM_INPUT,
1871 tmp_base_ndn, BACKSQL_MAX_DN_LEN );
1872 if ( rc != SQL_SUCCESS ) {
1873 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1874 "error binding base_ndn parameter (2)\n",
1876 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh,
1878 bsi->bsi_status = LDAP_OTHER;
1879 return BACKSQL_AVL_CONTINUE;
1884 case LDAP_SCOPE_ONELEVEL:
1885 assert( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) );
1887 Debug( LDAP_DEBUG_TRACE, "(one)id=" BACKSQL_IDFMT "\n",
1888 BACKSQL_IDARG(bsi->bsi_base_id.eid_id), 0, 0 );
1889 rc = backsql_BindParamID( sth, 2, SQL_PARAM_INPUT,
1890 &bsi->bsi_base_id.eid_id );
1891 if ( rc != SQL_SUCCESS ) {
1892 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1893 "error binding base id parameter\n", 0, 0, 0 );
1894 bsi->bsi_status = LDAP_OTHER;
1895 return BACKSQL_AVL_CONTINUE;
1900 rc = SQLExecute( sth );
1901 if ( !BACKSQL_SUCCESS( rc ) ) {
1902 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1903 "error executing query\n", 0, 0, 0 );
1904 backsql_PrintErrors( bi->sql_db_env, bsi->bsi_dbh, sth, rc );
1905 SQLFreeStmt( sth, SQL_DROP );
1906 bsi->bsi_status = LDAP_OTHER;
1907 return BACKSQL_AVL_CONTINUE;
1910 backsql_BindRowAsStrings_x( sth, &row, bsi->bsi_op->o_tmpmemctx );
1911 rc = SQLFetch( sth );
1912 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
1913 struct berval dn, pdn, ndn;
1914 backsql_entryID *c_id = NULL;
1917 ber_str2bv( row.cols[ 3 ], 0, 0, &dn );
1919 if ( backsql_api_odbc2dn( bsi->bsi_op, bsi->bsi_rs, &dn ) ) {
1923 ret = dnPrettyNormal( NULL, &dn, &pdn, &ndn, op->o_tmpmemctx );
1924 if ( dn.bv_val != row.cols[ 3 ] ) {
1928 if ( ret != LDAP_SUCCESS ) {
1932 if ( bi->sql_baseObject && dn_match( &ndn, &bi->sql_baseObject->e_nname ) ) {
1936 c_id = (backsql_entryID *)op->o_tmpcalloc( 1,
1937 sizeof( backsql_entryID ), op->o_tmpmemctx );
1938 #ifdef BACKSQL_ARBITRARY_KEY
1939 ber_str2bv_x( row.cols[ 0 ], 0, 1, &c_id->eid_id,
1941 ber_str2bv_x( row.cols[ 1 ], 0, 1, &c_id->eid_keyval,
1943 #else /* ! BACKSQL_ARBITRARY_KEY */
1944 if ( BACKSQL_STR2ID( &c_id->eid_id, row.cols[ 0 ], 0 ) != 0 ) {
1947 if ( BACKSQL_STR2ID( &c_id->eid_keyval, row.cols[ 1 ], 0 ) != 0 ) {
1950 #endif /* ! BACKSQL_ARBITRARY_KEY */
1951 c_id->eid_oc = bsi->bsi_oc;
1952 c_id->eid_oc_id = bsi->bsi_oc->bom_id;
1955 c_id->eid_ndn = ndn;
1957 /* append at end of list ... */
1958 c_id->eid_next = NULL;
1959 *bsi->bsi_id_listtail = c_id;
1960 bsi->bsi_id_listtail = &c_id->eid_next;
1962 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
1963 "added entry id=" BACKSQL_IDFMT " keyval=" BACKSQL_IDFMT " dn=\"%s\"\n",
1964 BACKSQL_IDARG(c_id->eid_id),
1965 BACKSQL_IDARG(c_id->eid_keyval),
1968 /* count candidates, for unchecked limit */
1969 bsi->bsi_n_candidates--;
1970 if ( bsi->bsi_n_candidates == -1 ) {
1976 if ( !BER_BVISNULL( &pdn ) ) {
1977 op->o_tmpfree( pdn.bv_val, op->o_tmpmemctx );
1979 if ( !BER_BVISNULL( &ndn ) ) {
1980 op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
1982 if ( c_id != NULL ) {
1986 backsql_FreeRow_x( &row, bsi->bsi_op->o_tmpmemctx );
1987 SQLFreeStmt( sth, SQL_DROP );
1989 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates(): %d\n",
1990 n_candidates - bsi->bsi_n_candidates, 0, 0 );
1992 return ( bsi->bsi_n_candidates == -1 ? BACKSQL_AVL_STOP : BACKSQL_AVL_CONTINUE );
1996 backsql_search( Operation *op, SlapReply *rs )
1998 backsql_info *bi = (backsql_info *)op->o_bd->be_private;
1999 SQLHDBC dbh = SQL_NULL_HDBC;
2001 Entry user_entry = { 0 },
2003 int manageDSAit = get_manageDSAit( op );
2004 time_t stoptime = 0;
2005 backsql_srch_info bsi = { 0 };
2006 backsql_entryID *eid = NULL;
2007 struct berval nbase = BER_BVNULL;
2008 #ifndef BACKSQL_ARBITRARY_KEY
2010 #endif /* ! BACKSQL_ARBITRARY_KEY */
2012 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): "
2013 "base=\"%s\", filter=\"%s\", scope=%d,",
2014 op->o_req_ndn.bv_val,
2015 op->ors_filterstr.bv_val,
2017 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, "
2018 "attributes to load: %s\n",
2021 op->ors_attrs == NULL ? "all" : "custom list" );
2023 if ( op->o_req_ndn.bv_len > BACKSQL_MAX_DN_LEN ) {
2024 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2025 "search base length (%ld) exceeds max length (%d)\n",
2026 op->o_req_ndn.bv_len, BACKSQL_MAX_DN_LEN, 0 );
2028 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
2029 * since it is impossible that such a long DN exists
2032 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
2033 send_ldap_result( op, rs );
2037 sres = backsql_get_db_conn( op, &dbh );
2038 if ( sres != LDAP_SUCCESS ) {
2039 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2040 "could not get connection handle - exiting\n",
2043 rs->sr_text = sres == LDAP_OTHER ? "SQL-backend error" : NULL;
2044 send_ldap_result( op, rs );
2048 /* compute it anyway; root does not use it */
2049 stoptime = op->o_time + op->ors_tlimit;
2052 bsi.bsi_e = &base_entry;
2053 rs->sr_err = backsql_init_search( &bsi, &op->o_req_ndn,
2055 stoptime, op->ors_filter,
2056 dbh, op, rs, op->ors_attrs,
2057 ( BACKSQL_ISF_MATCHED | BACKSQL_ISF_GET_ENTRY ) );
2058 switch ( rs->sr_err ) {
2063 if ( manageDSAit && !BER_BVISNULL( &bsi.bsi_e->e_nname ) &&
2064 dn_match( &op->o_req_ndn, &bsi.bsi_e->e_nname ) )
2066 rs->sr_err = LDAP_SUCCESS;
2068 rs->sr_matched = NULL;
2070 ber_bvarray_free( rs->sr_ref );
2076 /* an entry was created; free it */
2077 entry_clean( bsi.bsi_e );
2082 if ( !BER_BVISNULL( &base_entry.e_nname )
2083 && !access_allowed( op, &base_entry,
2084 slap_schema.si_ad_entry, NULL,
2085 ACL_DISCLOSE, NULL ) )
2087 rs->sr_err = LDAP_NO_SUCH_OBJECT;
2089 ber_bvarray_free( rs->sr_ref );
2092 rs->sr_matched = NULL;
2096 send_ldap_result( op, rs );
2099 ber_bvarray_free( rs->sr_ref );
2103 if ( !BER_BVISNULL( &base_entry.e_nname ) ) {
2104 entry_clean( &base_entry );
2109 /* NOTE: __NEW__ "search" access is required
2110 * on searchBase object */
2114 if ( get_assert( op ) &&
2115 ( test_filter( op, &base_entry, get_assertion( op ) )
2116 != LDAP_COMPARE_TRUE ) )
2118 rs->sr_err = LDAP_ASSERTION_FAILED;
2121 if ( ! access_allowed_mask( op, &base_entry,
2122 slap_schema.si_ad_entry,
2123 NULL, ACL_SEARCH, NULL, &mask ) )
2125 if ( rs->sr_err == LDAP_SUCCESS ) {
2126 rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
2130 if ( rs->sr_err != LDAP_SUCCESS ) {
2131 if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
2132 rs->sr_err = LDAP_NO_SUCH_OBJECT;
2135 send_ldap_result( op, rs );
2142 bsi.bsi_n_candidates =
2143 ( op->ors_limit == NULL /* isroot == TRUE */ ? -2 :
2144 ( op->ors_limit->lms_s_unchecked == -1 ? -2 :
2145 ( op->ors_limit->lms_s_unchecked ) ) );
2147 #ifndef BACKSQL_ARBITRARY_KEY
2148 /* If paged results are in effect, check the paging cookie */
2149 if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
2150 rs->sr_err = parse_paged_cookie( op, rs );
2151 if ( rs->sr_err != LDAP_SUCCESS ) {
2152 send_ldap_result( op, rs );
2156 #endif /* ! BACKSQL_ARBITRARY_KEY */
2158 switch ( bsi.bsi_scope ) {
2159 case LDAP_SCOPE_BASE:
2160 case BACKSQL_SCOPE_BASE_LIKE:
2162 * probably already found...
2164 bsi.bsi_id_list = &bsi.bsi_base_id;
2165 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
2168 case LDAP_SCOPE_SUBTREE:
2170 * if baseObject is defined, and if it is the root
2171 * of the search, add it to the candidate list
2173 if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &bsi.bsi_base_id.eid_id ) )
2175 bsi.bsi_id_list = &bsi.bsi_base_id;
2176 bsi.bsi_id_listtail = &bsi.bsi_base_id.eid_next;
2183 * for each objectclass we try to construct query which gets IDs
2184 * of entries matching LDAP query filter and scope (or at least
2185 * candidates), and get the IDs. Do this in ID order for paging.
2187 avl_apply( bi->sql_oc_by_id, backsql_oc_get_candidates,
2188 &bsi, BACKSQL_AVL_STOP, AVL_INORDER );
2190 /* check for abandon */
2191 if ( op->o_abandon ) {
2192 eid = bsi.bsi_id_list;
2193 rs->sr_err = SLAPD_ABANDON;
2198 if ( op->ors_limit != NULL /* isroot == FALSE */
2199 && op->ors_limit->lms_s_unchecked != -1
2200 && bsi.bsi_n_candidates == -1 )
2202 rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
2203 send_ldap_result( op, rs );
2208 * now we load candidate entries (only those attributes
2209 * mentioned in attrs and filter), test it against full filter
2210 * and then send to client; don't free entry_id if baseObject...
2212 for ( eid = bsi.bsi_id_list;
2214 eid = backsql_free_entryID(
2215 eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) )
2218 Attribute *a_hasSubordinate = NULL,
2219 *a_entryUUID = NULL,
2224 /* check for abandon */
2225 if ( op->o_abandon ) {
2226 rs->sr_err = SLAPD_ABANDON;
2230 /* check time limit */
2231 if ( op->ors_tlimit != SLAP_NO_LIMIT
2232 && slap_get_time() > stoptime )
2234 rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
2235 rs->sr_ctrls = NULL;
2236 rs->sr_ref = rs->sr_v2ref;
2240 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
2241 "for entry id=" BACKSQL_IDFMT " oc_id=" BACKSQL_IDNUMFMT ", keyval=" BACKSQL_IDFMT "\n",
2242 BACKSQL_IDARG(eid->eid_id),
2244 BACKSQL_IDARG(eid->eid_keyval) );
2247 switch ( op->ors_scope ) {
2248 case LDAP_SCOPE_BASE:
2249 case BACKSQL_SCOPE_BASE_LIKE:
2250 if ( !dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
2255 case LDAP_SCOPE_ONE:
2257 struct berval rdn = eid->eid_ndn;
2259 rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
2260 if ( !dnIsOneLevelRDN( &rdn ) ) {
2266 case LDAP_SCOPE_SUBORDINATE:
2267 /* discard the baseObject entry */
2268 if ( dn_match( &eid->eid_ndn, &op->o_req_ndn ) ) {
2272 case LDAP_SCOPE_SUBTREE:
2273 /* FIXME: this should never fail... */
2274 if ( !dnIsSuffix( &eid->eid_ndn, &op->o_req_ndn ) ) {
2280 if ( BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) {
2281 /* don't recollect baseObject... */
2282 e = bi->sql_baseObject;
2284 } else if ( eid == &bsi.bsi_base_id ) {
2285 /* don't recollect searchBase object... */
2289 bsi.bsi_e = &user_entry;
2290 rc = backsql_id2entry( &bsi, eid );
2291 if ( rc != LDAP_SUCCESS ) {
2292 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2293 "error %d in backsql_id2entry() "
2294 "- skipping\n", rc, 0, 0 );
2300 if ( !manageDSAit &&
2301 op->ors_scope != LDAP_SCOPE_BASE &&
2302 op->ors_scope != BACKSQL_SCOPE_BASE_LIKE &&
2303 is_entry_referral( e ) )
2307 refs = get_entry_referrals( op, e );
2309 backsql_srch_info bsi2 = { 0 };
2310 Entry user_entry2 = { 0 };
2312 /* retry with the full entry... */
2313 bsi2.bsi_e = &user_entry2;
2314 rc = backsql_init_search( &bsi2,
2319 BACKSQL_ISF_GET_ENTRY );
2320 if ( rc == LDAP_SUCCESS ) {
2321 if ( is_entry_referral( &user_entry2 ) )
2323 refs = get_entry_referrals( op,
2326 rs->sr_err = LDAP_OTHER;
2328 backsql_entry_clean( op, &user_entry2 );
2330 if ( bsi2.bsi_attrs != NULL ) {
2331 op->o_tmpfree( bsi2.bsi_attrs,
2337 rs->sr_ref = referral_rewrite( refs,
2341 ber_bvarray_free( refs );
2345 rs->sr_err = LDAP_REFERRAL;
2348 rs->sr_text = "bad referral object";
2352 rs->sr_matched = user_entry.e_name.bv_val;
2353 send_search_reference( op, rs );
2355 ber_bvarray_free( rs->sr_ref );
2357 rs->sr_matched = NULL;
2358 rs->sr_entry = NULL;
2359 if ( rs->sr_err == LDAP_REFERRAL ) {
2360 rs->sr_err = LDAP_SUCCESS;
2367 * We use this flag since we need to parse the filter
2368 * anyway; we should have used the frontend API function
2369 * filter_has_subordinates()
2371 if ( bsi.bsi_flags & BSQL_SF_FILTER_HASSUBORDINATE ) {
2372 rc = backsql_has_children( op, dbh, &e->e_nname );
2375 case LDAP_COMPARE_TRUE:
2376 case LDAP_COMPARE_FALSE:
2377 a_hasSubordinate = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
2378 if ( a_hasSubordinate != NULL ) {
2379 for ( ap = &user_entry.e_attrs;
2381 ap = &(*ap)->a_next );
2383 *ap = a_hasSubordinate;
2389 Debug(LDAP_DEBUG_TRACE,
2390 "backsql_search(): "
2391 "has_children failed( %d)\n",
2398 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYUUID ) {
2399 a_entryUUID = backsql_operational_entryUUID( bi, eid );
2400 if ( a_entryUUID != NULL ) {
2402 ap = &user_entry.e_attrs;
2405 for ( ; *ap; ap = &(*ap)->a_next );
2411 #ifdef BACKSQL_SYNCPROV
2412 if ( bsi.bsi_flags & BSQL_SF_FILTER_ENTRYCSN ) {
2413 a_entryCSN = backsql_operational_entryCSN( op );
2414 if ( a_entryCSN != NULL ) {
2416 ap = &user_entry.e_attrs;
2419 for ( ; *ap; ap = &(*ap)->a_next );
2424 #endif /* BACKSQL_SYNCPROV */
2426 if ( test_filter( op, e, op->ors_filter ) == LDAP_COMPARE_TRUE )
2428 #ifndef BACKSQL_ARBITRARY_KEY
2429 /* If paged results are in effect, see if the page limit was exceeded */
2430 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
2431 if ( rs->sr_nentries >= ((PagedResultsState *)op->o_pagedresults_state)->ps_size )
2434 send_paged_response( op, rs, &lastid );
2437 lastid = SQL_TO_PAGECOOKIE( eid->eid_id, eid->eid_oc_id );
2439 #endif /* ! BACKSQL_ARBITRARY_KEY */
2440 rs->sr_attrs = op->ors_attrs;
2441 rs->sr_operational_attrs = NULL;
2443 e->e_private = (void *)eid;
2444 rs->sr_flags = ( e == &user_entry ) ? REP_ENTRY_MODIFIABLE : 0;
2445 /* FIXME: need the whole entry (ITS#3480) */
2446 rs->sr_err = send_search_entry( op, rs );
2447 e->e_private = NULL;
2448 rs->sr_entry = NULL;
2449 rs->sr_attrs = NULL;
2450 rs->sr_operational_attrs = NULL;
2452 switch ( rs->sr_err ) {
2453 case LDAP_UNAVAILABLE:
2455 * FIXME: send_search_entry failed;
2458 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
2459 "connection lost\n", 0, 0, 0 );
2462 case LDAP_SIZELIMIT_EXCEEDED:
2468 if ( e == &user_entry ) {
2469 backsql_entry_clean( op, &user_entry );
2476 if ( rs->sr_nentries > 0 ) {
2477 rs->sr_ref = rs->sr_v2ref;
2478 rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS
2482 rs->sr_err = bsi.bsi_status;
2486 if ( rs->sr_err != SLAPD_ABANDON ) {
2487 #ifndef BACKSQL_ARBITRARY_KEY
2488 if ( get_pagedresults(op) > SLAP_CONTROL_IGNORED ) {
2489 send_paged_response( op, rs, NULL );
2491 #endif /* ! BACKSQL_ARBITRARY_KEY */
2493 send_ldap_result( op, rs );
2497 /* cleanup in case of abandon */
2498 for ( ; eid != NULL;
2499 eid = backsql_free_entryID(
2500 eid, eid == &bsi.bsi_base_id ? 0 : 1, op->o_tmpmemctx ) )
2503 backsql_entry_clean( op, &base_entry );
2505 /* in case we got here accidentally */
2506 backsql_entry_clean( op, &user_entry );
2508 if ( rs->sr_v2ref ) {
2509 ber_bvarray_free( rs->sr_v2ref );
2510 rs->sr_v2ref = NULL;
2513 #ifdef BACKSQL_SYNCPROV
2515 Operation op2 = *op;
2516 SlapReply rs2 = { REP_RESULT };
2517 Entry *e = entry_alloc();
2518 slap_callback cb = { 0 };
2520 op2.o_tag = LDAP_REQ_ADD;
2521 op2.o_bd = select_backend( &op->o_bd->be_nsuffix[0], 0 );
2523 op2.o_callback = &cb;
2525 ber_dupbv( &e->e_name, op->o_bd->be_suffix );
2526 ber_dupbv( &e->e_nname, op->o_bd->be_nsuffix );
2528 cb.sc_response = slap_null_cb;
2530 op2.o_bd->be_add( &op2, &rs2 );
2532 if ( op2.ora_e == e )
2535 #endif /* BACKSQL_SYNCPROV */
2538 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
2540 if ( bsi.bsi_attrs != NULL ) {
2541 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2544 if ( !BER_BVISNULL( &nbase )
2545 && nbase.bv_val != op->o_req_ndn.bv_val )
2547 ch_free( nbase.bv_val );
2550 /* restore scope ... FIXME: this should be done before ANY
2551 * frontend call that uses op */
2552 if ( op->ors_scope == BACKSQL_SCOPE_BASE_LIKE ) {
2553 op->ors_scope = LDAP_SCOPE_BASE;
2556 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
2561 /* return LDAP_SUCCESS IFF we can retrieve the specified entry.
2568 AttributeDescription *at,
2572 backsql_srch_info bsi = { 0 };
2573 SQLHDBC dbh = SQL_NULL_HDBC;
2575 SlapReply rs = { 0 };
2576 AttributeName anlist[ 2 ];
2580 rc = backsql_get_db_conn( op, &dbh );
2581 if ( rc != LDAP_SUCCESS ) {
2586 anlist[ 0 ].an_name = at->ad_cname;
2587 anlist[ 0 ].an_desc = at;
2588 BER_BVZERO( &anlist[ 1 ].an_name );
2591 bsi.bsi_e = entry_alloc();
2592 rc = backsql_init_search( &bsi,
2596 dbh, op, &rs, at ? anlist : NULL,
2597 BACKSQL_ISF_GET_ENTRY );
2599 if ( !BER_BVISNULL( &bsi.bsi_base_id.eid_ndn ) ) {
2600 (void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
2603 if ( rc == LDAP_SUCCESS ) {
2605 #if 0 /* not supported at present */
2606 /* find attribute values */
2607 if ( is_entry_alias( bsi.bsi_e ) ) {
2608 Debug( LDAP_DEBUG_ACL,
2609 "<= backsql_entry_get: entry is an alias\n",
2611 rc = LDAP_ALIAS_PROBLEM;
2612 goto return_results;
2616 if ( is_entry_referral( bsi.bsi_e ) ) {
2617 Debug( LDAP_DEBUG_ACL,
2618 "<= backsql_entry_get: entry is a referral\n",
2621 goto return_results;
2624 if ( oc && !is_entry_objectclass( bsi.bsi_e, oc, 0 ) ) {
2625 Debug( LDAP_DEBUG_ACL,
2626 "<= backsql_entry_get: "
2627 "failed to find objectClass\n",
2629 rc = LDAP_NO_SUCH_ATTRIBUTE;
2630 goto return_results;
2637 if ( bsi.bsi_attrs != NULL ) {
2638 op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
2641 if ( rc != LDAP_SUCCESS ) {
2643 entry_free( bsi.bsi_e );
2651 backsql_entry_clean(
2657 ctx = ldap_pvt_thread_pool_context();
2659 if ( ctx == NULL || ctx != op->o_tmpmemctx ) {
2660 if ( !BER_BVISNULL( &e->e_name ) ) {
2661 op->o_tmpfree( e->e_name.bv_val, op->o_tmpmemctx );
2662 BER_BVZERO( &e->e_name );
2665 if ( !BER_BVISNULL( &e->e_nname ) ) {
2666 op->o_tmpfree( e->e_nname.bv_val, op->o_tmpmemctx );
2667 BER_BVZERO( &e->e_nname );
2675 backsql_entry_release(
2680 backsql_entry_clean( op, e );
2687 #ifndef BACKSQL_ARBITRARY_KEY
2688 /* This function is copied verbatim from back-bdb/search.c */
2690 parse_paged_cookie( Operation *op, SlapReply *rs )
2692 int rc = LDAP_SUCCESS;
2693 PagedResultsState *ps = op->o_pagedresults_state;
2695 /* this function must be invoked only if the pagedResults
2696 * control has been detected, parsed and partially checked
2697 * by the frontend */
2698 assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED );
2700 /* cookie decoding/checks deferred to backend... */
2701 if ( ps->ps_cookieval.bv_len ) {
2702 PagedResultsCookie reqcookie;
2703 if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) {
2705 rs->sr_text = "paged results cookie is invalid";
2706 rc = LDAP_PROTOCOL_ERROR;
2710 AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie ));
2712 if ( reqcookie > ps->ps_cookie ) {
2714 rs->sr_text = "paged results cookie is invalid";
2715 rc = LDAP_PROTOCOL_ERROR;
2718 } else if ( reqcookie < ps->ps_cookie ) {
2719 rs->sr_text = "paged results cookie is invalid or old";
2720 rc = LDAP_UNWILLING_TO_PERFORM;
2725 /* Initial request. Initialize state. */
2735 /* This function is copied nearly verbatim from back-bdb/search.c */
2737 send_paged_response(
2742 LDAPControl ctrl, *ctrls[2];
2743 BerElementBuffer berbuf;
2744 BerElement *ber = (BerElement *)&berbuf;
2745 PagedResultsCookie respcookie;
2746 struct berval cookie;
2748 Debug(LDAP_DEBUG_ARGS,
2749 "send_paged_response: lastid=0x%08lx nentries=%d\n",
2750 lastid ? *lastid : 0, rs->sr_nentries, NULL );
2752 BER_BVZERO( &ctrl.ldctl_value );
2756 ber_init2( ber, NULL, LBER_USE_DER );
2759 respcookie = ( PagedResultsCookie )(*lastid);
2760 cookie.bv_len = sizeof( respcookie );
2761 cookie.bv_val = (char *)&respcookie;
2764 respcookie = ( PagedResultsCookie )0;
2765 BER_BVSTR( &cookie, "" );
2768 op->o_conn->c_pagedresults_state.ps_cookie = respcookie;
2769 op->o_conn->c_pagedresults_state.ps_count =
2770 ((PagedResultsState *)op->o_pagedresults_state)->ps_count +
2773 /* return size of 0 -- no estimate */
2774 ber_printf( ber, "{iO}", 0, &cookie );
2776 if ( ber_flatten2( ber, &ctrls[0]->ldctl_value, 0 ) == -1 ) {
2780 ctrls[0]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
2781 ctrls[0]->ldctl_iscritical = 0;
2783 rs->sr_ctrls = ctrls;
2784 rs->sr_err = LDAP_SUCCESS;
2785 send_ldap_result( op, rs );
2786 rs->sr_ctrls = NULL;
2789 (void) ber_free_buf( ber );
2791 #endif /* ! BACKSQL_ARBITRARY_KEY */