search.c 69.1 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
4
 * Copyright 1999-2013 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Portions Copyright 1999 Dmitry Kovalev.
6
 * Portions Copyright 2002 Pierangelo Masarati.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
 * Portions Copyright 2004 Mark Adamson.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
8
9
10
11
12
13
14
15
16
17
18
19
 * 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
20
21
 * by OpenLDAP Software.  Additional significant contributors include
 * Pierangelo Masarati and Mark Adamson.
22
23
24
25
26
27
 */

#include "portable.h"

#include <stdio.h>
#include <sys/types.h>
Pierangelo Masarati's avatar
Pierangelo Masarati committed
28
#include "ac/string.h"
29
#include "ac/ctype.h"
30

31
#include "lutil.h"
32
#include "slap.h"
33
#include "proto-sql.h"
34

35
static int backsql_process_filter( backsql_srch_info *bsi, Filter *f );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
36
37
38
39
40
41
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 );
42
43
44
static int backsql_process_filter_attr( backsql_srch_info *bsi, Filter *f, 
		backsql_at_map_rec *at );

45
46
47
48
49
50
/* For LDAP_CONTROL_PAGEDRESULTS, a 32 bit cookie is available to keep track of
   the state of paged results. The ldap_entries.id and oc_map_id values of the
   last entry returned are used as the cookie, so 6 bits are used for the OC id
   and the other 26 for ldap_entries ID number. If your max(oc_map_id) is more
   than 63, you will need to steal more bits from ldap_entries ID number and
   put them into the OC ID part of the cookie. */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
51
52
53

/* NOTE: not supported when BACKSQL_ARBITRARY_KEY is defined */
#ifndef BACKSQL_ARBITRARY_KEY
54
55
56
57
58
59
60
61
62
63
#define SQL_TO_PAGECOOKIE(id, oc) (((id) << 6 ) | ((oc) & 0x3F))
#define PAGECOOKIE_TO_SQL_ID(pc) ((pc) >> 6)
#define PAGECOOKIE_TO_SQL_OC(pc) ((pc) & 0x3F)

static int parse_paged_cookie( Operation *op, SlapReply *rs );

static void send_paged_response( 
	Operation *op,
	SlapReply *rs,
	ID  *lastid );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
64
#endif /* ! BACKSQL_ARBITRARY_KEY */
65

Pierangelo Masarati's avatar
Pierangelo Masarati committed
66
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
67
backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
68
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
69
70
	int 		n_attrs = 0;
	AttributeName	*an = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
71

72
	if ( bsi->bsi_attrs == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
73
74
75
		return 1;
	}

76
77
78
79
	/*
	 * clear the list (retrieve all attrs)
	 */
	if ( ad == NULL ) {
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;
83
84
85
		return 1;
	}

86
87
88
89
90
	/* strip ';binary' */
	if ( slap_ad_is_binary( ad ) ) {
		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 ];
Pierangelo Masarati's avatar
Pierangelo Masarati committed
93
		
Pierangelo Masarati's avatar
Pierangelo Masarati committed
94
		Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
95
			"attribute \"%s\" is in list\n", 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
96
			an->an_name.bv_val, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
97
98
99
100
		/*
		 * We can live with strcmp because the attribute 
		 * list has been normalized before calling be_search
		 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
101
		if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
102
103
104
105
106
			return 1;
		}
	}
	
	Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
107
		"adding \"%s\" to list\n", ad->ad_cname.bv_val, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
108

109
110
111
	an = (AttributeName *)bsi->bsi_op->o_tmprealloc( bsi->bsi_attrs,
			sizeof( AttributeName ) * ( n_attrs + 2 ),
			bsi->bsi_op->o_tmpmemctx );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
112
	if ( an == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
113
114
		return -1;
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
115
116
117

	an[ n_attrs ].an_name = ad->ad_cname;
	an[ n_attrs ].an_desc = ad;
118
	BER_BVZERO( &an[ n_attrs + 1 ].an_name );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
119

120
	bsi->bsi_attrs = an;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
121
	
Pierangelo Masarati's avatar
Pierangelo Masarati committed
122
	return 1;
123
124
}

125
126
127
128
/*
 * Initializes the search structure.
 * 
 * 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.
131
132
 *
 * NOTE: base must be normalized
133
134
 */
int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
135
136
backsql_init_search(
	backsql_srch_info 	*bsi, 
137
	struct berval		*nbase, 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
138
139
140
141
142
	int 			scope, 
	time_t 			stoptime, 
	Filter 			*filter, 
	SQLHDBC 		dbh,
	Operation 		*op,
143
	SlapReply		*rs,
144
	AttributeName 		*attrs,
145
	unsigned		flags )
146
{
147
	backsql_info		*bi = (backsql_info *)op->o_bd->be_private;
148
	int			rc = LDAP_SUCCESS;
149

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
155
156
157
	bsi->bsi_scope = scope;
	bsi->bsi_filter = filter;
	bsi->bsi_dbh = dbh;
	bsi->bsi_op = op;
158
	bsi->bsi_rs = rs;
159
	bsi->bsi_flags = BSQL_SF_NONE;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
160

161
162
163
164
165
166
167
	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;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
168
169

	} else {
170
171
		if ( BACKSQL_FETCH_ALL_USERATTRS( bi ) ) {
			bsi->bsi_flags |= BSQL_SF_ALL_USER;
172

173
174
175
		} else if ( BACKSQL_FETCH_ALL_OPATTRS( bi ) ) {
			bsi->bsi_flags |= BSQL_SF_ALL_OPER;
		}
176

177
178
179
		if ( attrs == NULL ) {
			/* NULL means all user attributes */
			bsi->bsi_flags |= BSQL_SF_ALL_USER;
180

181
182
183
		} else {
			AttributeName	*p;
			int		got_oc = 0;
184

185
186
187
188
189
190
			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++ ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
191
				if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) {
192
193
194
195
196
197
198
199
200
201
202
203
204
					/* 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;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
205
				} else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) {
206
207
208
209
210
211
212
213
214
215
216
217
218
					/* 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;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
219
				} else if ( BACKSQL_NCMP( &p->an_name, slap_bv_no_attrs ) == 0 ) {
220
221
222
223
224
225
226
227
					/* ignore "1.1" */
					continue;

				} else if ( p->an_desc == slap_schema.si_ad_objectClass ) {
					got_oc = 1;
				}

				backsql_attrlist_add( bsi, p->an_desc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
228
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
229

230
231
232
233
234
235
236
			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 );
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
237
		}
238

239
240
241
242
243
		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++ ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
244
				if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_user_attrs ) == 0 ) {
245
246
247
248
249
250
251
252
253
254
255
256
257
					/* 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;

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
258
				} else if ( BACKSQL_NCMP( &p->an_name, slap_bv_all_operational_attrs ) == 0 ) {
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
					/* 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 );
			}

276
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
277
278
	}

279
	bsi->bsi_id_list = NULL;
280
	bsi->bsi_id_listtail = &bsi->bsi_id_list;
281
282
	bsi->bsi_n_candidates = 0;
	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
291
292
	bsi->bsi_flt_where.bb_len = 0;
	bsi->bsi_filter_oc = NULL;

293
	if ( BACKSQL_IS_GET_ID( flags ) ) {
294
295
		int	matched = BACKSQL_IS_MATCHED( flags );
		int	getentry = BACKSQL_IS_GET_ENTRY( flags );
296
		int	gotit = 0;
297

298
		assert( op->o_bd->be_private != NULL );
299

300
		rc = backsql_dn2id( op, rs, dbh, nbase, &bsi->bsi_base_id,
301
				matched, 1 );
302
303
304
305

		/* 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 */
306
307
308
		if ( ( rc == LDAP_NO_SUCH_OBJECT && matched ) || getentry ) {
			if ( !BER_BVISNULL( &bsi->bsi_base_id.eid_ndn ) ) {
				assert( bsi->bsi_e != NULL );
309
310
311
312
313
314
				
				if ( dn_match( nbase, &bsi->bsi_base_id.eid_ndn ) )
				{
					gotit = 1;
				}
			
315
316
317
318
319
				/*
				 * 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 );
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
				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";
						}
336

337
338
339
					} else if ( !gotit ) {
						rc = rs->sr_err = LDAP_NO_SUCH_OBJECT;
					}
340
341
342
				}

			} else {
343
				rs->sr_err = rc;
344
345
			}
		}
346
347
348
349
350
351
352
353
354
355
356

		if ( gotit && BACKSQL_IS_GET_OC( flags ) ) {
			bsi->bsi_base_id.eid_oc = backsql_id2oc( bi,
				bsi->bsi_base_id.eid_oc_id );
			if ( bsi->bsi_base_id.eid_oc == NULL ) {
				/* error? */
				backsql_free_entryID( &bsi->bsi_base_id, 1,
					op->o_tmpmemctx );
				rc = rs->sr_err = LDAP_OTHER;
			}
		}
357
358
	}

359
360
	bsi->bsi_status = rc;

361
362
363
364
365
366
	switch ( rc ) {
	case LDAP_SUCCESS:
	case LDAP_REFERRAL:
		break;

	default:
367
368
		bsi->bsi_op->o_tmpfree( bsi->bsi_attrs,
				bsi->bsi_op->o_tmpmemctx );
369
		break;
370
371
372
	}

	return rc;
373
374
}

375
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
376
backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
377
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
378
379
380
381
382
	int		res;

	if ( !f ) {
		return 0;
	}
383

384
385
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */  );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
386
387
388
389
390
391
392
393
394
395

	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;
		}
396
 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
397
398
399
400
401
402
403
		f = f->f_next;
		if ( f == NULL ) {
			break;
		}

		switch ( op ) {
		case LDAP_FILTER_AND:
404
405
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx, "l",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
406
					(ber_len_t)STRLENOF( " AND " ), 
407
						" AND " );
408
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
409
410

		case LDAP_FILTER_OR:
411
412
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx, "l",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
413
					(ber_len_t)STRLENOF( " OR " ),
414
						" OR " );
415
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
416
417
		}
	}
418

419
420
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx, "c", /* ( */ ')' );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
421
422

	return 1;
423
424
}

425
static int
426
427
backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
	backsql_at_map_rec *at )
428
{
429
	backsql_info		*bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
430
	int			i;
431
	int			casefold = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
432
433
434
435
436

	if ( !f ) {
		return 0;
	}

437
438
	/* always uppercase strings by now */
#ifdef BACKSQL_UPPERCASE_FILTER
439
440
441
	if ( f->f_sub_desc->ad_type->sat_substr &&
			SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
				bi->sql_caseIgnoreMatch ) )
442
#endif /* BACKSQL_UPPERCASE_FILTER */
443
	{
444
445
446
		casefold = 1;
	}

447
448
449
	if ( f->f_sub_desc->ad_type->sat_substr &&
			SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
				bi->sql_telephoneNumberMatch ) )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
450
451
452
453
454
455
456
	{

		struct berval	bv;
		ber_len_t	i, s, a;

		/*
		 * to check for matching telephone numbers
457
		 * with intermixed chars, e.g. val='1234'
Pierangelo Masarati's avatar
Pierangelo Masarati committed
458
459
460
461
462
		 * use
		 * 
		 * val LIKE '%1%2%3%4%'
		 */

463
		BER_BVZERO( &bv );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
		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;
479
		if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
480
481
482
483
484
485
486
487
488
489
			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 ) {
490
			for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
491
492
493
494
495
496
497
498
499
500
				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;
			}
		}

501
		if ( !BER_BVISNULL( &f->f_sub_final ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
			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;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
519
520
521
522
523
	/*
	 * When dealing with case-sensitive strings 
	 * we may omit normalization; however, normalized
	 * SQL filters are more liberal.
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
524

525
526
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */  );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
527
528

	/* TimesTen */
529
530
531
	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,
532
533
		at->bam_sel_expr_u.bv_val ? "' '" : "",
		at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" );
534
	if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
535
		/*
536
537
		 * If a pre-upper-cased version of the column 
		 * or a precompiled upper function exists, use it
Pierangelo Masarati's avatar
Pierangelo Masarati committed
538
		 */
539
540
		backsql_strfcat_x( &bsi->bsi_flt_where, 
				bsi->bsi_op->o_tmpmemctx,
541
542
				"bl",
				&at->bam_sel_expr_u,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
543
				(ber_len_t)STRLENOF( " LIKE '" ),
544
545
					" LIKE '" );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
546
	} else {
547
548
549
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"bl",
550
				&at->bam_sel_expr,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
551
				(ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
552
	}
Dmitry Kovalev's avatar
Dmitry Kovalev committed
553
 
554
	if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
555
		ber_len_t	start;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
556

557
558
559
560
561
562
563
#ifdef BACKSQL_TRACE
		Debug( LDAP_DEBUG_TRACE, 
			"==>backsql_process_sub_filter(%s): "
			"sub_initial=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
			f->f_sub_initial.bv_val, 0 );
#endif /* BACKSQL_TRACE */

564
		start = bsi->bsi_flt_where.bb_val.bv_len;
565
566
567
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"b",
568
				&f->f_sub_initial );
569
		if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
570
			ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
571
572
573
		}
	}

574
575
576
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx,
			"c", '%' );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
577
578

	if ( f->f_sub_any != NULL ) {
579
		for ( i = 0; !BER_BVISNULL( &f->f_sub_any[ i ] ); i++ ) {
580
			ber_len_t	start;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
581

582
#ifdef BACKSQL_TRACE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
583
			Debug( LDAP_DEBUG_TRACE, 
584
				"==>backsql_process_sub_filter(%s): "
585
586
				"sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val, 
				i, f->f_sub_any[ i ].bv_val );
587
#endif /* BACKSQL_TRACE */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
588

589
			start = bsi->bsi_flt_where.bb_val.bv_len;
590
591
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
592
593
594
					"bc",
					&f->f_sub_any[ i ],
					'%' );
595
			if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
596
597
598
				/*
				 * Note: toupper('%') = '%'
				 */
599
				ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
600
601
			}
		}
602
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
603

604
	if ( !BER_BVISNULL( &f->f_sub_final ) ) {
605
		ber_len_t	start;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
606

607
608
609
610
611
612
613
614
#ifdef BACKSQL_TRACE
		Debug( LDAP_DEBUG_TRACE, 
			"==>backsql_process_sub_filter(%s): "
			"sub_final=\"%s\"\n", at->bam_ad->ad_cname.bv_val,
			f->f_sub_final.bv_val, 0 );
#endif /* BACKSQL_TRACE */

		start = bsi->bsi_flt_where.bb_val.bv_len;
615
616
617
    		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"b",
618
619
620
				&f->f_sub_final );
  		if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
			ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
621
622
623
		}
	}

624
625
626
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx,
			"l", 
627
			(ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" );
628
 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
629
	return 1;
630
631
}

632
633
634
635
636
637
638
639
static int
backsql_merge_from_tbls( backsql_srch_info *bsi, struct berval *from_tbls )
{
	if ( BER_BVISNULL( from_tbls ) ) {
		return LDAP_SUCCESS;
	}

	if ( !BER_BVISNULL( &bsi->bsi_from.bb_val ) ) {
640
641
		char		*start, *end;
		struct berval	tmp;
642

643
		ber_dupbv_x( &tmp, from_tbls, bsi->bsi_op->o_tmpmemctx );
644

645
		for ( start = tmp.bv_val, end = strchr( start, ',' ); start; ) {
646
647
648
649
650
651
			if ( end ) {
				end[0] = '\0';
			}

			if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL )
			{
652
653
654
				backsql_strfcat_x( &bsi->bsi_from,
						bsi->bsi_op->o_tmpmemctx,
						"cs", ',', start );
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
			}

			if ( end ) {
				/* in case there are spaces after the comma... */
				for ( start = &end[1]; isspace( start[0] ); start++ );
				if ( start[0] ) {
					end = strchr( start, ',' );
				} else {
					start = NULL;
				}
			} else {
				start = NULL;
			}
		}

670
		bsi->bsi_op->o_tmpfree( tmp.bv_val, bsi->bsi_op->o_tmpmemctx );
671
672

	} else {
673
674
675
		backsql_strfcat_x( &bsi->bsi_from,
				bsi->bsi_op->o_tmpmemctx,
				"b", from_tbls );
676
677
678
679
680
	}

	return LDAP_SUCCESS;
}

681
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
682
backsql_process_filter( backsql_srch_info *bsi, Filter *f )
683
{
684
	backsql_at_map_rec	**vat = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
685
	AttributeDescription	*ad = NULL;
686
	unsigned		i;
687
	int 			done = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
688
689
690
	int			rc = 0;

	Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 );
691
	if ( f->f_choice == SLAPD_FILTER_COMPUTED ) {
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
		struct berval	flt;
		char		*msg = NULL;

		switch ( f->f_result ) {
		case LDAP_COMPARE_TRUE:
			BER_BVSTR( &flt, "10=10" );
			msg = "TRUE";
			break;

		case LDAP_COMPARE_FALSE:
			BER_BVSTR( &flt, "11=0" );
			msg = "FALSE";
			break;

		case SLAPD_COMPARE_UNDEFINED:
			BER_BVSTR( &flt, "12=0" );
			msg = "UNDEFINED";
			break;

		default:
			rc = -1;
			goto done;
		}

716
		Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
717
718
719
720
			"filter computed (%s)\n", msg, 0, 0 );
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx, "b", &flt );
		rc = 1;
721
		goto done;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
722
723
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
724
725
726
727
728
729
730
731
732
733
	if ( f->f_choice & SLAPD_FILTER_UNDEFINED ) {
		backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx,
			"l",
			(ber_len_t)STRLENOF( "1=0" ), "1=0" );
		done = 1;
		rc = 1;
		goto done;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
734
735
736
737
738
739
740
741
742
	switch( f->f_choice ) {
	case LDAP_FILTER_OR:
		rc = backsql_process_filter_list( bsi, f->f_or, 
				LDAP_FILTER_OR );
		done = 1;
		break;
		
	case LDAP_FILTER_AND:
		rc = backsql_process_filter_list( bsi, f->f_and,
743
				LDAP_FILTER_AND );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
744
745
746
747
		done = 1;
		break;

	case LDAP_FILTER_NOT:
748
749
750
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"l",
751
				(ber_len_t)STRLENOF( "NOT (" /* ) */ ),
752
					"NOT (" /* ) */ );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
753
		rc = backsql_process_filter( bsi, f->f_not );
754
755
756
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"c", /* ( */ ')' );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
757
758
		done = 1;
		break;
759

Pierangelo Masarati's avatar
Pierangelo Masarati committed
760
761
762
763
	case LDAP_FILTER_PRESENT:
		ad = f->f_desc;
		break;
		
764
765
	case LDAP_FILTER_EXT:
		ad = f->f_mra->ma_desc;
766
767
768
769
770
771
772
773
774
		if ( f->f_mr_dnattrs ) {
			/*
			 * if dn attrs filtering is requested, better return 
			 * success and let test_filter() deal with candidate
			 * selection; otherwise we'd need to set conditions
			 * on the contents of the DN, e.g. "SELECT ... FROM
			 * ldap_entries AS attributeName WHERE attributeName.dn
			 * like '%attributeName=value%'"
			 */
775
776
777
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
778
					(ber_len_t)STRLENOF( "1=1" ), "1=1" );
779
780
781
782
			bsi->bsi_status = LDAP_SUCCESS;
			rc = 1;
			goto done;
		}
783
784
		break;
		
Pierangelo Masarati's avatar
Pierangelo Masarati committed
785
786
787
788
789
790
	default:
		ad = f->f_av_desc;
		break;
	}

	if ( rc == -1 ) {
791
		goto done;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
792
	}
793
 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
794
	if ( done ) {
795
		rc = 1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
796
797
798
		goto done;
	}

799
800
801
802
	/*
	 * Turn structuralObjectClass into objectClass
	 */
	if ( ad == slap_schema.si_ad_objectClass 
803
804
			|| ad == slap_schema.si_ad_structuralObjectClass )
	{
805
806
807
808
809
810
811
812
813
		/*
		 * If the filter is LDAP_FILTER_PRESENT, then it's done;
		 * otherwise, let's see if we are lucky: filtering
		 * for "structural" objectclass or ancestor...
		 */
		switch ( f->f_choice ) {
		case LDAP_FILTER_EQUALITY:
		{
			ObjectClass	*oc = oc_bvfind( &f->f_av_value );
814

815
			if ( oc == NULL ) {
816
817
818
819
820
				Debug( LDAP_DEBUG_TRACE,
						"backsql_process_filter(): "
						"unknown objectClass \"%s\" "
						"in filter\n",
						f->f_av_value.bv_val, 0, 0 );
821
				bsi->bsi_status = LDAP_OTHER;
822
823
				rc = -1;
				goto done;
824
825
826
			}

			/*
827
828
829
			 * "structural" objectClass inheritance:
			 * - a search for "person" will also return 
			 *   "inetOrgPerson"
830
831
832
			 * - a search for "top" will return everything
			 */
			if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
833
834
835
836
				static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" );

				backsql_merge_from_tbls( bsi, &ldap_entry_objclasses );

837
838
839
				backsql_strfcat_x( &bsi->bsi_flt_where,
						bsi->bsi_op->o_tmpmemctx,
						"lbl",
840
841
						(ber_len_t)STRLENOF( "(2=2 OR (ldap_entries.id=ldap_entry_objclasses.entry_id AND ldap_entry_objclasses.oc_name='" /* ')) */ ),
							"(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
844
						(ber_len_t)STRLENOF( /* ((' */ "'))" ),
							/* ((' */ "'))" );
845
846
847
				bsi->bsi_status = LDAP_SUCCESS;
				rc = 1;
				goto done;
848
849
850
851
852
853
			}

			break;
		}

		case LDAP_FILTER_PRESENT:
854
855
856
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
857
					(ber_len_t)STRLENOF( "3=3" ), "3=3" );
858
			bsi->bsi_status = LDAP_SUCCESS;
859
			rc = 1;
860
			goto done;
861
862

			/* FIXME: LDAP_FILTER_EXT? */
863
864
			
		default:
865
866
867
868
869
			Debug( LDAP_DEBUG_TRACE,
					"backsql_process_filter(): "
					"illegal/unhandled filter "
					"on objectClass attribute",
					0, 0, 0 );
870
			bsi->bsi_status = LDAP_OTHER;
871
872
			rc = -1;
			goto done;
873
		}
874

875
876
877
878
879
880
	} else if ( ad == slap_schema.si_ad_entryUUID ) {
		unsigned long	oc_id;
#ifdef BACKSQL_ARBITRARY_KEY
		struct berval	keyval;
#else /* ! BACKSQL_ARBITRARY_KEY */
		unsigned long	keyval;
881
		char		keyvalbuf[LDAP_PVT_INTTYPE_CHARS(unsigned long)];
882
883
884
885
886
887
888
889
890
891
892
893
894
#endif /* ! BACKSQL_ARBITRARY_KEY */

		switch ( f->f_choice ) {
		case LDAP_FILTER_EQUALITY:
			backsql_entryUUID_decode( &f->f_av_value, &oc_id, &keyval );

			if ( oc_id != bsi->bsi_oc->bom_id ) {
				bsi->bsi_status = LDAP_SUCCESS;
				rc = -1;
				goto done;
			}

#ifdef BACKSQL_ARBITRARY_KEY
895
896
897
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"bcblbc",
898
899
900
901
902
903
					&bsi->bsi_oc->bom_keytbl, '.',
					&bsi->bsi_oc->bom_keycol,
					STRLENOF( " LIKE '" ), " LIKE '",
					&keyval, '\'' );
#else /* ! BACKSQL_ARBITRARY_KEY */
			snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval );
904
905
906
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"bcbcs",
907
908
909
910
911
912
					&bsi->bsi_oc->bom_keytbl, '.',
					&bsi->bsi_oc->bom_keycol, '=', keyvalbuf );
#endif /* ! BACKSQL_ARBITRARY_KEY */
			break;

		case LDAP_FILTER_PRESENT:
913
914
915
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
916
					(ber_len_t)STRLENOF( "4=4" ), "4=4" );
917
918
919
920
921
922
923
924
925
926
927
			break;

		default:
			rc = -1;
			goto done;
		}

		bsi->bsi_flags |= BSQL_SF_FILTER_ENTRYUUID;
		rc = 1;
		goto done;

928
#ifdef BACKSQL_SYNCPROV
Pierangelo Masarati's avatar
Pierangelo Masarati committed
929
930
	} else if ( ad == slap_schema.si_ad_entryCSN ) {
		/*
931
		 * support for syncrepl as provider...
Pierangelo Masarati's avatar
Pierangelo Masarati committed
932
		 */
933
#if 0
934
		if ( !bsi->bsi_op->o_sync ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
935
936
937
938
939
			/* unsupported at present... */
			bsi->bsi_status = LDAP_OTHER;
			rc = -1;
			goto done;
		}
940
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
941

Pierangelo Masarati's avatar
Pierangelo Masarati committed
942
943
		bsi->bsi_flags |= ( BSQL_SF_FILTER_ENTRYCSN | BSQL_SF_RETURN_ENTRYUUID);

944
945
		/* if doing a syncrepl, try to return as much as possible,
		 * and always match the filter */
946
947
948
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"l",
949
				(ber_len_t)STRLENOF( "5=5" ), "5=5" );
950

951
952
953
954
955
956
957
958
959
960
		/* save for later use in operational attributes */
		/* FIXME: saves only the first occurrence, because 
		 * the filter during updates is written as
		 * "(&(entryCSN<={contextCSN})(entryCSN>={oldContextCSN})({filter}))"
		 * so we want our fake entryCSN to match the greatest
		 * value
		 */
		if ( bsi->bsi_op->o_private == NULL ) {
			bsi->bsi_op->o_private = &f->f_av_value;
		}
961
		bsi->bsi_status = LDAP_SUCCESS;
962

963
964
		rc = 1;
		goto done;
965
#endif /* BACKSQL_SYNCPROV */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
966

967
968
969
970
971
972
973
974
975
	} else if ( ad == slap_schema.si_ad_hasSubordinates || ad == NULL ) {
		/*
		 * FIXME: this is not robust; e.g. a filter
		 * '(!(hasSubordinates=TRUE))' fails because
		 * in SQL it would read 'NOT (1=1)' instead 
		 * of no condition.  
		 * Note however that hasSubordinates is boolean, 
		 * so a more appropriate filter would be 
		 * '(hasSubordinates=FALSE)'
976
977
978
979
980
		 *
		 * A more robust search for hasSubordinates
		 * would * require joining the ldap_entries table
		 * selecting if there are descendants of the
		 * candidate.
981
		 */
982
983
984
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"l",
985
				(ber_len_t)STRLENOF( "6=6" ), "6=6" );
986
		if ( ad == slap_schema.si_ad_hasSubordinates ) {
987
			/*
988
989
990
			 * instruct candidate selection algorithm
			 * and attribute list to try to detect
			 * if an entry has subordinates
991
992
			 */
			bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
993

994
995
996
997
998
999
1000
		} else {
			/*
			 * clear attributes to fetch, to require ALL
			 * and try extended match on all attributes
			 */
			backsql_attrlist_add( bsi, NULL );
		}
For faster browsing, not all history is shown. View entire blame