/* * Copyright (c) 1995, 1996 Gunther Schadow. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "pg_config.h" IDENT("@(#) odbm-fetch.cc (Gunther Schadow) 12/19/96"); #include "odbm.h" #include #include #include #include /*************************************************+ * retrieval methods */ /* * fetch with key found in structure. */ result odbm::fetch() { update_key(); datum new_data = gdbm_fetch(*dbfp, key); if(new_data.dptr == NULL) return FAIL; else { // delete the old data block if(data.dptr != NULL) delete [] data.dptr; // and activate the new one data = new_data; parse_data(); return SUCCESS; } } /* * fetch with supplied key, the key is copied as if it was read from * the database. */ result odbm::fetch(const char *k, u_int *cursor) { datum new_key; datum new_data; switch(int i = stringno(k)) { case 0: // could have called the simpler form return odbm::fetch(); case -1: // make a new key new_key = build_key(k); new_data = gdbm_fetch(*dbfp, new_key); if(new_data.dptr == NULL) { delete [] new_key.dptr; return FAIL; } break; default: // dereferenciate an index if(fltp != NULL) return fltfetch(i,k,cursor); else { new_data = deref_index(i, k, cursor, new_key); if(new_data.dptr == NULL) return FAIL; } break; } // only now actualize the key if(key.dptr != NULL) delete [] key.dptr; key = new_key; *keyp = (char *)parse_key(); // delete the old data block if(data.dptr != NULL) delete [] data.dptr; // and activate the new one data = new_data; parse_data(); return SUCCESS; } /* * fetch with key or index supplied */ result odbm::fetch(char **k, const char *value, u_int *cursor) { datum new_key; datum new_data; switch(int i = stringno(k)) { case 0: // could have called the simpler form return odbm::fetch(value); case -1: // the variable is no key nor string ERROR("variable is no key nor string"); default: // dereferenciate an index if(fltp != NULL) return fltfetch(i, value, cursor); else { new_data = deref_index(i, value, cursor, new_key); if(new_data.dptr == NULL) return FAIL; // only now actualize the key if(key.dptr != NULL) delete [] key.dptr; key = new_key; *keyp = (char *)parse_key(); // delete the old data block if(data.dptr != NULL) delete [] data.dptr; // and activate the new one data = new_data; parse_data(); return SUCCESS; } } } /* * look up the key found in structure */ bool odbm::exists() const { update_key(); return gdbm_exists(*dbfp, key); } /* * look up the supplied key */ bool odbm::exists(const char *k, u_int *cursor) const { datum new_key; bool r; switch(int i = stringno(k)) { case 0: // could have called the simpler form return odbm::exists(); case -1: // make a new key new_key = build_key(k); r = gdbm_exists(*dbfp, new_key); break; default: // dereferenciate an index r = ( deref_index(i, k, cursor, new_key).dptr != NULL ); break; } delete [] new_key.dptr; return r; } /* * look up the supplied value for key or index */ bool odbm::exists(char **k, const char *value, u_int *cursor) const { datum new_key; bool r; switch(int i = stringno(k)) { case 0: return odbm::exists(value); case -1: // the variable is no key nor string ERROR("variable is no key nor string"); default: // dereferenciate an index r = ( deref_index(i, *k, cursor, new_key).dptr != NULL ); break; } delete [] new_key.dptr; return r; } /* * fetch the first key in database */ const char * odbm::firstkey() const { odbm *that = (odbm *)this; // force the const warnings to be silent if(that->key.dptr != NULL) delete [] that->key.dptr; that->key = gdbm_firstkey(*dbfp); if(that->key.dptr == NULL) return NULL; else if(that->key.dptr[0] != 0) return odbm::nextkey(); else return parse_key(); } /* * fetch next key in database */ const char * odbm::nextkey() const { odbm *that = (odbm *)this; // force the const warnings to be silent do { datum lastkey = that->key; that->key = gdbm_nextkey(*dbfp, lastkey); if(lastkey.dptr != NULL) delete [] lastkey.dptr; if(that->key.dptr == NULL) return NULL; } while(that->key.dptr[0] != 0); return parse_key(); } /* * Fetch via index and test against filter */ result odbm::fltfetch(int i, const char *k, u_int *cursor) { datum new_key = (datum){NULL, 0}; // reset to NULL datum new_data; do { new_data = deref_index(i, k, cursor, new_key); if(new_data.dptr == NULL) return FAIL; else { // now actualize the key if(key.dptr != NULL) delete [] key.dptr; key = new_key; *keyp = (char *)parse_key(); // delete the old data block if(data.dptr != NULL) delete [] data.dptr; // and activate the new one data = new_data; parse_data(); } } while(!fltp->test(this) && ++(*cursor)); return SUCCESS; } /* * fetch via automatically selected index, it is assumed, that the key * is null and cannot be used to fetch the record. * * The most informative index is used as the primary index to fetch the * data. This reduces trial and error alternatives. The most infomative * index is the index which referes to the smallest set of data records, * i.e. whose index counter is minimal among the other indices. Since the * filter is tested sequencially it is slightly better to have the more * informative indices come first, however we do not know about the * information content of the non-index filter constraints. */ result odbm::fetch(u_int *cursor) { char *the_str = NULL; if(the_cursor ==(u_int)-1 || *cursor < the_cursor || *cursor > the_cursor + 1) { the_index = -1; the_cursor = (u_int)-1; if(*keyp != NULL) // if the key is set, pack any set string on filter { for(int i = 0; i < nostrings; i++) { char *str = strings[i]; if(str != NULL) // if string is non-null addfilt(i, str); } if(fetch() == SUCCESS) // fetch the key if(fltp == NULL) // if there is no filter return SUCCESS; // we are done else if(fltp->test(this)) return SUCCESS; // if the test succeeds, success else return FAIL; // otherwise fail ... else return FAIL; } else // now, the real job begins, look for the optimal index { u_int min_icount = (u_int)-1; for(int i = 0; i < nostrings; i++) { char *str = strings[i]; if(str != NULL) // if string is non-null { if(indices.test(i)) // is it an index? { u_int icount=index_counter(i, str); // number of records if(icount < min_icount) // less than what we had? { if(the_index > -1) addfilt(the_index, the_str);// old index on filter the_index = i; // a new index of choice the_str = str; // with the string min_icount = icount; // and a new minimum } else addfilt(i, str); // index goes on filter } else addfilt(i, str); // non-index go on filter } } if(the_str == NULL) // if we didn't actually found an index return FAIL; // what shall we look for? } } else { the_str = strings[the_index]; } the_cursor = *cursor; return fltfetch(the_index + 1, the_str, cursor); // go and get it }