2 * Copyright 1999, Dmitry Kovalev <mit@openldap.org>, All rights reserved.
4 * Redistribution and use in source and binary forms are permitted only
5 * as authorized by the OpenLDAP Public License. A copy of this
6 * license is available at http://www.OpenLDAP.org/license.html or
7 * in file LICENSE in the top-level directory of the distribution.
15 #include <sys/types.h>
16 #include "ac/string.h"
22 #include "schema-map.h"
27 backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
30 AttributeName *an = NULL;
32 if ( bsi->attrs == NULL ) {
36 for ( ; bsi->attrs[ n_attrs ].an_name.bv_val; n_attrs++ ) {
37 an = &bsi->attrs[ n_attrs ];
39 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
40 "attribute '%s' is in list\n",
41 an->an_name.bv_val, 0, 0 );
43 * We can live with strcmp because the attribute
44 * list has been normalized before calling be_search
46 if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) {
51 Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
52 "adding '%s' to list\n", ad->ad_cname.bv_val, 0, 0 );
54 an = (AttributeName *)ch_realloc( bsi->attrs,
55 sizeof( AttributeName ) * ( n_attrs + 2 ) );
60 an[ n_attrs ].an_name = ad->ad_cname;
61 an[ n_attrs ].an_desc = ad;
62 an[ n_attrs + 1 ].an_name.bv_val = NULL;
63 an[ n_attrs + 1 ].an_name.bv_len = 0;
72 backsql_srch_info *bsi,
84 AttributeName *attrs )
100 * FIXME: need to discover how to deal with 1.1 (NoAttrs)
106 if ( attrs == NULL || an_find( attrs, &AllUser ) ) {
110 bsi->attrs = (AttributeName *)ch_calloc( 1,
111 sizeof( AttributeName ) );
112 bsi->attrs[ 0 ].an_name.bv_val = NULL;
113 bsi->attrs[ 0 ].an_name.bv_len = 0;
115 for ( p = attrs; p->an_name.bv_val; p++ ) {
119 if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) {
122 } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) {
123 bsi->attr_flags |= BSQL_SF_ALL_OPER;
127 backsql_attrlist_add( bsi, p->an_desc );
133 bsi->n_candidates = 0;
134 bsi->stoptime = stoptime;
136 bsi->sel.bv_val = NULL;
139 bsi->from.bv_val = NULL;
140 bsi->from.bv_len = 0;
142 bsi->join_where.bv_val = NULL;
143 bsi->join_where.bv_len = 0;
145 bsi->flt_where.bv_val = NULL;
146 bsi->flt_where.bv_len = 0;
149 bsi->status = LDAP_SUCCESS;
153 backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
161 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c", '(' /* ) */ );
164 res = backsql_process_filter( bsi, f );
167 * TimesTen : If the query has no answers,
168 * don't bother to run the query.
179 case LDAP_FILTER_AND:
180 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
181 (ber_len_t)sizeof( " AND " ) - 1,
186 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
187 (ber_len_t)sizeof( " OR " ) - 1,
193 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c", /* ( */ ')' );
199 backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f )
202 backsql_at_map_rec *at;
208 at = backsql_ad2at( bsi->oc, f->f_sub_desc );
213 * When dealing with case-sensitive strings
214 * we may omit normalization; however, normalized
215 * SQL filters are more liberal.
218 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c", '(' /* ) */ );
221 Debug( LDAP_DEBUG_TRACE, "expr: '%s' '%s'\n", at->sel_expr.bv_val,
222 at->sel_expr_u.bv_val ? at->sel_expr_u.bv_val : "<NULL>", 0 );
223 if ( bsi->bi->upper_func.bv_val ) {
225 * If a pre-upper-cased version of the column exists, use it
227 if ( at->sel_expr_u.bv_val ) {
228 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len,
231 (ber_len_t)sizeof( " LIKE '" ) - 1,
234 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len,
236 &bsi->bi->upper_func,
240 (ber_len_t)sizeof( " LIKE '" ) - 1,
244 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "bl",
246 (ber_len_t)sizeof( " LIKE '" ) - 1, " LIKE '" );
249 if ( f->f_sub_initial.bv_val != NULL ) {
252 start = bsi->flt_where.bv_len;
253 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "b",
255 if ( bsi->bi->upper_func.bv_val ) {
256 ldap_pvt_str2upper( &bsi->flt_where.bv_val[ start ] );
260 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c", '%' );
262 if ( f->f_sub_any != NULL ) {
263 for ( i = 0; f->f_sub_any[ i ].bv_val != NULL; i++ ) {
267 Debug( LDAP_DEBUG_TRACE,
268 "==>backsql_process_sub_filter(): "
269 "sub_any='%s'\n", f->f_sub_any[ i ].bv_val,
271 #endif /* BACKSQL_TRACE */
273 start = bsi->flt_where.bv_len;
274 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len,
278 if ( bsi->bi->upper_func.bv_val ) {
280 * Note: toupper('%') = '%'
282 ldap_pvt_str2upper( &bsi->flt_where.bv_val[ start ] );
286 if ( f->f_sub_final.bv_val != NULL ) {
289 start = bsi->flt_where.bv_len;
290 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "b",
292 if ( bsi->bi->upper_func.bv_val ) {
293 ldap_pvt_str2upper( &bsi->flt_where.bv_val[ start ] );
298 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
299 (ber_len_t)sizeof( /* (' */ "')" ) - 1, /* ( */ "')" );
305 backsql_process_filter( backsql_srch_info *bsi, Filter *f )
307 backsql_at_map_rec *at;
308 backsql_at_map_rec oc_attr = {
309 slap_schema.si_ad_objectClass, BER_BVC(""), BER_BVC(""),
310 { 0, NULL }, NULL, NULL, NULL };
311 AttributeDescription *ad = NULL;
317 Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 );
318 if ( f == NULL || f->f_choice == SLAPD_FILTER_COMPUTED ) {
322 switch( f->f_choice ) {
324 rc = backsql_process_filter_list( bsi, f->f_or,
329 case LDAP_FILTER_AND:
330 rc = backsql_process_filter_list( bsi, f->f_and,
335 case LDAP_FILTER_NOT:
336 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
337 (ber_len_t)sizeof( "NOT (" /* ) */ ) - 1,
339 rc = backsql_process_filter( bsi, f->f_not );
340 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "c",
345 case LDAP_FILTER_PRESENT:
355 /* TimesTen : Don't run the query */
363 if ( ad != slap_schema.si_ad_objectClass ) {
364 at = backsql_ad2at( bsi->oc, ad );
368 backsql_strfcat( &at->sel_expr, &len, "cbc",
375 Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
376 "attribute '%s' is not defined for objectclass '%s'\n",
377 ad->ad_cname.bv_val, bsi->oc->name.bv_val, 0 );
378 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "l",
379 (ber_len_t)sizeof( " 1=0 " ) - 1, " 1=0 " );
383 backsql_merge_from_clause( &bsi->from, &bsi->from_len,
386 * need to add this attribute to list of attrs to load,
387 * so that we could do test_filter() later
389 backsql_attrlist_add( bsi, ad );
391 if ( at->join_where.bv_val != NULL
392 && strstr( bsi->join_where.bv_val, at->join_where.bv_val ) == NULL ) {
393 backsql_strfcat( &bsi->join_where, &bsi->jwhere_len, "lb",
394 (ber_len_t)sizeof( " AND " ) - 1, " AND ",
400 * FIXME: this is not required any more; however, note that
401 * attribute name syntax might collide with SQL legal aliases
403 if ( at != &oc_attr ) {
404 backsql_strfcat( &bsi->sel, &bsi->sel_len, "cblb",
407 (ber_len_t)sizeof( " AS " ) - 1, " AS ",
412 switch ( f->f_choice ) {
413 case LDAP_FILTER_EQUALITY:
415 * maybe we should check type of at->sel_expr here somehow,
416 * to know whether upper_func is applicable, but for now
417 * upper_func stuff is made for Oracle, where UPPER is
418 * safely applicable to NUMBER etc.
420 if ( bsi->bi->upper_func.bv_val ) {
423 if ( at->sel_expr_u.bv_val ) {
424 backsql_strfcat( &bsi->flt_where,
425 &bsi->fwhere_len, "cbl",
428 (ber_len_t)sizeof( "='" ) - 1,
431 backsql_strfcat( &bsi->flt_where,
432 &bsi->fwhere_len, "cbcbl",
434 &bsi->bi->upper_func,
437 (ber_len_t)sizeof( /* ( */ ")='" ) - 1,
441 start = bsi->flt_where.bv_len;
443 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len,
446 (ber_len_t)sizeof( /* (' */ "')" ) - 1,
449 ldap_pvt_str2upper( &bsi->flt_where.bv_val[ start ] );
452 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len,
456 (ber_len_t)sizeof( "='" ) - 1, "='",
458 (ber_len_t)sizeof( /* (' */ "')" ) - 1,
464 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "cblbc",
467 (ber_len_t)sizeof( ">=" ) - 1, ">=",
473 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "cblbc",
476 (ber_len_t)sizeof( "<=" ) - 1, "<=",
481 case LDAP_FILTER_PRESENT:
482 backsql_strfcat( &bsi->flt_where, &bsi->fwhere_len, "lbl",
483 (ber_len_t)sizeof( "NOT (" ) - 1, "NOT (",
485 (ber_len_t)sizeof( " IS NULL)" ) - 1, " IS NULL)" );
488 case LDAP_FILTER_SUBSTRINGS:
489 backsql_process_sub_filter( bsi, f );
494 if ( oc_attr.sel_expr.bv_val != NULL ) {
495 free( oc_attr.sel_expr.bv_val );
498 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter()\n", 0, 0, 0 );
502 if ( oc_attr.sel_expr.bv_val != NULL ) {
503 free( oc_attr.sel_expr.bv_val );
505 Debug( LDAP_DEBUG_TRACE, "<==backsql_process_filter() returns -1\n",
511 backsql_srch_query( backsql_srch_info *bsi, struct berval *query )
513 backsql_info *bi = (backsql_info *)bsi->be->be_private;
518 query->bv_val = NULL;
521 Debug( LDAP_DEBUG_TRACE, "==>backsql_srch_query()\n", 0, 0, 0 );
522 bsi->sel.bv_val = NULL;
525 bsi->from.bv_val = NULL;
526 bsi->from.bv_len = 0;
528 bsi->join_where.bv_val = NULL;
529 bsi->join_where.bv_len = 0;
531 bsi->flt_where.bv_val = NULL;
532 bsi->flt_where.bv_len = 0;
537 * FIXME: this query has been split in case a string cast function
538 * is defined; more sophisticated (pattern based) function should
541 backsql_strcat( &bsi->sel, &bsi->sel_len,
542 "SELECT DISTINCT ldap_entries.id,",
543 bsi->oc->keytbl.bv_val, ".", bsi->oc->keycol.bv_val,
544 ",'", bsi->oc->name.bv_val, "' AS objectClass",
545 ",ldap_entries.dn AS dn", NULL );
548 backsql_strfcat( &bsi->sel, &bsi->sel_len, "lbcbc",
549 (ber_len_t)sizeof( "SELECT DISTINCT ldap_entries.id," ) - 1,
550 "SELECT DISTINCT ldap_entries.id,",
556 if ( bi->strcast_func.bv_val ) {
557 backsql_strfcat( &bsi->sel, &bsi->sel_len, "blbl",
559 (ber_len_t)sizeof( "('" /* ') */ ) - 1,
562 (ber_len_t)sizeof( /* (' */ "')" ) - 1,
565 backsql_strfcat( &bsi->sel, &bsi->sel_len, "cbc",
570 backsql_strfcat( &bsi->sel, &bsi->sel_len, "l",
571 (ber_len_t)sizeof( " AS objectClass,ldap_entries.dn AS dn" ) - 1,
572 " AS objectClass,ldap_entries.dn AS dn" );
574 backsql_strfcat( &bsi->from, &bsi->from_len, "lb",
575 (ber_len_t)sizeof( " FROM ldap_entries," ) - 1,
576 " FROM ldap_entries,",
579 backsql_strfcat( &bsi->join_where, &bsi->jwhere_len, "lbcbl",
580 (ber_len_t)sizeof( " WHERE " ) - 1, " WHERE ",
584 (ber_len_t)sizeof( "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " ) - 1,
585 "=ldap_entries.keyval AND ldap_entries.oc_map_id=? AND " );
587 switch ( bsi->scope ) {
588 case LDAP_SCOPE_BASE:
589 if ( bsi->bi->upper_func.bv_val ) {
590 backsql_strfcat( &bsi->join_where, &bsi->jwhere_len,
592 &bsi->bi->upper_func,
593 (ber_len_t)sizeof( "(ldap_entries.dn)=" ) - 1,
594 "(ldap_entries.dn)=",
595 &bsi->bi->upper_func_open,
597 &bsi->bi->upper_func_close );
599 backsql_strfcat( &bsi->join_where, &bsi->jwhere_len,
601 (ber_len_t)sizeof( "ldap_entries.dn=?" ) - 1,
602 "ldap_entries.dn=?" );
606 case LDAP_SCOPE_ONELEVEL:
607 backsql_strfcat( &bsi->join_where, &bsi->jwhere_len, "l",
608 (ber_len_t)sizeof( "ldap_entries.parent=?" ) - 1,
609 "ldap_entries.parent=?" );
612 case LDAP_SCOPE_SUBTREE:
613 backsql_strfcat( &bsi->join_where, &bsi->jwhere_len, "b",
614 &bsi->bi->subtree_cond );
621 rc = backsql_process_filter( bsi, bsi->filter );
623 backsql_strfcat( query, &q_len, "bbblb",
627 (ber_len_t)sizeof( " AND " ) - 1, " AND ",
630 } else if ( rc < 0 ) {
632 * Indicates that there's no possible way the filter matches
633 * anything. No need to issue the query
635 Debug( LDAP_DEBUG_TRACE,
636 "<==backsql_srch_query() returns NULL\n", 0, 0, 0 );
637 free( query->bv_val );
638 query->bv_val = NULL;
641 free( bsi->sel.bv_val );
644 free( bsi->from.bv_val );
645 bsi->from.bv_len = 0;
647 free( bsi->join_where.bv_val );
648 bsi->join_where.bv_len = 0;
650 free( bsi->flt_where.bv_val );
651 bsi->flt_where.bv_len = 0;
654 Debug( LDAP_DEBUG_TRACE, "<==backsql_srch_query()\n", 0, 0, 0 );
656 return ( query->bv_val == NULL ? 1 : 0 );
660 backsql_oc_get_candidates( backsql_oc_map_rec *oc, backsql_srch_info *bsi )
665 backsql_entryID base_id, *c_id;
671 Debug( LDAP_DEBUG_TRACE, "==>backsql_oc_get_candidates(): oc='%s'\n",
672 oc->name.bv_val, 0, 0 );
674 if ( bsi->n_candidates == -1 ) {
675 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
676 "unchecked limit has been overcome\n", 0, 0, 0 );
681 if ( backsql_srch_query( bsi, &query ) ) {
682 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
683 "could not construct query for objectclass\n",
688 Debug( LDAP_DEBUG_TRACE, "Constructed query: %s\n",
689 query.bv_val, 0, 0 );
691 rc = backsql_Prepare( bsi->dbh, &sth, query.bv_val, 0 );
692 free( query.bv_val );
693 if ( rc != SQL_SUCCESS ) {
694 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
695 "error preparing query\n", 0, 0, 0 );
696 backsql_PrintErrors( bsi->bi->db_env, bsi->dbh, sth, rc );
700 if ( backsql_BindParamID( sth, 1, &bsi->oc->id ) != SQL_SUCCESS ) {
701 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
702 "error binding objectclass id parameter\n", 0, 0, 0 );
706 switch ( bsi->scope ) {
707 case LDAP_SCOPE_BASE:
708 rc = backsql_BindParamStr( sth, 2, bsi->base_dn->bv_val,
709 BACKSQL_MAX_DN_LEN );
710 if ( rc != SQL_SUCCESS ) {
711 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
712 "error binding base_dn parameter\n", 0, 0, 0 );
713 backsql_PrintErrors( bsi->bi->db_env, bsi->dbh,
719 case LDAP_SCOPE_SUBTREE: {
722 * + 1 because we need room for '%'; this makes a subtree
723 * search for a DN BACKSQL_MAX_DN_LEN long legal
724 * if it returns that DN only
726 char temp_base_dn[ BACKSQL_MAX_DN_LEN + 1 + 1 ];
729 * We do not accept DNs longer than BACKSQL_MAX_DN_LEN;
730 * however this should be handled earlier
732 assert( bsi->base_dn->bv_len <= BACKSQL_MAX_DN_LEN );
735 * Sets the parameters for the SQL built earlier
736 * NOTE that all the databases could actually use
737 * the TimesTen version, which would be cleaner
738 * and would also eliminate the need for the
739 * subtree_cond line in the configuration file.
740 * For now, I'm leaving it the way it is,
741 * so non-TimesTen databases use the original code.
742 * But at some point this should get cleaned up.
744 * If "dn" is being used, do a suffix search.
745 * If "dn_ru" is being used, do a prefix search.
747 if ( BACKSQL_HAS_LDAPINFO_DN_RU( bsi->bi ) ) {
748 temp_base_dn[ 0 ] = '\0';
749 for ( i = 0, j = bsi->base_dn->bv_len - 1;
751 temp_base_dn[ i ] = bsi->base_dn->bv_val[ j ];
753 temp_base_dn[ i ] = '%';
754 temp_base_dn[ i + 1 ] = '\0';
755 ldap_pvt_str2upper( temp_base_dn );
758 temp_base_dn[ 0 ] = '%';
759 AC_MEMCPY( &temp_base_dn[ 1 ], bsi->base_dn->bv_val,
760 bsi->base_dn->bv_len + 1 );
761 ldap_pvt_str2upper( &temp_base_dn[ 1 ] );
764 Debug( LDAP_DEBUG_TRACE, "dn '%s'\n", temp_base_dn, 0, 0 );
766 rc = backsql_BindParamStr( sth, 2, temp_base_dn,
767 BACKSQL_MAX_DN_LEN );
768 if ( rc != SQL_SUCCESS ) {
769 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
770 "error binding base_dn parameter (2)\n",
772 backsql_PrintErrors( bsi->bi->db_env, bsi->dbh,
779 case LDAP_SCOPE_ONELEVEL:
780 res = backsql_dn2id( bsi->bi, &base_id,
781 bsi->dbh, bsi->base_dn );
782 if ( res != LDAP_SUCCESS ) {
783 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
784 "could not retrieve base_dn id%s\n",
785 res == LDAP_NO_SUCH_OBJECT ? ": no such entry"
791 rc = backsql_BindParamID( sth, 2, &base_id.id );
792 backsql_free_entryID( &base_id, 0 );
793 if ( rc != SQL_SUCCESS ) {
794 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
795 "error binding base id parameter\n", 0, 0, 0 );
801 rc = SQLExecute( sth );
802 if ( !BACKSQL_SUCCESS( rc ) ) {
803 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
804 "error executing query\n", 0, 0, 0 );
805 backsql_PrintErrors( bsi->bi->db_env, bsi->dbh, sth, rc );
806 SQLFreeStmt( sth, SQL_DROP );
810 backsql_BindRowAsStrings( sth, &row );
811 rc = SQLFetch( sth );
812 for ( ; BACKSQL_SUCCESS( rc ); rc = SQLFetch( sth ) ) {
813 c_id = (backsql_entryID *)ch_calloc( 1,
814 sizeof( backsql_entryID ) );
815 c_id->id = strtol( row.cols[ 0 ], NULL, 0 );
816 c_id->keyval = strtol( row.cols[ 1 ], NULL, 0 );
817 c_id->oc_id = bsi->oc->id;
818 ber_str2bv( row.cols[ 3 ], 0, 1, &c_id->dn );
819 c_id->next = bsi->id_list;
823 Debug( LDAP_DEBUG_TRACE, "backsql_oc_get_candidates(): "
824 "added entry id=%ld, keyval=%ld dn='%s'\n",
825 c_id->id, c_id->keyval, row.cols[ 3 ] );
827 if ( bsi->n_candidates == -1 ) {
831 backsql_FreeRow( &row );
832 SQLFreeStmt( sth, SQL_DROP );
834 Debug( LDAP_DEBUG_TRACE, "<==backsql_oc_get_candidates()\n", 0, 0, 0 );
845 struct berval *nbase,
851 struct berval *filterstr,
852 AttributeName *attrs,
855 backsql_info *bi = (backsql_info *)be->be_private;
860 int manageDSAit = get_manageDSAit( op );
861 BerVarray v2refs = NULL;
863 backsql_srch_info srch_info;
864 backsql_entryID *eid = NULL;
865 struct slap_limits_set *limit = NULL;
868 Debug( LDAP_DEBUG_TRACE, "==>backsql_search(): "
869 "base='%s', filter='%s', scope=%d,",
870 nbase->bv_val, filterstr->bv_val, scope );
871 Debug( LDAP_DEBUG_TRACE, " deref=%d, attrsonly=%d, "
872 "attributes to load: %s\n",
873 deref, attrsonly, attrs == NULL ? "all" : "custom list" );
875 if ( nbase->bv_len > BACKSQL_MAX_DN_LEN ) {
876 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
877 "search base length (%ld) exceeds max length (%ld)\n",
878 nbase->bv_len, BACKSQL_MAX_DN_LEN, 0 );
880 * FIXME: a LDAP_NO_SUCH_OBJECT could be appropriate
881 * since it is impossible that such a long DN exists
884 send_ldap_result( conn, op, LDAP_ADMINLIMIT_EXCEEDED,
885 "", NULL, NULL, NULL );
889 sres = backsql_get_db_conn( be, conn, &dbh );
890 if ( sres != LDAP_SUCCESS ) {
891 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
892 "could not get connection handle - exiting\n",
894 send_ldap_result( conn, op, sres, "",
895 sres == LDAP_OTHER ? "SQL-backend error" : "",
900 /* TimesTen : Pass it along to the lower level routines */
901 srch_info.use_reverse_dn = BACKSQL_USE_REVERSE_DN( bi );
903 /* if not root, get appropriate limits */
904 if ( be_isroot( be, &op->o_ndn ) ) {
907 ( void ) get_limits( be, &op->o_ndn, &limit );
910 /* The time/size limits come first because they require very little
911 * effort, so there's no chance the candidates are selected and then
912 * the request is not honored only because of time/size constraints */
914 /* if no time limit requested, use soft limit (unless root!) */
917 tlimit = -1; /* allow root to set no limit */
925 /* if no limit is required, use soft limit */
927 tlimit = limit->lms_t_soft;
929 /* if requested limit higher than hard limit, abort */
930 } else if ( tlimit > limit->lms_t_hard ) {
931 /* no hard limit means use soft instead */
932 if ( limit->lms_t_hard == 0 && tlimit > limit->lms_t_soft ) {
933 tlimit = limit->lms_t_soft;
935 /* positive hard limit means abort */
936 } else if ( limit->lms_t_hard > 0 ) {
937 send_search_result( conn, op,
938 LDAP_UNWILLING_TO_PERFORM,
939 NULL, NULL, NULL, NULL, 0 );
943 /* negative hard limit means no limit */
946 /* if no limit is required, use soft limit */
948 slimit = limit->lms_s_soft;
950 /* if requested limit higher than hard limit, abort */
951 } else if ( slimit > limit->lms_s_hard ) {
952 /* no hard limit means use soft instead */
953 if ( limit->lms_s_hard == 0 && slimit > limit->lms_s_soft ) {
954 slimit = limit->lms_s_soft;
956 /* positive hard limit means abort */
957 } else if ( limit->lms_s_hard > 0 ) {
958 send_search_result( conn, op,
959 LDAP_UNWILLING_TO_PERFORM,
960 NULL, NULL, NULL, NULL, 0 );
964 /* negative hard limit means no limit */
968 /* compute it anyway; root does not use it */
969 stoptime = op->o_time + tlimit;
971 backsql_init_search( &srch_info, bi, nbase, scope,
972 slimit, tlimit, stoptime, filter, dbh,
973 be, conn, op, attrs );
976 * for each objectclass we try to construct query which gets IDs
977 * of entries matching LDAP query filter and scope (or at least
978 * candidates), and get the IDs
980 srch_info.n_candidates = ( isroot ? -2 : limit->lms_s_unchecked == -1
981 ? -2 : limit->lms_s_unchecked );
982 avl_apply( bi->oc_by_oc, (AVL_APPLY)backsql_oc_get_candidates,
983 &srch_info, 0, AVL_INORDER );
984 if ( !isroot && limit->lms_s_unchecked != -1 ) {
985 if ( srch_info.n_candidates == -1 ) {
986 send_search_result( conn, op,
987 LDAP_ADMINLIMIT_EXCEEDED,
988 NULL, NULL, NULL, NULL, 0 );
995 * now we load candidate entries (only those attributes
996 * mentioned in attrs and filter), test it against full filter
997 * and then send to client
999 for ( eid = srch_info.id_list; eid != NULL;
1000 eid = backsql_free_entryID( eid, 1 ) ) {
1002 /* check for abandon */
1003 if ( op->o_abandon ) {
1007 /* check time limit */
1008 if ( tlimit != -1 && slap_get_time() > stoptime ) {
1009 send_search_result( conn, op, LDAP_TIMELIMIT_EXCEEDED,
1010 NULL, NULL, v2refs, NULL, nentries );
1014 Debug(LDAP_DEBUG_TRACE, "backsql_search(): loading data "
1015 "for entry id=%ld, oc_id=%ld, keyval=%ld\n",
1016 eid->id, eid->oc_id, eid->keyval );
1018 entry = (Entry *)ch_calloc( sizeof( Entry ), 1 );
1019 res = backsql_id2entry( &srch_info, entry, eid );
1020 if ( res == NULL ) {
1021 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1022 "error in backsql_id2entry() "
1023 "- skipping entry\n", 0, 0, 0 );
1027 if ( !manageDSAit && scope != LDAP_SCOPE_BASE &&
1028 is_entry_referral( entry ) ) {
1029 BerVarray refs = get_entry_referrals( be, conn,
1032 send_search_reference( be, conn, op, entry, refs,
1034 ber_bvarray_free( refs );
1038 if ( test_filter( be, conn, op, entry, filter )
1039 == LDAP_COMPARE_TRUE ) {
1040 sres = send_search_entry( be, conn, op, entry,
1041 attrs, attrsonly, NULL );
1048 Debug( LDAP_DEBUG_TRACE, "backsql_search(): "
1049 "connection lost\n", 0, 0, 0 );
1054 * FIXME: send_search_entry failed;
1060 entry_free( entry );
1062 if ( slimit != -1 && nentries >= slimit ) {
1063 send_search_result( conn, op, LDAP_SIZELIMIT_EXCEEDED,
1064 NULL, NULL, v2refs, NULL, nentries );
1071 if ( nentries > 0 ) {
1072 send_search_result( conn, op,
1073 v2refs == NULL ? LDAP_SUCCESS : LDAP_REFERRAL,
1074 NULL, NULL, v2refs, NULL, nentries );
1076 send_ldap_result( conn, op, srch_info.status,
1077 NULL, NULL, NULL, 0 );
1081 ch_free( srch_info.attrs );
1083 Debug( LDAP_DEBUG_TRACE, "<==backsql_search()\n", 0, 0, 0 );
1087 #endif /* SLAPD_SQL */