search.c 62.9 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
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1999-2007 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Portions Copyright 1999 Dmitry Kovalev.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
 * Portions Copyright 2002 Pierangelo Masarati.
 * 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
Kurt Zeilenga's avatar
Kurt Zeilenga committed
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

Kurt Zeilenga's avatar
Kurt Zeilenga committed
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 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
45
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
46
backsql_attrlist_add( backsql_srch_info *bsi, AttributeDescription *ad )
47
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
48
49
	int 		n_attrs = 0;
	AttributeName	*an = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
50

51
	if ( bsi->bsi_attrs == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
52
53
54
		return 1;
	}

55
56
57
58
	/*
	 * clear the list (retrieve all attrs)
	 */
	if ( ad == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
59
		bsi->bsi_op->o_tmpfree( bsi->bsi_attrs, bsi->bsi_op->o_tmpmemctx );
60
		bsi->bsi_attrs = NULL;
61
		bsi->bsi_flags |= BSQL_SF_ALL_ATTRS;
62
63
64
		return 1;
	}

65
	for ( ; !BER_BVISNULL( &bsi->bsi_attrs[ n_attrs ].an_name ); n_attrs++ ) {
66
		an = &bsi->bsi_attrs[ n_attrs ];
Pierangelo Masarati's avatar
Pierangelo Masarati committed
67
		
Pierangelo Masarati's avatar
Pierangelo Masarati committed
68
		Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
69
			"attribute \"%s\" is in list\n", 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
70
			an->an_name.bv_val, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
71
72
73
74
		/*
		 * We can live with strcmp because the attribute 
		 * list has been normalized before calling be_search
		 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
75
		if ( !BACKSQL_NCMP( &an->an_name, &ad->ad_cname ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
76
77
78
79
80
			return 1;
		}
	}
	
	Debug( LDAP_DEBUG_TRACE, "==>backsql_attrlist_add(): "
81
		"adding \"%s\" to list\n", ad->ad_cname.bv_val, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
82

Kurt Zeilenga's avatar
Kurt Zeilenga committed
83
84
85
	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
86
	if ( an == NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
87
88
		return -1;
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
89
90
91

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

94
	bsi->bsi_attrs = an;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
95
	
Pierangelo Masarati's avatar
Pierangelo Masarati committed
96
	return 1;
97
98
}

99
100
101
102
/*
 * Initializes the search structure.
 * 
 * If get_base_id != 0, the field bsi_base_id is filled 
103
 * with the entryID of bsi_base_ndn; it must be freed
104
 * by backsql_free_entryID() when no longer required.
105
106
 *
 * NOTE: base must be normalized
107
108
 */
int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
109
110
backsql_init_search(
	backsql_srch_info 	*bsi, 
111
	struct berval		*nbase, 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
112
113
114
115
116
	int 			scope, 
	time_t 			stoptime, 
	Filter 			*filter, 
	SQLHDBC 		dbh,
	Operation 		*op,
117
	SlapReply		*rs,
118
	AttributeName 		*attrs,
119
	unsigned		flags )
120
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
121
	backsql_info		*bi = (backsql_info *)op->o_bd->be_private;
122
	int			rc = LDAP_SUCCESS;
123

124
	bsi->bsi_base_ndn = nbase;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
125
	bsi->bsi_use_subtree_shortcut = 0;
126
	BER_BVZERO( &bsi->bsi_base_id.eid_dn );
127
	BER_BVZERO( &bsi->bsi_base_id.eid_ndn );
128
129
130
131
	bsi->bsi_scope = scope;
	bsi->bsi_filter = filter;
	bsi->bsi_dbh = dbh;
	bsi->bsi_op = op;
132
	bsi->bsi_rs = rs;
133
	bsi->bsi_flags = BSQL_SF_NONE;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
134

Kurt Zeilenga's avatar
Kurt Zeilenga committed
135
136
137
138
139
140
141
	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
142
143

	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
144
145
		if ( BACKSQL_FETCH_ALL_USERATTRS( bi ) ) {
			bsi->bsi_flags |= BSQL_SF_ALL_USER;
146

Kurt Zeilenga's avatar
Kurt Zeilenga committed
147
148
149
		} else if ( BACKSQL_FETCH_ALL_OPATTRS( bi ) ) {
			bsi->bsi_flags |= BSQL_SF_ALL_OPER;
		}
150

Kurt Zeilenga's avatar
Kurt Zeilenga committed
151
152
153
		if ( attrs == NULL ) {
			/* NULL means all user attributes */
			bsi->bsi_flags |= BSQL_SF_ALL_USER;
154

Kurt Zeilenga's avatar
Kurt Zeilenga committed
155
156
157
		} else {
			AttributeName	*p;
			int		got_oc = 0;
158

Kurt Zeilenga's avatar
Kurt Zeilenga committed
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
			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 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
202
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
203

Kurt Zeilenga's avatar
Kurt Zeilenga committed
204
205
206
207
208
209
210
			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
211
		}
212

Kurt Zeilenga's avatar
Kurt Zeilenga committed
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
		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 );
			}

250
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
251
252
	}

253
	bsi->bsi_id_list = NULL;
254
	bsi->bsi_id_listtail = &bsi->bsi_id_list;
255
256
	bsi->bsi_n_candidates = 0;
	bsi->bsi_stoptime = stoptime;
257
	BER_BVZERO( &bsi->bsi_sel.bb_val );
258
	bsi->bsi_sel.bb_len = 0;
259
	BER_BVZERO( &bsi->bsi_from.bb_val );
260
	bsi->bsi_from.bb_len = 0;
261
	BER_BVZERO( &bsi->bsi_join_where.bb_val );
262
	bsi->bsi_join_where.bb_len = 0;
263
	BER_BVZERO( &bsi->bsi_flt_where.bb_val );
264
265
266
	bsi->bsi_flt_where.bb_len = 0;
	bsi->bsi_filter_oc = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
267
268
269
270
271
	if ( BACKSQL_IS_GET_ID( flags ) ) {
		int	matched = BACKSQL_IS_MATCHED( flags );
		int	getentry = BACKSQL_IS_GET_ENTRY( flags );
		int	gotit = 0;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
272
		assert( op->o_bd->be_private != NULL );
273

Kurt Zeilenga's avatar
Kurt Zeilenga committed
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
		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 {
317
				rs->sr_err = rc;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
			}
		}
	}

	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;
333
334
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
335
	return rc;
336
337
}

338
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
339
backsql_process_filter_list( backsql_srch_info *bsi, Filter *f, int op )
340
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
341
342
343
344
345
	int		res;

	if ( !f ) {
		return 0;
	}
346

Kurt Zeilenga's avatar
Kurt Zeilenga committed
347
348
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */  );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
349
350
351
352
353
354
355
356
357
358

	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;
		}
359
 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
360
361
362
363
364
365
366
		f = f->f_next;
		if ( f == NULL ) {
			break;
		}

		switch ( op ) {
		case LDAP_FILTER_AND:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
367
368
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx, "l",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
369
					(ber_len_t)STRLENOF( " AND " ), 
370
						" AND " );
371
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
372
373

		case LDAP_FILTER_OR:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
374
375
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx, "l",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
376
					(ber_len_t)STRLENOF( " OR " ),
377
						" OR " );
378
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
379
380
		}
	}
381

Kurt Zeilenga's avatar
Kurt Zeilenga committed
382
383
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx, "c", /* ( */ ')' );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
384
385

	return 1;
386
387
}

388
static int
389
390
backsql_process_sub_filter( backsql_srch_info *bsi, Filter *f,
	backsql_at_map_rec *at )
391
{
392
	backsql_info		*bi = (backsql_info *)bsi->bsi_op->o_bd->be_private;
393
	int			i;
394
	int			casefold = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
395
396
397
398
399

	if ( !f ) {
		return 0;
	}

400
401
	/* always uppercase strings by now */
#ifdef BACKSQL_UPPERCASE_FILTER
Kurt Zeilenga's avatar
Kurt Zeilenga committed
402
403
404
	if ( f->f_sub_desc->ad_type->sat_substr &&
			SLAP_MR_ASSOCIATED( f->f_sub_desc->ad_type->sat_substr,
				bi->sql_caseIgnoreMatch ) )
405
#endif /* BACKSQL_UPPERCASE_FILTER */
406
	{
407
408
409
		casefold = 1;
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
410
411
412
	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
413
414
415
416
417
418
419
	{

		struct berval	bv;
		ber_len_t	i, s, a;

		/*
		 * to check for matching telephone numbers
420
		 * with intermixed chars, e.g. val='1234'
Pierangelo Masarati's avatar
Pierangelo Masarati committed
421
422
423
424
425
		 * use
		 * 
		 * val LIKE '%1%2%3%4%'
		 */

426
		BER_BVZERO( &bv );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
		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;
442
		if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
443
444
445
446
447
448
449
450
451
452
			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 ) {
453
			for ( a = 0; !BER_BVISNULL( &f->f_sub_any[ a ] ); a++ ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
454
455
456
457
458
459
460
461
462
463
				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;
			}
		}

464
		if ( !BER_BVISNULL( &f->f_sub_final ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
			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
482
483
484
485
486
	/*
	 * When dealing with case-sensitive strings 
	 * we may omit normalization; however, normalized
	 * SQL filters are more liberal.
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
487

Kurt Zeilenga's avatar
Kurt Zeilenga committed
488
489
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx, "c", '(' /* ) */  );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
490
491

	/* TimesTen */
492
493
494
	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,
495
496
		at->bam_sel_expr_u.bv_val ? "' '" : "",
		at->bam_sel_expr_u.bv_val ? at->bam_sel_expr_u.bv_val : "" );
497
	if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
498
		/*
499
500
		 * If a pre-upper-cased version of the column 
		 * or a precompiled upper function exists, use it
Pierangelo Masarati's avatar
Pierangelo Masarati committed
501
		 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
502
503
		backsql_strfcat_x( &bsi->bsi_flt_where, 
				bsi->bsi_op->o_tmpmemctx,
504
505
				"bl",
				&at->bam_sel_expr_u,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
506
				(ber_len_t)STRLENOF( " LIKE '" ),
507
508
					" LIKE '" );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
509
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
510
511
512
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"bl",
513
				&at->bam_sel_expr,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
514
				(ber_len_t)STRLENOF( " LIKE '" ), " LIKE '" );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
515
	}
Dmitry Kovalev's avatar
Dmitry Kovalev committed
516
 
517
	if ( !BER_BVISNULL( &f->f_sub_initial ) ) {
518
		ber_len_t	start;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
519

520
521
522
523
524
525
526
#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 */

527
		start = bsi->bsi_flt_where.bb_val.bv_len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
528
529
530
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"b",
531
				&f->f_sub_initial );
532
		if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
533
			ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
534
535
536
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
537
538
539
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx,
			"c", '%' );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
540
541

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

545
#ifdef BACKSQL_TRACE
Pierangelo Masarati's avatar
Pierangelo Masarati committed
546
			Debug( LDAP_DEBUG_TRACE, 
547
				"==>backsql_process_sub_filter(%s): "
548
549
				"sub_any[%d]=\"%s\"\n", at->bam_ad->ad_cname.bv_val, 
				i, f->f_sub_any[ i ].bv_val );
550
#endif /* BACKSQL_TRACE */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
551

552
			start = bsi->bsi_flt_where.bb_val.bv_len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
553
554
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
555
556
557
					"bc",
					&f->f_sub_any[ i ],
					'%' );
558
			if ( casefold && BACKSQL_AT_CANUPPERCASE( at ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
559
560
561
				/*
				 * Note: toupper('%') = '%'
				 */
562
				ldap_pvt_str2upper( &bsi->bsi_flt_where.bb_val.bv_val[ start ] );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
563
564
			}
		}
565
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
566

567
	if ( !BER_BVISNULL( &f->f_sub_final ) ) {
568
		ber_len_t	start;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
569

570
571
572
573
574
575
576
577
#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;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
578
579
580
    		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"b",
581
582
583
				&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
584
585
586
		}
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
587
588
589
	backsql_strfcat_x( &bsi->bsi_flt_where,
			bsi->bsi_op->o_tmpmemctx,
			"l", 
590
			(ber_len_t)STRLENOF( /* (' */ "')" ), /* (' */ "')" );
591
 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
592
	return 1;
593
594
}

595
596
597
598
599
600
601
602
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 ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
603
604
		char		*start, *end;
		struct berval	tmp;
605

Kurt Zeilenga's avatar
Kurt Zeilenga committed
606
		ber_dupbv_x( &tmp, from_tbls, bsi->bsi_op->o_tmpmemctx );
607

Kurt Zeilenga's avatar
Kurt Zeilenga committed
608
		for ( start = tmp.bv_val, end = strchr( start, ',' ); start; ) {
609
610
611
612
613
614
			if ( end ) {
				end[0] = '\0';
			}

			if ( strstr( bsi->bsi_from.bb_val.bv_val, start) == NULL )
			{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
615
616
617
				backsql_strfcat_x( &bsi->bsi_from,
						bsi->bsi_op->o_tmpmemctx,
						"cs", ',', start );
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
			}

			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;
			}
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
633
		bsi->bsi_op->o_tmpfree( tmp.bv_val, bsi->bsi_op->o_tmpmemctx );
634
635

	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
636
637
638
		backsql_strfcat_x( &bsi->bsi_from,
				bsi->bsi_op->o_tmpmemctx,
				"b", from_tbls );
639
640
641
642
643
	}

	return LDAP_SUCCESS;
}

644
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
645
backsql_process_filter( backsql_srch_info *bsi, Filter *f )
646
{
647
	backsql_at_map_rec	**vat = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
648
	AttributeDescription	*ad = NULL;
649
	unsigned		i;
650
	int 			done = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
651
652
653
	int			rc = 0;

	Debug( LDAP_DEBUG_TRACE, "==>backsql_process_filter()\n", 0, 0, 0 );
654
	if ( f->f_choice == SLAPD_FILTER_COMPUTED ) {
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
		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;
		}

679
		Debug( LDAP_DEBUG_TRACE, "backsql_process_filter(): "
680
681
682
683
			"filter computed (%s)\n", msg, 0, 0 );
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx, "b", &flt );
		rc = 1;
684
		goto done;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
685
686
687
688
689
690
691
692
693
694
695
	}

	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,
696
				LDAP_FILTER_AND );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
697
698
699
700
		done = 1;
		break;

	case LDAP_FILTER_NOT:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
701
702
703
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"l",
704
				(ber_len_t)STRLENOF( "NOT (" /* ) */ ),
705
					"NOT (" /* ) */ );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
706
		rc = backsql_process_filter( bsi, f->f_not );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
707
708
709
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"c", /* ( */ ')' );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
710
711
		done = 1;
		break;
712

Pierangelo Masarati's avatar
Pierangelo Masarati committed
713
714
715
716
	case LDAP_FILTER_PRESENT:
		ad = f->f_desc;
		break;
		
717
718
	case LDAP_FILTER_EXT:
		ad = f->f_mra->ma_desc;
719
720
721
722
723
724
725
726
727
		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%'"
			 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
728
729
730
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
731
					(ber_len_t)STRLENOF( "1=1" ), "1=1" );
732
733
734
735
			bsi->bsi_status = LDAP_SUCCESS;
			rc = 1;
			goto done;
		}
736
737
		break;
		
Pierangelo Masarati's avatar
Pierangelo Masarati committed
738
739
740
741
742
743
	default:
		ad = f->f_av_desc;
		break;
	}

	if ( rc == -1 ) {
744
		goto done;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
745
	}
746
 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
747
	if ( done ) {
748
		rc = 1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
749
750
751
		goto done;
	}

752
753
754
755
	/*
	 * Turn structuralObjectClass into objectClass
	 */
	if ( ad == slap_schema.si_ad_objectClass 
756
757
			|| ad == slap_schema.si_ad_structuralObjectClass )
	{
758
759
760
761
762
763
764
765
766
		/*
		 * 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 );
767

768
			if ( oc == NULL ) {
769
770
771
772
773
				Debug( LDAP_DEBUG_TRACE,
						"backsql_process_filter(): "
						"unknown objectClass \"%s\" "
						"in filter\n",
						f->f_av_value.bv_val, 0, 0 );
774
				bsi->bsi_status = LDAP_OTHER;
775
776
				rc = -1;
				goto done;
777
778
779
			}

			/*
780
781
782
			 * "structural" objectClass inheritance:
			 * - a search for "person" will also return 
			 *   "inetOrgPerson"
783
784
785
			 * - a search for "top" will return everything
			 */
			if ( is_object_subclass( oc, bsi->bsi_oc->bom_oc ) ) {
786
787
788
789
				static struct berval ldap_entry_objclasses = BER_BVC( "ldap_entry_objclasses" );

				backsql_merge_from_tbls( bsi, &ldap_entry_objclasses );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
790
791
792
				backsql_strfcat_x( &bsi->bsi_flt_where,
						bsi->bsi_op->o_tmpmemctx,
						"lbl",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
793
794
						(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='" /* ')) */,
795
						&bsi->bsi_oc->bom_oc->soc_cname,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
796
797
						(ber_len_t)STRLENOF( /* ((' */ "'))" ),
							/* ((' */ "'))" );
798
799
800
				bsi->bsi_status = LDAP_SUCCESS;
				rc = 1;
				goto done;
801
802
803
804
805
806
			}

			break;
		}

		case LDAP_FILTER_PRESENT:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
807
808
809
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
810
					(ber_len_t)STRLENOF( "3=3" ), "3=3" );
811
			bsi->bsi_status = LDAP_SUCCESS;
812
			rc = 1;
813
			goto done;
814
815

			/* FIXME: LDAP_FILTER_EXT? */
816
817
			
		default:
818
819
820
821
822
			Debug( LDAP_DEBUG_TRACE,
					"backsql_process_filter(): "
					"illegal/unhandled filter "
					"on objectClass attribute",
					0, 0, 0 );
823
			bsi->bsi_status = LDAP_OTHER;
824
825
			rc = -1;
			goto done;
826
		}
827

828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
	} 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;
		char		keyvalbuf[] = "18446744073709551615";
#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
Kurt Zeilenga's avatar
Kurt Zeilenga committed
848
849
850
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"bcblbc",
851
852
853
854
855
856
					&bsi->bsi_oc->bom_keytbl, '.',
					&bsi->bsi_oc->bom_keycol,
					STRLENOF( " LIKE '" ), " LIKE '",
					&keyval, '\'' );
#else /* ! BACKSQL_ARBITRARY_KEY */
			snprintf( keyvalbuf, sizeof( keyvalbuf ), "%lu", keyval );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
857
858
859
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"bcbcs",
860
861
862
863
864
865
					&bsi->bsi_oc->bom_keytbl, '.',
					&bsi->bsi_oc->bom_keycol, '=', keyvalbuf );
#endif /* ! BACKSQL_ARBITRARY_KEY */
			break;

		case LDAP_FILTER_PRESENT:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
866
867
868
			backsql_strfcat_x( &bsi->bsi_flt_where,
					bsi->bsi_op->o_tmpmemctx,
					"l",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
869
					(ber_len_t)STRLENOF( "4=4" ), "4=4" );
870
871
872
873
874
875
876
877
878
879
880
			break;

		default:
			rc = -1;
			goto done;
		}

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

881
#ifdef BACKSQL_SYNCPROV
Pierangelo Masarati's avatar
Pierangelo Masarati committed
882
883
	} else if ( ad == slap_schema.si_ad_entryCSN ) {
		/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
884
		 * support for syncrepl as producer...
Pierangelo Masarati's avatar
Pierangelo Masarati committed
885
		 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
886
#if 0
887
		if ( !bsi->bsi_op->o_sync ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
888
889
890
891
892
			/* unsupported at present... */
			bsi->bsi_status = LDAP_OTHER;
			rc = -1;
			goto done;
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
893
#endif
Pierangelo Masarati's avatar
Pierangelo Masarati committed
894

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

897
898
		/* if doing a syncrepl, try to return as much as possible,
		 * and always match the filter */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
899
900
901
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"l",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
902
				(ber_len_t)STRLENOF( "5=5" ), "5=5" );
903

904
905
906
907
908
909
910
911
912
913
		/* 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;
		}
914
		bsi->bsi_status = LDAP_SUCCESS;
915

916
917
		rc = 1;
		goto done;
918
#endif /* BACKSQL_SYNCPROV */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
919

920
921
922
923
924
925
926
927
928
	} 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)'
929
930
931
932
933
		 *
		 * A more robust search for hasSubordinates
		 * would * require joining the ldap_entries table
		 * selecting if there are descendants of the
		 * candidate.
934
		 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
935
936
937
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"l",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
938
				(ber_len_t)STRLENOF( "6=6" ), "6=6" );
939
		if ( ad == slap_schema.si_ad_hasSubordinates ) {
940
			/*
941
942
943
			 * instruct candidate selection algorithm
			 * and attribute list to try to detect
			 * if an entry has subordinates
944
945
			 */
			bsi->bsi_flags |= BSQL_SF_FILTER_HASSUBORDINATE;
946

947
948
949
950
951
952
953
		} else {
			/*
			 * clear attributes to fetch, to require ALL
			 * and try extended match on all attributes
			 */
			backsql_attrlist_add( bsi, NULL );
		}
954
		rc = 1;
955
		goto done;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
956
	}
957

958
959
960
961
962
963
964
965
	/*
	 * attribute inheritance:
	 */
	if ( backsql_supad2at( bsi->bsi_oc, ad, &vat ) ) {
		bsi->bsi_status = LDAP_OTHER;
		rc = -1;
		goto done;
	}
966

967
968
969
	if ( vat == NULL ) {
		/* search anyway; other parts of the filter
		 * may succeeed */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
970
971
972
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"l",
Kurt Zeilenga's avatar
Kurt Zeilenga committed
973
				(ber_len_t)STRLENOF( "7=7" ), "7=7" );
974
		bsi->bsi_status = LDAP_SUCCESS;
975
		rc = 1;
976
		goto done;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
977
978
	}

979
	/* if required, open extra level of parens */
980
	done = 0;
981
	if ( vat[0]->bam_next || vat[1] ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
982
983
984
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"c", '(' );
985
986
		done = 1;
	}
987
988

	i = 0;
989
next:;
990
991
	/* apply attr */
	if ( backsql_process_filter_attr( bsi, f, vat[i] ) == -1 ) {
992
993
994
		return -1;
	}

995
996
	/* if more definitions of the same attr, apply */
	if ( vat[i]->bam_next ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
997
998
999
		backsql_strfcat_x( &bsi->bsi_flt_where,
				bsi->bsi_op->o_tmpmemctx,
				"l",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1000
			STRLENOF( " OR " ), " OR " );
For faster browsing, not all history is shown. View entire blame