xref: /titanic_44/usr/src/lib/libnisdb/db_mindex.cc (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  *	db_mindex.cc
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  *  Copyright 1988-2002 Sun Microsystems, Inc.  All rights reserved.
26*7c478bd9Sstevel@tonic-gate  *  Use is subject to license terms.
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <malloc.h>
34*7c478bd9Sstevel@tonic-gate #include <strings.h>
35*7c478bd9Sstevel@tonic-gate #include <string.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
37*7c478bd9Sstevel@tonic-gate #include "db_headers.h"
38*7c478bd9Sstevel@tonic-gate #include "db.h"
39*7c478bd9Sstevel@tonic-gate #include "db_mindex.h"
40*7c478bd9Sstevel@tonic-gate #include "db_pickle.h"
41*7c478bd9Sstevel@tonic-gate #include "nisdb_mt.h"
42*7c478bd9Sstevel@tonic-gate #include "nisdb_ldap.h"
43*7c478bd9Sstevel@tonic-gate #include "ldap_nisdbquery.h"
44*7c478bd9Sstevel@tonic-gate #include "ldap_map.h"
45*7c478bd9Sstevel@tonic-gate #include "ldap_ruleval.h"
46*7c478bd9Sstevel@tonic-gate #include "ldap_scheme.h"
47*7c478bd9Sstevel@tonic-gate #include "ldap_parse.h"
48*7c478bd9Sstevel@tonic-gate #include "nis_hashitem.h"
49*7c478bd9Sstevel@tonic-gate #include "ldap_nisplus.h"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  *  Constructor:  Create new table using scheme defintion supplied.
53*7c478bd9Sstevel@tonic-gate  *  (Make copy of scheme and keep it with table.)
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate db_mindex::db_mindex(db_scheme *how, char *tablePath) : rversion()
56*7c478bd9Sstevel@tonic-gate {
57*7c478bd9Sstevel@tonic-gate 	noWriteThrough.flag = 0;
58*7c478bd9Sstevel@tonic-gate 	noLDAPquery.flag = 0;
59*7c478bd9Sstevel@tonic-gate 	initialLoad.flag = 0;
60*7c478bd9Sstevel@tonic-gate 	objPath.ptr = NULL;
61*7c478bd9Sstevel@tonic-gate 	init(how);
62*7c478bd9Sstevel@tonic-gate 	if (tablePath != NULL)
63*7c478bd9Sstevel@tonic-gate 		configure(tablePath);
64*7c478bd9Sstevel@tonic-gate }
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate /* Constructor:  Create empty table (no scheme, no table or indices). */
67*7c478bd9Sstevel@tonic-gate db_mindex::db_mindex() : rversion()
68*7c478bd9Sstevel@tonic-gate {
69*7c478bd9Sstevel@tonic-gate 	scheme = NULL;
70*7c478bd9Sstevel@tonic-gate 	table = NULL;
71*7c478bd9Sstevel@tonic-gate 	indices.indices_len = 0;
72*7c478bd9Sstevel@tonic-gate 	indices.indices_val = NULL;
73*7c478bd9Sstevel@tonic-gate 	noWriteThrough.flag = 0;
74*7c478bd9Sstevel@tonic-gate 	noLDAPquery.flag = 0;
75*7c478bd9Sstevel@tonic-gate 	initialLoad.flag = 0;
76*7c478bd9Sstevel@tonic-gate 	objPath.ptr = NULL;
77*7c478bd9Sstevel@tonic-gate 	INITRW(mindex);
78*7c478bd9Sstevel@tonic-gate }
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate db_mindex::~db_mindex()
81*7c478bd9Sstevel@tonic-gate {
82*7c478bd9Sstevel@tonic-gate 	reset();   /* get rid of data structures first */
83*7c478bd9Sstevel@tonic-gate 	DESTROYRW(mindex);
84*7c478bd9Sstevel@tonic-gate }
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate /*
87*7c478bd9Sstevel@tonic-gate  * Initialize table using information given in scheme 'how'.
88*7c478bd9Sstevel@tonic-gate  * Record the scheme for later use (make copy of it);
89*7c478bd9Sstevel@tonic-gate  * create the required number of indices; and create table for storing
90*7c478bd9Sstevel@tonic-gate  * entries.
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate void
93*7c478bd9Sstevel@tonic-gate db_mindex::init(db_scheme * how)
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate 	scheme = new db_scheme(how);		// make copy
96*7c478bd9Sstevel@tonic-gate 	if (scheme == NULL)
97*7c478bd9Sstevel@tonic-gate 		FATAL("db_mindex::init: could not allocate space for scheme",
98*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	if (scheme->numkeys() == 0) {
101*7c478bd9Sstevel@tonic-gate 	    WARNING("db_mindex::init: empty scheme encountered");
102*7c478bd9Sstevel@tonic-gate 	    /* what action should we take here? */
103*7c478bd9Sstevel@tonic-gate 	}
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	indices.indices_len = how->numkeys();
106*7c478bd9Sstevel@tonic-gate 	db_key_desc * keys = how->keyloc();
107*7c478bd9Sstevel@tonic-gate 	int i;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	/* homogeneous indices for now */
110*7c478bd9Sstevel@tonic-gate 	indices.indices_val = new db_index[indices.indices_len];
111*7c478bd9Sstevel@tonic-gate 	if (indices.indices_val == NULL) {
112*7c478bd9Sstevel@tonic-gate 		delete scheme;
113*7c478bd9Sstevel@tonic-gate 		indices.indices_len = 0;
114*7c478bd9Sstevel@tonic-gate 		scheme = NULL;
115*7c478bd9Sstevel@tonic-gate 		FATAL("db_mindex::init: could not allocate space for indices",
116*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
117*7c478bd9Sstevel@tonic-gate 	}
118*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < indices.indices_len; i++) {
119*7c478bd9Sstevel@tonic-gate 		indices.indices_val[i].init(&(keys[i]));
120*7c478bd9Sstevel@tonic-gate 	}
121*7c478bd9Sstevel@tonic-gate 	table = new db_table();
122*7c478bd9Sstevel@tonic-gate 	if (table == NULL) {
123*7c478bd9Sstevel@tonic-gate 		delete scheme;
124*7c478bd9Sstevel@tonic-gate 		scheme = NULL;
125*7c478bd9Sstevel@tonic-gate 		delete indices.indices_val;
126*7c478bd9Sstevel@tonic-gate 		indices.indices_val = NULL;
127*7c478bd9Sstevel@tonic-gate 		indices.indices_len = 0;
128*7c478bd9Sstevel@tonic-gate 		FATAL("db_mindex::init: could not allocate space for table",
129*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT);
130*7c478bd9Sstevel@tonic-gate 	}
131*7c478bd9Sstevel@tonic-gate 	rversion.zero();
132*7c478bd9Sstevel@tonic-gate 	INITRW(mindex);
133*7c478bd9Sstevel@tonic-gate 	objPath.ptr = NULL;
134*7c478bd9Sstevel@tonic-gate }
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate /* empty associated tables associated */
137*7c478bd9Sstevel@tonic-gate void
138*7c478bd9Sstevel@tonic-gate db_mindex::reset_tables()
139*7c478bd9Sstevel@tonic-gate {
140*7c478bd9Sstevel@tonic-gate 	int i;
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	WRITELOCKV(this, "w db_mindex::reset_tables");
143*7c478bd9Sstevel@tonic-gate 	/* Add sanity check in case of table corruption */
144*7c478bd9Sstevel@tonic-gate 	if (indices.indices_val != NULL) {
145*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < indices.indices_len; i++) {
146*7c478bd9Sstevel@tonic-gate 			indices.indices_val[i].reset();
147*7c478bd9Sstevel@tonic-gate 		}
148*7c478bd9Sstevel@tonic-gate 	}
149*7c478bd9Sstevel@tonic-gate 	if (table) table->reset();
150*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_mindex::reset_tables");
151*7c478bd9Sstevel@tonic-gate }
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate /*
155*7c478bd9Sstevel@tonic-gate  * Return a list of index_entries that satsify the given query 'q'.
156*7c478bd9Sstevel@tonic-gate  * Return the size of the list in 'count'. Return NULL if list is empty.
157*7c478bd9Sstevel@tonic-gate  * Return in 'valid' FALSE if query is not well formed.
158*7c478bd9Sstevel@tonic-gate */
159*7c478bd9Sstevel@tonic-gate db_index_entry_p
160*7c478bd9Sstevel@tonic-gate db_mindex::satisfy_query(db_query *q, long *count, bool_t *valid) {
161*7c478bd9Sstevel@tonic-gate 	return (satisfy_query(q, count, valid, FALSE));
162*7c478bd9Sstevel@tonic-gate }
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate db_index_entry_p
165*7c478bd9Sstevel@tonic-gate db_mindex::satisfy_query(db_query *q, long *count, bool_t *valid,
166*7c478bd9Sstevel@tonic-gate 			bool_t fromLDAP) {
167*7c478bd9Sstevel@tonic-gate 	db_index_entry_p	ret;
168*7c478bd9Sstevel@tonic-gate 	bool_t			validRequest;
169*7c478bd9Sstevel@tonic-gate 	int			queryRes;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	/* Make sure we have somewhere to store the "request valid" status */
172*7c478bd9Sstevel@tonic-gate 	if (valid == NULL)
173*7c478bd9Sstevel@tonic-gate 		valid = &validRequest;
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	/* Prepare for a failed lock */
176*7c478bd9Sstevel@tonic-gate 	*count = 0;
177*7c478bd9Sstevel@tonic-gate 	*valid = FALSE;
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_mindex::satisfy_query");
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	/*
182*7c478bd9Sstevel@tonic-gate 	 * Only get data from LDAP if the caller requested it,
183*7c478bd9Sstevel@tonic-gate 	 * and if we're mapping for this table.
184*7c478bd9Sstevel@tonic-gate 	 */
185*7c478bd9Sstevel@tonic-gate 	fromLDAP = (fromLDAP && !noLDAPquery.flag &&
186*7c478bd9Sstevel@tonic-gate 		(table->mapping.fromLDAP ||
187*7c478bd9Sstevel@tonic-gate 			table->mapping.objType != NIS_TABLE_OBJ));
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	/*
190*7c478bd9Sstevel@tonic-gate 	 * If we always fetch data from LDAP for query's, then do so now,
191*7c478bd9Sstevel@tonic-gate 	 * before invoking the "real" satisfy_query().
192*7c478bd9Sstevel@tonic-gate 	 */
193*7c478bd9Sstevel@tonic-gate 	if (fromLDAP && table->mapping.matchFetch == mat_always) {
194*7c478bd9Sstevel@tonic-gate 		int	lockcode = 0;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 		READLOCKNR(table, lockcode,
197*7c478bd9Sstevel@tonic-gate 				"r db_mindex::satisfy_query table");
198*7c478bd9Sstevel@tonic-gate 		if (lockcode != 0) {
199*7c478bd9Sstevel@tonic-gate 			READUNLOCK(this, NULL, "ru db_mindex::satisfy_query");
200*7c478bd9Sstevel@tonic-gate 			return (NULL);
201*7c478bd9Sstevel@tonic-gate 		}
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 		queryRes = queryLDAP(q, 0, 1);
204*7c478bd9Sstevel@tonic-gate 
205*7c478bd9Sstevel@tonic-gate 		READUNLOCKNR(table, lockcode,
206*7c478bd9Sstevel@tonic-gate 				"ru db_mindex::satisfy_query table");
207*7c478bd9Sstevel@tonic-gate 		if (lockcode != 0) {
208*7c478bd9Sstevel@tonic-gate 			READUNLOCK(this, NULL, "ru db_mindex::satisfy_query");
209*7c478bd9Sstevel@tonic-gate 			return (NULL);
210*7c478bd9Sstevel@tonic-gate 		}
211*7c478bd9Sstevel@tonic-gate 		if (queryRes != LDAP_SUCCESS) {
212*7c478bd9Sstevel@tonic-gate 			/* queryLDAP() sets error codes etc. */
213*7c478bd9Sstevel@tonic-gate 			READUNLOCK(this, NULL, "ru db_mindex::satisfy_query");
214*7c478bd9Sstevel@tonic-gate 			return (NULL);
215*7c478bd9Sstevel@tonic-gate 		}
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	}
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	ret = satisfy_query_dbonly(q, count, fromLDAP ? TRUE : FALSE, valid);
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	/* If we found it, or if we're not mapping, return */
222*7c478bd9Sstevel@tonic-gate 	if (ret != NULL || !fromLDAP) {
223*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL, "ru db_mindex::satisfy_query");
224*7c478bd9Sstevel@tonic-gate 		return (ret);
225*7c478bd9Sstevel@tonic-gate 	} else if (ret == NULL && !(*valid)) {
226*7c478bd9Sstevel@tonic-gate 		/* No result, and the request wasn't valid */
227*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL, "ru db_mindex::satisfy_query");
228*7c478bd9Sstevel@tonic-gate 		return (NULL);
229*7c478bd9Sstevel@tonic-gate 	}
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	/* Get data from LDAP */
232*7c478bd9Sstevel@tonic-gate 	if (table->mapping.matchFetch != mat_never) {
233*7c478bd9Sstevel@tonic-gate 		queryRes = queryLDAP(q, 0, 1);
234*7c478bd9Sstevel@tonic-gate 	} else {
235*7c478bd9Sstevel@tonic-gate 		/*
236*7c478bd9Sstevel@tonic-gate 		 * We'll now go on to check for an un-expired entry again,
237*7c478bd9Sstevel@tonic-gate 		 * even though we're pretty sure that won't work (already
238*7c478bd9Sstevel@tonic-gate 		 * did that, and nothing's changed). However, we accept that
239*7c478bd9Sstevel@tonic-gate 		 * slight inefficiency in the interest of keeping the code
240*7c478bd9Sstevel@tonic-gate 		 * simple; we expect 'mat_never' to be used very rarely.
241*7c478bd9Sstevel@tonic-gate 		 */
242*7c478bd9Sstevel@tonic-gate 		queryRes = LDAP_SUCCESS;
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	if (queryRes == LDAP_SUCCESS) {
246*7c478bd9Sstevel@tonic-gate 		/*
247*7c478bd9Sstevel@tonic-gate 		 * Check if we've got a match now. If not, try one
248*7c478bd9Sstevel@tonic-gate 		 * last time for an expired match.
249*7c478bd9Sstevel@tonic-gate 		 */
250*7c478bd9Sstevel@tonic-gate 		ret = satisfy_query_dbonly(q, count, TRUE, valid);
251*7c478bd9Sstevel@tonic-gate 		if (ret == NULL) {
252*7c478bd9Sstevel@tonic-gate 			ret = satisfy_query_dbonly(q, count, FALSE, valid);
253*7c478bd9Sstevel@tonic-gate 			if (ret != NULL)
254*7c478bd9Sstevel@tonic-gate 				setMappingStatus(NIS_CACHEEXPIRED, queryRes);
255*7c478bd9Sstevel@tonic-gate 		}
256*7c478bd9Sstevel@tonic-gate 	} else {
257*7c478bd9Sstevel@tonic-gate 		/*
258*7c478bd9Sstevel@tonic-gate 		 * Check if we have an expired entry; if so, return
259*7c478bd9Sstevel@tonic-gate 		 * it with an appropriate status.
260*7c478bd9Sstevel@tonic-gate 		 */
261*7c478bd9Sstevel@tonic-gate 		ret = satisfy_query_dbonly(q, count, FALSE, valid);
262*7c478bd9Sstevel@tonic-gate 		setMappingStatus(ret ? NIS_CACHEEXPIRED : NIS_SUCCESS,
263*7c478bd9Sstevel@tonic-gate 				queryRes);
264*7c478bd9Sstevel@tonic-gate 	}
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, NULL, "ru db_mindex::satisfy_query");
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	return (ret);
269*7c478bd9Sstevel@tonic-gate }
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate db_index_entry_p
272*7c478bd9Sstevel@tonic-gate db_mindex::satisfy_query_dbonly(db_query *q, long *count,
273*7c478bd9Sstevel@tonic-gate 				bool_t checkExpire, bool_t *valid)
274*7c478bd9Sstevel@tonic-gate {
275*7c478bd9Sstevel@tonic-gate 	db_index_entry_p oldres = NULL, newres;
276*7c478bd9Sstevel@tonic-gate 	int i, curr_ind;
277*7c478bd9Sstevel@tonic-gate 	long num_new, num_old = 0;
278*7c478bd9Sstevel@tonic-gate 	int limit = q->size();
279*7c478bd9Sstevel@tonic-gate 	db_qcomp * comps = q->queryloc();
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	if (valid) *valid = TRUE;   /* True to begin with. */
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	/* Add sanity check in case table corrupted */
284*7c478bd9Sstevel@tonic-gate 	if (indices.indices_len != 0 && indices.indices_val == NULL) {
285*7c478bd9Sstevel@tonic-gate 		WARNING("db_mindex::satisfy_query: table has no indices");
286*7c478bd9Sstevel@tonic-gate 		if (valid) *valid = FALSE;
287*7c478bd9Sstevel@tonic-gate 		*count = 0;
288*7c478bd9Sstevel@tonic-gate 		return (NULL);
289*7c478bd9Sstevel@tonic-gate 	}
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < limit; i++) {
292*7c478bd9Sstevel@tonic-gate 		if ((curr_ind = comps[i].which_index) < indices.indices_len) {
293*7c478bd9Sstevel@tonic-gate 			newres = indices.indices_val[curr_ind].lookup(
294*7c478bd9Sstevel@tonic-gate 					comps[i].index_value, &num_new,
295*7c478bd9Sstevel@tonic-gate 					table, checkExpire);
296*7c478bd9Sstevel@tonic-gate 			if (newres == NULL) {
297*7c478bd9Sstevel@tonic-gate 				*count = 0;
298*7c478bd9Sstevel@tonic-gate 				return (NULL);
299*7c478bd9Sstevel@tonic-gate 			}
300*7c478bd9Sstevel@tonic-gate 			if (oldres == NULL) {
301*7c478bd9Sstevel@tonic-gate 				oldres = newres;
302*7c478bd9Sstevel@tonic-gate 				num_old = num_new;
303*7c478bd9Sstevel@tonic-gate 			} else {
304*7c478bd9Sstevel@tonic-gate 				oldres = newres->join(num_new, num_old,
305*7c478bd9Sstevel@tonic-gate 							oldres, &num_old);
306*7c478bd9Sstevel@tonic-gate 				if (oldres == NULL) {
307*7c478bd9Sstevel@tonic-gate 					*count = 0;
308*7c478bd9Sstevel@tonic-gate 					return (NULL);
309*7c478bd9Sstevel@tonic-gate 				}
310*7c478bd9Sstevel@tonic-gate 			}
311*7c478bd9Sstevel@tonic-gate 		} else {
312*7c478bd9Sstevel@tonic-gate 			WARNING("db_mindex::satisfy_query: index out of range");
313*7c478bd9Sstevel@tonic-gate 			if (valid) *valid = FALSE;
314*7c478bd9Sstevel@tonic-gate 			*count = 0;
315*7c478bd9Sstevel@tonic-gate 			return (NULL);
316*7c478bd9Sstevel@tonic-gate 		}
317*7c478bd9Sstevel@tonic-gate 	}
318*7c478bd9Sstevel@tonic-gate 	*count = num_old;
319*7c478bd9Sstevel@tonic-gate 	return (oldres);
320*7c478bd9Sstevel@tonic-gate }
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate /*
323*7c478bd9Sstevel@tonic-gate  * Returns an array of size 'count' of 'entry_object_p's, pointing to
324*7c478bd9Sstevel@tonic-gate  * copies of entry_objects named by the result list of db_index_entries 'res'.
325*7c478bd9Sstevel@tonic-gate  * Sets db_status 'statp' if error encountered; otherwise, leaves it unchanged.
326*7c478bd9Sstevel@tonic-gate */
327*7c478bd9Sstevel@tonic-gate entry_object_p *
328*7c478bd9Sstevel@tonic-gate db_mindex::prepare_results(int count, db_index_entry_p res, db_status *statp)
329*7c478bd9Sstevel@tonic-gate {
330*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_mindex::prepare_results");
331*7c478bd9Sstevel@tonic-gate 	READLOCK2(table, NULL, "r table db_mindex::prepare_results", this);
332*7c478bd9Sstevel@tonic-gate 	entry_object_p * entries = new entry_object_p[count];
333*7c478bd9Sstevel@tonic-gate 	int i;
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	if (entries == NULL) {
336*7c478bd9Sstevel@tonic-gate 		READUNLOCK2(this, table, NULL, NULL,
337*7c478bd9Sstevel@tonic-gate 	"ru db_mindex::prepare_results: could not allocate space",
338*7c478bd9Sstevel@tonic-gate 	"ru table db_mindex::prepare_results: could not allocate space");
339*7c478bd9Sstevel@tonic-gate 		FATAL3("db_mindex::prepare_results: could not allocate space",
340*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, NULL);
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
344*7c478bd9Sstevel@tonic-gate 		if (res == NULL) {
345*7c478bd9Sstevel@tonic-gate 			int j;
346*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < i; j++) // cleanup
347*7c478bd9Sstevel@tonic-gate 				free_entry(entries[j]);
348*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
349*7c478bd9Sstevel@tonic-gate 				"db_mindex::prepare_results: incorrect count");
350*7c478bd9Sstevel@tonic-gate 			*statp = DB_INTERNAL_ERROR;
351*7c478bd9Sstevel@tonic-gate 		} else {
352*7c478bd9Sstevel@tonic-gate 			entries[i] =
353*7c478bd9Sstevel@tonic-gate 				new_entry(table->get_entry(res->getlocation()));
354*7c478bd9Sstevel@tonic-gate 			res = res->getnextresult();
355*7c478bd9Sstevel@tonic-gate 		}
356*7c478bd9Sstevel@tonic-gate 	}
357*7c478bd9Sstevel@tonic-gate 	READUNLOCK2(this, table, entries, entries,
358*7c478bd9Sstevel@tonic-gate 			"ru db_mindex::prepare_results",
359*7c478bd9Sstevel@tonic-gate 			"ru db_mindex::prepare_results");
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 	return (entries);
362*7c478bd9Sstevel@tonic-gate }
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate /*
365*7c478bd9Sstevel@tonic-gate  * Returns a newly created db_query structure containing the index values
366*7c478bd9Sstevel@tonic-gate  * as obtained from the record named by 'recnum'.  The record itself, along
367*7c478bd9Sstevel@tonic-gate  * with information on the schema definition of this table, will determine
368*7c478bd9Sstevel@tonic-gate  * which values are extracted from the record and placed into the result.
369*7c478bd9Sstevel@tonic-gate  * Returns NULL if recnum is not a valid entry.
370*7c478bd9Sstevel@tonic-gate  * Note that space is allocated for the query and the index values
371*7c478bd9Sstevel@tonic-gate  * (i.e. do not share pointers with strings in 'obj'.)
372*7c478bd9Sstevel@tonic-gate  */
373*7c478bd9Sstevel@tonic-gate db_query *
374*7c478bd9Sstevel@tonic-gate db_mindex::extract_index_values_from_record(entryp recnum)
375*7c478bd9Sstevel@tonic-gate {
376*7c478bd9Sstevel@tonic-gate 	db_query	*ret;
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	ret = extract_index_values_from_object(table->get_entry(recnum));
379*7c478bd9Sstevel@tonic-gate 	return (ret);
380*7c478bd9Sstevel@tonic-gate }
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate /*
383*7c478bd9Sstevel@tonic-gate  * Returns a newly created db_query containing the index values as
384*7c478bd9Sstevel@tonic-gate  * obtained from the given object.  The object itself,
385*7c478bd9Sstevel@tonic-gate  * along with information on the scheme given, will determine
386*7c478bd9Sstevel@tonic-gate  * which values are extracted from the object and placed into the query.
387*7c478bd9Sstevel@tonic-gate  * Returns an empty query if 'obj' is not a valid entry.
388*7c478bd9Sstevel@tonic-gate  * Note that space is allocated for the query and the index values
389*7c478bd9Sstevel@tonic-gate  * (i.e. do not share pointers with strings in 'obj'.)
390*7c478bd9Sstevel@tonic-gate */
391*7c478bd9Sstevel@tonic-gate db_query *
392*7c478bd9Sstevel@tonic-gate db_mindex::extract_index_values_from_object(entry_object_p obj)
393*7c478bd9Sstevel@tonic-gate {
394*7c478bd9Sstevel@tonic-gate 	READLOCK(this, NULL, "r db_mindex::extract_index_values_from_object");
395*7c478bd9Sstevel@tonic-gate 	if (scheme->numkeys() != indices.indices_len) { // probably built wrong
396*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
397*7c478bd9Sstevel@tonic-gate 	    "number of keys (%d) does not equal number of indices (%d)",
398*7c478bd9Sstevel@tonic-gate 	    scheme->numkeys(), indices.indices_len);
399*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL,
400*7c478bd9Sstevel@tonic-gate 			"ru db_mindex::extract_index_values_from_object");
401*7c478bd9Sstevel@tonic-gate 		return (new db_query());	// null query
402*7c478bd9Sstevel@tonic-gate 	} else if (obj == NULL) {
403*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, NULL,
404*7c478bd9Sstevel@tonic-gate 			"ru db_mindex::extract_index_values_from_object");
405*7c478bd9Sstevel@tonic-gate 		return (NULL);
406*7c478bd9Sstevel@tonic-gate 	} else {
407*7c478bd9Sstevel@tonic-gate 		db_query* answer = new db_query(scheme, obj);
408*7c478bd9Sstevel@tonic-gate 		if (answer) {
409*7c478bd9Sstevel@tonic-gate 			/*
410*7c478bd9Sstevel@tonic-gate 			 * XXX If the unlock fails, and we return NULL,
411*7c478bd9Sstevel@tonic-gate 			 * we leak 'answer'. On the other hand, if we
412*7c478bd9Sstevel@tonic-gate 			 * return 'answer', the object may remain locked,
413*7c478bd9Sstevel@tonic-gate 			 * but the caller doesn't know that anything
414*7c478bd9Sstevel@tonic-gate 			 * went wrong.
415*7c478bd9Sstevel@tonic-gate 			 */
416*7c478bd9Sstevel@tonic-gate 			READUNLOCK(this, NULL,
417*7c478bd9Sstevel@tonic-gate 			"ru db_mindex::extract_index_values_from_object");
418*7c478bd9Sstevel@tonic-gate 			return (answer);
419*7c478bd9Sstevel@tonic-gate 		} else {
420*7c478bd9Sstevel@tonic-gate 			FATAL3("db_mindex::extract: could not allocate space",
421*7c478bd9Sstevel@tonic-gate 				DB_MEMORY_LIMIT, NULL);
422*7c478bd9Sstevel@tonic-gate 		}
423*7c478bd9Sstevel@tonic-gate 	}
424*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, NULL,
425*7c478bd9Sstevel@tonic-gate 		"ru db_mindex::extract_index_values_from_object");
426*7c478bd9Sstevel@tonic-gate 	return (NULL);
427*7c478bd9Sstevel@tonic-gate }
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate /*
430*7c478bd9Sstevel@tonic-gate  * Returns the first entry found in the table by setting 'answer' to
431*7c478bd9Sstevel@tonic-gate  * point to the a copy of entry_object.  Returns DB_SUCCESS if found;
432*7c478bd9Sstevel@tonic-gate  * DB_NOTFOUND otherwise.
433*7c478bd9Sstevel@tonic-gate */
434*7c478bd9Sstevel@tonic-gate db_status
435*7c478bd9Sstevel@tonic-gate db_mindex::first(entryp *where, entry_object ** answer)
436*7c478bd9Sstevel@tonic-gate {
437*7c478bd9Sstevel@tonic-gate 	db_status	ret = DB_SUCCESS;
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	/*
440*7c478bd9Sstevel@tonic-gate 	 * table->first_entry() returns a pointer into the table, so
441*7c478bd9Sstevel@tonic-gate 	 * we must keep the table read locked until we've copied the
442*7c478bd9Sstevel@tonic-gate 	 * entry_object. In order to maintain lock integrity, we must
443*7c478bd9Sstevel@tonic-gate 	 * lock the db_mindex (this) before the db_table (table).
444*7c478bd9Sstevel@tonic-gate 	 */
445*7c478bd9Sstevel@tonic-gate 	READLOCK(this, DB_LOCK_ERROR, "r db_mindex::first");
446*7c478bd9Sstevel@tonic-gate 	READLOCK2(table, DB_LOCK_ERROR, "r table db_mindex::first", this);
447*7c478bd9Sstevel@tonic-gate 	if (table->mapping.fromLDAP) {
448*7c478bd9Sstevel@tonic-gate 		struct timeval	now;
449*7c478bd9Sstevel@tonic-gate 		(void) gettimeofday(&now, NULL);
450*7c478bd9Sstevel@tonic-gate 		if (now.tv_sec >= table->mapping.enumExpire) {
451*7c478bd9Sstevel@tonic-gate 			int queryRes = queryLDAP(0, 0, 1);
452*7c478bd9Sstevel@tonic-gate 			if (queryRes == LDAP_SUCCESS)
453*7c478bd9Sstevel@tonic-gate 				table->mapping.enumExpire = now.tv_sec +
454*7c478bd9Sstevel@tonic-gate 					table->mapping.ttl;
455*7c478bd9Sstevel@tonic-gate 			else {
456*7c478bd9Sstevel@tonic-gate 				READUNLOCK2(this, table,
457*7c478bd9Sstevel@tonic-gate 					DB_LOCK_ERROR, DB_LOCK_ERROR,
458*7c478bd9Sstevel@tonic-gate 					"ru db_mindex::first LDAP",
459*7c478bd9Sstevel@tonic-gate 					"ru table db_mindex::first LDAP");
460*7c478bd9Sstevel@tonic-gate 				return (DB_INTERNAL_ERROR);
461*7c478bd9Sstevel@tonic-gate 			}
462*7c478bd9Sstevel@tonic-gate 		}
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate 	entry_object_p ptr = table->first_entry(where);
465*7c478bd9Sstevel@tonic-gate 	if (ptr == NULL)
466*7c478bd9Sstevel@tonic-gate 		ret = DB_NOTFOUND;
467*7c478bd9Sstevel@tonic-gate 	else
468*7c478bd9Sstevel@tonic-gate 		*answer = new_entry(ptr);
469*7c478bd9Sstevel@tonic-gate 	READUNLOCK2(this, table, ret, ret,
470*7c478bd9Sstevel@tonic-gate 		"ru db_mindex::first", "ru table db_mindex::first");
471*7c478bd9Sstevel@tonic-gate 	return (ret);
472*7c478bd9Sstevel@tonic-gate }
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate /*
475*7c478bd9Sstevel@tonic-gate  * Returns the next entry in the table after 'previous' by setting 'answer' to
476*7c478bd9Sstevel@tonic-gate  * point to copy of the entry_object.  Returns DB_SUCCESS if 'previous' is
477*7c478bd9Sstevel@tonic-gate  * valid and next entry is found; DB_NOTFOUND otherwise.  Sets 'where' to
478*7c478bd9Sstevel@tonic-gate  * location of where entry is found for input as subsequent 'next' operation.
479*7c478bd9Sstevel@tonic-gate */
480*7c478bd9Sstevel@tonic-gate db_status
481*7c478bd9Sstevel@tonic-gate db_mindex::next(entryp previous, entryp *where, entry_object **answer)
482*7c478bd9Sstevel@tonic-gate {
483*7c478bd9Sstevel@tonic-gate 	db_status	ret = DB_SUCCESS;
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	READLOCK(this, DB_LOCK_ERROR, "r db_mindex::next");
486*7c478bd9Sstevel@tonic-gate 	READLOCK2(table, DB_LOCK_ERROR, "r db_mindex::next", this);
487*7c478bd9Sstevel@tonic-gate 	if (!(table->entry_exists_p(previous)))
488*7c478bd9Sstevel@tonic-gate 		ret = DB_NOTFOUND;
489*7c478bd9Sstevel@tonic-gate 	else {
490*7c478bd9Sstevel@tonic-gate 		entry_object * ptr = table->next_entry(previous, where);
491*7c478bd9Sstevel@tonic-gate 		if (ptr == NULL)
492*7c478bd9Sstevel@tonic-gate 			ret = DB_NOTFOUND;
493*7c478bd9Sstevel@tonic-gate 		else
494*7c478bd9Sstevel@tonic-gate 			*answer = new_entry(ptr);
495*7c478bd9Sstevel@tonic-gate 	}
496*7c478bd9Sstevel@tonic-gate 	READUNLOCK2(this, table, ret, ret,
497*7c478bd9Sstevel@tonic-gate 		"ru db_mindex::next", "ru table db_mindex::next");
498*7c478bd9Sstevel@tonic-gate 	return (ret);
499*7c478bd9Sstevel@tonic-gate }
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate static void
502*7c478bd9Sstevel@tonic-gate delete_result_list(db_next_index_desc* orig)
503*7c478bd9Sstevel@tonic-gate {
504*7c478bd9Sstevel@tonic-gate 	db_next_index_desc* curr, *save_next;
505*7c478bd9Sstevel@tonic-gate 	for (curr = orig; curr != NULL; 0) {
506*7c478bd9Sstevel@tonic-gate 		save_next = curr->next;
507*7c478bd9Sstevel@tonic-gate 		delete curr;
508*7c478bd9Sstevel@tonic-gate 		curr = save_next;
509*7c478bd9Sstevel@tonic-gate 	}
510*7c478bd9Sstevel@tonic-gate }
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate static db_next_index_desc *
514*7c478bd9Sstevel@tonic-gate copy_result_list(db_index_entry* orig)
515*7c478bd9Sstevel@tonic-gate {
516*7c478bd9Sstevel@tonic-gate 	db_next_index_desc *head = NULL, *curr;
517*7c478bd9Sstevel@tonic-gate 	db_index_entry *current;
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	for (current = orig; current != NULL;
520*7c478bd9Sstevel@tonic-gate 		current = current->getnextresult()) {
521*7c478bd9Sstevel@tonic-gate 		curr = new db_next_index_desc(current->getlocation(), head);
522*7c478bd9Sstevel@tonic-gate 		if (curr == NULL) {
523*7c478bd9Sstevel@tonic-gate 			FATAL3(
524*7c478bd9Sstevel@tonic-gate 			"db_mindex::copy_result_list: could not allocate space",
525*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, NULL);
526*7c478bd9Sstevel@tonic-gate 		}
527*7c478bd9Sstevel@tonic-gate 		head = curr;  // list is actually reversed
528*7c478bd9Sstevel@tonic-gate 	}
529*7c478bd9Sstevel@tonic-gate 	return (head);
530*7c478bd9Sstevel@tonic-gate }
531*7c478bd9Sstevel@tonic-gate 
532*7c478bd9Sstevel@tonic-gate /*
533*7c478bd9Sstevel@tonic-gate  * Delete the given list of results; used when no longer interested in
534*7c478bd9Sstevel@tonic-gate  * the results of the first/next query that returned this list.
535*7c478bd9Sstevel@tonic-gate  */
536*7c478bd9Sstevel@tonic-gate db_status
537*7c478bd9Sstevel@tonic-gate db_mindex::reset_next(db_next_index_desc *orig)
538*7c478bd9Sstevel@tonic-gate {
539*7c478bd9Sstevel@tonic-gate 	if (orig == NULL)
540*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	delete_result_list(orig);
543*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
544*7c478bd9Sstevel@tonic-gate }
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate /*
547*7c478bd9Sstevel@tonic-gate * Finds entry that satisfy the query 'q'.  Returns the first answer by
548*7c478bd9Sstevel@tonic-gate * setting the pointer 'answer' to point to a copy of it.  'where' is set
549*7c478bd9Sstevel@tonic-gate * so that the other answers could be gotten by passing 'where' to 'next'
550*7c478bd9Sstevel@tonic-gate * successively.   Note that the answer is a  pointer to a copy of the entry.
551*7c478bd9Sstevel@tonic-gate * Returns DB_SUCCESS if search was successful; DB_NOTFOUND otherwise.
552*7c478bd9Sstevel@tonic-gate  */
553*7c478bd9Sstevel@tonic-gate db_status
554*7c478bd9Sstevel@tonic-gate db_mindex::first(db_query *q,
555*7c478bd9Sstevel@tonic-gate 		db_next_index_desc **where, entry_object ** answer)
556*7c478bd9Sstevel@tonic-gate {
557*7c478bd9Sstevel@tonic-gate 	READLOCK(this, DB_LOCK_ERROR, "r db_mindex::first");
558*7c478bd9Sstevel@tonic-gate 	READLOCK2(table, DB_LOCK_ERROR, "r table db_mindex::first", this);
559*7c478bd9Sstevel@tonic-gate 	long count;
560*7c478bd9Sstevel@tonic-gate 	bool_t valid_query;
561*7c478bd9Sstevel@tonic-gate 	db_status	ret = DB_SUCCESS;
562*7c478bd9Sstevel@tonic-gate 	db_index_entry * rp = satisfy_query(q, &count, &valid_query, TRUE);
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	if (valid_query != TRUE)
565*7c478bd9Sstevel@tonic-gate 		ret =  DB_BADQUERY;
566*7c478bd9Sstevel@tonic-gate 	else if (rp == NULL) {
567*7c478bd9Sstevel@tonic-gate 		*answer = NULL;
568*7c478bd9Sstevel@tonic-gate 		ret = DB_NOTFOUND;
569*7c478bd9Sstevel@tonic-gate 	} else {
570*7c478bd9Sstevel@tonic-gate 		*where = copy_result_list(rp);
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 		entry_object_p ptr = table->get_entry((*where)->location);
573*7c478bd9Sstevel@tonic-gate 		if (ptr == NULL)
574*7c478bd9Sstevel@tonic-gate 			ret = DB_NOTFOUND;
575*7c478bd9Sstevel@tonic-gate 		else
576*7c478bd9Sstevel@tonic-gate 			*answer = new_entry(ptr);
577*7c478bd9Sstevel@tonic-gate 	}
578*7c478bd9Sstevel@tonic-gate 	READUNLOCK2(this, table, ret, ret,
579*7c478bd9Sstevel@tonic-gate 		"ru db_mindex::first", "ru table db_mindex::first");
580*7c478bd9Sstevel@tonic-gate 	return (ret);
581*7c478bd9Sstevel@tonic-gate }
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate /*
584*7c478bd9Sstevel@tonic-gate  * Returns the next entry in the table after 'previous' by setting 'answer' to
585*7c478bd9Sstevel@tonic-gate  * point to copy of the entry_object.  Next is next in chain of answers found
586*7c478bd9Sstevel@tonic-gate  * in previous first search with query.   Returns DB_SUCCESS if 'previous' is
587*7c478bd9Sstevel@tonic-gate  * valid and next entry is found; DB_NOTFOUND otherwise.  Sets 'where' to
588*7c478bd9Sstevel@tonic-gate  * location of where entry is found for input as subsequent 'next' operation.
589*7c478bd9Sstevel@tonic-gate */
590*7c478bd9Sstevel@tonic-gate db_status
591*7c478bd9Sstevel@tonic-gate db_mindex::next(db_next_index_desc *previous, db_next_index_desc **where,
592*7c478bd9Sstevel@tonic-gate 		entry_object **answer)
593*7c478bd9Sstevel@tonic-gate {
594*7c478bd9Sstevel@tonic-gate 	READLOCK(this, DB_LOCK_ERROR, "r db_mindex::next");
595*7c478bd9Sstevel@tonic-gate 	READLOCK2(table, DB_LOCK_ERROR, "r table db_mindex::next", this);
596*7c478bd9Sstevel@tonic-gate 	db_status	ret = DB_SUCCESS;
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 	if (previous == NULL)
599*7c478bd9Sstevel@tonic-gate 		ret = DB_NOTFOUND;
600*7c478bd9Sstevel@tonic-gate 	else {
601*7c478bd9Sstevel@tonic-gate 		// should further check validity of 'previous' pointer
602*7c478bd9Sstevel@tonic-gate 		*where = previous->next;
603*7c478bd9Sstevel@tonic-gate 		delete previous;    // delete previous entry
604*7c478bd9Sstevel@tonic-gate 		if (*where == NULL)
605*7c478bd9Sstevel@tonic-gate 			ret = DB_NOTFOUND;
606*7c478bd9Sstevel@tonic-gate 		else {
607*7c478bd9Sstevel@tonic-gate 			entry_object * ptr =
608*7c478bd9Sstevel@tonic-gate 				table->get_entry((*where)->location);
609*7c478bd9Sstevel@tonic-gate 			if (ptr == NULL)
610*7c478bd9Sstevel@tonic-gate 				ret = DB_NOTFOUND;
611*7c478bd9Sstevel@tonic-gate 			else {
612*7c478bd9Sstevel@tonic-gate 				*answer = new_entry(ptr);
613*7c478bd9Sstevel@tonic-gate 				ret = DB_SUCCESS;
614*7c478bd9Sstevel@tonic-gate 			}
615*7c478bd9Sstevel@tonic-gate 		}
616*7c478bd9Sstevel@tonic-gate 	}
617*7c478bd9Sstevel@tonic-gate 	READUNLOCK2(this, table, ret, ret,
618*7c478bd9Sstevel@tonic-gate 		"ru db_mindex::next", "ru table db_mindex::next");
619*7c478bd9Sstevel@tonic-gate 	return (ret);
620*7c478bd9Sstevel@tonic-gate }
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate /*
623*7c478bd9Sstevel@tonic-gate  * Finds entry that satisfy the query 'q'.  Returns the answer by
624*7c478bd9Sstevel@tonic-gate  * setting the pointer 'rp' to point to the list of answers.
625*7c478bd9Sstevel@tonic-gate  * Note that the answers are pointers to the COPIES of entries.
626*7c478bd9Sstevel@tonic-gate  * Returns the number of answers find in 'count'.
627*7c478bd9Sstevel@tonic-gate  * Returns DB_SUCCESS if search found at least one answer;
628*7c478bd9Sstevel@tonic-gate  * returns DB_NOTFOUND if none is found.
629*7c478bd9Sstevel@tonic-gate */
630*7c478bd9Sstevel@tonic-gate db_status
631*7c478bd9Sstevel@tonic-gate db_mindex::lookup(db_query *q, long *count, entry_object_p **result)
632*7c478bd9Sstevel@tonic-gate {
633*7c478bd9Sstevel@tonic-gate 	bool_t valid_query;
634*7c478bd9Sstevel@tonic-gate 	db_index_entry * rp = satisfy_query(q, count, &valid_query, TRUE);
635*7c478bd9Sstevel@tonic-gate 	db_status stat = DB_SUCCESS;
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate 	if (valid_query != TRUE)
638*7c478bd9Sstevel@tonic-gate 		return (DB_BADQUERY);
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	if (rp == NULL) {
641*7c478bd9Sstevel@tonic-gate 		*result = NULL;
642*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
643*7c478bd9Sstevel@tonic-gate 	}
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 	*result = prepare_results((int)*count, rp, &stat);
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 	return (stat);
648*7c478bd9Sstevel@tonic-gate }
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate /*
651*7c478bd9Sstevel@tonic-gate  * Return all entries within table.  Returns the answer by
652*7c478bd9Sstevel@tonic-gate  * setting the pointer 'rp' to point to the list of answers.
653*7c478bd9Sstevel@tonic-gate  * Note that the answers are pointers to copies of the entries.
654*7c478bd9Sstevel@tonic-gate  * Returns the number of answers find in 'count'.
655*7c478bd9Sstevel@tonic-gate  * Returns DB_SUCCESS if search found at least one answer;
656*7c478bd9Sstevel@tonic-gate  * returns DB_NOTFOUND if none is found.
657*7c478bd9Sstevel@tonic-gate */
658*7c478bd9Sstevel@tonic-gate db_status
659*7c478bd9Sstevel@tonic-gate db_mindex::all(long *count, entry_object_p **result)
660*7c478bd9Sstevel@tonic-gate {
661*7c478bd9Sstevel@tonic-gate 	entry_object *ptr;
662*7c478bd9Sstevel@tonic-gate 	entryp where;
663*7c478bd9Sstevel@tonic-gate 	long how_many, i;
664*7c478bd9Sstevel@tonic-gate 	int	lret = 0;
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 	if (table == NULL) {
667*7c478bd9Sstevel@tonic-gate 		*result = NULL;
668*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
669*7c478bd9Sstevel@tonic-gate 	}
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 	READLOCK(this, DB_LOCK_ERROR, "r db_mindex::all");
672*7c478bd9Sstevel@tonic-gate 	/* Read lock 'table' while we're traversing it */
673*7c478bd9Sstevel@tonic-gate 	READLOCKNR(table, lret, "r table db_mindex::all");
674*7c478bd9Sstevel@tonic-gate 	if (lret != 0) {
675*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, DB_LOCK_ERROR, "ru db_mindex::all");
676*7c478bd9Sstevel@tonic-gate 		return (DB_LOCK_ERROR);
677*7c478bd9Sstevel@tonic-gate 	}
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate 	if (table->mapping.fromLDAP) {
680*7c478bd9Sstevel@tonic-gate 		struct timeval	now;
681*7c478bd9Sstevel@tonic-gate 		(void) gettimeofday(&now, NULL);
682*7c478bd9Sstevel@tonic-gate 		if (now.tv_sec >= table->mapping.enumExpire) {
683*7c478bd9Sstevel@tonic-gate 			int	queryRes = queryLDAP(0, 0, 1);
684*7c478bd9Sstevel@tonic-gate 			if (queryRes != LDAP_SUCCESS) {
685*7c478bd9Sstevel@tonic-gate 				READUNLOCKNR(table, lret,
686*7c478bd9Sstevel@tonic-gate 					"ru table db_mindex::all LDAP");
687*7c478bd9Sstevel@tonic-gate 				READUNLOCK(this, DB_LOCK_ERROR,
688*7c478bd9Sstevel@tonic-gate 					"ru db_mindex::all LDAP");
689*7c478bd9Sstevel@tonic-gate 				return (DB_INTERNAL_ERROR);
690*7c478bd9Sstevel@tonic-gate 			}
691*7c478bd9Sstevel@tonic-gate 		}
692*7c478bd9Sstevel@tonic-gate 	}
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	if ((how_many = table->fullness()) <= 0) {
695*7c478bd9Sstevel@tonic-gate 		/*
696*7c478bd9Sstevel@tonic-gate 		 * Set '*count' so that the caller avoids putting garbage
697*7c478bd9Sstevel@tonic-gate 		 * in an 'objects_len' field.
698*7c478bd9Sstevel@tonic-gate 		 */
699*7c478bd9Sstevel@tonic-gate 		*count = 0;
700*7c478bd9Sstevel@tonic-gate 		*result = NULL;
701*7c478bd9Sstevel@tonic-gate 		READUNLOCKNR(table, lret, "ru table db_mindex::all");
702*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, DB_NOTFOUND, "ru db_mindex::all");
703*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
704*7c478bd9Sstevel@tonic-gate 	}
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate 	entry_object_p * answer = new entry_object_p[how_many];
707*7c478bd9Sstevel@tonic-gate 	if (answer == NULL) {
708*7c478bd9Sstevel@tonic-gate 		READUNLOCKNR(table, lret, "ru table db_mindex::all");
709*7c478bd9Sstevel@tonic-gate 		READUNLOCK(this, DB_MEMORY_LIMIT, "ru db_mindex::all");
710*7c478bd9Sstevel@tonic-gate 		FATAL3("db_mindex::all: could not allocate space",
711*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, DB_MEMORY_LIMIT);
712*7c478bd9Sstevel@tonic-gate 	}
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	*count = how_many;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	ptr = table->first_entry(&where);
717*7c478bd9Sstevel@tonic-gate 	if (ptr != NULL)
718*7c478bd9Sstevel@tonic-gate 		answer[0] = new_entry(ptr);
719*7c478bd9Sstevel@tonic-gate 	else {
720*7c478bd9Sstevel@tonic-gate 		WARNING("db_mindex::all: null first entry found in all");
721*7c478bd9Sstevel@tonic-gate 		answer[0] = NULL;
722*7c478bd9Sstevel@tonic-gate 	}
723*7c478bd9Sstevel@tonic-gate 	for (i = 1; i < how_many; i++) {
724*7c478bd9Sstevel@tonic-gate 		ptr = table->next_entry(where, &where);
725*7c478bd9Sstevel@tonic-gate 		if (ptr != NULL)
726*7c478bd9Sstevel@tonic-gate 			answer[i] = new_entry(ptr);
727*7c478bd9Sstevel@tonic-gate 		else {
728*7c478bd9Sstevel@tonic-gate 			WARNING(
729*7c478bd9Sstevel@tonic-gate 			    "db_mindex::all: null internal entry found in all");
730*7c478bd9Sstevel@tonic-gate 			answer[i] = NULL; /* Answer gets null too. -CM */
731*7c478bd9Sstevel@tonic-gate 		}
732*7c478bd9Sstevel@tonic-gate 	}
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 	READUNLOCKNR(table, lret, "ru table db_mindex::all");
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	*result = answer;
737*7c478bd9Sstevel@tonic-gate 	READUNLOCK(this, DB_SUCCESS, "ru db_mindex::all");
738*7c478bd9Sstevel@tonic-gate 	return (DB_SUCCESS);
739*7c478bd9Sstevel@tonic-gate }
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate /*
742*7c478bd9Sstevel@tonic-gate  * Remove the entry identified by 'recloc' from:
743*7c478bd9Sstevel@tonic-gate  * 1.  all indices, as obtained by extracting the index values from the entry
744*7c478bd9Sstevel@tonic-gate  * 2.  table where entry is stored.
745*7c478bd9Sstevel@tonic-gate */
746*7c478bd9Sstevel@tonic-gate db_status
747*7c478bd9Sstevel@tonic-gate db_mindex::remove_aux(entryp recloc)
748*7c478bd9Sstevel@tonic-gate {
749*7c478bd9Sstevel@tonic-gate 	int i, curr_ind;
750*7c478bd9Sstevel@tonic-gate 	db_status	res = DB_SUCCESS;
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_mindex::remove_aux");
753*7c478bd9Sstevel@tonic-gate 	/* get index values of this record */
754*7c478bd9Sstevel@tonic-gate 	db_query * cq = extract_index_values_from_record(recloc);
755*7c478bd9Sstevel@tonic-gate 	if (cq == NULL) {
756*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_MEMORY_LIMIT, "wu db_mindex::remove_aux");
757*7c478bd9Sstevel@tonic-gate 		FATAL3("db_mindex::remove_aux: could not allocate space",
758*7c478bd9Sstevel@tonic-gate 			DB_MEMORY_LIMIT, DB_MEMORY_LIMIT);
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 	if (cq->size() != indices.indices_len) { /* something is wrong */
761*7c478bd9Sstevel@tonic-gate 		delete cq; // clean up
762*7c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
763*7c478bd9Sstevel@tonic-gate 	    "db_mindex::remove_aux: record contains wrong number of indices");
764*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK(this, DB_INTERNAL_ERROR,
765*7c478bd9Sstevel@tonic-gate 			"wu db_mindex::remove_aux");
766*7c478bd9Sstevel@tonic-gate 		return (DB_INTERNAL_ERROR);
767*7c478bd9Sstevel@tonic-gate 	}
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	if (!noWriteThrough.flag) {
770*7c478bd9Sstevel@tonic-gate 		nis_object	*o = 0;
771*7c478bd9Sstevel@tonic-gate 		entry_object    *e = table->get_entry(recloc);
772*7c478bd9Sstevel@tonic-gate 		int		queryRes, doingModify;
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate 		/*
775*7c478bd9Sstevel@tonic-gate 		 * If the removal is part of a modify operation, we
776*7c478bd9Sstevel@tonic-gate 		 * defer the LDAP update until the modified NIS+ object
777*7c478bd9Sstevel@tonic-gate 		 * is added back.
778*7c478bd9Sstevel@tonic-gate 		 */
779*7c478bd9Sstevel@tonic-gate 		if (saveOldObjForModify((entry_obj *)e, &doingModify) == 0)
780*7c478bd9Sstevel@tonic-gate 			res = DB_INTERNAL_ERROR;
781*7c478bd9Sstevel@tonic-gate 
782*7c478bd9Sstevel@tonic-gate 		if (res == DB_SUCCESS && !doingModify) {
783*7c478bd9Sstevel@tonic-gate 			/*
784*7c478bd9Sstevel@tonic-gate 			 * If we're removing a directory entry, and the
785*7c478bd9Sstevel@tonic-gate 			 * entry is LDAP-mapped, but the directory isn't,
786*7c478bd9Sstevel@tonic-gate 			 * we need a copy of the entry object in order
787*7c478bd9Sstevel@tonic-gate 			 * to remove if from LDAP.
788*7c478bd9Sstevel@tonic-gate 			 */
789*7c478bd9Sstevel@tonic-gate 			if (e != 0 && e->en_type != 0 &&
790*7c478bd9Sstevel@tonic-gate 					strcmp(e->en_type, "IN_DIRECTORY") == 0)
791*7c478bd9Sstevel@tonic-gate 				o = unmakePseudoEntryObj(e, 0);
792*7c478bd9Sstevel@tonic-gate 			queryRes = removeLDAP(cq, o);
793*7c478bd9Sstevel@tonic-gate 			if (queryRes != LDAP_SUCCESS) {
794*7c478bd9Sstevel@tonic-gate 				setMappingStatus(NIS_SUCCESS, queryRes);
795*7c478bd9Sstevel@tonic-gate 				if (table->mapping.storeErrorDisp == abandon)
796*7c478bd9Sstevel@tonic-gate 					res = DB_INTERNAL_ERROR;
797*7c478bd9Sstevel@tonic-gate 			}
798*7c478bd9Sstevel@tonic-gate 			if (o != 0)
799*7c478bd9Sstevel@tonic-gate 				nis_destroy_object(o);
800*7c478bd9Sstevel@tonic-gate 		}
801*7c478bd9Sstevel@tonic-gate 	}
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 	if (res == DB_SUCCESS) {
804*7c478bd9Sstevel@tonic-gate 		db_qcomp * comps = cq->queryloc();
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 		/* Add sanity check in case of corrupted table */
807*7c478bd9Sstevel@tonic-gate 		if (indices.indices_val != NULL) {
808*7c478bd9Sstevel@tonic-gate 			/* update indices */
809*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < indices.indices_len; i++) {
810*7c478bd9Sstevel@tonic-gate 				/* unnec. if sorted */
811*7c478bd9Sstevel@tonic-gate 				curr_ind = comps[i].which_index;
812*7c478bd9Sstevel@tonic-gate 				indices.indices_val[curr_ind].remove(
813*7c478bd9Sstevel@tonic-gate 						comps[i].index_value, recloc);
814*7c478bd9Sstevel@tonic-gate 			}
815*7c478bd9Sstevel@tonic-gate 		}
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 		/* update table where record is stored */
818*7c478bd9Sstevel@tonic-gate 		table->delete_entry(recloc);
819*7c478bd9Sstevel@tonic-gate 	}
820*7c478bd9Sstevel@tonic-gate 
821*7c478bd9Sstevel@tonic-gate 	/* delete query */
822*7c478bd9Sstevel@tonic-gate 	delete cq;
823*7c478bd9Sstevel@tonic-gate 
824*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, DB_SUCCESS, "wu db_mindex::remove_aux");
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 	return (res);
827*7c478bd9Sstevel@tonic-gate }
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate /*
830*7c478bd9Sstevel@tonic-gate  * Removes the entry in the table named by given query 'q'.
831*7c478bd9Sstevel@tonic-gate  * If a NULL query is supplied, all entries in table are removed.
832*7c478bd9Sstevel@tonic-gate  * Returns DB_NOTFOUND if no entry is found.
833*7c478bd9Sstevel@tonic-gate  * Returns DB_SUCCESS if one entry is found; this entry is removed from
834*7c478bd9Sstevel@tonic-gate  * its record storage, and it is also removed from all the indices of the
835*7c478bd9Sstevel@tonic-gate  * table. If more than one entry satisfying 'q' is found, all are removed.
836*7c478bd9Sstevel@tonic-gate  */
837*7c478bd9Sstevel@tonic-gate db_status
838*7c478bd9Sstevel@tonic-gate db_mindex::remove(db_query *q)
839*7c478bd9Sstevel@tonic-gate {
840*7c478bd9Sstevel@tonic-gate 	long count = 0;
841*7c478bd9Sstevel@tonic-gate 	db_index_entry *rp;
842*7c478bd9Sstevel@tonic-gate 	db_status rstat;
843*7c478bd9Sstevel@tonic-gate 	bool_t valid_query;
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_mindex::remove");
846*7c478bd9Sstevel@tonic-gate 	WRITELOCK2(table, DB_LOCK_ERROR, "w table db_mindex::remove", this);
847*7c478bd9Sstevel@tonic-gate 	if (q == NULL)  {  /* remove all entries in table */
848*7c478bd9Sstevel@tonic-gate 		if (table->mapping.toLDAP && !noWriteThrough.flag) {
849*7c478bd9Sstevel@tonic-gate 			int	queryRes = removeLDAP(q, 0);
850*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_LDAP_DEBUG
851*7c478bd9Sstevel@tonic-gate 			if (queryRes != LDAP_SUCCESS)
852*7c478bd9Sstevel@tonic-gate 				abort();
853*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_LDAP_DEBUG */
854*7c478bd9Sstevel@tonic-gate 		}
855*7c478bd9Sstevel@tonic-gate 		if (table != NULL && table->getsize() > 0) {
856*7c478bd9Sstevel@tonic-gate 			reset_tables();
857*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK2(table, this, DB_SUCCESS, DB_SUCCESS,
858*7c478bd9Sstevel@tonic-gate 					"wu table db_mindex::remove",
859*7c478bd9Sstevel@tonic-gate 					"wu db_mindex::remove");
860*7c478bd9Sstevel@tonic-gate 			return (DB_SUCCESS);
861*7c478bd9Sstevel@tonic-gate 		} else {
862*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK2(table, this, DB_NOTFOUND, DB_NOTFOUND,
863*7c478bd9Sstevel@tonic-gate 					"wu table db_mindex::remove",
864*7c478bd9Sstevel@tonic-gate 					"wu db_mindex::remove");
865*7c478bd9Sstevel@tonic-gate 			return (DB_NOTFOUND);
866*7c478bd9Sstevel@tonic-gate 		}
867*7c478bd9Sstevel@tonic-gate 	}
868*7c478bd9Sstevel@tonic-gate 
869*7c478bd9Sstevel@tonic-gate 	rp = satisfy_query(q, &count, &valid_query, FALSE);
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	if (valid_query != TRUE) {
872*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK2(table, this, DB_BADQUERY, DB_BADQUERY,
873*7c478bd9Sstevel@tonic-gate 			"wu table db_mindex::remove", "wu db_mindex::remove");
874*7c478bd9Sstevel@tonic-gate 		return (DB_BADQUERY);
875*7c478bd9Sstevel@tonic-gate 	}
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate 	if (count == 0) {	/* not found */
878*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK2(table, this, DB_NOTFOUND, DB_NOTFOUND,
879*7c478bd9Sstevel@tonic-gate 			"wu table db_mindex::remove", "wu db_mindex::remove");
880*7c478bd9Sstevel@tonic-gate 		return (DB_NOTFOUND);
881*7c478bd9Sstevel@tonic-gate 	} else if (count == 1) {	/* found, update indices  */
882*7c478bd9Sstevel@tonic-gate 		db_status	s;
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 		s = remove_aux(rp->getlocation());
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK2(table, this, s, s,
887*7c478bd9Sstevel@tonic-gate 			"wu table db_mindex::remove", "wu db_mindex::remove");
888*7c478bd9Sstevel@tonic-gate 		return (s);
889*7c478bd9Sstevel@tonic-gate 	} else {		/* ambiguous, remove all entries */
890*7c478bd9Sstevel@tonic-gate 		int i;
891*7c478bd9Sstevel@tonic-gate 		db_index_entry *next_entry;
892*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < count; i++) {
893*7c478bd9Sstevel@tonic-gate 			if (rp == NULL) {
894*7c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR,
895*7c478bd9Sstevel@tonic-gate 			"db_mindex::remove:  incorrect number of indices");
896*7c478bd9Sstevel@tonic-gate 				WRITEUNLOCK2(table, this, DB_INTERNAL_ERROR,
897*7c478bd9Sstevel@tonic-gate 					DB_INTERNAL_ERROR,
898*7c478bd9Sstevel@tonic-gate 					"wu table db_mindex::remove",
899*7c478bd9Sstevel@tonic-gate 					"wu db_mindex::remove");
900*7c478bd9Sstevel@tonic-gate 				return (DB_INTERNAL_ERROR);
901*7c478bd9Sstevel@tonic-gate 			}
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 			next_entry = rp->getnextresult(); // save before removal
904*7c478bd9Sstevel@tonic-gate 			rstat = remove_aux(rp->getlocation());
905*7c478bd9Sstevel@tonic-gate 			if (rstat != DB_SUCCESS) {
906*7c478bd9Sstevel@tonic-gate 				WRITEUNLOCK2(table, this, rstat, rstat,
907*7c478bd9Sstevel@tonic-gate 					"wu table db_mindex::remove",
908*7c478bd9Sstevel@tonic-gate 					"wu db_mindex::remove");
909*7c478bd9Sstevel@tonic-gate 				return (rstat);
910*7c478bd9Sstevel@tonic-gate 			}
911*7c478bd9Sstevel@tonic-gate 			rp = next_entry;		// go on to next
912*7c478bd9Sstevel@tonic-gate 		}
913*7c478bd9Sstevel@tonic-gate 		WRITEUNLOCK2(table, this, DB_SUCCESS, DB_SUCCESS,
914*7c478bd9Sstevel@tonic-gate 			"wu table db_mindex::remove", "wu db_mindex::remove");
915*7c478bd9Sstevel@tonic-gate 		return (DB_SUCCESS);
916*7c478bd9Sstevel@tonic-gate 	}
917*7c478bd9Sstevel@tonic-gate }
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate /*
920*7c478bd9Sstevel@tonic-gate  * Add copy of given entry to table.  Entry is identified by query 'q'.
921*7c478bd9Sstevel@tonic-gate  * The entry (if any) satisfying the query is first deleted, then
922*7c478bd9Sstevel@tonic-gate  *  added to the indices (using index values extracted form the given entry)
923*7c478bd9Sstevel@tonic-gate  * and the table.
924*7c478bd9Sstevel@tonic-gate  * Returns DB_NOTUNIQUE if more than one entry satisfies the query.
925*7c478bd9Sstevel@tonic-gate  * Returns DB_NOTFOUND if query is not well-formed.
926*7c478bd9Sstevel@tonic-gate  * Returns DB_SUCCESS if entry can be added.
927*7c478bd9Sstevel@tonic-gate */
928*7c478bd9Sstevel@tonic-gate db_status
929*7c478bd9Sstevel@tonic-gate db_mindex::add(db_query *q, entry_object * obj)
930*7c478bd9Sstevel@tonic-gate {
931*7c478bd9Sstevel@tonic-gate 	long count = 0;
932*7c478bd9Sstevel@tonic-gate 	int i, curr_ind;
933*7c478bd9Sstevel@tonic-gate 	bool_t valid;
934*7c478bd9Sstevel@tonic-gate 	db_index_entry *rp = NULL;
935*7c478bd9Sstevel@tonic-gate 	db_status rstat;
936*7c478bd9Sstevel@tonic-gate 	char		*myself = "db_mindex::add";
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate 	/*
939*7c478bd9Sstevel@tonic-gate 	 *  The argument q is only NULL when we know that there are
940*7c478bd9Sstevel@tonic-gate 	 *  no objects in the database that match the object.
941*7c478bd9Sstevel@tonic-gate 	 */
942*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, DB_LOCK_ERROR, "w db_mindex::add");
943*7c478bd9Sstevel@tonic-gate 	WRITELOCK2(table, DB_LOCK_ERROR, "w table db_mindex::add", this);
944*7c478bd9Sstevel@tonic-gate 	if (q) {
945*7c478bd9Sstevel@tonic-gate 		rp = satisfy_query(q, &count, &valid, FALSE);
946*7c478bd9Sstevel@tonic-gate 		if (!valid) {
947*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK2(this, table, DB_LOCK_ERROR, DB_LOCK_ERROR,
948*7c478bd9Sstevel@tonic-gate 					"wu db_mindex::add",
949*7c478bd9Sstevel@tonic-gate 					"wu table db_mindex::add");
950*7c478bd9Sstevel@tonic-gate 			return (DB_BADQUERY);
951*7c478bd9Sstevel@tonic-gate 		}
952*7c478bd9Sstevel@tonic-gate 	}
953*7c478bd9Sstevel@tonic-gate 	if (count == 1) {	/* found, first delete */
954*7c478bd9Sstevel@tonic-gate 		rstat = remove_aux(rp->getlocation());
955*7c478bd9Sstevel@tonic-gate 		if (rstat != DB_SUCCESS) {
956*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK2(this, table, rstat, rstat,
957*7c478bd9Sstevel@tonic-gate 				"wu db_mindex::add",
958*7c478bd9Sstevel@tonic-gate 				"wu table db_mindex::add");
959*7c478bd9Sstevel@tonic-gate 			return (rstat);
960*7c478bd9Sstevel@tonic-gate 		}
961*7c478bd9Sstevel@tonic-gate 		count = 0;	/* fall through to add */
962*7c478bd9Sstevel@tonic-gate 	}
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate 	if (count == 0) { 	/* not found, insert */
965*7c478bd9Sstevel@tonic-gate 		/* add object to table */
966*7c478bd9Sstevel@tonic-gate 		entryp recloc = table->add_entry(obj, initialLoad.flag);
967*7c478bd9Sstevel@tonic-gate 		/* get index values of this object, might be same as 'q' */
968*7c478bd9Sstevel@tonic-gate 		db_query *cq = extract_index_values_from_object(obj);
969*7c478bd9Sstevel@tonic-gate 		if (cq == NULL) {
970*7c478bd9Sstevel@tonic-gate 			table->delete_entry(recloc);
971*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK2(this, table,
972*7c478bd9Sstevel@tonic-gate 				DB_MEMORY_LIMIT, DB_MEMORY_LIMIT,
973*7c478bd9Sstevel@tonic-gate 				"wu db_mindex::add DB_MEMORY_LIMIT",
974*7c478bd9Sstevel@tonic-gate 				"wu table db_mindex::add DB_MEMORY_LIMIT");
975*7c478bd9Sstevel@tonic-gate 			FATAL3("db_mindex::add: could not allocate space for",
976*7c478bd9Sstevel@tonic-gate 				DB_MEMORY_LIMIT, DB_MEMORY_LIMIT);
977*7c478bd9Sstevel@tonic-gate 		}
978*7c478bd9Sstevel@tonic-gate 		if (cq ->size() != indices.indices_len) { /* something wrong */
979*7c478bd9Sstevel@tonic-gate 			table->delete_entry(recloc);
980*7c478bd9Sstevel@tonic-gate 			delete cq; // clean up
981*7c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR,
982*7c478bd9Sstevel@tonic-gate 		    "db_mindex::add: record contains wrong number of indices");
983*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK2(this, table,
984*7c478bd9Sstevel@tonic-gate 				DB_INTERNAL_ERROR, DB_INTERNAL_ERROR,
985*7c478bd9Sstevel@tonic-gate 				"wu db_mindex::add DB_INTERNAL_ERROR",
986*7c478bd9Sstevel@tonic-gate 				"wu table db_mindex::add DB_INTERNAL_ERROR");
987*7c478bd9Sstevel@tonic-gate 			return (DB_INTERNAL_ERROR);
988*7c478bd9Sstevel@tonic-gate 		}
989*7c478bd9Sstevel@tonic-gate 		db_qcomp * comps = cq->queryloc();
990*7c478bd9Sstevel@tonic-gate 
991*7c478bd9Sstevel@tonic-gate 		/* update indices */
992*7c478bd9Sstevel@tonic-gate 		if (indices.indices_val != NULL) {
993*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < indices.indices_len; i++) {
994*7c478bd9Sstevel@tonic-gate 				curr_ind = comps[i].which_index;
995*7c478bd9Sstevel@tonic-gate 				indices.indices_val[curr_ind].add(
996*7c478bd9Sstevel@tonic-gate 					comps[i].index_value, recloc);
997*7c478bd9Sstevel@tonic-gate 			}
998*7c478bd9Sstevel@tonic-gate 		}
999*7c478bd9Sstevel@tonic-gate 		delete cq;  // clean up
1000*7c478bd9Sstevel@tonic-gate 		if (!noWriteThrough.flag) {
1001*7c478bd9Sstevel@tonic-gate 			int		queryRes;
1002*7c478bd9Sstevel@tonic-gate 			entry_object	*e = 0;
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 			if (retrieveOldObjForModify((entry_obj **)&e) == 0) {
1005*7c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1006*7c478bd9Sstevel@tonic-gate 			"%s: Error retrieving old object for LDAP update",
1007*7c478bd9Sstevel@tonic-gate 					myself);
1008*7c478bd9Sstevel@tonic-gate 				return (DB_INTERNAL_ERROR);
1009*7c478bd9Sstevel@tonic-gate 			}
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 			queryRes = storeLDAP(q, obj, 0, e, 0);
1012*7c478bd9Sstevel@tonic-gate 			if (queryRes != LDAP_SUCCESS) {
1013*7c478bd9Sstevel@tonic-gate 				if (table->mapping.storeErrorDisp == abandon) {
1014*7c478bd9Sstevel@tonic-gate 					WRITEUNLOCK2(this, table,
1015*7c478bd9Sstevel@tonic-gate 						DB_INTERNAL_ERROR,
1016*7c478bd9Sstevel@tonic-gate 						DB_INTERNAL_ERROR,
1017*7c478bd9Sstevel@tonic-gate 						"wu db_mindex::add LDAP",
1018*7c478bd9Sstevel@tonic-gate 						"wu table db_mindex::add LDAP");
1019*7c478bd9Sstevel@tonic-gate 					return (DB_INTERNAL_ERROR);
1020*7c478bd9Sstevel@tonic-gate 				} else {
1021*7c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1022*7c478bd9Sstevel@tonic-gate 						"%s: LDAP store failed: %s",
1023*7c478bd9Sstevel@tonic-gate 						myself,
1024*7c478bd9Sstevel@tonic-gate 						ldap_err2string(queryRes));
1025*7c478bd9Sstevel@tonic-gate 				}
1026*7c478bd9Sstevel@tonic-gate 			}
1027*7c478bd9Sstevel@tonic-gate 		}
1028*7c478bd9Sstevel@tonic-gate 		rstat = DB_SUCCESS;
1029*7c478bd9Sstevel@tonic-gate 	} else  /* ambiguous */
1030*7c478bd9Sstevel@tonic-gate 		rstat = DB_NOTUNIQUE;
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK2(this, table, rstat, rstat,
1033*7c478bd9Sstevel@tonic-gate 			"wu db_mindex::add",
1034*7c478bd9Sstevel@tonic-gate 			"wu table db_mindex::add");
1035*7c478bd9Sstevel@tonic-gate 	return (rstat);
1036*7c478bd9Sstevel@tonic-gate }
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate /* ************************* pickle_mindex ********************* */
1039*7c478bd9Sstevel@tonic-gate /* Does the actual writing to/from file specific for db_mindex structure. */
1040*7c478bd9Sstevel@tonic-gate static bool_t
1041*7c478bd9Sstevel@tonic-gate transfer_aux(XDR* x, pptr rp)
1042*7c478bd9Sstevel@tonic-gate {
1043*7c478bd9Sstevel@tonic-gate 	return (xdr_db_mindex(x, (db_mindex*) rp));
1044*7c478bd9Sstevel@tonic-gate }
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate class pickle_mindex: public pickle_file {
1047*7c478bd9Sstevel@tonic-gate     public:
1048*7c478bd9Sstevel@tonic-gate 	pickle_mindex(char *f, pickle_mode m) : pickle_file(f, m) {}
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 	/* Transfers db_mindex structure pointed to by dp to/from file. */
1051*7c478bd9Sstevel@tonic-gate 	int transfer(db_mindex* dp)
1052*7c478bd9Sstevel@tonic-gate 		{
1053*7c478bd9Sstevel@tonic-gate 			int	ret;
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 			WRITELOCK(dp, -1, "w pickle_mindex::transfer");
1056*7c478bd9Sstevel@tonic-gate 			ret = pickle_file::transfer((pptr) dp, &transfer_aux);
1057*7c478bd9Sstevel@tonic-gate 			WRITEUNLOCK(dp, ret, "wu pickle_mindex::transfer");
1058*7c478bd9Sstevel@tonic-gate 			return (ret);
1059*7c478bd9Sstevel@tonic-gate 		}
1060*7c478bd9Sstevel@tonic-gate };
1061*7c478bd9Sstevel@tonic-gate 
1062*7c478bd9Sstevel@tonic-gate /* Write this structure (table, indices, scheme) into the specified file. */
1063*7c478bd9Sstevel@tonic-gate int
1064*7c478bd9Sstevel@tonic-gate db_mindex::dump(char *file)
1065*7c478bd9Sstevel@tonic-gate {
1066*7c478bd9Sstevel@tonic-gate 	pickle_mindex f(file, PICKLE_WRITE);
1067*7c478bd9Sstevel@tonic-gate 	int status = f.transfer(this);
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	if (status == 1)
1070*7c478bd9Sstevel@tonic-gate 		return (-1); /* could not open for write */
1071*7c478bd9Sstevel@tonic-gate 	else
1072*7c478bd9Sstevel@tonic-gate 		return (status);
1073*7c478bd9Sstevel@tonic-gate }
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate /*
1076*7c478bd9Sstevel@tonic-gate  * Reset the table by: deleting all the indices, table of entries, and its
1077*7c478bd9Sstevel@tonic-gate  * scheme.
1078*7c478bd9Sstevel@tonic-gate */
1079*7c478bd9Sstevel@tonic-gate void
1080*7c478bd9Sstevel@tonic-gate db_mindex::reset()
1081*7c478bd9Sstevel@tonic-gate {
1082*7c478bd9Sstevel@tonic-gate 	WRITELOCKV(this, "w db_mindex::reset");
1083*7c478bd9Sstevel@tonic-gate 	reset_tables();   /* clear table contents first */
1084*7c478bd9Sstevel@tonic-gate 
1085*7c478bd9Sstevel@tonic-gate 	if (indices.indices_val) {
1086*7c478bd9Sstevel@tonic-gate 		delete [] indices.indices_val;
1087*7c478bd9Sstevel@tonic-gate 		indices.indices_val = NULL;
1088*7c478bd9Sstevel@tonic-gate 	}
1089*7c478bd9Sstevel@tonic-gate 	if (table) { delete table; table = NULL;  }
1090*7c478bd9Sstevel@tonic-gate 	if (scheme) { delete scheme; scheme = NULL;  }
1091*7c478bd9Sstevel@tonic-gate 	indices.indices_len = 0;
1092*7c478bd9Sstevel@tonic-gate 	rversion.zero();
1093*7c478bd9Sstevel@tonic-gate 	if (objPath.ptr != 0) {
1094*7c478bd9Sstevel@tonic-gate 		free(objPath.ptr);
1095*7c478bd9Sstevel@tonic-gate 		objPath.ptr = 0;
1096*7c478bd9Sstevel@tonic-gate 	}
1097*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCKV(this, "wu db_mindex::reset");
1098*7c478bd9Sstevel@tonic-gate }
1099*7c478bd9Sstevel@tonic-gate 
1100*7c478bd9Sstevel@tonic-gate /*
1101*7c478bd9Sstevel@tonic-gate  * Initialize table using information from specified file.
1102*7c478bd9Sstevel@tonic-gate  * The table is first 'reset', then the attempt to load from the file
1103*7c478bd9Sstevel@tonic-gate  * is made.  If the load failed, the table is again reset.
1104*7c478bd9Sstevel@tonic-gate  * Therefore, the table will be modified regardless of the success of the
1105*7c478bd9Sstevel@tonic-gate  * load.  Returns 0 if successful, 1 if DB disk file couldn't be opened,
1106*7c478bd9Sstevel@tonic-gate  * -1 for various other failures.
1107*7c478bd9Sstevel@tonic-gate */
1108*7c478bd9Sstevel@tonic-gate int
1109*7c478bd9Sstevel@tonic-gate db_mindex::load(char *file)
1110*7c478bd9Sstevel@tonic-gate {
1111*7c478bd9Sstevel@tonic-gate 	pickle_mindex f(file, PICKLE_READ);
1112*7c478bd9Sstevel@tonic-gate 	int status;
1113*7c478bd9Sstevel@tonic-gate 	int	init_table = (this->table == NULL);
1114*7c478bd9Sstevel@tonic-gate 	int	init_scheme = (this->scheme == NULL);
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 	WRITELOCK(this, -1, "w db_mindex::load");
1117*7c478bd9Sstevel@tonic-gate 	reset();
1118*7c478bd9Sstevel@tonic-gate 
1119*7c478bd9Sstevel@tonic-gate 	/* load new mindex */
1120*7c478bd9Sstevel@tonic-gate 	if ((status = f.transfer(this)) != 0) {
1121*7c478bd9Sstevel@tonic-gate 		/* load failed.  Reset. */
1122*7c478bd9Sstevel@tonic-gate 		reset();
1123*7c478bd9Sstevel@tonic-gate 	}
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 	/* Initialize the 'scheme' locking */
1126*7c478bd9Sstevel@tonic-gate 	if (status == 0 && this->scheme != 0 && init_scheme) {
1127*7c478bd9Sstevel@tonic-gate 		/*
1128*7c478bd9Sstevel@tonic-gate 		 * Since we've added fields to the db_scheme that aren't
1129*7c478bd9Sstevel@tonic-gate 		 * read from disk, we need to re-allocate so that the
1130*7c478bd9Sstevel@tonic-gate 		 * db_scheme instance is large enough.
1131*7c478bd9Sstevel@tonic-gate 		 */
1132*7c478bd9Sstevel@tonic-gate 		db_scheme	*tmpscheme = new db_scheme();
1133*7c478bd9Sstevel@tonic-gate 		if (tmpscheme != 0) {
1134*7c478bd9Sstevel@tonic-gate 			(void) memcpy(tmpscheme, this->scheme,
1135*7c478bd9Sstevel@tonic-gate 					this->scheme->oldstructsize());
1136*7c478bd9Sstevel@tonic-gate 			free(this->scheme);
1137*7c478bd9Sstevel@tonic-gate 			this->scheme = tmpscheme;
1138*7c478bd9Sstevel@tonic-gate 		} else {
1139*7c478bd9Sstevel@tonic-gate 			status = -1;
1140*7c478bd9Sstevel@tonic-gate 		}
1141*7c478bd9Sstevel@tonic-gate 	}
1142*7c478bd9Sstevel@tonic-gate 	/*
1143*7c478bd9Sstevel@tonic-gate 	 * If the 'table' field was NULL before the load, but not now,
1144*7c478bd9Sstevel@tonic-gate 	 * initialize the table locking and mapping.
1145*7c478bd9Sstevel@tonic-gate 	 */
1146*7c478bd9Sstevel@tonic-gate 	if (status == 0 && this->table != 0 && init_table) {
1147*7c478bd9Sstevel@tonic-gate 		/*
1148*7c478bd9Sstevel@tonic-gate 		 * As for the db_scheme, make sure the db_table is large
1149*7c478bd9Sstevel@tonic-gate 		 * enough.
1150*7c478bd9Sstevel@tonic-gate 		 */
1151*7c478bd9Sstevel@tonic-gate 		db_table	*tmptable = new db_table();
1152*7c478bd9Sstevel@tonic-gate 		if (tmptable != 0) {
1153*7c478bd9Sstevel@tonic-gate 			(void) memcpy(tmptable, this->table,
1154*7c478bd9Sstevel@tonic-gate 					this->table->oldstructsize());
1155*7c478bd9Sstevel@tonic-gate 			free(this->table);
1156*7c478bd9Sstevel@tonic-gate 			this->table = tmptable;
1157*7c478bd9Sstevel@tonic-gate 			(void) this->configure(file);
1158*7c478bd9Sstevel@tonic-gate 		} else {
1159*7c478bd9Sstevel@tonic-gate 			status = -1;
1160*7c478bd9Sstevel@tonic-gate 		}
1161*7c478bd9Sstevel@tonic-gate 	}
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate 	if (status == 0 && this->indices.indices_val != NULL) {
1164*7c478bd9Sstevel@tonic-gate 		/*
1165*7c478bd9Sstevel@tonic-gate 		 * Recreate the db_index instance so that it is
1166*7c478bd9Sstevel@tonic-gate 		 * correctly initialized.
1167*7c478bd9Sstevel@tonic-gate 		 */
1168*7c478bd9Sstevel@tonic-gate 		db_index *tmp_indices;
1169*7c478bd9Sstevel@tonic-gate 		int	n_index = this->indices.indices_len;
1170*7c478bd9Sstevel@tonic-gate 
1171*7c478bd9Sstevel@tonic-gate 		tmp_indices = new db_index[n_index];
1172*7c478bd9Sstevel@tonic-gate 		if (tmp_indices != NULL) {
1173*7c478bd9Sstevel@tonic-gate 			for (int i = 0; i < n_index; i++) {
1174*7c478bd9Sstevel@tonic-gate 			    if (tmp_indices[i].move_xdr_db_index
1175*7c478bd9Sstevel@tonic-gate 				(&this->indices.indices_val[i]) != DB_SUCCESS) {
1176*7c478bd9Sstevel@tonic-gate 					status = -1;
1177*7c478bd9Sstevel@tonic-gate 					break;
1178*7c478bd9Sstevel@tonic-gate 			    }
1179*7c478bd9Sstevel@tonic-gate 			}
1180*7c478bd9Sstevel@tonic-gate 			free(this->indices.indices_val);
1181*7c478bd9Sstevel@tonic-gate 			this->indices.indices_val = tmp_indices;
1182*7c478bd9Sstevel@tonic-gate 			this->indices.indices_len = n_index;
1183*7c478bd9Sstevel@tonic-gate 		} else {
1184*7c478bd9Sstevel@tonic-gate 			status = -1;
1185*7c478bd9Sstevel@tonic-gate 		}
1186*7c478bd9Sstevel@tonic-gate 	}
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate 	WRITEUNLOCK(this, status, "wu db_mindex::load");
1189*7c478bd9Sstevel@tonic-gate 	return (status);
1190*7c478bd9Sstevel@tonic-gate }
1191*7c478bd9Sstevel@tonic-gate 
1192*7c478bd9Sstevel@tonic-gate /*
1193*7c478bd9Sstevel@tonic-gate  * Prints statistics of the table.  This includes the size of the table,
1194*7c478bd9Sstevel@tonic-gate  * the number of entries, and the index sizes.
1195*7c478bd9Sstevel@tonic-gate  */
1196*7c478bd9Sstevel@tonic-gate void
1197*7c478bd9Sstevel@tonic-gate db_mindex::print_stats()
1198*7c478bd9Sstevel@tonic-gate {
1199*7c478bd9Sstevel@tonic-gate 	long size, count, i;
1200*7c478bd9Sstevel@tonic-gate 	long *stats = table->stats(TRUE);
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	printf("table_size = %d\n", stats[0]);
1203*7c478bd9Sstevel@tonic-gate 	printf("last_used = %d\n", stats[1]);
1204*7c478bd9Sstevel@tonic-gate 	printf("count = %d\n", stats[2]);
1205*7c478bd9Sstevel@tonic-gate 	printf("free list size = %d\n", stats[3]);
1206*7c478bd9Sstevel@tonic-gate 	printf("free list count = %d\n", stats[4]);
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	for (i = 5; i < 5+stats[4]; i++) {
1209*7c478bd9Sstevel@tonic-gate 		printf("%d, ", stats[i]);
1210*7c478bd9Sstevel@tonic-gate 	}
1211*7c478bd9Sstevel@tonic-gate 	printf("\n");
1212*7c478bd9Sstevel@tonic-gate 	free((char *)stats);
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 	/* Add sanity check in case of corrupted table */
1215*7c478bd9Sstevel@tonic-gate 	if (indices.indices_val == NULL) {
1216*7c478bd9Sstevel@tonic-gate 		printf("No indices to print\n");
1217*7c478bd9Sstevel@tonic-gate 		return;
1218*7c478bd9Sstevel@tonic-gate 	}
1219*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < indices.indices_len; i++) {
1220*7c478bd9Sstevel@tonic-gate 		printf("***** INDEX %d ******\n", i);
1221*7c478bd9Sstevel@tonic-gate 		indices.indices_val[i].stats(&size, &count);
1222*7c478bd9Sstevel@tonic-gate 		printf("index table size = %d\ncount = %d\n", size, count);
1223*7c478bd9Sstevel@tonic-gate 	}
1224*7c478bd9Sstevel@tonic-gate }
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate /* Prints statistics about all indices of table. */
1227*7c478bd9Sstevel@tonic-gate void
1228*7c478bd9Sstevel@tonic-gate db_mindex::print_all_indices()
1229*7c478bd9Sstevel@tonic-gate {
1230*7c478bd9Sstevel@tonic-gate 	int i;
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate 	READLOCKV(this, "r db_mindex::print_all_indices");
1233*7c478bd9Sstevel@tonic-gate 	/* Add sanity check in case of corrupted table */
1234*7c478bd9Sstevel@tonic-gate 	if (indices.indices_val == NULL) {
1235*7c478bd9Sstevel@tonic-gate 		printf("No indices to print\n");
1236*7c478bd9Sstevel@tonic-gate 		READUNLOCKV(this, "ru db_mindex::print_all_indices");
1237*7c478bd9Sstevel@tonic-gate 		return;
1238*7c478bd9Sstevel@tonic-gate 	}
1239*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < indices.indices_len; i++) {
1240*7c478bd9Sstevel@tonic-gate 		printf("***** INDEX %d ******\n", i);
1241*7c478bd9Sstevel@tonic-gate 		indices.indices_val[i].print();
1242*7c478bd9Sstevel@tonic-gate 	}
1243*7c478bd9Sstevel@tonic-gate 	READUNLOCKV(this, "ru db_mindex::print_all_indices");
1244*7c478bd9Sstevel@tonic-gate }
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate /* Prints statistics about indices identified by 'n'. */
1247*7c478bd9Sstevel@tonic-gate void
1248*7c478bd9Sstevel@tonic-gate db_mindex::print_index(int n)
1249*7c478bd9Sstevel@tonic-gate {
1250*7c478bd9Sstevel@tonic-gate 	READLOCKV(this, "r db_mindex::print_index");
1251*7c478bd9Sstevel@tonic-gate 	if (n >= 0 && n < indices.indices_len)
1252*7c478bd9Sstevel@tonic-gate 		indices.indices_val[n].print();
1253*7c478bd9Sstevel@tonic-gate 	READUNLOCKV(this, "ru db_mindex::print_index");
1254*7c478bd9Sstevel@tonic-gate }
1255