index.c 9.61 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
/* index.c - routines for dealing with attribute indexes */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
5
6
/*
 * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7

Kurt Zeilenga's avatar
Kurt Zeilenga committed
8
9
#include "portable.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
10
#include <stdio.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
11
12
13
14

#include <ac/string.h>
#include <ac/socket.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
15
16
17
#include "slap.h"
#include "back-ldbm.h"

18

19
static int	change_value(Backend *be,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
20
			  DBCache *db,
21
22
23
			  char *type,
			  int indextype,
			  char *val,
24
25
			  ID id,
			  int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
26
			  (*idl_func)(Backend *, DBCache *, Datum, ID));
27
static int	index2prefix(int indextype);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

int
index_add_entry(
    Backend	*be,
    Entry	*e
)
{
	Attribute	*ap;
	struct berval	bv;
	struct berval	*bvals[2];

	Debug( LDAP_DEBUG_TRACE, "=> index_add( %ld, \"%s\" )\n", e->e_id,
	    e->e_dn, 0 );

	/*
	 * dn index entry - make it look like an attribute so it works
44
	 * with index_change_values() call
Kurt Zeilenga's avatar
Kurt Zeilenga committed
45
46
	 */

47
	bv.bv_val = ch_strdup( e->e_ndn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
48
49
50
51
52
	bv.bv_len = strlen( bv.bv_val );
	bvals[0] = &bv;
	bvals[1] = NULL;

	/* add the dn to the indexes */
53
54
	{
		char *dn = ch_strdup("dn");
55
56
57
#ifdef SLAPD_SCHEMA_NOT_COMPAT
		/* not yet implemented */
#else
58
		index_change_values( be, dn, bvals, e->e_id, SLAP_INDEX_ADD_OP );
59
#endif
60
61
		free( dn );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
62
63
64
65
66

	free( bv.bv_val );

	/* add each attribute to the indexes */
	for ( ap = e->e_attrs; ap != NULL; ap = ap->a_next ) {
67
68
69
#ifdef SLAPD_SCHEMA_NOT_COMPAT
		/* index_change_values( be, SLAP_INDEX_ADD_OP, e->e_id, ap ); */
#else
70
		index_change_values( be, ap->a_type, ap->a_vals, e->e_id,
71
				     SLAP_INDEX_ADD_OP );
72
#endif
Kurt Zeilenga's avatar
Kurt Zeilenga committed
73
74
75
	}

	Debug( LDAP_DEBUG_TRACE, "<= index_add( %ld, \"%s\" ) 0\n", e->e_id,
76
	    e->e_ndn, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
77
78
79
80
81
82
	return( 0 );
}

int
index_add_mods(
    Backend	*be,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
83
    LDAPModList	*ml,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
84
85
86
87
88
    ID		id
)
{
	int	rc;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
89
90
91
92
	for ( ; ml != NULL; ml = ml->ml_next ) {
		LDAPMod *mod = &ml->ml_mod;

		switch ( mod->mod_op & ~LDAP_MOD_BVALUES ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
93
		case LDAP_MOD_REPLACE:
94
95
96
97
			/* XXX: Delete old index data==>problem when this 
			 * gets called we lost values already!
			 */
		case LDAP_MOD_ADD:
98
99
100
101
			rc = index_change_values( be,
					       mod->mod_type,
					       mod->mod_bvalues,
					       id,
102
					       SLAP_INDEX_ADD_OP );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
103
104
			break;
		case LDAP_MOD_DELETE:
105
106
107
108
			rc =  index_change_values( be,
						   mod->mod_type,
						   mod->mod_bvalues,
						   id,
109
						   SLAP_INDEX_DELETE_OP );
110
111
			break;
 		case LDAP_MOD_SOFTADD:	/* SOFTADD means index was there */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
112
113
114
115
116
117
118
119
120
121
122
123
			rc = 0;
			break;
		}

		if ( rc != 0 ) {
			return( rc );
		}
	}

	return( 0 );
}

124
ID_BLOCK *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
125
126
127
128
129
130
131
index_read(
    Backend	*be,
    char	*type,
    int		indextype,
    char	*val
)
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
132
	DBCache	*db;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
133
	Datum   	key;
134
	ID_BLOCK		*idl;
135
	int		indexmask;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
136
137
138
139
	char		prefix;
	char		*realval, *tmpval;
	char		buf[BUFSIZ];

140
	char		*at_cn;
141

142
	ldbm_datum_init( key );
143

Kurt Zeilenga's avatar
Kurt Zeilenga committed
144
	prefix = index2prefix( indextype );
145
146
	Debug( LDAP_DEBUG_TRACE, "=> index_read(\"%c%s\"->\"%s\")\n",
	    prefix, type, val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
147

148
	attr_mask( be->be_private, type, &indexmask );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
149
150
151
	if ( ! (indextype & indexmask) ) {
		idl =  idl_allids( be );
		Debug( LDAP_DEBUG_TRACE,
152
		    "<= index_read %ld candidates (allids - not indexed)\n",
153
		    idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
154
155
156
		return( idl );
	}

157
158
159
#ifdef SLAPD_SCHEMA_NOT_COMPAT
	at_cn = at_canonical_name( at_find( type ) );
#else
Kurt Zeilenga's avatar
Kurt Zeilenga committed
160
	attr_normalize( type );
161
	at_cn = at_canonical_name( type );
162
#endif
163

164
165
166
167
168
169
170
	if ( at_cn == NULL ) {
		Debug( LDAP_DEBUG_ANY,
		    "<= index_read no canonical name for type \"%s\"\n",
			type != NULL ? type : "(NULL)", 0, 0 );
		return( NULL );
	}

171
	if ( (db = ldbm_cache_open( be, at_cn, LDBM_SUFFIX, LDBM_WRCREAT ))
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172
173
	    == NULL ) {
		Debug( LDAP_DEBUG_ANY,
174
175
		    "<= index_read NULL (could not open %s%s)\n",
			at_cn, LDBM_SUFFIX, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
176
177
178
179
180
		return( NULL );
	}

	realval = val;
	tmpval = NULL;
181
	if ( prefix != UNKNOWN_PREFIX ) {
182
		unsigned int	len = strlen( val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
183

184
		if ( (len + 2) < sizeof(buf) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
185
186
187
188
189
190
			realval = buf;
		} else {
			/* value + prefix + null */
			tmpval = (char *) ch_malloc( len + 2 );
			realval = tmpval;
		}
191
192
193

		realval[0] = prefix;
		strcpy( &realval[1], val );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
194
195
196
197
198
199
	}

	key.dptr = realval;
	key.dsize = strlen( realval ) + 1;

	idl = idl_fetch( be, db, key );
200
	if ( tmpval != NULL ) {
201
              free( tmpval );
202
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
203
204
205

	ldbm_cache_close( be, db );

206
	Debug( LDAP_DEBUG_TRACE, "<= index_read %ld candidates\n",
207
	       idl ? ID_BLOCK_NIDS(idl) : 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
208
209
210
	return( idl );
}

211
/* Add or remove stuff from index files */
212
213

static int
214
change_value(
215
    Backend		*be,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
216
    DBCache	*db,
217
218
219
    char		*type,
    int			indextype,
    char		*val,
220
    ID			id,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
221
    int			(*idl_func)(Backend *, DBCache *, Datum, ID)
222
223
)
{
224
225
226
227
228
229
230
231
232
233
234
	int	rc;
	Datum   key;
	char	*tmpval = NULL;
	char	*realval = val;
	char	buf[BUFSIZ];

	char	prefix = index2prefix( indextype );

	ldbm_datum_init( key );

	Debug( LDAP_DEBUG_TRACE,
235
236
	       "=> change_value( \"%c%s\", op=%s )\n",
	       prefix, val, (idl_func == idl_insert_key ? "ADD":"DELETE") );
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254

	if ( prefix != UNKNOWN_PREFIX ) {
              unsigned int     len = strlen( val );

              if ( (len + 2) < sizeof(buf) ) {
			realval = buf;
	      } else {
			/* value + prefix + null */
			tmpval = (char *) ch_malloc( len + 2 );
			realval = tmpval;
	      }
              realval[0] = prefix;
              strcpy( &realval[1], val );
	}

	key.dptr = realval;
	key.dsize = strlen( realval ) + 1;

255
	rc = idl_func( be, db, key, id );
256
257
258
259
260
261
262

	if ( tmpval != NULL ) {
		free( tmpval );
	}

	ldap_pvt_thread_yield();

263
	Debug( LDAP_DEBUG_TRACE, "<= change_value %d\n", rc, 0, 0 );
264
265

	return( rc );
266

267
}/* static int change_value() */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
268

269
270

int
271
index_change_values(
272
273
274
    Backend		*be,
    char		*type,
    struct berval	**vals,
275
276
    ID			id,
    unsigned int	op
277
278
)
{
279
280
	char		*val, *p, *code, *w;
	unsigned	i, j, len;
281
	int		indexmask, syntax;
282
283
284
	char		buf[SUBLEN + 1];
	char		vbuf[BUFSIZ];
	char		*bigbuf;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
285
	DBCache	*db;
286

287
	int		(*idl_funct)(Backend *,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
288
				    DBCache *,
289
290
291
				    Datum, ID);
	char		*at_cn;	/* Attribute canonical name */
	int		mode;
292

293
294
295
	if( vals == NULL ) {
		Debug( LDAP_DEBUG_TRACE,
			"=> index_change_values( %s, NULL, %ld, op=%s )\n", 
296
			type, id, ((op == SLAP_INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
297
298
299
		return 0;
	}

300
	Debug( LDAP_DEBUG_TRACE,
301
	       "=> index_change_values( \"%s\", %ld, op=%s )\n", 
302
	       type, id, ((op == SLAP_INDEX_ADD_OP) ? "ADD" : "DELETE" ) );
303
304

	
305
	if (op == SLAP_INDEX_ADD_OP) {
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

	    /* Add values */

	    idl_funct =  idl_insert_key;
	    mode = LDBM_WRCREAT;

	} else {

	    /* Delete values */

	    idl_funct = idl_delete_key;
	    mode = LDBM_WRITER;

	}

321
#ifndef SLAPD_SCHEMA_NOT_COMPAT
322
	attr_normalize(type);
323
#endif
324
	attr_mask( be->be_private, type, &indexmask );
325

326
327
328
329
	if ( indexmask == 0 ) {
		return( 0 );
	}

330
331
332
#ifdef SLAPD_SCHEMA_NOT_COMPAT
	at_cn = at_canonical_name( at_find( type ) );
#else
333
	syntax = attr_syntax( type );
334
	at_cn = at_canonical_name( type );
335
#endif
336

337
338
339
340
341
342
343
	if ( at_cn == NULL ) {
		Debug( LDAP_DEBUG_ANY,
		    "<= index_change_values no canonical name for type \"%s\"\n",
			type != NULL ? type : "(NULL)", 0, 0 );
		return( -1 );
	}

344
	if ( (db = ldbm_cache_open( be, at_cn, LDBM_SUFFIX, mode ))
345
346
	     == NULL ) {
		Debug( LDAP_DEBUG_ANY,
347
		       "<= index_change_values (couldn't open(%s%s),md=%s)\n",
348
		       at_cn, LDBM_SUFFIX,
349
		       ((mode==LDBM_WRCREAT)?"LDBM_WRCREAT":"LDBM_WRITER") );
350
351
352
353
		return( -1 );
	}


354
355
356
#ifdef SLAPD_SCHEMA_NOT_COMPAT
	/* not yet implemented */
#else
357
	for ( i = 0; vals[i] != NULL; i++ ) {
358
		/*
359
		 * presence index entry
360
		 */
361
		if ( indexmask & SLAP_INDEX_PRESENCE ) {
362

363
			change_value( be, db, at_cn, SLAP_INDEX_PRESENCE,
364
365
				      "*", id, idl_funct );

366
367
368
		}

		Debug( LDAP_DEBUG_TRACE,
369
		       "index_change_values syntax 0x%x syntax bin 0x%x\n",
370
371
372
		       syntax, SYNTAX_BIN, 0 );

		if ( syntax & SYNTAX_BIN ) {
373

374
375
			ldbm_cache_close( be, db );
			return( 0 );
376

377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
		}

		bigbuf = NULL;
		len = vals[i]->bv_len;

		/* value + null */
		if ( len + 2 > sizeof(vbuf) ) {
			bigbuf = (char *) ch_malloc( len + 1 );
			val = bigbuf;
		} else {
			val = vbuf;
		}
		(void) memcpy( val, vals[i]->bv_val, len );
		val[len] = '\0';

		value_normalize( val, syntax );

		/* value_normalize could change the length of val */
		len = strlen( val );

		/*
		 * equality index entry
		 */
400
		if ( indexmask & SLAP_INDEX_EQUALITY ) {
401
		    
402
			change_value( be, db, at_cn, SLAP_INDEX_EQUALITY,
403
				      val, id, idl_funct);
404
405
406
407
408
409

		}

		/*
		 * approximate index entry
		 */
410
		if ( indexmask & SLAP_INDEX_APPROX ) {
411
412
			for ( w = first_word( val ); w != NULL;
			    w = next_word( w ) ) {
413
				if ( (code = phonetic( w )) != NULL ) {
414
					change_value( be,
415
416
						      db,
						      at_cn,
417
						      SLAP_INDEX_APPROX,
418
						      code,
419
420
						      id,
						      idl_funct );
421
422
423
424
425
426
427
428
					free( code );
				}
			}
		}

		/*
		 * substrings index entry
		 */
429
		if ( indexmask & SLAP_INDEX_SUB ) {
430
431
432
433
434
435
436
437
			/* leading and trailing */
			if ( len > SUBLEN - 2 ) {
				buf[0] = '^';
				for ( j = 0; j < SUBLEN - 1; j++ ) {
					buf[j + 1] = val[j];
				}
				buf[SUBLEN] = '\0';

438
				change_value( be, db, at_cn, SLAP_INDEX_SUB,
439
					      buf, id, idl_funct );
440
441
442
443
444
445
446
447

				p = val + len - SUBLEN + 1;
				for ( j = 0; j < SUBLEN - 1; j++ ) {
					buf[j] = p[j];
				}
				buf[SUBLEN - 1] = '$';
				buf[SUBLEN] = '\0';

448
				change_value( be, db, at_cn, SLAP_INDEX_SUB,
449
					      buf, id, idl_funct );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
450
451
452
453
454
455
456
457
458
			}

			/* any */
			for ( p = val; p < (val + len - SUBLEN + 1); p++ ) {
				for ( j = 0; j < SUBLEN; j++ ) {
					buf[j] = p[j];
				}
				buf[SUBLEN] = '\0';

459
				change_value( be, db, at_cn, SLAP_INDEX_SUB,
460
					      buf, id, idl_funct );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
461
462
463
464
465
466
467
			}
		}

		if ( bigbuf != NULL ) {
			free( bigbuf );
		}
	}
468
#endif
469

Kurt Zeilenga's avatar
Kurt Zeilenga committed
470
471
472
	ldbm_cache_close( be, db );

	return( 0 );
473
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
474
475
476
477
478
479
480

static int
index2prefix( int indextype )
{
	int	prefix;

	switch ( indextype ) {
481
	case SLAP_INDEX_EQUALITY:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
482
483
		prefix = EQ_PREFIX;
		break;
484
	case SLAP_INDEX_APPROX:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
485
486
		prefix = APPROX_PREFIX;
		break;
487
	case SLAP_INDEX_SUB:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
488
489
490
		prefix = SUB_PREFIX;
		break;
	default:
491
		prefix = UNKNOWN_PREFIX;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
492
493
494
495
496
		break;
	}

	return( prefix );
}