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