📄 search.c
字号:
/* $OpenLDAP: pkg/ldap/servers/slapd/back-sql/search.c,v 1.81.2.13 2007/03/05 18:39:51 ando Exp $ *//* This work is part of OpenLDAP Software <http://www.openldap.org/>. * * Copyright 1999-2007 The OpenLDAP Foundation. * Portions Copyright 1999 Dmitry Kovalev. * Portions Copyright 2002 Pierangelo Masarati. * Portions Copyright 2004 Mark Adamson. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * <http://www.OpenLDAP.org/license.html>. *//* ACKNOWLEDGEMENTS: * This work was initially developed by Dmitry Kovalev for inclusion * by OpenLDAP Software. Additional significant contributors include * Pierangelo Masarati and Mark Adamson. */#include "portable.h"#include <stdio.h>#include <sys/types.h>#include "ac/string.h"#include "ac/ctype.h"#include "lutil.h"#include "slap.h"#include "proto-sql.h"static int backsql_process_filter( backsql_srch_info *bsi, Filter *f );static int backsql_process_filter_eq( backsql_srch_info *bsi, backsql_at_map_rec *at, int casefold, struct berval *filter_value );static int backsql_process_filter_like( backsql_srch_info *bsi, backsql_at_map_rec *at, int casefold, struct berval *filter_value );static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at );static intbacksql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad ){ int n_attrs = 0; AttributeName *an = NULL; if ( bsi->bsi_attrs == NULL ) { return 1; } /* * clear the list (retrieve all attrs) */ if ( ad == NULL ) { bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx ); bsi->bsi_attrs = NULL; bsi->bsi_flags |= BSQL_SF_ALL_ATTRS; return 1; } for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) { an = &bsi->bsi_attrs[ n_attrs ]; Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): " "attribute \"%s\" is in list\n", an->an_name.bv_val, 0, 0 ); /* * We can live with strcmp because the attribute * list has been normalized before calling be_search */ if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) { return 1; } } Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): " "adding \"%s\" to list\n", ad->ad_cname.bv_val, 0, 0 ); an = (AttributeName *)bsi->bsi_op->o_tmprealloc( bsi->bsi_attrs, sizeof( AttributeName ) * ( n_attrs + 2 ), bsi->bsi_op->o_tmpmemctx ); if ( an == NULL ) { return -1; } an[ n_attrs ].an_name = ad->ad_cname; an[ n_attrs ].an_desc = ad; BER_BVZERO( &an[ n_attrs + 1 ].an_name ); bsi->bsi_attrs = an; return 1;}/* * Initializes the search structure. * * If get_base_id != 0, the field bsi_base_id is filled * with the entryID of bsi_base_ndn; it must be freed * by backsql_free_entryID() when no longer required. * * NOTE: base must be normalized */intbacksql_init_search( backsql_srch_info *bsi, struct berval *nbase, int scope, time_t stoptime, Filter *filter, SQLHDBC dbh, Operation *op, SlapReply *rs, AttributeName *attrs, unsigned flags ){ backsql_info *bi = (backsql_info *)op->o_bd->be_private; int rc = LDAP_SUCCESS; bsi->bsi_base_ndn = nbase; bsi->bsi_use_subtree_shortcut = 0; BER_BVZERO( &bsi->bsi_base_id.eid_dn ); BER_BVZERO( &bsi->bsi_base_id.eid_ndn ); bsi->bsi_scope = scope; bsi->bsi_filter = filter; bsi->bsi_dbh = dbh; bsi->bsi_op = op; bsi->bsi_rs = rs; bsi->bsi_flags = BSQL_SF_NONE; bsi->bsi_attrs = NULL; if ( BACKSQL_FETCH_ALL_ATTRS( bi ) ) { /* * if requested, simply try to fetch all attributes */ bsi->bsi_flags |= BSQL_SF_ALL_ATTRS; } else { if ( BACKSQL_FETCH_ALL_USERATTRS( bi ) ) { bsi->bsi_flags |= BSQL_SF_ALL_USER; } else if ( BACKSQL_FETCH_ALL_OPATTRS( bi ) ) { bsi->bsi_flags |= BSQL_SF_ALL_OPER; } if ( attrs == NULL ) { /* NULL means all user attributes */ bsi->bsi_flags |= BSQL_SF_ALL_USER; } else { AttributeName *p; int got_oc = 0; bsi->bsi_attrs = (AttributeName *)bsi->bsi_op->o_tmpalloc( sizeof( AttributeName ), bsi->bsi_op->o_tmpmemctx ); BER_BVZERO( &bsi->bsi_attrs[ 0 ].an_name ); for ( p = attrs; !BER_BVISNULL( &p->an_name ); p++ ) { if ( BACKSQL_NCMP( &p->an_name, &AllUser ) == 0 ) { /* handle "*" */ bsi->bsi_flags |= BSQL_SF_ALL_USER; /* if all attrs are requested, there's * no need to continue */ if ( BSQL_ISF_ALL_ATTRS( bsi ) ) { bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx ); bsi->bsi_attrs = NULL; break; } continue; } else if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) { /* handle "+" */ bsi->bsi_flags |= BSQL_SF_ALL_OPER; /* if all attrs are requested, there's * no need to continue */ if ( BSQL_ISF_ALL_ATTRS( bsi ) ) { bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx ); bsi->bsi_attrs = NULL; break; } continue; } else if ( BACKSQL_NCMP( &p->an_name, &NoAttrs ) == 0 ) { /* ignore "1.1" */ continue; } else if ( p->an_desc == slap_schema.si_ad_objectClass ) { got_oc = 1; } backsql_attrlist_add( bsi, p->an_desc ); } if ( got_oc == 0 && !( bsi->bsi_flags & BSQL_SF_ALL_USER ) ) { /* add objectClass if not present, * because it is required to understand * if an entry is a referral, an alias * or so... */ backsql_attrlist_add( bsi, slap_schema.si_ad_objectClass ); } } if ( !BSQL_ISF_ALL_ATTRS( bsi ) && bi->sql_anlist ) { AttributeName *p; /* use hints if available */ for ( p = bi->sql_anlist; !BER_BVISNULL( &p->an_name ); p++ ) { if ( BACKSQL_NCMP( &p->an_name, &AllUser ) == 0 ) { /* handle "*" */ bsi->bsi_flags |= BSQL_SF_ALL_USER; /* if all attrs are requested, there's * no need to continue */ if ( BSQL_ISF_ALL_ATTRS( bsi ) ) { bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx ); bsi->bsi_attrs = NULL; break; } continue; } else if ( BACKSQL_NCMP( &p->an_name, &AllOper ) == 0 ) { /* handle "+" */ bsi->bsi_flags |= BSQL_SF_ALL_OPER; /* if all attrs are requested, there's * no need to continue */ if ( BSQL_ISF_ALL_ATTRS( bsi ) ) { bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx ); bsi->bsi_attrs = NULL; break; } continue; } backsql_attrlist_add( bsi, p->an_desc ); } } } bsi->bsi_id_list = NULL; bsi->bsi_id_listtail = &bsi->bsi_id_list; bsi->bsi_n_candidates = 0; bsi->bsi_stoptime = stoptime; BER_BVZERO( &bsi->bsi_sel.bb_val ); bsi->bsi_sel.bb_len = 0; BER_BVZERO( &bsi->bsi_from.bb_val ); bsi->bsi_from.bb_len = 0; BER_BVZERO( &bsi->bsi_join_where.bb_val ); bsi->bsi_join_where.bb_len = 0; BER_BVZERO( &bsi->bsi_flt_where.bb_val ); bsi->bsi_flt_where.bb_len = 0; bsi->bsi_filter_oc = NULL; if ( BACKSQL_IS_GET_ID( flags ) ) { int matched = BACKSQL_IS_MATCHED( flags ); int getentry = BACKSQL_IS_GET_ENTRY( flags ); int gotit = 0; assert( op->o_bd->be_private != NULL ); rc = backsql_dn2id( op, rs, dbh, nbase, &bsi->bsi_base_id, matched, 1 ); /* the entry is collected either if requested for by getentry * or if get noSuchObject and requested to climb the tree, * so that a matchedDN or a referral can be returned */ if ( ( rc == LDAP_NO_SUCH_OBJECT && matched ) || getentry ) { if ( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ) { assert( bsi->bsi_e != NULL ); if ( dn_match( nbase, &bsi->bsi_base_id.eid_ndn ) ) { gotit = 1; } /* * let's see if it is a referral and, in case, get it */ backsql_attrlist_add( bsi, slap_schema.si_ad_ref ); rc = backsql_id2entry( bsi, &bsi->bsi_base_id ); if ( rc == LDAP_SUCCESS ) { if ( is_entry_referral( bsi->bsi_e ) ) { BerVarray erefs = get_entry_referrals( op, bsi->bsi_e ); if ( erefs ) { rc = rs->sr_err = LDAP_REFERRAL; rs->sr_ref = referral_rewrite( erefs, &bsi->bsi_e->e_nname, &op->o_req_dn, scope ); ber_bvarray_free( erefs ); } else { rc = rs->sr_err = LDAP_OTHER; rs->sr_text = "bad referral object"; } } else if ( !gotit ) { rc = rs->sr_err = LDAP_NO_SUCH_OBJECT; } } } else { rs->sr_err = rc; } } } bsi->bsi_status = rc; switch ( rc ) { case LDAP_SUCCESS: case LDAP_REFERRAL: break; default: bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx ); break; } return rc;}static intbacksql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op ){ int res; if ( !f ) { return 0; } backsql_strfcat_x( &bsi->bsi_flt_where, bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ ); while ( 1 ) { res = backsql_process_filter( bsi, f ); if ( res < 0 ) { /* * TimesTen : If the query has no answers, * don't bother to run the query. */ return -1; } f = f->f_next; if ( f == NULL ) { break; } switch ( op ) { case LDAP_FILTER_AND: backsql_strfcat_x( &bsi->bsi_flt_where, bsi->bsi_op->o_tmpmemctx, "l", (ber_len_t)STRLENOF( " AND " ), " AND " ); break; case LDAP_FILTER_OR: backsql_strfcat_x( &bsi->bsi_flt_where, bsi->bsi_op->o_tmpmemctx, "l", (ber_len_t)STRLENOF( " OR " ), " OR " ); break; } } backsql_strfcat_x( &bsi->bsi_flt_where, bsi->bsi_op->o_tmpmemctx, "c", /* ( */ ')' ); return 1;}static intbacksql_process_sub_filter( backsql_srch_info *bsi, Filter *f, backsql_at_map_rec *at ){ backsql_info *bi = (backsql_info *)bsi->bsi_op->o_bd->be_private; int i; int casefold = 0; if ( !f ) { return 0; } /* always uppercase strings by now */#ifdef BACKSQL_UPPERCASE_FILTER if ( f->f_sub_desc->ad_type->sat_substr && SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr, bi->sql_caseIgnoreMatch ) )#endif /* BACKSQL_UPPERCASE_FILTER */ { casefold = 1; } if ( f->f_sub_desc->ad_type->sat_substr && SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr, bi->sql_telephoneNumberMatch ) ) { struct berval bv; ber_len_t i, s, a; /* * to check for matching telephone numbers * with intermixed chars, e.g. val='1234' * use * * val LIKE '%1%2%3%4%' */ BER_BVZERO( &bv ); if ( f->f_sub_initial.bv_val ) { bv.bv_len += f->f_sub_initial.bv_len; } if ( f->f_sub_any != NULL ) { for ( a = 0; f->f_sub_any[ a ].bv_val != NULL; a++ ) { bv.bv_len += f->f_sub_any[ a ].bv_len; } } if ( f->f_sub_final.bv_val ) { bv.bv_len += f->f_sub_final.bv_len; } bv.bv_len = 2 * bv.bv_len - 1; bv.bv_val = ch_malloc( bv.bv_len + 1 ); s = 0; if ( !BER_BVISNULL( &f->f_sub_initial ) ) { bv.bv_val[ s ] = f->f_sub_initial.bv_val[ 0 ]; for ( i = 1; i < f->f_sub_initial.bv_len; i++ ) { bv.bv_val[ s + 2 * i - 1 ] = '%'; bv.bv_val[ s + 2 * i ] = f->f_sub_initial.bv_val[ i ]; } bv.bv_val[ s + 2 * i - 1 ] = '%'; s += 2 * i; } if ( f->f_sub_any != NULL ) { for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) { bv.bv_val[ s ] = f->f_sub_any[ a ].bv_val[ 0 ]; for ( i = 1; i < f->f_sub_any[ a ].bv_len; i++ ) { bv.bv_val[ s + 2 * i - 1 ] = '%'; bv.bv_val[ s + 2 * i ] = f->f_sub_any[ a ].bv_val[ i ]; } bv.bv_val[ s + 2 * i - 1 ] = '%'; s += 2 * i; } } if ( !BER_BVISNULL( &f->f_sub_final ) ) { bv.bv_val[ s ] = f->f_sub_final.bv_val[ 0 ]; for ( i = 1; i < f->f_sub_final.bv_len; i++ ) { bv.bv_val[ s + 2 * i - 1 ] = '%'; bv.bv_val[ s + 2 * i ] = f->f_sub_final.bv_val[ i ]; } bv.bv_val[ s + 2 * i - 1 ] = '%'; s += 2 * i; } bv.bv_val[ s - 1 ] = '\0'; (void)backsql_process_filter_like( bsi, at, casefold, &bv ); ch_free( bv.bv_val ); return 1; } /* * When dealing with case-sensitive strings * we may omit normalization; however, normalized * SQL filters are more liberal. */ backsql_strfcat_x( &bsi->bsi_flt_where, bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */ ); /* TimesTen */ Debug( LDAP_DEBUG_TRACE, "backsql_process_sub_filter(%s):\n", at->bam_ad->ad_cname.bv_val, 0, 0 ); Debug(LDAP_DEBUG_TRACE, " expr: '%s%s%s'\n", at->bam_sel_expr.bv_val, at->bam_sel_expr_u.bv_val ? "' '" : "", at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" ); if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) { /* * If a pre-upper-cased version of the column * or a precompiled upper function exists, use it */ backsql_strfcat_x( &bsi->bsi_flt_where, bsi->bsi_op->o_tmpmemctx, "bl", &at->bam_sel_expr_u, (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" ); } else { backsql_strfcat_x( &bsi->bsi_flt_where, bsi->bsi_op->o_tmpmemctx, "bl", &at->bam_sel_expr, (ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -