From 26eff174ee8bf6b76ecf7f641286ad59c08f2672 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Tue, 24 May 2005 13:31:22 +0000 Subject: r6956: added start of ldb_sqlite3 work (This used to be commit ac396a4a53756f40ad5e1d45ca23e002f9c649e7) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 951 ++++++++++++++++++++++++++++++ source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 25 + source4/lib/ldb/ldb_sqlite3/schema | 240 ++++++++ 3 files changed, 1216 insertions(+) create mode 100644 source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c create mode 100644 source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h create mode 100644 source4/lib/ldb/ldb_sqlite3/schema (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c new file mode 100644 index 0000000000..67debd8a4e --- /dev/null +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -0,0 +1,951 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldb sqlite backend + * + * Description: core files for SQLITE3 backend + * + * Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend) + */ + +#include "includes.h" +#include "ldb/include/ldb.h" +#include "ldb/include/ldb_private.h" +#include "ldb/ldb_sqlite3/ldb_sqlite3.h" + +#if 0 +/* + we don't need this right now, but will once we add some backend + options +*/ + +/* + find an option in an option list (a null terminated list of strings) + + this assumes the list is short. If it ever gets long then we really + should do this in some smarter way + */ +static const char *lsqlite3_option_find(const struct lsqlite3_private *lsqlite3, const char *name) +{ + int i; + size_t len = strlen(name); + + if (!lsqlite3->options) return NULL; + + for (i=0;lsqlite3->options[i];i++) { + if (strncmp(lsqlite3->options[i], name, len) == 0 && + lsqlite3->options[i][len] == '=') { + return &lsqlite3->options[i][len+1]; + } + } + + return NULL; +} +#endif + +/* + rename a record +*/ +static int lsqlite3_rename(struct ldb_module *module, const char *olddn, const char *newdn) +{ + int column; + struct lsqlite3_private *lsqlite3 = module->private_data; + + /* ignore ltdb specials */ + if (olddn[0] == '@' ||newdn[0] == '@') { + return 0; + } + + /* Bind old distinguished names */ + column = sqlite3_bind_parameter_index(lsqlite3->renameDN, ":oldDN"); + if (sqlite3_bind_text(lsqlite3->renameDN, column, + olddn, strlen(olddn), + SQLITE_STATIC) != SQLITE_OK) { + return -1; + } + + /* Bind new distinguished names */ + column = sqlite3_bind_parameter_index(lsqlite3->renameDN, ":newDN"); + if (sqlite3_bind_text(lsqlite3->renameDN, column, + newdn, strlen(newdn), + SQLITE_STATIC) != SQLITE_OK) { + return -1; + } + + do { + lsqlite3->last_rc = sqlite3_step(lsqlite3->renameDN); + (void) sqlite3_reset(lsqlite3->renameDN); + } while lsqlite3->last_rc == SQLITE3_BUSY; + + return lsqlite3->last_rc == 0 ? 0 : -1; +} + +/* + delete a record +*/ +static int lsqlite3_delete(struct ldb_module *module, const char *dn) +{ + int ret = 0; + int column; + struct lsqlite3_private *lsqlite3 = module->private_data; + + /* ignore ltdb specials */ + if (dn[0] == '@') { + return 0; + } + + /* Bind new distinguished names */ + column = sqlite3_bind_parameter_index(lsqlite3->renameDN, ":dn"); + if (sqlite3_bind_text(lsqlite3->deleteDN, column, + dn, strlen(dn), + SQLITE_STATIC) != SQLITE_OK) { + return -1; + } + + do { + lsqlite3->last_rc = sqlite3_step(lsqlite3->deleteDN); + (void) sqlite3_reset(lsqlite3->deleteDN); + } while lsqlite3->last_rc == SQLITE3_BUSY; + + return lsqlite3->last_rc == 0 ? 0 : -1; +} + +/* + free a search result +*/ +static int lsqlite3_search_free(struct ldb_module *module, struct ldb_message **res) +{ + talloc_free(res); + return 0; +} + + +/* + add a single set of ldap message values to a ldb_message +*/ +static int lsqlite3_add_msg_attr(struct ldb_context *ldb, + struct ldb_message *msg, + const char *attr, struct berval **bval) +{ + int count, i; + struct ldb_message_element *el; + + count = ldap_count_values_len(bval); + + if (count <= 0) { + return -1; + } + + el = talloc_realloc(msg, msg->elements, struct ldb_message_element, + msg->num_elements + 1); + if (!el) { + errno = ENOMEM; + return -1; + } + + msg->elements = el; + + el = &msg->elements[msg->num_elements]; + + el->name = talloc_strdup(msg->elements, attr); + if (!el->name) { + errno = ENOMEM; + return -1; + } + el->flags = 0; + + el->num_values = 0; + el->values = talloc_array(msg->elements, struct ldb_val, count); + if (!el->values) { + errno = ENOMEM; + return -1; + } + + for (i=0;ivalues[i].data = talloc_memdup(el->values, bval[i]->bv_val, bval[i]->bv_len); + if (!el->values[i].data) { + return -1; + } + el->values[i].length = bval[i]->bv_len; + el->num_values++; + } + + msg->num_elements++; + + return 0; +} + +/* + search for matching records +*/ +static int lsqlite3_search(struct ldb_module *module, const char *base, + enum ldb_scope scope, const char *expression, + const char * const *attrs, struct ldb_message ***res) +{ + struct ldb_context *ldb = module->ldb; + struct lsqlite3_private *lsqlite3 = module->private_data; + int count, msg_count; + + if (base == NULL) { + base = ""; + } + + lsqlite3->last_rc = ldap_search_s(lsqlite3->ldap, base, (int)scope, + expression, + discard_const_p(char *, attrs), + 0, &ldapres); + if (lsqlite3->last_rc != LDAP_SUCCESS) { + return -1; + } + + count = ldap_count_entries(lsqlite3->ldap, ldapres); + if (count == -1 || count == 0) { + ldap_msgfree(ldapres); + return count; + } + + (*res) = talloc_array(lsqlite3, struct ldb_message *, count+1); + if (! *res) { + ldap_msgfree(ldapres); + errno = ENOMEM; + return -1; + } + + (*res)[0] = NULL; + + msg_count = 0; + + /* loop over all messages */ + for (msg=ldap_first_entry(lsqlite3->ldap, ldapres); + msg; + msg=ldap_next_entry(lsqlite3->ldap, msg)) { + BerElement *berptr = NULL; + char *attr, *dn; + + if (msg_count == count) { + /* hmm, got too many? */ + ldb_debug(ldb, LDB_DEBUG_FATAL, "Fatal: ldap message count inconsistent\n"); + break; + } + + (*res)[msg_count] = talloc(*res, struct ldb_message); + if (!(*res)[msg_count]) { + goto failed; + } + (*res)[msg_count+1] = NULL; + + dn = ldap_get_dn(lsqlite3->ldap, msg); + if (!dn) { + goto failed; + } + + (*res)[msg_count]->dn = talloc_strdup((*res)[msg_count], dn); + ldap_memfree(dn); + if (!(*res)[msg_count]->dn) { + goto failed; + } + + + (*res)[msg_count]->num_elements = 0; + (*res)[msg_count]->elements = NULL; + (*res)[msg_count]->private_data = NULL; + + /* loop over all attributes */ + for (attr=ldap_first_attribute(lsqlite3->ldap, msg, &berptr); + attr; + attr=ldap_next_attribute(lsqlite3->ldap, msg, berptr)) { + struct berval **bval; + bval = ldap_get_values_len(lsqlite3->ldap, msg, attr); + + if (bval) { + lsqlite3_add_msg_attr(ldb, (*res)[msg_count], attr, bval); + ldap_value_free_len(bval); + } + + ldap_memfree(attr); + } + if (berptr) ber_free(berptr, 0); + + msg_count++; + } + + ldap_msgfree(ldapres); + + return msg_count; + +failed: + if (*res) lsqlite3_search_free(module, *res); + return -1; +} + + +/* + Issue a series of SQL statements to implement the requests in the ldb_message +*/ +static int lsqlite3_msg_to_sql(struct ldb_context *ldb, + const struct ldb_message *msg, + int modify_existing) +{ + unsigned int i, j; + struct ldb_context *ldb = module->ldb; + struct lsqlite3_private *lsqlite3 = module->private_data; + sqlite3_stmt *stmt = NULL; + + for (i=0;inum_elements;i++) { + const struct ldb_message_element *el = &msg->elements[i]; + + if (! modify_existing) { + /* This is a new DN. Bind new distinguished name */ + column = + sqlite3_bind_parameter_index( + lsqlite3->queries.newDN, + ":dn"); + if (sqlite3_bind_text(lsqlite3->queries.newDN, column, + msg->dn, strlen(msg->dn), + SQLITE_STATIC) != SQLITE_OK) { + return -1; + } + + /* Add this new DN */ + do { + lsqlite3->last_rc = + sqlite3_step(lsqlite3->queries.newDN); + (void) sqlite3_reset(lsqlite3->queries.newDN); + } while lsqlite3->last_rc == SQLITE_BUSY; + + if (lsqlite3->last_rc != SQLITE_DONE) { + return -1; + } + + dn_id = last_insert_rowid(lsqlite3->sqlite3); + + stmt = lsqlite3->queries.newAttribute; + + } else { + /* Get the dn_id for the specified DN */ + xxx; + + switch (el->flags & LDB_FLAG_MOD_MASK) { + case LDB_FLAG_MOD_ADD: + stmt = lsqlite3->queries.addAttrValuePair; + break; + case LDB_FLAG_MOD_DELETE: + stmt = lsqlite3->queries.deleteAttrValuePairs; + break; + case LDB_FLAG_MOD_REPLACE: + stmt = lsqlite3->queries.replaceAttrValuePairs; + break; + } + + } + + for (j=0;jnum_values;j++) { + mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals, + struct berval); + if (!mods[num_mods]->mod_vals.modv_bvals[j]) { + goto failed; + } + mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data; + mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length; + } + mods[num_mods]->mod_vals.modv_bvals[j] = NULL; + num_mods++; + } + + return mods; + +failed: + talloc_free(mods); + return NULL; +} + + +/* + add a record +*/ +static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_context *ldb = module->ldb; + struct lsqlite3_private *lsqlite3 = module->private_data; + LDAPMod **mods; + int ret = 0; + + /* ignore ltdb specials */ + if (msg->dn[0] == '@') { + return 0; + } + + mods = lsqlite3_msg_to_mods(ldb, msg, 0); + + lsqlite3->last_rc = ldap_add_s(lsqlite3->ldap, msg->dn, mods); + if (lsqlite3->last_rc != LDAP_SUCCESS) { + ret = -1; + } + + talloc_free(mods); + + return ret; +} + + +/* + modify a record +*/ +static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_context *ldb = module->ldb; + struct lsqlite3_private *lsqlite3 = module->private_data; + LDAPMod **mods; + int ret = 0; + + /* ignore ltdb specials */ + if (msg->dn[0] == '@') { + return 0; + } + + mods = lsqlite3_msg_to_mods(ldb, msg, 1); + + lsqlite3->last_rc = ldap_modify_s(lsqlite3->ldap, msg->dn, mods); + if (lsqlite3->last_rc != LDAP_SUCCESS) { + ret = -1; + } + + talloc_free(mods); + + return ret; +} + +static int lsqlite3_lock(struct ldb_module *module, const char *lockname) +{ + int ret = 0; + struct ldb_context *ldb = module->ldb; + struct lsqlite3_private *lsqlite3 = module->private_data; + + if (lockname == NULL) { + return -1; + } + + /* If we're already locked, just update lock count */ + if (++lsqlite3->lock_count > 1) { + return -1; + } + + /* Write-lock (but not read-lock) the database */ + lsqlite3->last_rc = sqlite3_step(lsqlite3->begin); + + /* Ready the compiled statememt for its next use */ + (void ) sqlite_reset(lsqlite3->begin); + + return lsqlite3->last_rc == 0 ? 0 : -1; +} + +static int lsqlite3_unlock(struct ldb_module *module, const char *lockname) +{ + int ret = 0; + struct ldb_context *ldb = module->ldb; + struct lsqlite3_private *lsqlite3 = module->private_data; + + if (lockname == NULL) { + return -1; + } + + /* If we're not already locked, there's nothing to do */ + if (lsqlite3->lock_count == 0) { + return 0; + } + + /* Decrement lock count */ + if (--lsqlite3->lock_count == 0) { + + /* Final unlock. Unlock the database */ + lsqlite3->last_rc = sqlite3_step(lsqlite3->commit); + + /* Ready the compiled statememt for its next use */ + (void ) sqlite_reset(lsqlite3->commit); + } + + return lsqlite3->last_rc == 0 ? 0 : -1; +} + +/* + return extended error information +*/ +static const char *lsqlite3_errstring(struct ldb_module *module) +{ + struct lsqlite3_private *lsqlite3 = module->private_data; + return sqlite3_errmsg(lsqlite3->sqlite3); +} + + +static const struct ldb_module_ops lsqlite3_ops = { + "sqlite", + lsqlite3_search, + lsqlite3_search_free, + lsqlite3_add, + lsqlite3_modify, + lsqlite3_delete, + lsqlite3_rename, + lsqlite3_lock, + lsqlite3_unlock, + lsqlite3_errstring +}; + + +static int lsqlite3_destructor(void *p) +{ + struct lsqlite3_private *lsqlite3 = p; + (void) sqlite3_close(lsqlite3->sqlite3); + return 0; +} + +static int lsqlite3_initialize(lsqlite3_private *lsqlite3, + const char *url) +{ + int bNewDatabase = False; + char *p; + char *pTail; + struct stat statbuf; + sqlite3_stmt *stmt; + const char *schema = + " + -- ------------------------------------------------------ + + PRAGMA auto_vacuum=1; + + -- ------------------------------------------------------ + + BEGIN EXCLUSIVE; + + -- ------------------------------------------------------ + + CREATE TABLE ldb_info AS + SELECT 'LDB' AS database_type, + '1.0' AS version; + + CREATE TABLE ldb_distinguished_names + ( + dn_id INTEGER PRIMARY KEY AUTOINCREMENT, + dn TEXT UNIQUE + ); + + CREATE TABLE ldb_object_classes + ( + class_name TEXT PRIMARY KEY, + tree_key TEXT, + max_child_num INTEGER + ); + + CREATE TABLE ldb_dn_object_classes + ( + dn_id INTEGER REFERENCES ldb_distinguished_names, + class_name TEXT REFERENCES ldb_object_classes + ); + + CREATE TABLE ldb_attributes + ( + attr_name TEXT PRIMARY KEY, + case_insensitive_p BOOLEAN DEFAULT FALSE, + wildcard_p BOOLEAN DEFAULT FALSE, + hidden_p BOOLEAN DEFAULT FALSE, + integer_p BOOLEAN DEFAULT FALSE + ); + + CREATE TABLE ldb_attr_value_pairs + ( + dn_id INTEGER REFERENCES ldb_distinguished_names, + attr_name TEXT REFERENCES ldb_attributes, + attr_value TEXT + ); + + -- ------------------------------------------------------ + + CREATE TRIGGER ldb_distinguished_names_delete_tr + AFTER DELETE + ON ldb_distinguished_names + FOR EACH ROW + BEGIN + DELETE FROM ldb_attr_value_pairs + WHERE dn_id = old.dn_id; + DELETE FROM ldb_dn_object_classes + WHERE dn_id = old.dn_id; + END; + + CREATE TRIGGER ldb_attr_value_pairs_insert_tr + BEFORE INSERT + ON ldb_attr_value_pairs + FOR EACH ROW + BEGIN + INSERT OR IGNORE INTO ldb_attributes + (attr_name) + VALUES + (new.attr_name); + END; + + CREATE TRIGGER ldb_attr_value_pairs_delete_tr + AFTER DELETE + ON ldb_attr_value_pairs + FOR EACH ROW + BEGIN + DELETE FROM ldb_attributes + WHERE (SELECT COUNT(*) + FROM ldb_attr_value_pairs + WHERE attr_name = old.attr_name) = 0 + AND attr_name = old.attr_name; + END; + + -- ------------------------------------------------------ + + CREATE INDEX ldb_distinguished_names_dn_idx + ON ldb_distinguished_names (dn); + + CREATE INDEX ldb_object_classes_tree_key_idx + ON ldb_object_classes (tree_key); + + + CREATE INDEX ldb_dn_object_classes_dn_id_idx + ON ldb_dn_object_classes (dn_id); + + CREATE INDEX ldb_dn_object_classes_class_name_idx + ON ldb_dn_object_classes (class_name); + + + CREATE INDEX ldb_attr_value_pairs_dn_id_name_case_idx + ON ldb_attr_value_pairs (dn_id, attr_name); + + CREATE INDEX ldb_attr_value_pairs_dn_id_name_nocase_idx + ON ldb_attr_value_pairs (dn_id, attr_name COLLATE NOCASE); + + -- ------------------------------------------------------ + + /* all defaults for dn, initially */ + INSERT INTO ldb_attributes (attr_name) + VALUES ('dn'); + + /* We need an implicit "top" level object class */ + INSERT INTO ldb_object_classes (class_name, tree_key) + SELECT 'top', /* next_tree_key(NULL) */ '0001'; + + -- ------------------------------------------------------ + + COMMIT; + + -- ------------------------------------------------------ + "; + + /* Skip protocol indicator of url */ + if ((p = strchr(url, ':')) == NULL) { + return SQLITE_MISUSE; + } else { + ++p; + } + + /* + * See if we'll be creating a new database, or opening an existing one + */ + if ((stat(p, &statbuf) < 0 && errno == ENOENT) || + statbuf.st_size == 0) { + + bNewDatabase = True; + } + + /* Try to open the (possibly empty/non-existent) database */ + if ((lsqlite3->last_rc = sqlite3_open(p, &lsqlite3->sqlite3)) != SQLITE_SUCCESS) { + return ret; + } + + if (bNewDatabase) { + /* + * Create the database schema + */ + for (pTail = schema; pTail != NULL; ) { + + if ((lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + pTail, + -1, + &stmt, + &pTail)) != SQLITE_SUCCESS || + (lsqlite3->last_rc = sqlite3_step(stmt)) != SQLITE_DONE || + (lsqlite3->last_rc = sqlite_finalize(stmt)) != SQLITE_SUCCESS) { + + (void) sqlite3_close(lsqlite3->sqlite3); + return ret; + } + } + } else { + /* + * Ensure that the database we opened is one of ours + */ + if ((lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "SELECT COUNT(*) " + " FROM sqlite_master " + " WHERE type = 'table' " + " AND name IN " + " (" + " 'ldb_info', " + " 'ldb_distinguished_names', " + " 'ldb_object_classes', " + " 'ldb_dn_object_classes', " + " 'ldb_attributes', " + " 'ldb_attr_value_pairs' " + " );", + -1, + &stmt, + &pTail)) != SQLITE_SUCCESS || + (lsqlite3->last_rc = sqlite3_step(stmt)) != SQLITE_ROW || + sqlite3_column_int(stmt, 0) != 6 || + (lsqlite3->last_rc = sqlite_finalize(stmt)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "SELECT 1 " + " FROM ldb_info " + " WHERE database_type = 'LDB' " + " AND version = '1.0';", + -1, + &stmt, + &pTail)) != SQLITE_SUCCESS || + (lsqlite3->last_rc = sqlite3_step(stmt)) != SQLITE_ROW || + (lsqlite3->last_rc = sqlite_finalize(stmt)) != SQLITE_SUCCESS) { + + /* It's not one that we created. See ya! */ + (void) sqlite3_close(lsqlite3->sqlite3); + return SQLITE_MISUSE; + } + } + + /* + * Pre-compile each of the queries we'll be using. + */ + + if ((lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "BEGIN IMMEDIATE;", + -1, + &lsqlite3->queries.begin, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "COMMIT;", + -1, + &lsqlite3->queries.commit, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "ROLLBACK;", + -1, + &lsqlite3->queries.rollback, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "INSERT INTO ldb_distinguished_names (dn_id, dn) " + " VALUES (:dn_id, :dn);", + -1, + &lsqlite3->queries.newDN, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "UPDATE ldb_distinguished_names " + " SET dn = :newDN " + " WHERE dn = :oldDN;", + -1, + &lsqlite3->queries.renameDN, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "DELETE FROM ldb_distinguished_names " + " WHERE dn = :dn;", + -1, + &lsqlite3->queries.deleteDN, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "INSERT OR IGNORE INTO ldb_object_classes " + " (class_name, tree_key)" + " SELECT :class_name, next_tree_key(NULL);", + -1, + &lsqlite3->queries.newObjectClass, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "INSERT OR REPLACE INTO ldb_dn_object_classes " + " (dn_id, class_name) " + " VALUES (:dn_id, :class_name);", + -1, + &lsqlite3->queries.assignObjectClass, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "INSERT OR IGNORE INTO ldb_attributes (name) " + " VALUES (:name);", + -1, + &lsqlite3->queries.newAttributeUseDefaults, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "INSERT OR REPLACE INTO ldb_attributes " + " (name, " + " case_insensitive_p, " + " wildcard_p, " + " hidden_p, " + " integer_p) " + " VALUES (:name, " + " :case_insensitive_p, " + " :wildcard_p, " + " :hidden_p, " + " :integer_p);", + -1, + &lsqlite3->queries.newAttribute, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "INSERT INTO ldb_attr_value_pairs " + " (dn_id, attr_name, attr_value) " + " VALUES (:dn_id, :attr_name, :attr_value);", + -1, + &lsqlite3->queries.addAttrValuePair, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "UPDATE ldb_attr_value_pairs " + " SET attr_value = :attr_value " + " WHERE dn_id = :dn_id " + " AND attr_name = :attr_name;", + -1, + &lsqlite3->queries.addAttrValuePair, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "DELETE FROM ldb_attr_value_pairs " + " WHERE dn_id = :dn_id " + " AND attr_name = :attr_name;" + -1, + &lsqlite3->queries.deleteAttrValuePair, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "INSERT OR REPLACE INTO ldb_object_classes " + " (class_name, tree_key) " + " SELECT :child_class, next_tree_key(:parent_class);" + -1, + &lsqlite3->queries.insertSubclass, + &pTail)) != SQLITE_SUCCESS) { + + (void) sqlite3_close(lsqlite3->sqlite3); + return ret; + } + + return SQLITE_SUCCESS; +} + +/* + connect to the database +*/ +struct ldb_context *lsqlite3_connect(const char *url, + unsigned int flags, + const char *options[]) +{ + struct ldb_context *ldb = NULL; + struct lsqlite3_private *lsqlite3 = NULL; + int i; + + ldb = talloc(NULL, struct ldb_context); + if (!ldb) { + errno = ENOMEM; + goto failed; + } + + lsqlite3 = talloc(ldb, struct lsqlite3_private); + if (!lsqlite3) { + errno = ENOMEM; + goto failed; + } + + lsqlite3->sqlite3 = NULL; + lsqlite3->options = NULL; + lsqlite3->lock_count = 0; + + lsqlite3->last_rc = lsqlite3_initialize(&lsqlite3->sqlite3, url); + if (lsqlite3->last_rc != LDAP_SUCCESS) { + goto failed; + } + + talloc_set_destructor(lsqlite3, lsqlite3_destructor); + + ldb->modules = talloc(ldb, struct ldb_module); + if (!ldb->modules) { + errno = ENOMEM; + goto failed; + } + ldb->modules->ldb = ldb; + ldb->modules->prev = ldb->modules->next = NULL; + ldb->modules->private_data = lsqlite3; + ldb->modules->ops = &lsqlite3_ops; + + if (options) { + /* take a copy of the options array, so we don't have to rely + on the caller keeping it around (it might be dynamic) */ + for (i=0;options[i];i++) ; + + lsqlite3->options = talloc_array(lsqlite3, char *, i+1); + if (!lsqlite3->options) { + goto failed; + } + + for (i=0;options[i];i++) { + lsqlite3->options[i+1] = NULL; + lsqlite3->options[i] = talloc_strdup(lsqlite3->options, options[i]); + if (!lsqlite3->options[i]) { + goto failed; + } + } + } + + return ldb; + +failed: + if (lsqlite3->sqlite3 != NULL) { + (void) sqlite3_close(lsqlite3->sqlite3); + } + talloc_free(ldb); + return NULL; +} + diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h new file mode 100644 index 0000000000..75105fe264 --- /dev/null +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h @@ -0,0 +1,25 @@ +#include + +struct lsqlite3_private { + char **options; + const char *basedn; + sqlite3 * sqlite; + int lock_count; + int last_rc; + struct { + sqlite3_stmt *begin; + sqlite3_stmt *commit; + sqlite3_stmt *rollback; + sqlite3_stmt *newDN; + sqlite3_stmt *renameDN; + sqlite3_stmt *deleteDN; + sqlite3_stmt *newObjectClass; + sqlite3_stmt *assignObjectClass; + sqlite3_stmt *newAttributeUseDefaults; + sqlite3_stmt *newAttribute; + sqlite3_stmt *addAttrValuePair; + sqlite3_stmt *replaceAttrValuePairs; + sqlite3_stmt *deleteAttrValuePairs; + sqlite3_stmt *insertSubclass; + } queries; +}; diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema new file mode 100644 index 0000000000..2ba188c785 --- /dev/null +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -0,0 +1,240 @@ + -- ------------------------------------------------------ + + PRAGMA auto_vacuum=1; + + -- ------------------------------------------------------ + + BEGIN EXCLUSIVE; + + -- ------------------------------------------------------ + + CREATE TABLE ldb_info AS + SELECT 'LDB' AS database_type, + '1.0' AS version; + + CREATE TABLE ldb_distinguished_names + ( + dn_id INTEGER PRIMARY KEY AUTOINCREMENT, + dn TEXT UNIQUE + ); + + CREATE TABLE ldb_object_classes + ( + class_name TEXT PRIMARY KEY, + tree_key TEXT, + max_child_num INTEGER + ); + + CREATE TABLE ldb_dn_object_classes + ( + dn_id INTEGER REFERENCES ldb_distinguished_names, + class_name TEXT REFERENCES ldb_object_classes + ); + + CREATE TABLE ldb_attributes + ( + attr_name TEXT PRIMARY KEY, + case_insensitive_p BOOLEAN DEFAULT FALSE, + wildcard_p BOOLEAN DEFAULT FALSE, + hidden_p BOOLEAN DEFAULT FALSE, + integer_p BOOLEAN DEFAULT FALSE + ); + + CREATE TABLE ldb_attr_value_pairs + ( + dn_id INTEGER REFERENCES ldb_distinguished_names, + attr_name TEXT REFERENCES ldb_attributes, + attr_value TEXT + ); + + -- ------------------------------------------------------ + + CREATE TRIGGER ldb_distinguished_names_delete_tr + AFTER DELETE + ON ldb_distinguished_names + FOR EACH ROW + BEGIN + DELETE FROM ldb_attr_value_pairs + WHERE dn_id = old.dn_id; + DELETE FROM ldb_dn_object_classes + WHERE dn_id = old.dn_id; + END; + + CREATE TRIGGER ldb_attr_value_pairs_insert_tr + BEFORE INSERT + ON ldb_attr_value_pairs + FOR EACH ROW + BEGIN + INSERT OR IGNORE INTO ldb_attributes + (attr_name) + VALUES + (new.attr_name); + END; + + CREATE TRIGGER ldb_attr_value_pairs_delete_tr + AFTER DELETE + ON ldb_attr_value_pairs + FOR EACH ROW + BEGIN + DELETE FROM ldb_attributes + WHERE (SELECT COUNT(*) + FROM ldb_attr_value_pairs + WHERE attr_name = old.attr_name) = 0 + AND attr_name = old.attr_name; + END; + + -- ------------------------------------------------------ + + CREATE INDEX ldb_distinguished_names_dn_idx + ON ldb_distinguished_names (dn); + + CREATE INDEX ldb_object_classes_tree_key_idx + ON ldb_object_classes (tree_key); + + + CREATE INDEX ldb_dn_object_classes_dn_id_idx + ON ldb_dn_object_classes (dn_id); + + CREATE INDEX ldb_dn_object_classes_class_name_idx + ON ldb_dn_object_classes (class_name); + + + CREATE INDEX ldb_attr_value_pairs_dn_id_name_case_idx + ON ldb_attr_value_pairs (dn_id, attr_name); + + CREATE INDEX ldb_attr_value_pairs_dn_id_name_nocase_idx + ON ldb_attr_value_pairs (dn_id, attr_name COLLATE NOCASE); + + -- ------------------------------------------------------ + + /* all defaults for dn, initially */ + INSERT INTO ldb_attributes (attr_name) + VALUES ('dn'); + + /* We need an implicit "top" level object class */ + INSERT INTO ldb_object_classes (class_name, tree_key) + SELECT 'top', /* next_tree_key(NULL) */ '0001'; + + -- ------------------------------------------------------ + + COMMIT; + + -- ------------------------------------------------------ + +/* + * dn: o=University of Michigan,c=US + * objectclass: organization + * objectclass: domainRelatedObject + */ +-- newDN +INSERT INTO ldb_distinguished_names (dn_id, dn) + VALUES (1, 'o=University of Michigan,c=US'); + +-- newObjectClass +INSERT OR IGNORE INTO ldb_object_classes (class_name, tree_key) + SELECT 'organization', /* next_tree_key(NULL) */ '0002'; + +INSERT OR IGNORE INTO ldb_object_classes (class_name, tree_key) + SELECT 'domainRelatedObject', /* next_tree_key(NULL) */ '0003'; + +-- assignObjectClass +INSERT OR IGNORE INTO ldb_dn_object_classes (dn_id, class_name) + VALUES (1, 'organization'); + +INSERT OR IGNORE INTO ldb_dn_object_classes (dn_id, class_name) + VALUES (1, 'domainRelatedObject'); + +/* + * l: Ann Arbor, Michigan + * st: Michigan + * o: University of Michigan + * o: UMICH + * o: UM + * o: U-M + * o: U of M + * description: The University of Michigan at Ann Arbor + * seeAlso: + * postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481 + * 09 $ US + * telephonenumber: +1 313 764-1817 + * associateddomain: example.com + */ +-- addAttrValuePair +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'l', 'Ann Arbor, Michigan'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'st', 'Michigan'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'o', 'University of Michigan'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'o', 'UMICH'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'o', 'UM'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'o', 'U-M'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'o', 'U of M'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'description', 'The University of Michigan at Ann Arbor'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'seeAlso', ''); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'postaladdress', 'University of Michigan $ 535 W. William St. $ Ann Arbor, MI 48109 $ US'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'telephonenumber', '+1 313 764-1817'); +INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) + VALUES (1, 'associateddomain', 'example.com'); + +-- ---------------------------------------------------------------------- + +/* + * dn: @ATTRIBUTES + * uid: CASE_INSENSITIVE WILDCARD + * cn: CASE_INSENSITIVE + * ou: CASE_INSENSITIVE + * dn: CASE_INSENSITIVE + */ +-- newAttribute +INSERT OR REPLACE INTO ldb_attributes + (attr_name, case_insensitive_p, wildcard_p, hidden_p, integer_p) + VALUES ('uid', 1, 1, 0, 0); +INSERT OR REPLACE INTO ldb_attributes + (attr_name, case_insensitive_p, wildcard_p, hidden_p, integer_p) + VALUES ('cn', 1, 0, 0, 0); +INSERT OR REPLACE INTO ldb_attributes + (attr_name, case_insensitive_p, wildcard_p, hidden_p, integer_p) + VALUES ('ou', 1, 0, 0, 0); +INSERT OR REPLACE INTO ldb_attributes + (attr_name, case_insensitive_p, wildcard_p, hidden_p, integer_p) + VALUES ('dn', 1, 0, 0, 0); + +-- ---------------------------------------------------------------------- + +/* + * dn: @SUBCLASSES + * top: domain + * top: person + * domain: domainDNS + * person: organizationalPerson + * person: fooPerson + * organizationalPerson: user + * organizationalPerson: OpenLDAPperson + * user: computer + */ +-- insertSubclass +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'domain', /* next_tree_key('top') */ '00010001'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'person', /* next_tree_key('top') */ '00010002'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'domainDNS', /* next_tree_key('domain') */ '000100010001'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'organizationalPerson', /* next_tree_key('person') */ '000100020001'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'fooPerson', /* next_tree_key('person') */ '000100020002'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'user', /* next_tree_key('organizationalPerson') */ '0001000200010001'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'OpenLDAPperson', /* next_tree_key('organizationPerson') */ '0001000200010002'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'computer', /* next_tree_key('user') */ '0001000200010001'; -- cgit From a81630c0c43c756b74feea84019769357f03a3e5 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Thu, 26 May 2005 02:16:45 +0000 Subject: r6984: added tree representation documentation and utility code, to be used for subclasses of object classes (This used to be commit 7aca32dca6daac54ac77a66438bc5168d5e04227) --- source4/lib/ldb/ldb_sqlite3/README | 4 + source4/lib/ldb/ldb_sqlite3/base160.c | 154 +++ source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 6 +- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 7 + source4/lib/ldb/ldb_sqlite3/trees.ps | 1760 +++++++++++++++++++++++++++++ 5 files changed, 1928 insertions(+), 3 deletions(-) create mode 100644 source4/lib/ldb/ldb_sqlite3/README create mode 100644 source4/lib/ldb/ldb_sqlite3/base160.c create mode 100644 source4/lib/ldb/ldb_sqlite3/trees.ps (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/README b/source4/lib/ldb/ldb_sqlite3/README new file mode 100644 index 0000000000..a0b3dcb16d --- /dev/null +++ b/source4/lib/ldb/ldb_sqlite3/README @@ -0,0 +1,4 @@ +trees.ps contains an explanation of the Genealogical Representation of Trees +in Databases which is being used in ldb_sqlite3. Note that we use fgID +representation with 4 bytes per level, so we can represent 6.5E+08 subclasses +of any object class. This should be adequate for our purposes. :-) diff --git a/source4/lib/ldb/ldb_sqlite3/base160.c b/source4/lib/ldb/ldb_sqlite3/base160.c new file mode 100644 index 0000000000..e7220433fc --- /dev/null +++ b/source4/lib/ldb/ldb_sqlite3/base160.c @@ -0,0 +1,154 @@ +/* + base160 code used by ldb_sqlite3 + + Copyright (C) 2004 Derrell Lipman + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/* + * ldb_sqlite3_base160() + * + * Convert an integer value to a string containing the base 160 representation + * of the integer. We always convert to a string representation that is 4 + * bytes in length, and we always null terminate. + * + * Parameters: + * val -- + * The value to be converted + * + * result -- + * Buffer in which the result is to be placed + * + * Returns: + * nothing + */ +static unsigned char base160tab[161] = +{ + 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , /* 0-9 */ + 58 , 59 , 65 , 66 , 67 , 68 , 69 , 70 , 71 , 72 , /* : ; A-H */ + 73 , 74 , 75 , 76 , 77 , 78 , 79 , 80 , 81 , 82 , /* I-R */ + 83 , 84 , 85 , 86 , 87 , 88 , 89 , 90 , 97 , 98 , /* S-Z , a-b */ + 99 , 100, 101, 102, 103, 104, 105, 106, 107, 108, /* c-l */ + 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, /* m-v */ + 119, 120, 121, 122, 160, 161, 162, 163, 164, 165, /* w-z, latin1 */ + 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, /* latin1 */ + 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, /* latin1 */ + 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, /* latin1 */ + 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, /* latin1 */ + 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, /* latin1 */ + 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, /* latin1 */ + 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, /* latin1 */ + 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, /* latin1 */ + 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, /* latin1 */ + '\0' +}; + + +/* + * lsqlite3_base160() + * + * Convert an unsigned long integer into a base160 representation of the + * number. + * + * Parameters: + * val -- + * value to be converted + * + * result -- + * character array, 5 bytes long, into which the base160 representation + * will be placed. The result will be a four-digit representation of the + * number (with leading zeros prepended as necessary), and null + * terminated. + * + * Returns: + * Nothing + */ +void +lsqlite3_base160(unsigned long val, + unsigned char result[5]) +{ + int i; + + for (i = 3; i >= 0; i--) { + + result[i] = base160tab[val % 160]; + val /= 160; + } + + result[4] = '\0'; +} + + +/* + * lsqlite3_base160Next() + * + * Retrieve the next-greater number in the base160 sequence for the terminal + * tree node (the last four digits). Only one tree level (four digits) are + * operated on. + * + * Parameters: + * base160 -- a character array containing either an empty string (in which + * case no operation is performed), or a string of base160 digits + * with a length of a multiple of four digits. + * + * Upon return, the trailing four digits (one tree level) will + * have been incremented by 1. + * + * Returns: + * base160 -- the modified array + */ +char * +lsqlite3_base160Next(char base160[]) +{ + int i; + unsigned char * pTab; + char * pBase160 = base160; + + /* + * We need a minimum of four digits, and we will always get a multiple of + * four digits. + */ + if (*pBase160 != '\0') + { + pBase160 += strlen(pBase160) - 1; + + /* We only carry through four digits: one level in the tree */ + for (i = 0; i < 4; i++) { + + /* What base160 value does this digit have? */ + pTab = strchr(base160tab, *pBase160); + + /* Is there a carry? */ + if (pTab < base160tab + sizeof(base160tab) - 1) { + + /* Nope. Just increment this value and we're done. */ + *pBase160 = *++pTab; + break; + } else { + + /* + * There's a carry. This value gets base160tab[0], we + * decrement the buffer pointer to get the next higher-order + * digit, and continue in the loop. + */ + *pBase160-- = base160tab[0]; + } + } + } + + return base160; +} diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 67debd8a4e..932da0af31 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -457,7 +457,7 @@ static int lsqlite3_lock(struct ldb_module *module, const char *lockname) /* Write-lock (but not read-lock) the database */ lsqlite3->last_rc = sqlite3_step(lsqlite3->begin); - /* Ready the compiled statememt for its next use */ + /* Ready the compiled statement for its next use */ (void ) sqlite_reset(lsqlite3->begin); return lsqlite3->last_rc == 0 ? 0 : -1; @@ -484,7 +484,7 @@ static int lsqlite3_unlock(struct ldb_module *module, const char *lockname) /* Final unlock. Unlock the database */ lsqlite3->last_rc = sqlite3_step(lsqlite3->commit); - /* Ready the compiled statememt for its next use */ + /* Ready the compiled statement for its next use */ (void ) sqlite_reset(lsqlite3->commit); } @@ -904,7 +904,7 @@ struct ldb_context *lsqlite3_connect(const char *url, lsqlite3->lock_count = 0; lsqlite3->last_rc = lsqlite3_initialize(&lsqlite3->sqlite3, url); - if (lsqlite3->last_rc != LDAP_SUCCESS) { + if (lsqlite3->last_rc != SQLITE_SUCCESS) { goto failed; } diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h index 75105fe264..46aa4ab7c5 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h @@ -23,3 +23,10 @@ struct lsqlite3_private { sqlite3_stmt *insertSubclass; } queries; }; + +void +lsqlite3_base160(unsigned long val, + unsigned char result[5]); + +char * +lsqlite3_base160Next(char base160[]); diff --git a/source4/lib/ldb/ldb_sqlite3/trees.ps b/source4/lib/ldb/ldb_sqlite3/trees.ps new file mode 100644 index 0000000000..433a064816 --- /dev/null +++ b/source4/lib/ldb/ldb_sqlite3/trees.ps @@ -0,0 +1,1760 @@ +%!PS-Adobe-2.0 +%%Creator: dvips(k) 5.86 Copyright 1999 Radical Eye Software +%%Title: trees.dvi +%%Pages: 7 +%%PageOrder: Ascend +%%BoundingBox: 0 0 596 842 +%%EndComments +%DVIPSWebPage: (www.radicaleye.com) +%DVIPSCommandLine: dvips -f trees.dvi +%DVIPSParameters: dpi=600, compressed +%DVIPSSource: TeX output 2000.05.06:2055 +%%BeginProcSet: texc.pro +%! +/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S +N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 +mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 +0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ +landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize +mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ +matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round +exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ +statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] +N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin +/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array +/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 +array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N +df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A +definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get +}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} +B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr +1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3 +1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx +0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx +sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{ +rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp +gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B +/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{ +/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{ +A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy +get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse} +ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp +fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17 +{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add +chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{ +1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop} +forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn +/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put +}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ +bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A +mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ +SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ +userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X +1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 +index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N +/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ +/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) +(LaserWriter 16/600)]{A length product length le{A length product exch 0 +exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse +end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask +grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} +imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round +exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto +fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p +delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} +B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ +p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S +rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end + +%%EndProcSet +TeXDict begin 39158280 55380996 1000 600 600 (trees.dvi) +@start +%DVIPSBitmapFont: Fa cmr10 10 6 +/Fa 6 55 df<146014E0EB01C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B +120F90C7FCA25A121EA2123EA35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A2 +6C7EA26C7E1378A27F7F130E7FEB0380EB01C0EB00E01460135278BD20>40 +D<12C07E12707E7E7E120F6C7E6C7EA26C7E6C7EA21378A2137C133C133E131EA2131F7F +A21480A3EB07C0A6EB03E0B2EB07C0A6EB0F80A31400A25B131EA2133E133C137C1378A2 +5BA2485A485AA2485A48C7FC120E5A5A5A5A5A13527CBD20>I<15301578B3A6007FB812 +F8B912FCA26C17F8C80078C8FCB3A6153036367BAF41>43 D48 DI54 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fb cmr7 7 3 +/Fb 3 55 df48 D<13381378EA01F8121F12FE12E01200B3AB487EB512F8A2 +15267BA521>I54 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fc cmmi10 10 1 +/Fc 1 69 df<0103B7FC4916E018F8903B0007F80007FE4BEB00FFF03F80020FED1FC018 +0F4B15E0F007F0021F1503A24B15F81801143F19FC5DA2147FA292C8FCA25C18035CA213 +0119F84A1507A2130319F04A150FA2010717E0181F4A16C0A2010FEE3F80A24AED7F0018 +7E011F16FE4D5A4A5D4D5A013F4B5A4D5A4A4A5A057FC7FC017F15FEEE03FC91C7EA0FF0 +49EC7FC0B8C8FC16FC16C03E397DB845>68 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fd ectt1000 10 73 +/Fd 73 126 df37 +D39 +D<143814FC13011303EB07F8EB0FF0EB1FC0EB3F80EB7F0013FE485A485A5B12075B120F +5B485AA2123F90C7FCA25A127EA312FE5AAC7E127EA3127F7EA27F121FA26C7E7F12077F +12037F6C7E6C7E137FEB3F80EB1FC0EB0FF0EB07F8EB03FC130113001438164272B92C> +I<127012FC7E7E6C7E6C7EEA0FE06C7E6C7E6C7E6C7E137F7F1480131F14C0130FEB07E0 +A214F01303A214F81301A314FC1300AC130114F8A3130314F0A2130714E0A2EB0FC0131F +1480133F14005B13FE485A485A485A485AEA3FC0485A48C7FC5A5A1270164279B92C>I< +EB0380497EA60020140800F8143E00FE14FE00FF13C1EBC7C7EBE7CF003FB512F8000F14 +E0000314806C140038007FFCA248B5FC481480000F14E0003F14F839FFE7CFFEEBC7C7EB +07C100FE13C000F8143E0020140800001400A66D5A1F247AAA2C>I<147014F8AF003FB6 +12E0B712F8A4C700F8C7FCB0147025267DAB2C>II<121FEA3F80EA7FC0EAFFE0A5EA7FC0EA3F80EA1F000B0B708A2C>46 +D<1507ED0F80A2151F16005D153E157E157CA215FC5D14015D14035D14075D140F5D141F +92C7FC5C143EA2147E147C14FC5C13015C13035C13075C130F5C131F91C8FC5B133EA213 +7E137C13FC5B12015B12035B12075B120F5B121F90C9FCA25A123E127E127C12FC5AA212 +7021417BB92C>II<1307497EA2131F +A2133F137F13FF5A1207127FB5FC13DF139FEA7C1F1200B3AE007FB512E0B612F0A36C14 +E01C3477B32C>II<000FB512FE4880A35D0180C8FCADEB83FE90389FFF8090B512E015F881 +9038FE03FE9038F000FF01C07F49EB3F8090C7121F6C15C0C8120FA2ED07E0A4123C127E +B4FC150F16C0A248141F007EEC3F80007FEC7F006C6C5B6D485A391FF80FFC6CB55A6C5C +000114C06C6C90C7FCEB0FF823347CB22C>53 DI<1278B712C016E0A316C000FCC7EA3F80ED7F0015FE00785CC712014A +5A4A5A5D140F5D4A5A143F92C7FC5C147E14FE5C13015CA2495AA213075CA3495AA4495A +A5133F91C8FCAA131E23357CB32C>I59 D<1502ED0F80151F157F15 +FF913803FE00EC0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390 +C8FCEA07FCEA1FF8EA3FE0EAFF8090C9FCA27FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE0 +6D7EEB07FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157F151F150FED +0200212A7BAD2C>I<007FB612F0B712F8A36C15F0CAFCA8007FB612F0B712F8A36C15F0 +25127DA12C>I<122012F87EB4FC7FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE06D7EEB07 +FC6D7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157FA215FF913803FE00EC +0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390C8FCEA07FCEA1F +F8EA3FE0EAFF8090C9FC12FC5A1220212A7BAD2C>I<14FE497EA4497FA214EFA2130781 +A214C7A2010F7FA314C390381F83F0A590383F01F8A490387E00FCA549137E90B512FEA3 +4880A29038F8003FA34848EB1F80A4000715C049130FD87FFEEBFFFC6D5AB514FE6C15FC +497E27347EB32C>65 D<007FB512E015F8B612FE6C8016C03903F0003FED0FE0ED07F015 +03A2ED01F8A6ED03F0A21507ED0FE0ED1FC0EDFF8090B612005D5D15FF16C09039F0001F +E0ED07F0ED03F81501ED00FCA216FE167EA616FE16FC1501ED03F8150FED3FF0007FB612 +E016C0B712806CECFE0015F027337FB22C>I<02FF13700107EBE0F84913F9013F13FD49 +13FFEBFF813901FE007F4848131FD807F0130F1507485A491303485A150148C7FCA25A00 +7EEC00F01600A212FE5AAB7E127EA3007F15F06CEC01F8A26C7EA26C6C13036D14F06C6C +130716E0D803FC131F6C6CEB3FC03A00FF81FF806DB512006D5B010F5B6D13F001001380 +25357DB32C>I<007FB5FCB612C015F0816C803907E003FEEC00FFED7F80153FED1FC0ED +0FE0A2150716F0150316F81501A4ED00FCACED01F8A3150316F0A2150716E0150FED1FC0 +153FED7F80EDFF00EC03FE007FB55AB65A5D15C06C91C7FC26337EB22C>I<007FB612F0 +B712F8A37E3903F00001A7ED00F01600A4EC01E04A7EA490B5FCA5EBF003A46E5A91C8FC +A5163C167EA8007FB612FEB7FCA36C15FC27337EB22C>I<007FB612F8B712FCA37ED803 +F0C7FCA716781600A515F04A7EA490B5FCA5EBF001A46E5A92C7FCAD387FFFE0B5FC805C +7E26337EB22C>I<903901FC038090390FFF87C04913EF017F13FF90B6FC4813073803FC +01497E4848137F4848133F49131F121F5B003F140F90C7FCA2127EED078092C7FCA212FE +5AA8913803FFF84A13FCA27E007E6D13F89138000FC0A36C141FA27F121F6D133F120F6D +137F6C7E6C6C13FF6D5A3801FF076C90B5FC6D13EF011F13CF6DEB0780D901FCC7FC2635 +7DB32C>II<007FB512F8B612FCA36C14 +F839000FC000B3B3A5007FB512F8B612FCA36C14F81E3379B22C>I75 D<387FFFE0B57EA36C5BD803F0C8FCB3AE16F0 +ED01F8A8007FB6FCB7FCA36C15F025337DB22C>IIII<007FB512C0B612 +F88115FF6C15802603F00013C0153FED0FE0ED07F0A2150316F81501A6150316F01507A2 +ED0FE0ED3FC015FF90B61280160015FC5D15C001F0C8FCB0387FFF80B57EA36C5B25337E +B22C>II<387FFFFCB67E15E015F86C803907E007FE1401EC007F6F7E151FA2 +6F7EA64B5AA2153F4BC7FCEC01FE140790B55A5D15E081819038E007FCEC01FE1400157F +81A8160FEE1F80A5D87FFEEB1FBFB5ECFF00815E6C486D5AC8EA01F029347EB22C>I<90 +381FF80790B5EA0F804814CF000714FF5A381FF01F383FC003497E48C7FC007E147F00FE +143F5A151FA46CEC0F00007E91C7FC127F7FEA3FE0EA1FFCEBFFC06C13FC0003EBFFC06C +14F06C6C7F01077F9038007FFEEC07FF02001380153FED1FC0A2ED0FE0A20078140712FC +A56CEC0FC0A26CEC1F806D133F01E0EB7F009038FE01FF90B55A5D00F914F0D8F83F13C0 +D8700790C7FC23357CB32C>I<007FB612FCB712FEA43AFC007E007EA70078153CC71400 +B3AF90383FFFFCA2497F6D5BA227337EB22C>I<3B7FFF803FFFC0B56C4813E0A36C496C +13C03B03F00001F800B3AF6D130300015DA26D130700005D6D130F017F495A6D6C485AEC +E0FF6DB5C7FC6D5B010313F86D5B9038003F802B3480B22C>III<3A3FFF03FFE0484913F0148714076C6D13E03A01 +F800FE007F0000495A13FE017E5BEB7F03013F5B1487011F5B14CF010F5B14FF6D5BA26D +90C7FCA26D5AA26D5AA2497EA2497EA2497F81EB0FCF81EB1FC7EC87F0EB3F83EC03F8EB +7F01017E7FEBFE00497F0001147E49137F000380491480151FD87FFEEBFFFC6D5AB514FE +6C15FC497E27337EB22C>II<387FFFFCB512FEA314FC00FCC7FCB3B3B3B512FC14FEA36C13FC +17416FB92C>91 D<127012F8A27E127C127E123E123F7EA27F120F7F12077F12037F1201 +7F12007F137C137E133EA2133F7F80130F80130780130380130180130080147C147E143E +A2143F8081140F81140781140381140181140081157CA2157E153E153F811680150FA2ED +070021417BB92C>I<387FFFFCB512FEA37EC7127EB3B3B3387FFFFEB5FCA36C13FC1741 +7DB92C>II<007FB6FCB71280A46C150021067B7D +2C>I<1338137CEA01FC1203EA07F813F0EA0FC0EA1F80A2EA3F00123E127E127CA212FC +5AA3EAFFC013E013F013F8A2127FA2123F13F0EA1FE0EA07C00E1D72B82C>I<3801FFF0 +000713FE001F6D7E15E048809038C01FF81407EC01FC381F80000006C77EC8127EA3ECFF +FE131F90B5FC1203120F48EB807E383FF800EA7FC090C7FC12FE5AA47E007F14FEEB8003 +383FE01F6CB612FC6C15FE6C14BF0001EBFE1F3A003FF007FC27247CA32C>II<90 +3803FFE0011F13F8017F13FE48B5FC48804848C6FCEA0FF0485A49137E4848131890C9FC +5A127EA25AA8127EA2127F6C140F6DEB1F806C7E6D133F6C6CEB7F003907FE03FF6CB55A +6C5C6C6C5B011F13E0010390C7FC21247AA32C>III103 +DI< +1307EB1FC0A2497EA36D5AA20107C7FC90C8FCA7387FFFC080B5FC7EA2EA0007B3A8007F +B512FCB612FEA36C14FC1F3479B32C>I107 D<387FFFE0B57EA37EEA0003B3B3A5007F +B61280B712C0A36C158022337BB22C>I<3A7F83F007E09039CFFC1FF83AFFDFFE3FFCD8 +7FFF13FF91B57E3A07FE1FFC3E01FCEBF83F496C487E01F013E001E013C0A301C01380B3 +3B7FFC3FF87FF0027F13FFD8FFFE6D13F8D87FFC4913F0023F137F2D2481A32C>I<397F +F01FE039FFF87FFC9038F9FFFE01FB7F6CB6FC00019038F03F80ECC01F02807FEC000F5B +5BA25BB3267FFFE0B5FCB500F11480A36C01E0140029247FA32C>II<397FF01FE0 +39FFF8FFF801FB13FE90B6FC6C158000019038F07FC09138801FE091380007F049EB03F8 +5BED01FC491300A216FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F9138801FE0 +9138E07FC091B51280160001FB5B01F813F8EC3FC091C8FCAD387FFFE0B57EA36C5B2736 +7FA32C>I<903903FC078090391FFF0FC0017F13CF48B512EF4814FF3807FE07380FF001 +48487E49137F4848133F90C7FC48141F127E150F5AA87E007E141FA26C143F7F6C6C137F +6D13FF380FF0033807FC0F6CB6FC6C14EF6C6C138F6D130FEB07F890C7FCAD0203B5FC4A +1480A36E140029367DA32C>II<90387FF8700003B512F8120F5A5A387FC00F387E00034813015AA36CEB +00F0007F140013F0383FFFC06C13FE6CEBFF80000314E0C66C13F8010113FCEB0007EC00 +FE0078147F00FC143F151F7EA26C143F6D133E6D13FE9038F007FC90B5FC15F815E000F8 +148039701FFC0020247AA32C>I<131E133FA9007FB6FCB71280A36C1500D8003FC8FCB1 +ED03C0ED07E0A5EC800F011FEB1FC0ECE07F6DB51280160001035B6D13F89038003FE023 +2E7EAD2C>I<3A7FF003FF80486C487FA3007F7F0001EB000FB3A3151FA2153F6D137F39 +00FE03FF90B7FC6D15807F6D13CF902603FE07130029247FA32C>I<3A3FFF03FFF04801 +8713F8A36C010313F03A00FC007E005D90387E01F8013F5BEB1F83EC87E090380FCFC090 +3807EF80EB03FF6D90C7FC5C6D5A147C14FE130180903803EF80903807CFC0EB0FC7EC83 +E090381F01F0013F7FEB7E00017C137C49137E0001803A7FFF01FFFC1483B514FE6C15FC +140127247EA32C>120 D<3A7FFF01FFFCB5008113FE148314816C010113FC3A03E0000F +806C7E151F6D140012005D6D133E137C017E137E013E137CA2013F13FC6D5BA2EB0F815D +A2EB07C1ECC3E0A2EB03E3ECE7C0130114F75DEB00FFA292C7FC80A2143EA2147E147CA2 +14FC5CA2EA0C01003F5BEA7F83EB87E0EA7E0F495A387FFF806C90C8FC6C5A6C5AEA07E0 +27367EA32C>I<15FF02071380141F147F91B512004913C04AC7FCEB03F85CB31307EB1F +E013FF007F5BB55A49C8FC6D7E6C7FC67F131FEB07F01303B380EB01FEECFFC06D13FF6E +1380141F14070200130021417BB92C>123 D<127812FCB3B3B3A9127806416DB92C>II E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fe ecti1000 10 33 +/Fe 33 122 df28 D<150C151C153815F0EC01E0EC03C0EC0780EC0F00141E5C147C5C5C495A1303 +495A5C130F49C7FCA2133EA25BA25BA2485AA212035B12075BA2120F5BA2121FA290C8FC +A25AA2123EA2127EA2127CA412FC5AAD1278A57EA3121C121EA2120E7EA26C7E6C7EA212 +001E5274BD22>40 D<140C140E80EC0380A2EC01C015E0A2140015F0A21578A4157C153C +AB157CA715FCA215F8A21401A215F0A21403A215E0A21407A215C0140F1580A2141F1500 +A2143EA25CA25CA2495AA2495A5C1307495A91C7FC5B133E133C5B5B485A12035B48C8FC +120E5A12785A12C01E527FBD22>I<4B7EA3150393C8FCA35D1506A3150E150CA3151C15 +18A315381530A31570B912E0A2C80060C8FC15E05DA314015DA3140392C9FCA35C1406A3 +140E140CA3141C1418A2333275AD40>43 DI<120E +EA3F80127F12FFA31300127E123C0909778819>46 D<0103B612FEEFFFC018F0903B0007 +F8000FF84BEB03FCEF00FE020F157FF03F804B141F19C0021F150F19E05D1807143F19F0 +5DA2147FA292C8FCA25C180F5CA2130119E04A151FA2130319C04A153FA201071780187F +4A1600A2010F16FEA24A4A5A60011F15034D5A4A5D4D5A013F4B5A173F4A4AC7FC17FC01 +7FEC03F84C5A91C7EA1FC04949B45A007F90B548C8FCB712F016803C397CB83F>68 +D<0103B512F8A390390007F8005DA2140FA25DA2141FA25DA2143FA25DA2147FA292C7FC +A25CA25CA21301A25CA21303A25CA21307A25CA2130FA25CA2131FA25CA2133FA25CA213 +7FA291C8FC497EB6FCA25C25397CB820>73 D<0107B512FCA25E9026000FF8C7FC5D5D14 +1FA25DA2143FA25DA2147FA292C8FCA25CA25CA21301A25CA21303A25CA21307A25CA213 +0F170C4A141CA2011F153C17384A1478A2013F157017F04A14E01601017F140317C091C7 +1207160F49EC1F80163F4914FF000102071300B8FCA25E2E397BB834>76 +D79 +D81 D<92383FC00E913901FFF01C020713FC91 +391FC07E3C91393F001F7C027CEB0FF84A130749481303495A4948EB01F0A2495AA2011F +15E091C7FCA34915C0A36E90C7FCA2806D7E14FCECFF806D13F015FE6D6D7E6D14E00100 +80023F7F14079138007FFC150F15031501A21500A2167C120EA3001E15FC5EA3003E4A5A +A24B5AA2007F4A5A4B5A6D49C7FC6D133ED8F9F013FC39F8FC03F839F07FFFE0D8E01F13 +8026C003FCC8FC2F3D7ABA2F>83 D<0007B812E0A25AD9F800EB001F01C049EB07C0485A +D900011403121E001C5C003C17801403123800785C00701607140700F01700485CA2140F +C792C7FC5DA2141FA25DA2143FA25DA2147FA292C9FCA25CA25CA21301A25CA21303A25C +A21307A25CA2130FA25CEB3FF0007FB512F8B6FCA2333971B83B>I<14F8EB07FE90381F +871C90383E03FE137CEBF801120148486C5A485A120FEBC001001F5CA2EA3F801403007F +5C1300A21407485C5AA2140F5D48ECC1C0A2141F15831680143F1587007C017F1300ECFF +076C485B9038038F8E391F0F079E3907FE03FC3901F000F0222677A42A>97 +D<133FEA1FFFA3C67E137EA313FE5BA312015BA312035BA31207EBE0F8EBE7FE9038EF0F +80390FFC07C013F89038F003E013E0D81FC013F0A21380A2123F1300A214075A127EA214 +0F12FE4814E0A2141F15C05AEC3F80A215005C147E5C387801F8007C5B383C03E0383E07 +C0381E1F80D80FFEC7FCEA01F01C3B77B926>I<147F903803FFC090380FC1E090381F00 +70017E13784913383901F801F83803F003120713E0120FD81FC013F091C7FC485AA2127F +90C8FCA35A5AA45AA3153015381578007C14F0007EEB01E0003EEB03C0EC0F806CEB3E00 +380F81F83803FFE0C690C7FC1D2677A426>II<147F903803FFC090380FC1E09038 +3F00F0017E13785B485A485A485A120F4913F8001F14F0383F8001EC07E0EC1F80397F81 +FF00EBFFF8148090C8FC5A5AA55AA21530007C14381578007E14F0003EEB01E0EC03C06C +EB0F806CEB3E00380781F83803FFE0C690C7FC1D2677A426>IIIII108 +DII<147F903803FFC090380FC1F090381F00F8 +017E137C5B4848137E4848133E0007143F5B120F485AA2485A157F127F90C7FCA215FF5A +4814FEA2140115FC5AEC03F8A2EC07F015E0140F007C14C0007EEB1F80003EEB3F00147E +6C13F8380F83F03803FFC0C648C7FC202677A42A>I<9039078007C090391FE03FF09039 +3CF0787C903938F8E03E9038787FC00170497EECFF00D9F0FE148013E05CEA01E113C15C +A2D80003143FA25CA20107147FA24A1400A2010F5C5E5C4B5A131F5EEC80035E013F495A +6E485A5E6E48C7FC017F133EEC70FC90387E3FF0EC0F8001FEC9FCA25BA21201A25BA212 +03A25B1207B512C0A3293580A42A>I<3903C003F0390FF01FFC391E783C0F381C7C703A +3C3EE03F8038383FC0EB7F800078150000701300151CD8F07E90C7FCEAE0FE5BA2120012 +015BA312035BA312075BA3120F5BA3121F5BA3123F90C9FC120E212679A423>114 +D<14FE903807FF8090380F83C090383E00E04913F00178137001F813F00001130313F0A2 +15E00003EB01C06DC7FC7FEBFFC06C13F814FE6C7F6D13807F010F13C01300143F141F14 +0F123E127E00FE1480A348EB1F0012E06C133E00705B6C5B381E03E06CB45AD801FEC7FC +1C267AA422>II<01F013 +0ED803FC133FD8071EEB7F80EA0E1F121C123C0038143F49131F0070140FA25BD8F07E14 +0000E08013FEC6485B150E12015B151E0003141C5BA2153C000714385B5DA35DA24A5A14 +0300035C6D48C7FC0001130E3800F83CEB7FF8EB0FC0212679A426>118 +D<903907E007C090391FF81FF89039787C383C9038F03E703A01E01EE0FE3803C01F0180 +13C0D8070014FC481480000E1570023F1300001E91C7FC121CA2C75AA2147EA214FEA25C +A21301A24A1370A2010314F016E0001C5B007E1401010714C000FEEC0380010F1307010E +EB0F0039781CF81E9038387C3C393FF03FF03907C00FC027267CA427>120 +D<13F0D803FCEB01C0D8071EEB03E0D80E1F1307121C123C0038140F4914C01270A24913 +1FD8F07E148012E013FEC648133F160012015B5D0003147E5BA215FE00075C5BA214015D +A314035D14070003130FEBF01F3901F87FE038007FF7EB1FC7EB000F5DA2141F003F5C48 +133F92C7FC147E147C007E13FC387001F8EB03E06C485A383C1F80D80FFEC8FCEA03F023 +3679A428>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Ff cmsy10 10 1 +/Ff 1 16 df15 +D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fg ecbx1000 10 36 +/Fg 36 119 df<913803FFC0027F13F00103B512FC010FEB00FED93FF8133FD97FE0EBFF +8049485A5A1480484A13C04A6C1380A36F1300167E93C7FCA592383FFFC0B8FCA4000390 +C7FCB3ABB5D8FC3F13FFA4303A7EB935>28 D45 +DI<141E143E +14FE1307137FB5FCA3138FEA000FB3B3A5007FB61280A4213679B530>49 +DI54 D58 D66 DII73 +D76 DII< +EDFFF8020FEBFF80027F14F0903A01FFC01FFC010790380007FFD91FFC010113C0D93FF0 +6D6C7E49486E7E49486E7E48496E7E48834890C86C7EA248486F1380A248486F13C0A200 +3F18E0A348486F13F0A400FF18F8AC007F18F06D5DA3003F18E0A26D5D001F18C0A26C6C +4B13806C18006E5C6C6D4A5A6C5F6C6D4A5A6D6C4A5AD93FFC49485A6DB401075B0107D9 +C01F90C7FC010190B512FC6D6C14F0020F1480020001F8C8FC3D3B7BB948>III83 D85 DII<13 +FFB5FCA412077EAF4AB47E020F13F0023F13FC9138FE03FFDAF00013804AEB7FC00280EB +3FE091C713F0EE1FF8A217FC160FA217FEAA17FCA3EE1FF8A217F06E133F6EEB7FE06E14 +C0903AFDF001FF80903AF8FC07FE009039F03FFFF8D9E00F13E0D9C00390C7FC2F3A7EB9 +35>98 D100 +D<903803FF80011F13F0017F13FC3901FF83FE3A03FE007F804848133F484814C0001FEC +1FE05B003FEC0FF0A2485A16F8150712FFA290B6FCA301E0C8FCA4127FA36C7E1678121F +6C6C14F86D14F000071403D801FFEB0FE06C9038C07FC06DB51200010F13FC010113E025 +257DA42C>II<161FD907FEEBFFC090387FFFE348B6EAEFE02607FE07138F260FF801131F48486C13 +8F003F15CF4990387FC7C0EEC000007F81A6003F5DA26D13FF001F5D6C6C4890C7FC3907 +FE07FE48B512F86D13E0261E07FEC8FC90CAFCA2123E123F7F6C7E90B512F8EDFF8016E0 +6C15F86C816C815A001F81393FC0000F48C8138048157F5A163FA36C157F6C16006D5C6C +6C495AD81FF0EB07FCD807FEEB3FF00001B612C06C6C91C7FC010713F02B377DA530>I< +EA01F0EA07FC487EA2487EA56C5AA26C5AEA01F0C8FCA913FF127FA412077EB3A9B512F8 +A4153B7DBA1B>105 D<13FFB5FCA412077EAF92380FFFE0A4923803FC0016F0ED0FE0ED +1F804BC7FC157E5DEC03F8EC07E04A5A141FEC7FE04A7E8181A2ECCFFEEC0FFF496C7F80 +6E7F6E7F82157F6F7E6F7E82150F82B5D8F83F13F8A42D3A7EB932>107 +D<13FFB5FCA412077EB3B3ACB512FCA4163A7DB91B>I<01FED97FE0EB0FFC00FF902601 +FFFC90383FFF80020701FF90B512E0DA1F81903983F03FF0DA3C00903887801F000749DA +CF007F00034914DE6D48D97FFC6D7E4A5CA24A5CA291C75BB3A3B5D8FC1FB50083B512F0 +A44C257DA451>I<01FEEB7FC000FF903803FFF8020F13FE91381F03FFDA3C0113800007 +13780003497E6D4814C05CA25CA291C7FCB3A3B5D8FC3F13FFA430257DA435>I<903801 +FFC0010F13F8017F13FFD9FF807F3A03FE003FE048486D7E48486D7E48486D7EA2003F81 +491303007F81A300FF1680A9007F1600A3003F5D6D1307001F5DA26C6C495A6C6C495A6C +6C495A6C6C6CB45A6C6CB5C7FC011F13FC010113C029257DA430>I<9038FE03F000FFEB +0FFEEC3FFF91387C7F809138F8FFC000075B6C6C5A5CA29138807F80ED3F00150C92C7FC +91C8FCB3A2B512FEA422257EA427>114 D<90383FF0383903FFFEF8000F13FF381FC00F +383F0003007E1301007C130012FC15787E7E6D130013FCEBFFE06C13FCECFF806C14C06C +14F06C14F81203C614FC131F9038007FFE140700F0130114007E157E7E157C6C14FC6C14 +F8EB80019038F007F090B512C000F8140038E01FF81F257DA426>I<130FA55BA45BA25B +5BA25A1207001FEBFFE0B6FCA3000390C7FCB21578A815F86CEB80F014816CEBC3E09038 +3FFFC06D1380903803FE001D357EB425>I118 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fh ecrm1000 10 89 +/Fh 89 126 df<486C1360000314E039070001C0000EEB038048EB070000181306003813 +0E0030130C0070131C00601318A200E01338481330A400CEEB338039FF803FE001C013F0 +A3007F131FA2393F800FE0390E0003801C1981B91C>16 D<001C1307007FEB1FC039FF80 +3FE0A201C013F0A3007F131F001CEB073000001300A400011470491360A2000314E090C7 +12C048130100061480000E130348EB070048130E485B006013181C1980B91C>I21 D27 +DI30 D36 D<141FEC7FC0903801F0 +E0903803C0600107137090380F803090381F00381518A25BA2133E133F15381530A21570 +5D5D140190381F838092CAFC1487148E02DC49B51280EB0FF85C4A9039003FF8000107ED +0FC06E5D71C7FC6E140E010F150CD91DFC141C01391518D970FE143801E015302601C07F +1470D803805D00076D6C5BD80F00EBC00148011F5C4890380FE003003E6E48C8FC007E90 +3807F8060203130E00FE6E5A6E6C5A1400ED7F706C4B13036F5A6F7E6C6C6D6C5B701306 +6C6C496C130E6DD979FE5B281FF001F07F133C3C07F80FE03FC0F86CB539800FFFF0C690 +26FE000313C0D91FF0D9007FC7FC393E7DBB41>38 D<121C127FEAFF80A213C0A3127F12 +1C1200A412011380A2120313005A1206120E5A5A5A12600A1979B917>I<146014E0EB01 +C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B120F90C7FCA25A121EA2123E +A35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A26C7EA26C7E1378A27F7F130E +7FEB0380EB01C0EB00E01460135278BD20>I<12C07E12707E7E7E120F6C7E6C7EA26C7E +6C7EA21378A2137C133C133E131EA2131F7FA21480A3EB07C0A6EB03E0B2EB07C0A6EB0F +80A31400A25B131EA2133E133C137C1378A25BA2485A485AA2485A48C7FC120E5A5A5A5A +5A13527CBD20>I<1530B3A8B912FCA2C80030C8FCB3A836367BAF41>43 +D<121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A1206120E5A5A5A +12600A19798817>II<121C127FEAFF80A5EA7F00121C09097988 +17>I<1506A2150E150CA2151C151815381530A215701560A215E015C0A214011580A214 +0315005C1406A2140E140CA2141C1418A214381430A21470146014E05CA213015CA21303 +91C7FCA25B1306A2130E130C131C1318A213381330A213701360A213E05BA212015B1203 +90C8FCA25A1206A2120E120CA2121C1218A21238123012701260A212E05AA21F537BBD2A +>II +III<1538A2157815F8A214011403 +1407A2140F141F141B14331473146314C313011483EB030313071306130C131C13181330 +1370136013C01201EA038013005A120E120C5A123812305A12E0B712F8A3C73803F800AA +4A7E0103B512F8A325387EB72A>I<0006140CD80780133C9038F003F890B5FC5D5D1580 +92C7FC14FC38067FE090C9FCAAEB07F8EB1FFE9038780F809038E007E03907C003F0496C +7E130000066D7E81C8FC8181A21680A4121C127F5A7FA390C713005D12FC00605C12704A +5A6C5C6C1303001E495A6C6C485A3907E03F800001B5C7FC38007FFCEB1FE021397CB62A +>II<12301238123E003FB612E0A316C05A168016 +000070C712060060140E5D5D00E014304814705D5DC712014A5A4AC7FC1406140E5CA25C +1478147014F05C1301A213035C1307A2130FA3131F5CA2133FA5137FA96DC8FC131E233A +7BB72A>III<121C127FEAFF80A5 +EA7F00121CC7FCB2121C127FEAFF80A5EA7F00121C092479A317>I<121C127FEAFF80A5 +EA7F00121CC7FCB2121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A +1206120E5A5A5A12600A3479A317>II<007FB812F8B912FCCCFCB0B912FC6C17F836147B9E41>I<12E01278121EEA07C0 +EA01F0EA003C130FEB03C0EB00F0143C140FEC03E0EC00F8151EED0780ED01E0ED007816 +1EEE07C0EE01F0EE003C170FEF03C0A2EF0F00173CEE01F0EE07C0041EC7FC1678ED01E0 +ED0780031EC8FC15F8EC03E0020FC9FC143C14F0EB03C0010FCAFC133CEA01F0EA07C000 +1ECBFC127812E0322E79AB41>II<1538A3157CA315FEA34A7EA34A6C7EA202077FEC063FA202 +0E7FEC0C1FA2021C7FEC180FA202387FEC3007A202707FEC6003A202C07F1501A2D90180 +7F81A249C77F167FA20106810107B6FCA24981010CC7121FA2496E7EA3496E7EA3496E7E +A213E0707E1201486C81D80FFC02071380B56C90B512FEA3373C7DBB3E>65 +DI<913A01FF800180020FEBE003027F13F8903A01FF807E07903A03 +FC000F0FD90FF0EB039F4948EB01DFD93F80EB00FF49C8127F01FE153F12014848151F48 +48150FA248481507A2485A1703123F5B007F1601A35B00FF93C7FCAD127F6DED0180A312 +3F7F001F160318006C7E5F6C7E17066C6C150E6C6C5D00001618017F15386D6C5CD91FE0 +5C6D6CEB03C0D903FCEB0F80902701FF803FC7FC9039007FFFFC020F13F002011380313D +7BBA3C>IIIIIII<013FB512 +E0A39039001FFC00EC07F8B3B3A3123FEA7F80EAFFC0A44A5A1380D87F005B0070131F6C +5C6C495A6C49C7FC380781FC3801FFF038007F80233B7DB82B>IIIIIIIII< +D90FF813C090383FFE0190B512813903F807E33907E000F74848137F4848133F48C7121F +003E140F007E1407A2007C140312FC1501A36C1400A37E6D14006C7E7F13F86CB47E6C13 +F8ECFF806C14E06C14F86C14FEC680013F1480010714C0EB007F020713E0EC007FED3FF0 +151F150FED07F8A200C01403A21501A37EA216F07E15036C15E06C14076C15C06C140F6D +EB1F80D8FBF0EB3F00D8F0FE13FE39E03FFFF8010F13E0D8C00190C7FC253D7CBA2E>I< +003FB812E0A3D9C003EB001F273E0001FE130348EE01F00078160000701770A300601730 +A400E01738481718A4C71600B3B0913807FF80011FB612E0A335397DB83C>IIII89 D<003FB7FCA39039FC0001FE +01C0130349495A003EC7FC003C4A5A5E0038141F00784A5A12704B5A5E006014FF4A90C7 +FCA24A5A5DC712074A5AA24A5A5D143F4A5AA24A5A92C8FC5B495AA2495A5C130F4948EB +0180A2495A5C137F495A16034890C7FC5B1203485AEE0700485A495C001F5D48485C5E48 +48495A49130FB8FCA329397BB833>II93 D<007FB81280B912C0A26C17 +803204797041>95 D97 DIIII<147E903803FF8090 +380FC1E0EB1F8790383F0FF0137EA213FCA23901F803C091C7FCADB512FCA3D801F8C7FC +B3AB487E387FFFF8A31C3B7FBA19>IIIIIII<2703F00FF0EB1FE000FFD93FFCEB +7FF8913AF03F01E07E903BF1C01F83803F3D0FF3800FC7001F802603F70013CE01FE14DC +49D907F8EB0FC0A2495CA3495CB3A3486C496CEB1FE0B500C1B50083B5FCA340257EA445 +>I<3903F00FF000FFEB3FFCECF03F9039F1C01F803A0FF3800FC03803F70013FE496D7E +A25BA35BB3A3486C497EB500C1B51280A329257EA42E>II<3903F01F +E000FFEB7FF89038F1E07E9039F3801F803A07F7000FC0D803FEEB07E049EB03F04914F8 +49130116FC150016FEA3167FAA16FEA3ED01FCA26DEB03F816F06D13076DEB0FE001F614 +C09039F7803F009038F1E07E9038F0FFF8EC1FC091C8FCAB487EB512C0A328357EA42E> +II<3807E01F00FFEB7FC09038E1E3E09038E387F0380FE707EA03E613EE9038EC03E0 +9038FC0080491300A45BB3A2487EB512F0A31C257EA421>II<1318A51338A31378A313F812011203 +1207001FB5FCB6FCA2D801F8C7FCB215C0A93800FC011580EB7C03017E13006D5AEB0FFE +EB01F81A347FB220>IIIIII<003FB512FCA2EB8003D83E0013F8003CEB07F00038 +EB0FE012300070EB1FC0EC3F800060137F150014FE495AA2C6485A495AA2495A495A495A +A290387F000613FEA2485A485A0007140E5B4848130C4848131CA24848133C48C7127C48 +EB03FC90B5FCA21F247EA325>II<126012F0B3B3B3 +B3A91260045377BD17>I<12FCEAFFC0EA07F0EA01FCEA007E7F80131F80130FB3A78013 +07806D7E6D7EEB007EEC1FF0EC07F8EC1FF0EC7E00495A495A495A5C130F5CB3A7131F5C +133F91C7FC137E485AEA07F0EAFFC000FCC8FC1D537ABD2A>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fi ecbx1440 14.4 34 +/Fi 34 118 df28 D45 D<151E153E15FE1403140F147FEB07FF00 +03B5FCB6FCA3EBF87FEAFC00C7FCB3B3B3A6007FB712FCA52E4E76CD42>49 +DI<913807FFC0027F13FC0103B67E010F15E090 +261FF80313F890267FC0007F01FEC7EA3FFE48488148486E138013FE486C6C6D13C08048 +17E080A66C5B18C06C5B6C90C75AD80038168090C8FC4C1300A24C5A5F4C5A4B5B4B13C0 +030F5BDB7FFEC7FC91387FFFF816C016FCEEFF80DA000313E09238007FF8EE3FFE707E70 +138018C07013E018F07013F8A218FC82A218FEA3EA03C0EA0FF0EA3FFC487EA2B5FCA218 +FCA25E18F8A26C4816F0495C4916E0D83FE04A13C06C485CD80FF04A1380D807FE91387F +FE003B03FFE003FFFC6C90B65A6C6C15E0010F92C7FC010114FCD9001F1380374F7BCD42 +>I<17FC1601A216031607160FA2161F163F167FA216FF5D5DA25D5D5D167F153E157E15 +FC15F8EC01F01403EC07E015C0EC0F80141FEC3F00143E5C14FC495A5C495A1307495A5C +49C7FC5B137E137C5B1201485A5B485A120F485A90C8FC123E127E5ABA1280A5C901FCC7 +FCAF021FB71280A5394F7CCE42>I<486C150601F0153E01FEEC01FED9FFF0133F91B65A +5F5F5F5F5F94C7FC16FC5E16E093C8FC15FC01F0138091CAFCAC913807FF80023F13F891 +B512FE01F36E7E9026FFFC0113E09139E0007FF891C76C7E496E7E01F86E7E5B70138049 +16C0C9FC18E08218F0A418F8A31203EA0FE0EA3FF8487EA212FF7FA218F0A25B5E6C4816 +E05B01C016C06CC85A18806C6C4A13007FD80FF04A5A6C6CECFFFCD803FE4913F02701FF +E00F5B6C6CB612806D92C7FC010F14F8010114C09026003FFCC8FC354F7ACD42>I58 +D<932603FFF01407047F01FF5C0307B600E05B033F03F85B92B700FE5B02039126C003FF +5B020F01F8C7EA3FC1023F01C0EC0FE391B5C80003B5FC4901FC814949814901E082011F +498249498292CA7E4948834948835A4A83485B4885A2484984A2485B87A2485B87A25AA2 +98C8FC91CFFCA2B5FCAE7E067FB7128080A37E95C76C90C7FC807EA36C7FA26C7FA26C7F +7E806C7F137F6D7E816D6D93B5FC01077F6D01F85D6D7F6D01FF5D023F01E0EC0FEF020F +01FCEC3FE30203903AFFE001FF81020091B6C6FC033F03FC133F030703F0130FDB007F02 +801303040301F8CAFC595479D267>71 D73 D76 +D78 D80 D<93381FFF800303B512FC033FECFFC0 +92B712F00207D9F80113FE021F903AC0003FFF804A48C700077FDAFFF8020113F049496E +7F49496F7E49496F7E49496F7E4990C96C7F4948707F4948707F01FF854849707F4A8248 +86A24849717E48864A83A2481B80A248497113C0A4481BE0A291CB7EA3B51AF0AF6C1BE0 +A36E5FA26C1BC0A36C1B806E5FA26C1B006E5F6C62A26C6DD903FC4A5A6CDB0FFF5D6E49 +EBC0016C4B01E05C6D6C90277E07F0035B6E9039F801F807902A3FFF01F000780F5B6D04 +7C5C6DD981E06D4890C7FC6D01E191381F7FFE010101F1EDFFF86DD9F9F06D5BDA3FFF16 +C06E6D013F5B02079027FE01FFFEC8FC020190B612F8DA003F4B141003071838DB001FEB +83F893C7EA03FC1C7885726C14F8F2C003F2F01F97B512F084A31CE085A27314C01C8085 +1C00735B735B735B735B9638003FC0556A79D263>III<003FBB12FCA59126C0007FEB000301FCC7ED003FD87FF0F00FFE491807 +49180349180190C81600A2007E1A7EA3007C1A3EA500FC1A3F481A1FA6C91700B3B3AC49 +B912C0A550517BD05B>I97 D<913803FFE0023F13FE91B67E010315E0010F9038003FF8D93FFCEB +07FC4948497E4948131F4849497E485B485BA24890C7FC5A5B003F6F5A705A705A007F92 +C8FC5BA312FFAD127F7FA3123F7F6CEE0F80A26C6D141F18006C6D5C6C6D143E6C6D147E +6C6D5C6D6C495A6DB4EB07F0010F9038C01FE06D90B5128001014AC7FCD9003F13F80203 +138031387CB63A>99 D<943803FF80040FB5FCA5EE003F170FB3A4913803FF80023F13F8 +49B512FE0107ECFF8F011F9038C03FEF90273FFE0007B5FCD97FF8130149487F48498048 +4980484980488291C8FC5A5B123FA2127F5BA312FFAD127FA37F123FA3121F7F6C5E6C6D +5C5F6C6D91B5FC6C6D5B6C6D4914E0D97FFCD90FEFEBFF80D91FFFEB7F8F010790B5120F +010114FC6D6C13E00207010049C7FC41547CD249>I<913807FF80027F13F849B512FE01 +076E7E011F010313E0903A3FFC007FF0D97FF06D7E49486D7E4849130F48496D7E488248 +90C77E1880485A82003F17C0A3485A18E082A212FFA290B8FCA401FCCAFCA6127FA37F12 +3FA2EF03E06C7E17076C17C06C6D140F18806C6D141F6C6DEC3F006C6D147ED97FFC495A +D91FFFEB07F86D9038E03FF0010390B512C001005D023F01FCC7FC020113E033387CB63C +>IIII<133FEBFFC0 +487F487FA2487FA66C5BA26C5B6C5B013FC7FC90C8FCAEEB1FF8B5FCA512017EB3B3A6B6 +12F0A51C547CD324>I108 +DII<913801FFC0023F13FE91B67E010315E001 +0F018013F8903A3FFC001FFED97FF0EB07FF49486D7F48496D7F48496D7F91C8127F4883 +488349153F001F83A2003F8349151FA2007F83A400FF1880AC007F1800A3003F5F6D153F +A2001F5FA26C6C4B5AA26C6D4A5A6C5F6C6D495B6C6D495B6D6C4990C7FCD93FFCEB1FFE +6DB46CB45A010790B512F0010115C0D9003F49C8FC020313E039387CB642>II<90393FF001FCB590 +380FFF804B13E0037F13F09238FE1FF89138F1F83F00019138F07FFC6CEBF3E015C0ECF7 +80A2ECFF00EE3FF84AEB1FF0EE0FE093C7FC5CA45CB3ABB612FEA52E367DB535>114 +D<903903FFC00E011FEBFC1E90B6127E000315FE3907FE003FD80FF0130F484813034848 +1301491300127F90C8127EA248153EA27FA27F01F091C7FC13FCEBFF806C13FEECFFF06C +14FE6F7E6C15E06C816C15FC6C81C681133F010F15801301D9000F14C0EC003F030713E0 +150100F880167F6C153FA2161F7EA217C07E6D143F17807F6DEC7F0001F85C6DEB03FE90 +39FF801FFC486CB512F0D8F81F14C0D8F00791C7FC39E0007FF02B387CB634>I<147CA6 +14FCA41301A31303A21307A2130F131F133F137F13FF1203000F90B512FEB7FCA426007F +FCC8FCB3A9EE0F80ABEE1F006D7EA2011F143E806D6D5A6DEBC1F86DEBFFF001005C023F +1380DA03FEC7FC294D7ECB33>II E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fj ecrm0900 9 5 +/Fj 5 109 df<123C127E12FFA4127E123C08087A8715>46 D97 DI104 +D108 +D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fk ecbx0900 9 7 +/Fk 7 117 df65 D97 DI<903807FF80013F13F090B512FC3903FE01FE4848487EEA0FF8EA1FF0EA3FE0 +A2007F6D5A496C5A153000FF91C7FCA9127F7FA2003FEC07807F6C6C130F000FEC1F00D8 +07FE133E3903FF80FCC6EBFFF8013F13E0010790C7FC21217DA027>I<3901F81F8000FF +EB7FF0ECFFF89038F9E3FC9038FBC7FE380FFF876C1307A213FEEC03FCEC01F8EC006049 +1300B1B512F0A41F217EA024>114 D<9038FFE1C0000713FF5A383F803F387E000F1407 +5A14037EA26C6CC7FC13FCEBFFE06C13FC806CEBFF80000F14C06C14E0C6FC010F13F0EB +007F140F00F0130714037EA26C14E06C13076CEB0FC09038C01F8090B5120000F913FC38 +E03FE01C217DA023>I<133CA5137CA313FCA21201A212031207001FB51280B6FCA3D807 +FCC7FCB0EC03C0A79038FE078012033901FF0F006C13FEEB3FFCEB0FF01A2F7EAE22>I +E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fl ecrm1200 12 25 +/Fl 25 122 df<121EEA7F8012FF13C0A213E0A3127FEA1E601200A413E013C0A3120113 +80120313005A1206120E5A5A5A12600B1D78891B>44 D<14FF010713E090381F81F89038 +3E007C01FC133F4848EB1F8049130F4848EB07C04848EB03E0A2000F15F0491301001F15 +F8A2003F15FCA390C8FC4815FEA54815FFB3A46C15FEA56D1301003F15FCA3001F15F8A2 +6C6CEB03F0A36C6CEB07E0000315C06D130F6C6CEB1F806C6CEB3F00013E137C90381F81 +F8903807FFE0010090C7FC28447CC131>48 D50 D54 D<16C04B7EA34B7EA34B7EA34B7EA3ED +19FEA3ED30FFA203707FED607FA203E07FEDC03FA2020180ED801FA2DA03007F160FA202 +06801607A24A6D7EA34A6D7EA34A6D7EA20270810260147FA202E08191B7FCA249820280 +C7121FA249C87F170FA20106821707A2496F7EA3496F7EA3496F7EA201788313F8486C83 +D80FFF03037FB500E0027FEBFFC0A342477DC649>65 DI68 D77 +D<003FB912F8A3903BF0001FF8001F01806D481303003EC7150048187C0078183CA20070 +181CA30060180CA5481806A5C81600B3B3A54B7EED7FFE49B77EA33F447DC346>84 +D +I97 +D99 D<167FED3FFFA315018182B3EC7F80903803 +FFF090380FC07C90383F000E017E1307496D5AD803F87F48487F5B000F81485AA2485AA2 +127FA290C8FC5AAB7E7FA2123FA26C7EA2000F5D7F6C6C5B00035C6C6C9038077F806C6C +010E13C0013F011C13FE90380FC0F8903803FFE09026007F0013002F467DC436>II103 D105 D108 D<3901FC01FE00FF903807FFC091381E +07F091383801F8000701707F0003EBE0002601FDC07F5C01FF147F91C7FCA25BA35BB3A8 +486CECFF80B5D8F83F13FEA32F2C7DAB36>110 DI<3903F803F000FFEB1FFCEC3C3EEC707F0007EBE0FF3803F9C000015B13FBEC00 +7E153C01FF13005BA45BB3A748B4FCB512FEA3202C7DAB26>114 +D<90383FE0183901FFFC383907E01F78390F0003F8001E1301481300007C1478127800F8 +1438A21518A27EA27E6C6C13006C7E13FC383FFFE06C13FC6C13FF6C14C06C14E0C614F0 +011F13F81300EC0FFC140300C0EB01FE1400157E7E153EA27EA36C143C6C147C15786C14 +F86CEB01F039F38003E039F1F00F8039E07FFE0038C00FF01F2E7DAC26>I<1306A5130E +A4131EA3133E137EA213FE12011207001FB512F0B6FCA2C648C7FCB3A4150CAA017E131C +017F1318A26D133890381F8030ECC070903807E0E0903801FFC09038007F001E3E7EBC26 +>III< +B539F001FFFCA3000790C7EA7FE06C48EC1F8000011600160E0000150C6D141C6D1418A2 +6E1338013F1430A26D6C5BA26E13E0010F5CA26D6C485AA2ECF803010391C7FCA2903801 +FC06A2ECFE0E0100130CA2EC7F18A215B8EC3FB0A2EC1FE0A36E5AA26E5AA36EC8FCA214 +06A35CA25CA2123C007E5BB4FC5CA25CEAFE01387C0380D87007C9FCEA3C1EEA0FFCEA03 +F02E3F7EAA33>121 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fm ecbx1200 12 47 +/Fm 47 123 df<0118140C017C143E01FC147E48485C4848495A495C4848495A4848495A +001F140F90C75B003E4AC7FCA2003C141E007C143E0078143CA200F8147CA2481478D8F1 +F014F8D8F7FCEB7BFEB46CEB7FFF6D1580028014C0A36C80A36C806C496C13806C486D13 +006C486D5AD801F0EB00F82A2283C427>16 DI28 D46 D48 DIII<163FA25E5E5D5DA25D5D5D5DA25D92B5FCEC01F7EC03E7140715 +C7EC0F87EC1F07143E147E147C14F8EB01F0EB03E0130714C0EB0F80EB1F00133E5BA25B +485A485A485A120F5B48C7FC123E5A12FCB91280A5C8000F90C7FCAC027FB61280A53141 +7DC038>I<0007150301E0143F01FFEB07FF91B6FC5E5E5E5E5E16804BC7FC5D15E092C8 +FC01C0C9FCAAEC3FF001C1B5FC01C714C001DF14F09039FFE03FFC9138000FFE01FC6D7E +01F06D13804915C0497F6C4815E0C8FC6F13F0A317F8A4EA0F80EA3FE0487E12FF7FA317 +F05B5D6C4815E05B007EC74813C0123E003F4A1380D81FC0491300D80FF0495AD807FEEB +FFFC6CB612F0C65D013F1480010F01FCC7FC010113C02D427BC038>I<4AB47E021F13F0 +027F13FC49B6FC01079038807F8090390FFC001FD93FF014C04948137F4948EBFFE04849 +5A5A1400485A120FA248486D13C0EE7F80EE1E00003F92C7FCA25B127FA2EC07FC91381F +FF8000FF017F13E091B512F89039F9F01FFC9039FBC007FE9039FF8003FF17804A6C13C0 +5B6F13E0A24915F0A317F85BA4127FA5123FA217F07F121FA2000F4A13E0A26C6C15C06D +4913806C018014006C6D485A6C9038E01FFC6DB55A011F5C010714C0010191C7FC903800 +3FF02D427BC038>I<121E121F13FC90B712FEA45A17FC17F817F017E017C0A248168000 +7EC8EA3F00007C157E5E00785D15014B5A00F84A5A484A5A5E151FC848C7FC157E5DA24A +5A14035D14074A5AA2141F5D143FA2147F5D14FFA25BA35B92C8FCA35BA55BAA6D5A6D5A +6D5A2F447AC238>I58 D<1A60F101F01907191FF17FC0953801FF00F007FCF01FF0F07FC04D48C7FCEF07 +FCEF3FF0EFFFC0040390C8FCEE0FFCEE3FE0EEFF80DB03FEC9FCED0FF8ED3FE0EDFF80DA +07FECAFCEC1FF8EC7FE0903801FF80D907FCCBFCEB1FF0EB7FC04848CCFCEA07FCEA1FF0 +EA7FC048CDFCA2EA7FC0EA1FF0EA07FCEA01FF38007FC0EB1FF0EB07FC903801FF809038 +007FE0EC1FF8EC07FE913800FF80ED3FE0ED0FF8ED03FE923800FF80EE3FE0EE0FFCEE03 +FF040013C0EF3FF0EF07FCEF01FF9438007FC0F01FF0F007FCF001FF9538007FC0F11FF0 +19071901F10060444277B957>60 D<126012F812FE6C7EEA3FE0EA0FF8EA03FEC66C7EEB +3FE0EB0FF8EB03FE903800FFC0EC3FF0EC0FFCEC03FF9138007FC0ED1FF0ED07FCED01FF +9238007FC0EE1FF0EE07FE933801FF809338007FE0EF1FF8EF03FE943800FF80F03FE0F0 +0FF8F003FE953800FF80F13FE0F10FF0A2F13FE0F1FF80953803FE00F00FF8F03FE0F0FF +80DD03FEC7FCEF1FF8EF7FE0933801FF80DC07FEC8FCEE1FF0EE7FC04B48C9FCED07FCED +1FF0ED7FC0DA03FFCAFCEC0FFCEC3FF0ECFFC0D903FECBFCEB0FF8EB3FE0EBFF80D803FE +CCFCEA0FF8EA3FE0EAFF8048CDFC12F81260444277B957>62 D<923803FFF0037FEBFF80 +0203B612F0020F15FC913A3FFC000FFFDAFFC0010013C0D903FEC8EA1FF0D907F0ED03F8 +D91FC0ED00FE4948167F017ECAEA1F8049717E4848717E49DAFF8013034848010F01F06D +7E4848013F01FC6D7E92B6FC4848489026C07F80137C49489026001FC0133C484948D907 +E0133E001E49486D6C131E003E49480101141F023F913800FFE0003C4A82007C017F1880 +007819074A5AA300F81AC04848491603AB6C6C7F12781B801A076E7E127C003C133F003E +6E1700021F4A5C001E6D6C5B001F6D6C49EBF01E6C6D6C011F143E6D6CD9C07F6D5A6C6C +6C90B5383FFFF8033FD9FC0F5B6C6C010FD9F0035B6C6C0100903980007F806D91CBFC6C +7E137E6D7E6D6CEF7FC0D907F0EE03FFD903FE043F1300902600FFC0913803FFF8DA3FFC +49B512C0020FB748C7FC020316E0DA007F02FCC8FC030349C9FC4A477AC557>64 +DIIII73 D77 D<923807FFC092B512FE0207ECFFC0021F15F0 +91267FFE0013FC902601FFF0EB1FFF01070180010313C04990C76C7FD91FFC6E6C7E4948 +6F7E49486F7E01FF8348496F7E48496F1380A248496F13C0A24890C96C13E0A24819F049 +82003F19F8A3007F19FC49177FA400FF19FEAD007F19FC6D17FFA3003F19F8A26D5E6C19 +F0A26E5D6C19E0A26C6D4B13C06C19806E5D6C6D4B13006C6D4B5A6D6C4B5A6D6C4B5A6D +6C4A5B6D01C001075B6D01F0011F5B010101FE90B5C7FC6D90B65A023F15F8020715C002 +004AC8FC030713C047467AC454>79 D83 D<007FBA12E0BB12F0A46C19E04406776757>95 D<903801FFE0011F13FE017F6D +7E48B612E03A03FE007FF84848EB1FFC6D6D7E486C6D7EA26F7FA36F7F6C5A6C5AEA00F0 +90C7FCA40203B5FC91B6FC1307013F13F19038FFFC01000313E0481380381FFE00485A5B +127F5B12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEBFFC03A1FFF80FC7F0007EBFFF8 +6CECE01FC66CEB8007D90FFCC9FC322F7DAD36>97 DIIIIIII<137C48B4FC4813804813C0A24813E0A56C13 +C0A26C13806C1300EA007C90C7FCAAEB7FC0EA7FFFA512037EB3AFB6FCA518467CC520> +I108 D<90277F8007FEEC0FFC +B590263FFFC090387FFF8092B5D8F001B512E002816E4880913D87F01FFC0FE03FF8913D +8FC00FFE1F801FFC0003D99F009026FF3E007F6C019E6D013C130F02BC5D02F86D496D7E +A24A5D4A5DA34A5DB3A7B60081B60003B512FEA5572D7CAC5E>I<90397F8007FEB59038 +3FFF8092B512E0028114F8913987F03FFC91388F801F000390399F000FFE6C139E14BC02 +F86D7E5CA25CA35CB3A7B60083B512FEA5372D7CAC3E>II<90397FC00FF8B590B57E02C314E002CF14F89139DFC03F +FC9139FF001FFE000301FCEB07FF6C496D13804A15C04A6D13E05C7013F0A2EF7FF8A4EF +3FFCACEF7FF8A318F017FFA24C13E06E15C06E5B6E4913806E4913006E495A9139DFC07F +FC02CFB512F002C314C002C091C7FCED1FF092C9FCADB67EA536407DAC3E>II<90387F807FB53881FFE002 +8313F0028F13F8ED8FFC91389F1FFE000313BE6C13BC14F8A214F0ED0FFC9138E007F8ED +01E092C7FCA35CB3A5B612E0A5272D7DAC2E>I<90391FFC038090B51287000314FF120F +381FF003383FC00049133F48C7121F127E00FE140FA215077EA27F01E090C7FC13FE387F +FFF014FF6C14C015F06C14FC6C800003806C15806C7E010F14C0EB003F020313E0140000 +F0143FA26C141F150FA27EA26C15C06C141FA26DEB3F8001E0EB7F009038F803FE90B55A +00FC5CD8F03F13E026E007FEC7FC232F7CAD2C>II< +D97FC049B4FCB50103B5FCA50003EC000F6C81B3A85EA25EA25E7E6E491380017FD901F7 +13FE9138F807E76DB512C7010F1407010313FE9026007FF0EBFC00372E7CAC3E>I +I120 +D<001FB71280A49026FC001F130001E0495A5B49495A90C7485A48495B123E4A5B4A5B00 +3C495BA24A90C7FC4A5A4A5AC7FC4A5A495B495BA2495B499038800780491300A2495A49 +48130F49481400A2485B48495B485BA248495B4890C75A48485C15034848EB1FFEB7FCA4 +292C7DAB32>122 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fn ecrm1728 17.28 8 +/Fn 8 117 df68 D70 D97 D102 D<1378EA01FE487E487FA66C +90C7FC6C5AEA007890C8FCB3A2EB0780EA0FFFB5FCA41203C6FCA2137FB3B3AC497E487F +B61280A4195F7BDE25>105 D<010FEB07F8D80FFFEB1FFEB590387FFF809238F81FC091 +3801E03F913903C07FE00003EB0780C6EB0F00140E6D5A0218EB3FC00238EB1F800230EB +0600027090C7FCA2146014E0A25CA55CB3B0497E4813F0B612F8A42B3F7BBE34>114 +D<9138FFC003010FEBF807017FEBFE0F3A01FF003F9FD803F0EB07DF48486DB4FCD80F80 +1300001F8148C8FC003E81007E81127C00FC81A4827EA27E7F6C7E6D91C7FC13F8EA3FFE +381FFFE06C13FF15F0000314FE6C6E7E6C6C14E0011F14F801078001008002077FDA003F +13801507030113C0ED007F00E0ED3FE0161F17F06C150F1607A36C1503A37EA26C16E016 +077E17C06D140F6D15806D141FD8FDF0EC3F00D8F8F8147E017C495A3AF01F801FF06DB5 +12C0D8E00391C7FC39C0007FF02C417CBF35>I<1470A714F0A51301A31303A21307A213 +0FA2131F133F137F13FF1203000F90B6FCB8FCA326000FF0C8FCB3AEEE01C0AE6D6CEB03 +80A316076D6C14005E6D6C130E6D6C131E6E6C5A91383FE0F86EB45A020713C0020090C7 +FC2A597ED734>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fo ecbx1728 17.28 18 +/Fo 18 117 df68 D<942603FFF8151C94B66C +143C040F03F0147C047F03FC14FC0303B81301030FDAC00113C0033F01F8C7381FF00392 +B500C0913807F807020349C83801FE0F020F01F89238007F1F4A01E0EE3FBF4A49EE0FFF +91B5CA7E494983494983494983495B4949187F4B183F491A1F495B90B5CC120FA2484919 +075A4A19035A4A19015AA24A19005AA348491A7CA35A9AC8FCA35CA2B5FCB07EA26E043F +B81280A47E96C7000701FCC7FCA26C7FA37E80A27E807E807E6C7FA26D7F6D7F7F816D7F +6D6D5F6D7F6D6D5F6D6D7E023F6D5E6E01F05E6E6DEEFE7F020301FF923801FC3F020002 +C0913807F80F033F01FC91381FF007030F903BFFE001FFC001030391B6EA8000DB007F4B +C7123C040F03F8140C040003C091C8FC050301F8CBFC696677E37A>71 +D82 D<001FBD12F0A59126F8000191C7123F4801C0 +060713F849C71700491A7F01F01A1F491A0F491A07A2491A03A290C81801A2007EF300FC +A4007C1C7CA7481C3EA5C91900B3B3B3A5023FB912F8A55F617AE06C>84 +D<913803FFF0027F13FF0103B612E0010F15F890263FFC0013FED97FC090381FFF8049C7 +6C7F4801C06D7F486D6D7F6E6D7F48836E7F84177F84A36C496E7FA26C5B6C5B013FC8FC +90C9FCA75F0307B6FC4AB7FC141F91B5EAF03F0103EBFE00010F13F0013F1380D9FFFEC7 +FC485B485B485B485B485B485BA24890C8FC1A7CA2485AA35FA394B5FC7F6C5D6EEB03DF +6CDB07CFEBC0F86C6DEB0F8F6C6DD91F07EBF3F06C01F8017E14FF6C9027FE01FC0314E0 +C690B5D8F00114C0013F9126C0007F1380010791C7383FFE009026003FF8EC07F846437B +C14D>97 D<903807FF80B6FCA5C6FC7F7FB3A9933801FFE0041F13FE047FEBFFC00381B6 +12F0922687FC0113FC923A9FE0003FFEDBBF8090380FFF8003FEC76C7F4B6E7F4B6E7F4B +6E7F4B824B157F4B82737EA21B80851BC0A31BE085A41BF0AE1BE0A44F13C0A31B80A24F +1300A262197F6F5E6F4B5A4E5B6F4A5BDAFCF84A5BDAF87E4A5B4A6C4A90C7FC9126E01F +C0EB7FFC913BC00FF803FFF8DA8003B612E091C71580013E023F01FCC8FC90C800031380 +4C657CE356>II101 DII105 D<903807FF80B6FCA5C6FC7F7FB3B3B3B3AFB7 +12E0A523647CE32A>108 D110 D<92381FFF804AB512F8020F +14FF023F15C09126FFFC0313F001039039E0007FFC490180EB1FFED91FFEC73807FF8049 +486E7F49486E7F49486E7F48496F7EA248496F7E4884A248496F7EA2481980A24819C091 +C97EA24819E0A5B518F0AD6C19E0A46C6D4B13C0A36C1980A26C6D4B1300A26C606E157F +6C606C6D4B5A6C606D6C4A5B6D6C4A5B6D6C4A5B6D6C6C011F90C7FC010301E0EB7FFC6D +9039FC03FFF86D6CB612E0020F92C8FC020114F8DA001F138044437CC14D>I<903B07FF +8001FFE0B6011F13FE047FEBFFC00381B612F0922687FC0313FC923A9FE0007FFEC6DABF +806D6C7E6D01FEC7000F7F6D496E7F4B824B6E7F4B6E7F4B804B82737EA21B80851BC0A2 +851BE0A4851BF0AE4F13E0A41BC061A21B80A24F1300A24F5AA26F4A5B6F4A5B626F4A5B +6F4A5B03FE4A5B03BF027F90C7FCDB9FC0EBFFFC92268FF8075B0383B612E00380158004 +3F01FCC8FC0403138093CBFCB3A4B712E0A54C5D7CC056>I114 DII E +%EndDVIPSBitmapFont +end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 600dpi +TeXDict begin +%%PaperSize: A4 + +%%EndSetup +%%Page: 1 1 +1 0 bop 290 639 a Fo(Genealogical)56 b(Represen)l(tation)e(of)f(T)-13 +b(rees)52 b(in)g(Databases)1686 822 y Fn(First)46 b(Draft)1247 +1063 y Fm(Miguel)36 b(Sofer)i()1359 1179 +y Fl(Univ)m(ersidad)33 b(T)-8 b(orcuato)33 b(Di)f(T)-8 +b(ella)1728 1295 y(Buenos)33 b(Aires)1797 1411 y(Argen)m(tina)1746 +1606 y(Ma)m(y)h(6,)e(2000)1839 1905 y Fk(Abstract)441 +2035 y Fj(blah)25 b(blah)h(.)13 b(.)g(.)118 2310 y Fi(1)131 +b(In)l(tro)t(duction)118 2491 y Fh(T)-7 b(rees)28 b(are)h(a)g(v)n(ery)f +(frequen)n(t)h(data)f(structure.)41 b(They)30 b(are)e(the)h(natural)g +(represen)n(tation)e(for)i(instance)g(for)f(organiza-)118 +2591 y(tional)f(c)n(harts,)g(threaded)g(discussion)g(groups,)f(some)h +(bills)g(of)h(materials,)e(.)14 b(.)g(.)243 2691 y(A)n(t)28 +b(least)f(t)n(w)n(o)f(alternativ)n(e)h(represen)n(tations)e(for)i +(trees)g(in)h(RDBMs)g(are)e(kno)n(wn)h(and)h(used:)220 +2857 y(1.)41 b Fg(P)m(oin)m(ters:)k Fh(a)31 b(\034eld)h(in)h(the)f(c)n +(hild)g(record)e(references)h(the)h(paren)n(t)f(no)r(de.)50 +b(This)32 b(seems)g(to)f(b)r(e)i(the)f(canonical)326 +2956 y(represen)n(tation.)38 b(Some)29 b(DB)g(engines)f(pro)n(vide)g +(sp)r(ecial)g(SQL)g(extensions)g(to)h(simplify)g(tree)g(searc)n(hes;)e +(Oracle)326 3056 y(tree)d(extensions)g(are)g(an)h(example)f(\(see)h +(for)f(instance)g([1]\);)i(DB2's)f(WITH)g(can)f(b)r(e)i(used)e(for)h +(this)g(purp)r(ose)f(to)r(o)326 3156 y(\(see)j([3],)g(pp)h(139-162\).) +220 3322 y(2.)41 b Fg(Nested)35 b(Sets:)43 b Fh(t)n(w)n(o)30 +b(n)n(umeric)h(\034elds)g(in)g(ev)n(ery)f(no)r(de)h(record)f(co)r(de)h +(the)g(tree)g(structure.)47 b(I)31 b(can't)g(pro)n(vide)f(a)326 +3421 y(b)r(etter)e(or)e(briefer)h(description)g(of)h(this)g(metho)r(d)g +(than)f(the)h(four)f(articles)g([2].)118 3587 y(These)g(t)n(w)n(o)g +(metho)r(ds)h(o\033er)f(di\033eren)n(t)h(adv)-5 b(an)n(tages)25 +b(and)j(disadv)-5 b(an)n(tages:)243 3753 y Ff(\017)41 +b Fh(P)n(oin)n(ters)30 b(are)g(extremely)g(e\036cien)n(t)h(for)f(no)r +(de)h(insertion)f(and/or)g(deletion,)h(but)h(require)e(recursiv)n(e)f +(table)i(ac-)326 3853 y(cesses)e(to)h(searc)n(h)f(the)h(tree)g(\(I)h +(do)f(not)g(kno)n(w)f(the)i(implemen)n(tation)f(details)g(of)g(the)h +(Oracle)e(tree)g(extensions,)326 3953 y(whic)n(h)e(as)g(far)g(as)g(I)g +(kno)n(w)g(ma)n(y)g(solv)n(e)f(this)i(problem)f(in)n(ternally;)g(they)g +(de\034nitely)h(solv)n(e)f(it)g(for)g(the)h(end)g(user\).)243 +4119 y Ff(\017)41 b Fh(Nested)30 b(sets)g(are)f(v)n(ery)f(e\036cien)n +(t)i(for)g(tree)f(searc)n(hes,)g(but)i(are)e(rather)f(exp)r(ensiv)n(e)i +(for)f(no)r(de)h(insertion)f(and/or)326 4218 y(deletion:)37 +b(they)27 b(require)g(up)r(dating)g(p)r(oten)n(tially)h(man)n(y)f(no)r +(des.)243 4384 y(W)-7 b(e)30 b(prop)r(ose)f(here)h(a)g(di\033eren)n(t)h +(represen)n(tation,)e(based)g(on)i(no)r(de)f(iden)n(ti\034ers)g(whic)n +(h)g(are)f(\020genealogical)f(iden)n(ti-)118 4484 y(\034ers\021:)44 +b(they)32 b(con)n(tain)f(the)h(complete)f(genealogy)f(of)h(the)h(no)r +(de,)h(i.e.,)g(the)f(list)g(of)g(ancestors)d(up)j(to)g(the)g(ro)r(ot)f +(of)g(the)118 4584 y(tree.)243 4683 y(This)j(allo)n(ws)f(to)i(replace)e +(man)n(y)h(searc)n(hes)f(in)h(database)g(tables)g(with)h(string)f(op)r +(erations)f(on)h(the)h(index.)58 b(The)118 4783 y(result,)24 +b(as)f(explained)h(in)g(Section)g(3)f(is)h(that)g(tree)f(searc)n(hes)f +(pro)r(ceed)h(at)h(\020nested)f(sets\021)30 b(sp)r(eed,)25 +b(while)f(no)r(de)g(insertions)118 4882 y(and)k(deletions)f(are)f(as)h +(fast)h(as)f(with)h(p)r(oin)n(ters.)243 4982 y(The)i(ob)n(vious)f(do)n +(wnside)h(of)h(the)g(metho)r(d)g(is)f(that)h(the)g(primary)f(k)n(ey)f +(in)i(the)g(tree)f(needs)h(to)f(b)r(e)h(a)g(v)-5 b(ariable)29 +b(size)118 5082 y(text)j(\034eld,)h(and)f(that)g(the)g(iden)n +(ti\034ers)f(ma)n(y)g(b)r(e)i(extremelly)e(long)g(for)g(deep)h(trees.) +49 b(W)-7 b(e)32 b(will)g(pro)n(vide)e(estimates)i(of)118 +5181 y(the)c(size)f(required)g(as)g(a)g(function)h(of)g(the)f +(magnitude)h(of)f(the)h(tree.)1987 5653 y(1)p eop +%%Page: 2 2 +2 1 bop 118 291 a Fi(2)131 b(Genealogical)45 b(iden)l(ti\034ers)g(for)f +(trees)118 489 y Fm(2.1)112 b(De\034nition)118 642 y +Fh(W)-7 b(e)28 b(de\034ne)g Fe(gene)l(alo)l(gic)l(al)k(identi\034ers)j +Fh(recursiv)n(ely)25 b(as)i(follo)n(ws:)326 808 y Fg(De\034nition:)59 +b Fe(The)42 b(gene)l(alo)l(gic)l(al)h(identi\034er)f(\(gID\))e(of)i(a)f +(no)l(de)h(is)f(obtaine)l(d)h(by)g(app)l(ending)g(a)f(child)326 +908 y(identi\034er)30 b(to)g(the)g(gene)l(alo)l(gic)l(al)h +(identi\034er)g(of)f(the)g(p)l(ar)l(ent)f(no)l(de.)243 +1074 y Fh(Remark)40 b(that)h(genealogical)e(iden)n(ti\034ers)i(are)f +(rather)g(w)n(ell)h(kno)n(wn)f(and)h(used;)48 b(common)41 +b(examples)f(are)g(the)118 1174 y(\020path+\034le-name\021)33 +b(in)28 b(a)f(computer)g(\034le)h(system)f(and)h(the)f(URLs)h(within)g +(a)f(WWW.)243 1273 y(The)d(name)g(\020genealogical)e(iden)n +(ti\034er\021)30 b(is)24 b(suggested)g(b)n(y)g(the)g(fact)h(that)f(the) +h(v)-5 b(alue)24 b(of)g(the)h(iden)n(ti\034er)f(con)n(tains)f(the)118 +1373 y(complete)30 b(genealogy)d(of)j(the)g(no)r(de:)41 +b(it)30 b(con)n(tains)e(as)h(a)h(substring)f(the)h(gID)f(of)h(its)g +(father,)g(whic)n(h)f(in)h(turn)g(con)n(tains)118 1472 +y(as)d(a)g(substring)g(the)h(gID)g(of)f(the)h(grandfather,)e(.)14 +b(.)g(.)243 1572 y(The)27 b(ro)r(ot)g(no)r(de)h(of)f(the)h(tree)f(has)g +(a)h(gID)f(with)h(v)-5 b(alue)28 b(\021)34 b(\(the)28 +b(empt)n(y)g(string\),)f(as)g(it)h(has)f(no)g(paren)n(t.)118 +1804 y Fm(2.2)112 b(Child)36 b(iden)m(ti\034ers)118 1958 +y Fh(The)26 b(ob)n(vious)e(c)n(hild)i(iden)n(ti\034er)g(is)f(a)h +(zero-based)d(coun)n(ter:)35 b(iden)n(tify)26 b(the)h(c)n(hild)e(b)n(y) +h(the)g(n)n(um)n(b)r(er)f(of)h(older)f(brethren)g(it)118 +2057 y(has.)243 2157 y(W)-7 b(e)25 b(could)f(represen)n(t)g(the)h(coun) +n(ter)f(in)h(base)f(10;)h(this)g(ho)n(w)n(ev)n(er)e(is)i(extremely)f(w) +n(asteful)g(of)h(resources.)34 b(It)25 b(is)g(m)n(uc)n(h)118 +2257 y(b)r(etter)33 b(to)f(represen)n(t)f(the)h(coun)n(ter)g(in)g(as)g +(large)e(a)i(base)g(as)f(p)r(ossible:)46 b(in)n(terpret)32 +b(as)f(n)n(um)n(b)r(ers)h(a)g(set)g(of)g(c)n(haracters)118 +2356 y(larger)26 b(than)h({0,1,.)14 b(.)g(.)g(9}.)243 +2456 y(As)26 b(tree)f(op)r(erations)f(will)i(in)n(v)n(olv)n(e)f(string) +g(op)r(erations)f(on)i(the)g(indices,)g(in)g(order)f(to)g(a)n(v)n(oid)g +(a)g(\020quoting)g(hell\021)33 b(it)26 b(is)118 2555 +y(desirable)d(to)h(a)n(v)n(oid)e(using)h(an)n(y)g(c)n(haracter)f(with)i +(a)g(sp)r(ecial)f(meaning)h(in)g(LIKE)g(expressions)e(or)g(regular)g +(expressions;)118 2655 y(i.e.,)28 b(w)n(e)f(will)h(not)f(use)h(an)n(y)f +(of)g(the)h(sym)n(b)r(ols)70 b Fd(.)44 b(*)f(^)g(\\)g([)g(])g({)h(})f +(\()g(\))g(<)g(>)71 b Fh(?)37 b(|)28 b(&)f($)243 2755 +y(W)-7 b(e)28 b(prop)r(ose)e(to)h(reserv)n(e)f(also)g(/)i(as)f(a)g +(separator)e(\(see)i(\020V)-7 b(ariable)27 b(Sized)g(gID\021)34 +b(b)r(elo)n(w\).)243 2854 y(If)g(w)n(e)f(limit)i(ourselv)n(es)d(to)i +(ascii)f(c)n(haracters,)g(and)h(a)n(v)n(oid)e(to)i(b)r(e)g(safe)f(a)h +(lot)g(of)g(other)f(c)n(haracters,)g(w)n(e)g(can)h(use)118 +2954 y(n)n(um)n(b)r(ers)27 b(in)h(base)f(64)g(b)n(y)g(represen)n(ting) +243 3120 y Ff(\017)41 b Fh(0-9)26 b(with)i('0'-'9')f(\(dec)g(ascii)g +(co)r(de)h(48-57\))243 3286 y Ff(\017)41 b Fh(10)26 b(with)i(':')37 +b(\(dec)28 b(ascii)f(co)r(de)h(58\))243 3452 y Ff(\017)41 +b Fh(11)26 b(with)i(';')g(\(dec)g(ascii)f(co)r(de)g(59\))243 +3618 y Ff(\017)41 b Fh(12-37)25 b(with)j('A'-'Z')g(\(dec)f(ascii)g(co)r +(de)h(65-90\))243 3784 y Ff(\017)41 b Fh(38-63)25 b(with)j('a'-'z')f +(\(dec)h(ascii)f(co)r(de)g(97-122\))118 3950 y(By)g(using)g(base)f(64,) +h(up)g(to)h(4096)d(c)n(hildren)i(can)f(b)r(e)i(represen)n(ted)e(using)h +(t)n(w)n(o)f(suc)n(h)h(digits,)g(up)h(to)f(262144)d(with)k(three)118 +4050 y(digits,)g(and)f(up)h(to)f(16777216)d(with)k(four)f(digits.)243 +4149 y(If)37 b(the)g(RDBMs)g(supp)r(orts)f(in)n(ternational)g(c)n +(haracters,)h(it)g(is)g(p)r(ossible)f(to)h(further)f(increase)g(the)h +(base;)k(as)36 b(an)118 4249 y(example,)30 b(b)n(y)f(using)g(the)h(95)f +(additional)g(c)n(haracters)e(of)i(the)h(latin-1)f(c)n(haracter)e(set,) +k(w)n(e)e(could)g(co)r(de)g(n)n(um)n(b)r(ers)g(in)h(a)118 +4349 y(base)f(up)g(to)g(160)f(\025)g(remark)g(that)h(ev)n(ery)f(single) +h(digit)g(is)g(still)h(one)e(b)n(yte)h(in)h(this)f(represen)n(tation.) +40 b(This)29 b(means)f(that)118 4448 y(w)n(e)f(expand)h(the)f(sym)n(b)r +(ols)g(ab)r(o)n(v)n(e)f(b)n(y)i(represen)n(ting)243 4614 +y Ff(\017)41 b Fh(64-159)25 b(with)j(dec)f(latin1)g(co)r(de)h(160-255) +243 4780 y(In)23 b(base)g(160,)g(up)g(to)h(25600)d(c)n(hildren)i(can)f +(b)r(e)i(represen)n(ted)e(using)h(t)n(w)n(o)g(digits,)h(up)g(to)f +(4096000)d(with)k(three)f(digits,)118 4880 y(and)28 b(up)f(to)h +(6.5E+08)e(with)i(four)f(digits.)243 4980 y(Remark)g(that)h(base)f(con) +n(v)n(ersions)f(only)h(need)i(to)e(b)r(e)i(p)r(erformed)e(at)h +(insertion)g(time,)g(when)h(the)f(index)g(of)g(a)g(new)118 +5079 y(no)r(de)g(is)f(computed.)37 b(They)28 b(will)f(therefore)g(only) +g(ha)n(v)n(e)f(an)i(impact)f(on)h(insertion)f(timings.)1987 +5653 y(2)p eop +%%Page: 3 3 +3 2 bop 118 291 a Fm(2.3)112 b(Coun)m(ters:)50 b(\020delimited\021)44 +b(vs.)51 b(\020\034xed)38 b(size\021)118 444 y Fh(The)33 +b(standard)g(represen)n(tation)e(of)i(gID)h(uses)e(a)h(v)-5 +b(ariable)32 b(size)h(c)n(hild)h(iden)n(ti\034er,)g(and)f(delimiters)g +(to)h(separate)d(the)118 543 y(gID)f(of)g(the)h(c)n(hild)f(no)r(de)g +(from)f(the)i(gID)f(of)g(its)g(paren)n(t.)43 b(F)-7 b(or)30 +b(example,)g(w)n(e)g(can)f(represen)n(t)g(the)i(\034fth)g(c)n(hild)f +(of)g(no)r(de)118 643 y('/23/27/1')24 b(as)j('/23/27/1/4'.)32 +b(Let)c(us)f(call)g(this)h(a)f Fg(vgID)h Fh(represen)n(tation)e(\(V)-7 +b(ariable)27 b(Size)h(Genealogical)d(ID\).)243 743 y(This)30 +b(represen)n(tation)f(allo)n(ws)f(for)i(an)n(y)g(n)n(um)n(b)r(er)g(of)g +(c)n(hildren)g(of)h(a)f(no)r(de,)h(sub)5 b(ject)30 b(only)g(to)g(the)h +(limitations)f(the)118 842 y(RDBMS)e(ma)n(y)f(ha)n(v)n(e)f(as)h(to)h +(the)g(length)f(of)h(a)f(v)-5 b(ariable)27 b(sized)g(string.)243 +942 y(Alternativ)n(ely)-7 b(,)24 b(w)n(e)f(could)h(c)n(ho)r(ose)f(to)h +(limit)g(from)g(the)g(outset)g(the)g(quan)n(tit)n(y)g(of)f(c)n(hildren) +h(that)g(a)g(no)r(de)g(ma)n(y)f(ha)n(v)n(e;)118 1042 +y(this)28 b(limit)g(w)n(ould)f(dep)r(end)i(of)e(course)f(on)i(the)g +(application.)36 b(Let)27 b(us)h(call)f(this)h(a)f Fg(fgID)h +Fh(represen)n(tation.)243 1141 y(F)-7 b(or)25 b(example,)h(if)g(no)g +(no)r(de)f(is)h(allo)n(w)n(ed)f(to)g(ha)n(v)n(e)g(more)g(than)h(25600)d +(c)n(hildren,)j(w)n(e)g(could)f(represen)n(t)g(the)h(coun)n(ters)118 +1241 y(alw)n(a)n(ys)36 b(with)i(2)f(digits.)67 b(The)38 +b(no)r(de)f(whic)n(h)h(w)n(as)f(previously)f('/23/27/1/4')d(is)k(no)n +(w)g('23270104'.)64 b(If)38 b(w)n(e)f(require)118 1340 +y(a)g(three)g(digit)h(represen)n(tation)d(of)i(no)r(des)g(\(up)h(to)f +(ab)r(out)h(4)f(million)g(c)n(hildren\),)j(then)d(it)h(will)g(b)r(e)f +(represen)n(ted)f(as)118 1440 y('023027001004'.)118 1672 +y Fm(2.4)112 b(Ordering)37 b(of)h(no)s(des)118 1825 y +Fh(F)-7 b(or)35 b(some)g(applications)g(it)h(is)f(necessary)f(to)i +(obtain)f(subtrees)g(ordered)f(according)g(to)i(some)f(sp)r(ecial)g +(rules.)60 b(F)-7 b(or)118 1925 y(instance:)220 2090 +y(1.)41 b(the)34 b(complete)g(subtree)f(starting)g(at)h(a)f(no)r(de)h +(is)g(listed)g(immediately)g(after)f(the)i(no)r(de)f(in)g(question)f +(\(\020depth)326 2189 y(\034rst\021\))220 2354 y(2.)41 +b(no)r(des)27 b(with)h(a)f(common)g(paren)n(t)g(are)g(listed)g(c)n +(hronologically)243 2519 y(F)-7 b(or)39 b(instance,)k(the)d(displa)n(y) +f(of)h(an)f(organization)f(c)n(hart)h(is)g(usually)h(required)e(to)i +(satisfy)g(at)f(least)h(the)g(\034rst)118 2619 y(condition.)h(In)29 +b(a)g(threaded)f(discussion)h(group)e(one)i(wishes)g(to)f(satisfy)h(b)r +(oth)h(conditions)e(to)h(displa)n(y)f(the)h(messages)118 +2718 y(in)20 b(a)g(thread)g(\025)f(the)i(threads)e(themselv)n(es)h +(\(i.e.,)i(c)n(hildren)e(of)g(the)g(ro)r(ot)f(no)r(de\))i(are)e +(usually)g(listed)i(in)f(in)n(v)n(erse)f(c)n(hronolical)118 +2818 y(order.)243 2917 y(T)-7 b(o)35 b(mak)n(e)f(a)h(particular)f +(ordering)g(e\036cien)n(t,)j(it)f(w)n(ould)f(b)r(e)h(a)f(nice)g +(feature)g(if)h(it)g(could)f(b)r(e)h(made)f(to)g(coincide)118 +3017 y(with)28 b(a)f(lexicographic)f(ordering)f(of)j(the)g(indices)f +(\025i.e.,)g(as)g(pro)r(duced)g(b)n(y)h(an)f(\020ORDER)h(BY)f(id)h +(ASC\021)35 b(in)27 b(SQL.)h(The)118 3117 y(lexicographic)d(ordering)h +(of)h(fgID)h(satis\034es)e(b)r(oth)i(conditions.)36 b(The)27 +b(lexicographic)f(ordering)f(of)i(vgID)g(as)g(describ)r(ed)118 +3216 y(ab)r(o)n(v)n(e)34 b(satis\034es)g(the)h(\034rst)g(requisite)f +(if)i(the)f(separator)d(has)j(the)g(minimal)g(binary)g(represen)n +(tation)e(of)i(all)f(allo)n(w)n(ed)118 3316 y(sym)n(b)r(ols)c(in)h(an)f +(index)h(\025)f(this)h(is)g(wh)n(y)f(w)n(e)g(reserv)n(ed)f(/)h(for)g +(the)i(separator.)43 b(But)31 b(the)g(second)f(prop)r(ert)n(y)g(is)g +(missing:)118 3416 y(for)d(instance,)g(the)h(index)g('/1/10')d(is)j +(lexicographically)d(b)r(efore)i('/1/2'.)243 3515 y(If)c(the)h(second)e +(prop)r(ert)n(y)g(is)i(also)e(required)g(for)h(vgID,)g(w)n(e)f(can)h +(sp)r(ecify)h(the)f(c)n(hild)h(iden)n(ti\034ers)e(with)i(coun)n(ters)e +(built)118 3615 y(in)28 b(the)g(follo)n(wing)e(w)n(a)n(y:)36 +b(represen)n(t)26 b(a)h(n)n(um)n(b)r(er)h(b)n(y)f(a)g(string)g(of)g +(digits,)h(where)243 3779 y Ff(\017)41 b Fh(the)25 b(\034rst)g(digit)h +Fc(D)896 3791 y Fb(0)958 3779 y Fh(represen)n(ts)e(the)i(length)f(in)h +(digits)f(of)g(the)h(decimal)f(expansion)f(of)i(the)f(n)n(um)n(b)r(er,) +h(min)n(us)f(one)243 3945 y Ff(\017)41 b Fh(the)28 b(follo)n(wing)e +Fa(\()p Fc(D)920 3957 y Fb(0)976 3945 y Fa(+)18 b(1\))27 +b Fh(digits)h(are)e(the)i(decimal)g(expansion)e(of)i(the)g(n)n(um)n(b)r +(er)118 4109 y(Let)g(us)f(call)h(these)f(iden)n(ti\034ers)g +Fg(m-vgID)p Fh(,)g(\020m\021)34 b(for)27 b(mo)r(di\034ed.)243 +4209 y(As)e(an)f(example,)h(the)g(no)r(de)g(whic)n(h)g(w)n(as)f +(previously)f(represen)n(ted)h(b)n(y)g(/15/3/182)d(will,)k(after)g +(this)g(mo)r(di\034cation,)118 4309 y(ha)n(v)n(e)h(the)i(index)g +(/115/03/2182.)243 4408 y(The)37 b(lexicographic)f(ordering)g(of)i +(m-vgID)f(is)h(the)g(desired)f(ordering)f(of)h(the)h(tree)g(no)r(des.) +67 b(The)38 b(cost)f(of)g(this)118 4508 y(prop)r(ert)n(y)31 +b(is)i(that)f(\(a\))h(the)g(ID)f(are)g(no)n(w)g(longer,)g(\(b\))h(no)f +(no)r(de)g(can)g(ha)n(v)n(e)g(more)f(than)i Fa(160)3106 +4478 y Fb(160)3240 4508 y Fh(c)n(hildren)f(\(actually)-7 +b(,)118 4607 y(this)32 b(is)g(a)f(non-issue\),)h(and)f(\(c\))h(the)g +(index)g(structure)f(is)h(redundan)n(t,)g(some)f(formally)f(correct)h +(indices)g(are)g(in)n(v)-5 b(alid)118 4707 y(\025e.g.,)24 +b(/316/013/11.)30 b(The)24 b(third)g(issue)g(can)g(b)r(e)g(addressed)f +(b)n(y)g(k)n(eeping)g(a)h(strict)g(con)n(trol)e(on)i(the)g(generation)f +(of)h(new)118 4807 y(indices)k(to)f(insure)g(that)h(all)f(indices)h +(are)e(formally)h(correct.)243 4906 y(The)32 b(issue)f(of)h(the)g(rev)n +(erse)e(c)n(hronological)f(indexing)j(of)f(threads)h(in)g(threaded)f +(discussion)g(groups)g(can)g(b)r(e)h(ad-)118 5006 y(dressed)d(easily)f +(enough)h(in)h(fgID:)f(coun)n(t)g(\020do)n(wn\021)36 +b(instead)29 b(of)g(\020up\021)36 b(the)30 b(c)n(hildren)f(of)g(the)h +(ro)r(ot)e(no)r(de)i(\025)f(this)h(implies)118 5106 y(only)e(an)g +(inconsequen)n(tial)f(mo)r(di\034cation)h(of)g(the)g(no)r(de)h +(insertion)e(routine,)h(as)g(sho)n(wn)f(b)r(elo)n(w.)38 +b(The)29 b(problem)e(is)h(less)118 5205 y(trivial)i(with)g(vgID;)h(in)f +(this)h(case,)f(ma)n(yb)r(e)f(a)h(thread)g(iden)n(ti\034er)g(should)g +(b)r(e)h(k)n(ept)f(in)g(a)g(di\033eren)n(t)g(\034eld)h(-)f(i.e.,)h +(repre-)118 5305 y(sen)n(ting)h(the)h(structure)f(as)g(a)h(forest)f +(rather)f(than)i(a)f(tree,)i(where)e(the)h(thread_id)f(\034eld)h +(selects)f(the)h(\020tree\021)38 b(in)33 b(the)118 5404 +y(forest.)1987 5653 y(3)p eop +%%Page: 4 4 +4 3 bop 118 291 a Fi(3)131 b(T)-11 b(ree)45 b(op)t(erations)e(using)h +(genealogical)g(indices)118 472 y Fh(In)32 b(this)f(section)g(w)n(e)g +(sho)n(w)g(ho)n(w)g(to)g(implemen)n(t)h(v)-5 b(arious)30 +b(tree)h(op)r(erations)f(using)h(gID)g(as)g(the)h(primary)e(k)n(ey)h +(in)g(the)118 572 y(no)r(de)d(table.)243 672 y(Some)h(implemen)n +(tation)h(issues)g(are)f(relev)-5 b(an)n(t)29 b(here,)h(esp)r(ecially)f +(concerning)g(the)h(utilisation)g(of)g(indices)g(b)n(y)f(the)118 +771 y(DB)f(engine.)243 871 y(W)-7 b(e)28 b(discuss)f(a)g(tree)g +(represen)n(ted)f(in)i(a)f(table)h(of)f(the)h(form)326 +1034 y Fd(CREATE)41 b(TABLE)g(tree)h(\()456 1134 y(gid)304 +b(text)42 b(PRIMARY)f(KEY,)456 1234 y(nchildren)f(integer)h(DEFAULT)f +(0,)456 1333 y(\\ldots)h(the)i(actual)e(node)h(data)326 +1433 y(\);)118 1597 y Fh(The)26 b(\034eld)g(\020nc)n(hildren\021)32 +b(is)26 b(a)f(coun)n(ter)g(for)g(the)i(n)n(um)n(b)r(er)e(of)h(c)n +(hildren)f(that)h(the)h(no)r(de)f(has)f Fe(ever)35 b +Fh(had;)27 b(w)n(e)e(assume)g(here)118 1696 y(it)j(is)g(not)f(up)r +(dated)h(when)g(no)r(des)f(or)g(subtrees)g(are)f(deleted.)243 +1796 y(Section)h(4)g(pro)n(vides)f(a)i(complete)f(implemen)n(tation)h +(of)f(these)h(op)r(erations)e(for)h(fgID)h(in)g(P)n(ostgreSQL.)118 +2028 y Fm(3.1)112 b(Computing)37 b(the)g(lev)m(el)f(of)h(a)h(no)s(de) +118 2181 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations)g(\(no)g(table)g +(ac)l(c)l(ess\))243 2280 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r +(eration,)f(no)i(table)f(access)g(is)g(required.)243 +2460 y Ff(\017)41 b Fg(vgID:)27 b Fh(coun)n(t)h(the)g(n)n(um)n(b)r(er)f +(of)g(separators)e(\('/'\))j(in)g(the)g(PK)243 2625 y +Ff(\017)41 b Fg(fgID:)27 b Fh(coun)n(t)g(the)h(n)n(um)n(b)r(er)g(of)f +(c)n(haracters)e(in)j(the)g(PK,)g(divide)g(b)n(y)f(the)h(\034xed)f +(size)h(of)f(the)h(coun)n(ters.)118 2857 y Fm(3.2)112 +b(Selecting)36 b(or)h(deleting)f(a)i(subtree)118 3010 +y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243 +3173 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g +(/26/5/7)e(is)i(selected)g(b)n(y)508 3338 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('/26/5/7\045')d(AND)j(id)h(<)g('/26/5/70')243 +3503 y Ff(\017)e Fg(m-vgID:)26 b Fh(The)h(subtree)h(ro)r(oted)e(at)i +(/126/05/07)22 b(is)28 b(selected)f(b)n(y)508 3668 y +Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07\045')243 +3833 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(subtree)f(ro)r(oted)g(at)g +(260507)e(is)i(selected)h(b)n(y)508 3997 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('260507\045')118 4229 y Fm(3.3)112 +b(Selecting)36 b(the)h(direct)f(c)m(hildren)g(of)i(a)g(no)s(de)118 +4382 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243 +4562 y Ff(\017)41 b Fg(vgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h +(/26/5/7)c(are)j(selected)g(b)n(y)508 4727 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('/26/5/7/\045')d(AND)j(id)h(NOT)f(LIKE)g +('26/5/7/\045/\045')243 4892 y Ff(\017)f Fg(m-vgID:)26 +b Fh(The)h(direct)h(c)n(hildren)f(of)g(/26/5/7)e(are)h(selected)i(b)n +(y)508 5056 y Fd(...)43 b(WHERE)e(id)i(LIKE)f('/126/06/07/\045')37 +b(AND)43 b(id)f(NOT)h(LIKE)f('/126/05/07/\045/\045)o(')243 +5221 y Ff(\017)f Fg(fgID:)27 b Fh(The)h(direct)f(c)n(hildren)g(of)h +(260507)c(are)j(selected)g(b)n(y)508 5386 y Fd(...)43 +b(WHERE)e(id)i(LIKE)f('260507\045')d(AND)k(char_length\(id\))37 +b(=)43 b(\(char_length\('26)o(05)o(07')o(\)+)o(2\))1987 +5653 y Fh(4)p eop +%%Page: 5 5 +5 4 bop 118 291 a Fm(3.4)112 b(Inserting)37 b(a)h(no)s(de)g(or)f(a)h +(subtree)118 444 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l +(e)l(e)f(+)h(string)f(and)h(math)g(op)l(er)l(ations)243 +543 y Fh(Insertion)f(is)g(a)h(pro)r(cedural)e(op)r(eration.)42 +b(As)30 b(eac)n(h)f(RDBMS)h(has)f(a)h(di\033eren)n(t)f(w)n(a)n(y)g(of)g +(de\034ning)h(pro)r(cedures,)f(w)n(e)118 643 y(will)f(just)g(describ)r +(e)f(here)g(the)h(necessary)e(steps.)37 b(Examples)27 +b(for)g(P)n(ostgreSQL)f(are)h(pro)n(vided)f(in)i(4.)243 +743 y(In)22 b(order)f(to)h(insert)g(a)g(new)g(c)n(hild)h(of)f +(\020daddy\021)28 b(\(either)23 b(one)f(of)g(/26/5/7,)e(/126/05/07)d +(or)22 b(260507)d(in)k(the)f(examples)118 842 y(ab)r(o)n(v)n(e\))27 +b(y)n(ou)f(ha)n(v)n(e)h(to)220 1008 y(1.)41 b(add)27 +b(one)g(to)h(the)g(n)n(um)n(b)r(er)f(of)g(c)n(hildren)h(of)f +(\020daddy\021)508 1174 y Fd(UPDATE)41 b(tree)h(SET)h(nchildren)c(=)k +(\(nchildren)d(+)j(1\))g(WHERE)e(ID)i(=)g(``daddy'';)220 +1340 y Fh(2.)e(enco)r(de)27 b(the)h(n)n(um)n(b)r(er)f(of)g(c)n(hildren) +g(of)h(\020daddy\021)33 b(in)28 b(base)f(160,)f(bring)h(it)h(to)f(the)h +(correct)e(format)h(dep)r(ending)h(on)326 1440 y(the)c(v)-5 +b(arian)n(t)23 b(of)h(gID)g(\(pad)g(with)h(0)e(or)g(not,)i(prep)r(end)f +(a)g(digit)g(coun)n(ter)f(or)g(not,)i(prep)r(end)f(/)g(or)f(not,)i +(coun)n(t)e(do)n(wn)326 1540 y(or)j(up,)i(.)14 b(.)g(.)g(\))37 +b(and)28 b(app)r(end)f(it)h(to)g(daddy's)f(gID)g(to)h(obtain)f(the)h +(new)g(no)r(de's)f(gID.)220 1706 y(3.)41 b(insert)27 +b(the)h(new)f(no)r(de)243 1872 y(When)35 b(inserting)g(a)f(subtree,)j +(the)e(index)g(of)g(the)h(ro)r(ot)e(of)h(the)g(subtree)g(has)f(to)h(b)r +(e)h(computed)f(as)f(ab)r(o)n(v)n(e,)i(and)118 1971 y(prep)r(ended)28 +b(to)f(the)h(index)g(of)f(eac)n(h)g(no)r(de)h(of)f(the)h(subtree)f(b)r +(efore)h(insertion.)243 2071 y(Remark)e(that)i(only)f(the)h(paren)n(t)f +(no)r(de)h(has)f(to)g(b)r(e)h(up)r(dated)g(on)f(insertion.)118 +2303 y Fm(3.5)112 b(Selecting)36 b(the)h(ancestors)h(of)g(a)g(no)s(de) +118 2457 y Fg(Cost:)f Fe(index)30 b(sc)l(an)g(of)g(the)g(tr)l(e)l(e)243 +2556 y Fh(Y)-7 b(ou)27 b(can)g(sp)r(ecify)h(all)g(ancestors)d(of)j(a)f +(no)r(de)h(in)f(a)h(single)f(SQL)g(statemen)n(t;)g(for)g(instance)h +(for)f(vgID)326 2722 y Fd(...)42 b(WHERE)f('/25/6/7')f(LIKE)i(\(id)g +(||)h('/\045'\))f(AND)g(id)h(<)g('/25/6/7')118 2888 y +Fh(The)31 b(second)e(part)h(of)h(the)g(clause,)f(while)h(logically)e +(redundan)n(t,)h(is)h(a)f(\020hin)n(t\021)37 b(to)30 +b(the)h(optimizer.)45 b(A)n(t)31 b(least)f(in)g(P)n(ost-)118 +2988 y(greSQL,)c(without)i(it)g(the)g(optimizer)f(will)h(c)n(ho)r(ose)e +(a)i(sequen)n(tial)e(scan)h(of)h(the)g(table)f(and)h(disregard)d(the)j +(index.)118 3220 y Fm(3.6)112 b(Selecting)36 b(all)g(lea)m(v)m(es)118 +3374 y Fg(Cost:)h Fe(sc)l(an)30 b(of)g(the)g(tr)l(e)l(e)243 +3473 y Fh(A)e(leaf)f(is)g(a)h(no)r(de)f(without)h(descendan)n(ts:)36 +b(it)28 b(has)f(0)g(c)n(hildren.)37 b(Hence)326 3639 +y Fd(...)42 b(WHERE)f(nchildren)f(=)j(0)118 3805 y Fh(If)28 +b(this)g(t)n(yp)r(e)g(of)f(query)g(is)h(often)f(necessary)-7 +b(,)26 b(y)n(ou)h(ma)n(y)g(b)r(e)h(w)n(ell)f(advised)g(to)g(k)n(eep)g +(an)h(index)f(on)h(tree\(nc)n(hildren\).)118 4038 y Fm(3.7)112 +b(Determining)35 b(if)i(A)g(is)g(a)h(descendan)m(t)g(of)g(B)118 +4191 y Fg(Cost:)f Fe(string)30 b(op)l(er)l(ations,)h(no)f(table)g(ac)l +(c)l(ess)243 4291 y Fh(This)d(is)h(a)f(pure)g(string)g(op)r(eration)f +(on)i(the)g(indices,)f(no)g(table)h(access)e(is)i(necessary)-7 +b(.)118 4565 y Fi(4)131 b(Putting)45 b(it)f(all)h(together:)57 +b(a)44 b(P)l(ostgreSQL)f(implemen)l(tation)118 4747 y +Fh(h)n(ttp://www.p)r(ostgresql.org/mhonarc/pgsq)o(l-sql/)o(20)o(00)o +(-0)o(4/)o(msg0)o(02)o(67)o(.h)n(tml)243 4847 y(W)-7 +b(e)30 b(describ)r(e)g(here)g(a)g(small)f(pac)n(k)-5 +b(age)29 b(that)i(can)e(b)r(e)i(used)f(for)g(implemen)n(ting)g(gID)g +(on)g(P)n(ostgreSQL.)f(It)i(can)e(b)r(e)118 4946 y(found)f(at)f()243 5046 y(The)21 b(pac)n(k)-5 b(age)21 b(uses)g(the)h(pro) +r(cedural)e(language)h(PL/PGsql.)35 b(A)22 b(b)r(etter)g(implemen)n +(tation)g(w)n(ould)f(probably)g(de\034ne)118 5145 y(the)28 +b(gID)g(as)f(new)g(P)n(ostgres)f(t)n(yp)r(es,)i(and)f(co)r(de)g(all)h +(this)g(in)f(C.)243 5245 y(The)g(\034les)h(should)f(b)r(e)h(loaded)f +(in)h(alphab)r(etical)f(order.)1987 5653 y(5)p eop +%%Page: 6 6 +6 5 bop 118 291 a Fm(4.1)112 b(tree0_enco)s(ding.sql)118 +444 y Fh(This)28 b(\034le)f(de\034nes)h(and)f(p)r(opulates)h(the)f +(table)h(_b160_digits)d(of)j(\020digits\021)33 b(in)28 +b(base)f(160,)326 604 y Fd(CREATE)41 b(TABLE)g(\\_b160\\_digits)d +(\(deci)j(integer,)f(code)i(char\);)118 764 y Fh(and)28 +b(the)f(t)n(w)n(o)g(functions)326 924 y Fd(CREATE)41 +b(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er\))d(RETURNS)j(string) +413 1024 y(AS)j('....')e(LANGUAGE)f('plpgsql';)326 1124 +y(CREATE)h(FUNCTION)f(\\_b160\\_encode\(i)o(nt)o(eg)o(er,)o(in)o(te)o +(ger)o(\))d(RETURNS)k(string)413 1223 y(AS)i('....')e(LANGUAGE)f +('plpgsql';)118 1384 y Fh(The)22 b(\034rst)h(function)f(returns)g(a)g +(v)-5 b(ariable)21 b(size)h(enco)r(ding;)i(the)f(second)e(a)h(\034xed)h +(size)f(enco)r(ding)g(\(the)h(second)e(parameter)118 +1483 y(is)g(the)h(size\),)g(and)f(raises)e(an)i(exception)g(if)h(the)f +(n)n(um)n(b)r(er)g(is)g(to)r(o)g(large)e(to)i(b)r(e)h(represen)n(ted)e +(with)h(the)h(requested)e(n)n(um)n(b)r(er)118 1583 y(of)28 +b(digits.)118 1814 y Fm(4.2)112 b(tree1_de\034ne.sql)118 +1967 y Fh(This)28 b(\034le)f(pro)n(vides)f(a)i(function)326 +2127 y Fd(CREATE)41 b(FUNCTION)f(_tree_create\(tex)o(t,)o(in)o(teg)o +(er)o(,t)o(ext)o(,t)o(ex)o(t\))d(RETURNS)k(bpchar)413 +2227 y(AS)i('....')e(LANGUAGE)f('plpgsql';)118 2387 y +Fh(that)e(creates)f(a)h(tree)f(infrastructure)g(of)h(either)g(fgID)g +(or)f(vgID.)h(Assuming)f(y)n(ou)g(ha)n(v)n(e)g(a)h(table)f(\020m)n +(ytable\021)44 b(with)118 2487 y(primary)26 b(k)n(ey)h(\020m)n +(yid\021,)g(then)h(calling)326 2647 y Fd(SELECT)41 b(_tree_create\('m)o +(yt)o(ree)o(',)o(2,')o(my)o(ta)o(ble)o(',)o('m)o(yid)o('\))o(;)118 +2807 y Fh(will)28 b(cause:)220 2967 y(1.)41 b(the)28 +b(creation)e(of)i(a)f(table)508 3131 y Fd(CREATE)41 b(TABLE)h +(mytree_bkg\()683 3230 y(gid)g(text)g(PRIMARY)e(KEY,)683 +3330 y(nchildren)f(int,)683 3429 y(sid)j(integer)f(REFERENCES)e +(mytable\(myid\))508 3529 y(\);)508 3629 y(CREATE)i(UNIQUE)g(INDEX)h +(mytree_bkg_sid)37 b(ON)43 b(mytree_bkg\(sid\);)326 3792 +y Fh(for)27 b(the)h(tree)f(structure.)220 3955 y(2.)41 +b(the)28 b(creation)e(of)i(a)f(view)508 4118 y Fd(CREATE)41 +b(VIEW)h(mytree)f(AS)639 4218 y(SELECT)g(t.gid,n.*)900 +4317 y(FROM)h(mytable)f(n,)i(mytree_bkg)c(t)900 4417 +y(WHERE)j(t.sid=n.myid;)326 4580 y Fh(with:)35 b(a)23 +b(trigger)e(on)i(UPD)n(A)-7 b(TE)25 b(that)e(blo)r(c)n(ks)g(up)r +(dating)g(the)h(gid)f(and)g(allo)n(ws)f(up)r(dating)h(the)g(no)r(de)h +(data,)f(a)g(rule)326 4680 y(on)k(DELETE)i(that)f(deletes)f(the)h +(corresp)r(onding)e(en)n(try)h(b)r(oth)h(in)g(m)n(ytree_bkg)d(and)j(m)n +(ytable,)f(and)g(a)g(trigger)326 4779 y(ON)h(INSER)-7 +b(T)30 b(that)f(raises)e(an)h(exception)g(and)g(informs)h(the)f(user)g +(to)h(use)f(the)h(insertion)f(function)h(describ)r(ed)326 +4879 y(b)r(elo)n(w.)220 5042 y(3.)41 b(t)n(w)n(o)26 b(insertion)h +(functions)h(that)g(compute)g(automatically)e(the)i(gID)g(of)f(the)h +(new)g(no)r(de:)425 5205 y Ff(\017)41 b Fh(a)27 b(function)i(m)n +(ytree_insert\(text,text,in)n(teger,text\))d(for)h(insertion)g(sim)n +(ultaneosly)f(in)i(b)r(oth)g(tables:)508 5305 y(m)n +(ytree_insert\('2201','hello',0,'not)15 b(m)n(uc)n(h'\))j(inserts)g(a)g +(new)g(c)n(hild)h(of)f(2201)f(with)h(data1='hello',)h(data2=0)508 +5404 y(and)28 b(data3='not)e(m)n(uc)n(h')1987 5653 y(6)p +eop +%%Page: 7 7 +7 6 bop 425 291 a Ff(\017)41 b Fh(a)27 b(function)i(m)n +(ytree_insert_no)r(de\(text,in)n(teger\))c(for)i(insertion)g(in)h(m)n +(ytree_bkg)508 390 y(m)n(ytree_insert\('2201',25\))c(inserts)j(in)h(m)n +(ytree_bkg)e(a)h(new)h(c)n(hild)f(of)h(2201)d(with)j(sid=25)220 +556 y(4.)41 b(a)27 b(function)h(m)n(ytree_mo)n(v)n(e\(text,text\))e +(that)i(mo)n(v)n(es)e(subtrees:)326 656 y(m)n(ytree_mo)n(v)n +(e\('2201','23'\))d(mo)n(v)n(es)j(the)i(subtree)f(ro)r(oted)g(at)g +(2201)f(to)h(a)h(place)f(b)r(elo)n(w)g(23)f(\(ma)n(yb)r(e)i(2307\))220 +822 y(5.)41 b(a)c(function)g(m)n(ytree_len\(\))g(that)h(returns)e(the)i +(length)f(of)g(the)h(enco)r(dings)f(used)g(in)h(the)f(gID)g(\(2)h +(here;)j(0)c(if)326 922 y(v)-5 b(ariable)26 b(size\).)118 +1196 y Fi(5)131 b(Non-tree)44 b(hierarc)l(hies)118 1378 +y Fh(sequence)22 b(as)f(id,)j(table)e(with)h(\(id,g-index\))f(with)g(p) +r(ossibly)g(man)n(y)g(g-indices)f(for)h(eac)n(h)f(id)h(\(if)h(TOO)f +(man)n(y)-7 b(,)23 b(bad)f(mo)r(del:)118 1478 y(list)28 +b(all)f(genealogies,)f(i.e.,)h(paths)h(from)f(the)h(ro)r(ot\))118 +1752 y Fi(References)160 1934 y Fh([1])41 b(Philip)28 +b(Greenspun,)g Fe(T)-6 b(r)l(e)l(es)29 b(in)h(Or)l(acle)g(SQL)p +Fh(,)d(in)h Fg(SQL)k(for)g(W)-8 b(eb)31 b(Nerds)289 2033 +y Fh()160 2200 +y([2])41 b(Jo)r(e)27 b(Celk)n(o,)f Fe(SQL)j(for)i(Smarties)p +Fh(,)d(in)g Fg(DBMS)j(Online)p Fh(,)26 b(Marc)n(h)h(to)g(June)h(1996) +289 2299 y()289 +2399 y()289 +2498 y()289 +2598 y()160 +2764 y([3])41 b(Graeme)26 b(Birc)n(hall,)h Fg(DB2)32 +b(UDB)g(V6.1)f(SQL)h(Co)s(okb)s(o)s(ok)p Fh(,)289 2864 +y()1987 5653 +y(7)p eop +%%Trailer +end +userdict /end-hook known{end-hook}if +%%EOF -- cgit From a3972de8949f5d1c804c316b0be61c17e61d903b Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Mon, 30 May 2005 16:46:54 +0000 Subject: r7116: work in progress (This used to be commit c860a4f9940c04021ecc859240c5f35c3d1c4bed) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 356 +++++++++++++++++++----------- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 1 + source4/lib/ldb/ldb_sqlite3/schema | 6 +- 3 files changed, 237 insertions(+), 126 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 932da0af31..a0ffffca9e 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -37,11 +37,21 @@ #include "ldb/include/ldb_private.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" +#undef SQL_EXEC /* just in case; not expected to be defined */ +#define SQL_EXEC(lsqlite3, query, reset) \ + do { \ + lsqlite3->last_rc = \ + sqlite3_step(lsqlite3->queries.query); \ + if (lsqlite3->last_rc == SQLITE_BUSY || reset) \ + (void) sqlite3_reset(lsqlite3->queries.query); \ + } while lsqlite3->last_rc == SQLITE_BUSY; + + + #if 0 /* - we don't need this right now, but will once we add some backend - options -*/ + * we don't need this right now, but will once we add some backend options + */ /* find an option in an option list (a null terminated list of strings) @@ -68,8 +78,8 @@ static const char *lsqlite3_option_find(const struct lsqlite3_private *lsqlite3, #endif /* - rename a record -*/ + * rename a record + */ static int lsqlite3_rename(struct ldb_module *module, const char *olddn, const char *newdn) { int column; @@ -81,32 +91,32 @@ static int lsqlite3_rename(struct ldb_module *module, const char *olddn, const c } /* Bind old distinguished names */ - column = sqlite3_bind_parameter_index(lsqlite3->renameDN, ":oldDN"); - if (sqlite3_bind_text(lsqlite3->renameDN, column, + column = sqlite3_bind_parameter_index(lsqlite3->queries.renameDN, + ":oldDN"); + if (sqlite3_bind_text(lsqlite3->queries.renameDN, column, olddn, strlen(olddn), SQLITE_STATIC) != SQLITE_OK) { return -1; } /* Bind new distinguished names */ - column = sqlite3_bind_parameter_index(lsqlite3->renameDN, ":newDN"); - if (sqlite3_bind_text(lsqlite3->renameDN, column, + column = sqlite3_bind_parameter_index(lsqlite3->queries.renameDN, + ":newDN"); + if (sqlite3_bind_text(lsqlite3->queries.renameDN, column, newdn, strlen(newdn), SQLITE_STATIC) != SQLITE_OK) { return -1; } - do { - lsqlite3->last_rc = sqlite3_step(lsqlite3->renameDN); - (void) sqlite3_reset(lsqlite3->renameDN); - } while lsqlite3->last_rc == SQLITE3_BUSY; + /* Execute the query. This sets lsqlite3->last_rc */ + SQL_EXEC(lsqlite3, renameDN, TRUE); return lsqlite3->last_rc == 0 ? 0 : -1; } /* - delete a record -*/ + * delete a record + */ static int lsqlite3_delete(struct ldb_module *module, const char *dn) { int ret = 0; @@ -118,25 +128,24 @@ static int lsqlite3_delete(struct ldb_module *module, const char *dn) return 0; } - /* Bind new distinguished names */ - column = sqlite3_bind_parameter_index(lsqlite3->renameDN, ":dn"); - if (sqlite3_bind_text(lsqlite3->deleteDN, column, + /* Bind distinguished names */ + column = sqlite3_bind_parameter_index(lsqlite3->queries.deleteDN, + ":dn"); + if (sqlite3_bind_text(lsqlite3->queries.deleteDN, column, dn, strlen(dn), SQLITE_STATIC) != SQLITE_OK) { return -1; } - do { - lsqlite3->last_rc = sqlite3_step(lsqlite3->deleteDN); - (void) sqlite3_reset(lsqlite3->deleteDN); - } while lsqlite3->last_rc == SQLITE3_BUSY; + /* Execute the query. This sets lsqlite3->last_rc */ + SQL_EXEC(lsqlite3, deleteDN, TRUE); return lsqlite3->last_rc == 0 ? 0 : -1; } /* - free a search result -*/ + * free a search result + */ static int lsqlite3_search_free(struct ldb_module *module, struct ldb_message **res) { talloc_free(res); @@ -145,8 +154,8 @@ static int lsqlite3_search_free(struct ldb_module *module, struct ldb_message ** /* - add a single set of ldap message values to a ldb_message -*/ + * add a single set of ldap message values to a ldb_message + */ static int lsqlite3_add_msg_attr(struct ldb_context *ldb, struct ldb_message *msg, const char *attr, struct berval **bval) @@ -200,8 +209,8 @@ static int lsqlite3_add_msg_attr(struct ldb_context *ldb, } /* - search for matching records -*/ + * search for matching records + */ static int lsqlite3_search(struct ldb_module *module, const char *base, enum ldb_scope scope, const char *expression, const char * const *attrs, struct ldb_message ***res) @@ -304,117 +313,175 @@ failed: /* - Issue a series of SQL statements to implement the requests in the ldb_message -*/ + * Issue a series of SQL statements to implement the ADD/MODIFY/DELETE + * requests in the ldb_message + */ static int lsqlite3_msg_to_sql(struct ldb_context *ldb, const struct ldb_message *msg, - int modify_existing) + long long dn_id, + int use_flags) { + int flags; unsigned int i, j; struct ldb_context *ldb = module->ldb; struct lsqlite3_private *lsqlite3 = module->private_data; sqlite3_stmt *stmt = NULL; - for (i=0;inum_elements;i++) { + for (i = 0; i < msg->num_elements; i++) { const struct ldb_message_element *el = &msg->elements[i]; - if (! modify_existing) { - /* This is a new DN. Bind new distinguished name */ - column = - sqlite3_bind_parameter_index( - lsqlite3->queries.newDN, - ":dn"); - if (sqlite3_bind_text(lsqlite3->queries.newDN, column, - msg->dn, strlen(msg->dn), - SQLITE_STATIC) != SQLITE_OK) { - return -1; - } + if (! use_flags) { + flags = LDB_FLAG_MOD_ADD; + } else { + flags = el->flags & LDB_FLAG_MOD_MASK; + } - /* Add this new DN */ - do { - lsqlite3->last_rc = - sqlite3_step(lsqlite3->queries.newDN); - (void) sqlite3_reset(lsqlite3->queries.newDN); - } while lsqlite3->last_rc == SQLITE_BUSY; + /* Determine which query to use */ + switch (flags) { + case LDB_FLAG_MOD_ADD: + stmt = lsqlite3->queries.addAttrValuePair; + break; - if (lsqlite3->last_rc != SQLITE_DONE) { - return -1; - } + case LDB_FLAG_MOD_DELETE: + stmt = lsqlite3->queries.deleteAttrValuePairs; + break; - dn_id = last_insert_rowid(lsqlite3->sqlite3); + case LDB_FLAG_MOD_REPLACE: + stmt = lsqlite3->queries.replaceAttrValuePairs; + break; + } - stmt = lsqlite3->queries.newAttribute; + /* + * All queries use dn id and attribute name. Bind them now. + */ - } else { - /* Get the dn_id for the specified DN */ - xxx; + /* Bind distinguished name id */ + column = + sqlite3_bind_parameter_index( + stmt, + ":dn_id"); + if (sqlite3_bind_int64(stmt, + column, + dn_id) != SQLITE_OK) { - switch (el->flags & LDB_FLAG_MOD_MASK) { - case LDB_FLAG_MOD_ADD: - stmt = lsqlite3->queries.addAttrValuePair; - break; - case LDB_FLAG_MOD_DELETE: - stmt = lsqlite3->queries.deleteAttrValuePairs; - break; - case LDB_FLAG_MOD_REPLACE: - stmt = lsqlite3->queries.replaceAttrValuePairs; - break; - } - + return -1; } - for (j=0;jnum_values;j++) { - mods[num_mods]->mod_vals.modv_bvals[j] = talloc(mods[num_mods]->mod_vals.modv_bvals, - struct berval); - if (!mods[num_mods]->mod_vals.modv_bvals[j]) { - goto failed; - } - mods[num_mods]->mod_vals.modv_bvals[j]->bv_val = el->values[j].data; - mods[num_mods]->mod_vals.modv_bvals[j]->bv_len = el->values[j].length; + /* Bind attribute name */ + column = + sqlite3_bind_parameter_index( + stmt, + ":attr_name"); + if (sqlite3_bind_text(lsqlite3->queries.deleteDN, column, + el->name, strlen(el->name), + SQLITE_STATIC) != SQLITE_OK) { + + return -1; + } + + + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + + /* ... bind the attribute value, if necessary */ + switch (flags) { + case LDB_FLAG_MOD_ADD: + case LDB_FLAG_MOD_REPLACE: + /* Bind attribute value */ + column = + sqlite3_bind_parameter_index( + stmt, + ":attr_value"); + if (sqlite3_bind_text( + stmt, column, + el->values[j].data, + el->values[j].length, + SQLITE_STATIC) != SQLITE_OK) { + + return -1; + } + + break; + + case LDB_FLAG_MOD_DELETE: + /* No additional parameters to this query */ + break; + } + + /* Execute the query */ + do { + lsqlite3->last_rc = sqlite3_step(stmt); + (void) sqlite3_reset(stmt); + } while lsqlite3->last_rc == SQLITE_BUSY; + + /* Make sure we succeeded */ + if (lsqlite3->last_rc != SQLITE_OK) { + return -1; + } } - mods[num_mods]->mod_vals.modv_bvals[j] = NULL; - num_mods++; } - return mods; - -failed: - talloc_free(mods); - return NULL; + return 0; } /* - add a record -*/ + * add a record + */ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg) { struct ldb_context *ldb = module->ldb; struct lsqlite3_private *lsqlite3 = module->private_data; - LDAPMod **mods; - int ret = 0; + int ret; /* ignore ltdb specials */ if (msg->dn[0] == '@') { return 0; } - mods = lsqlite3_msg_to_mods(ldb, msg, 0); + /* Begin a transaction */ + SQL_EXEC(lsqlite3, begin, TRUE); - lsqlite3->last_rc = ldap_add_s(lsqlite3->ldap, msg->dn, mods); - if (lsqlite3->last_rc != LDAP_SUCCESS) { - ret = -1; - } + /* This is a new DN. Bind new distinguished name */ + column = sqlite3_bind_parameter_index(lsqlite3->queries.newDN, ":dn"); + if (sqlite3_bind_text(lsqlite3->queries.newDN, column, + msg->dn, strlen(msg->dn), + SQLITE_STATIC) != SQLITE_OK) { + return -1; + } + + /* Add this new DN. This sets lsqlite3->last_rc */ + SQL_EXEC(lsqlite3, newDN, TRUE); + + if (lsqlite3->last_rc != SQLITE_DONE) { + return -1; + } + + /* Get the id of the just-added DN */ + dn_id = sqlite3_last_insert_rowid(lsqlite3->sqlite3); + + ret = lsqlite3_msg_to_sql(ldb, msg, dn_id, FALSE); - talloc_free(mods); + /* Did the attribute additions (if any) succeeded? */ + if (ret == 0) + { + /* Yup. Commit the transaction */ + SQL_EXEC(lsqlite3, commit, TRUE); + } + else + { + /* Attribute addition failed. Rollback the transaction */ + SQL_EXEC(lsqlite3, rollback, TRUE); + } - return ret; + /* If everything succeeded, return success */ + return lsqlite3->last_rc == SQLITE_DONE && ret == 0 ? 0 : -1; } /* - modify a record -*/ + * modify a record + */ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) { struct ldb_context *ldb = module->ldb; @@ -427,16 +494,48 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * return 0; } - mods = lsqlite3_msg_to_mods(ldb, msg, 1); + /* Begin a transaction */ + SQL_EXEC(lsqlite3, begin, TRUE); + + /* Get the dn_id for the specified DN */ + column = + sqlite3_bind_parameter_index( + lsqlite3->queries.getDNID, + ":dn"); + if (sqlite3_bind_text(lsqlite3->queries.getDNID, + column, + msg->dn, strlen(msg->dn), + SQLITE_STATIC) != SQLITE_OK) { + return -1; + } + + /* Get the id of this DN. This sets lsqlite3->last_rc */ + SQL_EXEC(lsqlite3, getDNID, FALSE); + + if (lsqlite3->last_rc != SQLITE_ROW) { + return -1; + } - lsqlite3->last_rc = ldap_modify_s(lsqlite3->ldap, msg->dn, mods); - if (lsqlite3->last_rc != LDAP_SUCCESS) { - ret = -1; - } + dn_id = sqlite3_column_int64(lsqlite3->queries.getDNID, + column); + (void) sqlite3_reset(lsqlite3->queries.getDNID); - talloc_free(mods); + ret = lsqlite3_msg_to_sql(ldb, msg, dn_id, FALSE); - return ret; + /* Did the attribute additions (if any) succeeded? */ + if (ret == 0) + { + /* Yup. Commit the transaction */ + SQL_EXEC(lsqlite3, commit, TRUE); + } + else + { + /* Attribute addition failed. Rollback the transaction */ + SQL_EXEC(lsqlite3, rollback, TRUE); + } + + /* If everything succeeded, return success */ + return lsqlite3->last_rc == SQLITE_DONE && ret == 0 ? 0 : -1; } static int lsqlite3_lock(struct ldb_module *module, const char *lockname) @@ -455,10 +554,7 @@ static int lsqlite3_lock(struct ldb_module *module, const char *lockname) } /* Write-lock (but not read-lock) the database */ - lsqlite3->last_rc = sqlite3_step(lsqlite3->begin); - - /* Ready the compiled statement for its next use */ - (void ) sqlite_reset(lsqlite3->begin); + SQL_EXEC(lsqlite3, begin, TRUE); return lsqlite3->last_rc == 0 ? 0 : -1; } @@ -482,18 +578,15 @@ static int lsqlite3_unlock(struct ldb_module *module, const char *lockname) if (--lsqlite3->lock_count == 0) { /* Final unlock. Unlock the database */ - lsqlite3->last_rc = sqlite3_step(lsqlite3->commit); - - /* Ready the compiled statement for its next use */ - (void ) sqlite_reset(lsqlite3->commit); + SQL_EXEC(lsqlite3, commit, TRUE); } return lsqlite3->last_rc == 0 ? 0 : -1; } /* - return extended error information -*/ + * return extended error information + */ static const char *lsqlite3_errstring(struct ldb_module *module) { struct lsqlite3_private *lsqlite3 = module->private_data; @@ -577,8 +670,10 @@ static int lsqlite3_initialize(lsqlite3_private *lsqlite3, CREATE TABLE ldb_attr_value_pairs ( dn_id INTEGER REFERENCES ldb_distinguished_names, - attr_name TEXT REFERENCES ldb_attributes, - attr_value TEXT + attr_name TEXT, -- optionally REFERENCES ldb_attributes + attr_value TEXT, + + UNIQUE (dn_id, attr_name, attr_value) ); -- ------------------------------------------------------ @@ -645,7 +740,7 @@ static int lsqlite3_initialize(lsqlite3_private *lsqlite3, INSERT INTO ldb_attributes (attr_name) VALUES ('dn'); - /* We need an implicit "top" level object class */ + /* We need an implicit 'top' level object class */ INSERT INTO ldb_object_classes (class_name, tree_key) SELECT 'top', /* next_tree_key(NULL) */ '0001'; @@ -867,6 +962,15 @@ static int lsqlite3_initialize(lsqlite3_private *lsqlite3, " SELECT :child_class, next_tree_key(:parent_class);" -1, &lsqlite3->queries.insertSubclass, + &pTail)) != SQLITE_SUCCESS || + + (lsqlite3->last_rc = sqlite3_prepare( + lsqlite3->sqlite3, + "SELECT dn_id " + " FROM ldb_distinguished_names " + " WHERE dn = :dn;" + -1, + &lsqlite3->queries.getDNID, &pTail)) != SQLITE_SUCCESS) { (void) sqlite3_close(lsqlite3->sqlite3); @@ -877,11 +981,11 @@ static int lsqlite3_initialize(lsqlite3_private *lsqlite3, } /* - connect to the database -*/ + * connect to the database + */ struct ldb_context *lsqlite3_connect(const char *url, - unsigned int flags, - const char *options[]) + unsigned int flags, + const char *options[]) { struct ldb_context *ldb = NULL; struct lsqlite3_private *lsqlite3 = NULL; @@ -921,8 +1025,10 @@ struct ldb_context *lsqlite3_connect(const char *url, ldb->modules->ops = &lsqlite3_ops; if (options) { - /* take a copy of the options array, so we don't have to rely - on the caller keeping it around (it might be dynamic) */ + /* + * take a copy of the options array, so we don't have to rely + * on the caller keeping it around (it might be dynamic) + */ for (i=0;options[i];i++) ; lsqlite3->options = talloc_array(lsqlite3, char *, i+1); @@ -931,8 +1037,10 @@ struct ldb_context *lsqlite3_connect(const char *url, } for (i=0;options[i];i++) { + lsqlite3->options[i+1] = NULL; - lsqlite3->options[i] = talloc_strdup(lsqlite3->options, options[i]); + lsqlite3->options[i] = + talloc_strdup(lsqlite3->options, options[i]); if (!lsqlite3->options[i]) { goto failed; } diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h index 46aa4ab7c5..2fa08fdcb7 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h @@ -21,6 +21,7 @@ struct lsqlite3_private { sqlite3_stmt *replaceAttrValuePairs; sqlite3_stmt *deleteAttrValuePairs; sqlite3_stmt *insertSubclass; + sqlite3_stmt *getDNID; } queries; }; diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema index 2ba188c785..d06d7d0c34 100644 --- a/source4/lib/ldb/ldb_sqlite3/schema +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -43,8 +43,10 @@ CREATE TABLE ldb_attr_value_pairs ( dn_id INTEGER REFERENCES ldb_distinguished_names, - attr_name TEXT REFERENCES ldb_attributes, - attr_value TEXT + attr_name TEXT, -- optionally REFERENCES ldb_attributes + attr_value TEXT, + + UNIQUE (dn_id, attr_name, attr_value) ); -- ------------------------------------------------------ -- cgit From 913c19cd5b9b43f653652967edf9dc4d9816c79b Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Tue, 31 May 2005 03:31:54 +0000 Subject: r7133: work in progress, including a HIGHLY revised and simplified schema (This used to be commit aa9bb6ad4cb7219a80a6589d406e47a15ac2c3a1) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 204 +++++++++------- source4/lib/ldb/ldb_sqlite3/schema | 377 ++++++++++++++++++++---------- 2 files changed, 366 insertions(+), 215 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index a0ffffca9e..d36ced2667 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1,22 +1,22 @@ /* ldb database library - + Copyright (C) Andrew Tridgell 2004 - - ** NOTE! The following LGPL license applies to the ldb - ** library. This does NOT imply that all of Samba is released - ** under the LGPL + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This library 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 Lesser General Public License for more details. - + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -25,7 +25,7 @@ /* * Name: ldb * - * Component: ldb sqlite backend + * Component: ldb sqlite3 backend * * Description: core files for SQLITE3 backend * @@ -39,30 +39,30 @@ #undef SQL_EXEC /* just in case; not expected to be defined */ #define SQL_EXEC(lsqlite3, query, reset) \ - do { \ - lsqlite3->last_rc = \ - sqlite3_step(lsqlite3->queries.query); \ - if (lsqlite3->last_rc == SQLITE_BUSY || reset) \ - (void) sqlite3_reset(lsqlite3->queries.query); \ - } while lsqlite3->last_rc == SQLITE_BUSY; + do { \ + lsqlite3->last_rc = \ + sqlite3_step(lsqlite3->queries.query); \ + if (lsqlite3->last_rc == SQLITE_BUSY || reset) \ + (void) sqlite3_reset(lsqlite3->queries.query); \ + } while lsqlite3->last_rc == SQLITE_BUSY; #if 0 /* * we don't need this right now, but will once we add some backend options + * + * find an option in an option list (a null terminated list of strings) + * + * this assumes the list is short. If it ever gets long then we really should + * do this in some smarter way */ - -/* - find an option in an option list (a null terminated list of strings) - - this assumes the list is short. If it ever gets long then we really - should do this in some smarter way - */ -static const char *lsqlite3_option_find(const struct lsqlite3_private *lsqlite3, const char *name) +static const char * +lsqlite3_option_find(const struct lsqlite3_private *lsqlite3, + const char *name) { - int i; - size_t len = strlen(name); + int i; + size_t len = strlen(name); if (!lsqlite3->options) return NULL; @@ -80,10 +80,13 @@ static const char *lsqlite3_option_find(const struct lsqlite3_private *lsqlite3, /* * rename a record */ -static int lsqlite3_rename(struct ldb_module *module, const char *olddn, const char *newdn) +static int +lsqlite3_rename(struct ldb_module *module, + const char *olddn, + const char *newdn) { - int column; - struct lsqlite3_private *lsqlite3 = module->private_data; + int column; + struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ if (olddn[0] == '@' ||newdn[0] == '@') { @@ -117,11 +120,13 @@ static int lsqlite3_rename(struct ldb_module *module, const char *olddn, const c /* * delete a record */ -static int lsqlite3_delete(struct ldb_module *module, const char *dn) +static int +lsqlite3_delete(struct ldb_module *module, + const char *dn) { - int ret = 0; - int column; - struct lsqlite3_private *lsqlite3 = module->private_data; + int ret = 0; + int column; + struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ if (dn[0] == '@') { @@ -146,7 +151,9 @@ static int lsqlite3_delete(struct ldb_module *module, const char *dn) /* * free a search result */ -static int lsqlite3_search_free(struct ldb_module *module, struct ldb_message **res) +static int +lsqlite3_search_free(struct ldb_module *module, + struct ldb_message **res) { talloc_free(res); return 0; @@ -156,12 +163,15 @@ static int lsqlite3_search_free(struct ldb_module *module, struct ldb_message ** /* * add a single set of ldap message values to a ldb_message */ -static int lsqlite3_add_msg_attr(struct ldb_context *ldb, - struct ldb_message *msg, - const char *attr, struct berval **bval) +static int +lsqlite3_add_msg_attr(struct ldb_context *ldb, + struct ldb_message *msg, + const char *attr, + struct berval **bval) { - int count, i; - struct ldb_message_element *el; + int i; + int count; + struct ldb_message_element * el; count = ldap_count_values_len(bval); @@ -211,13 +221,18 @@ static int lsqlite3_add_msg_attr(struct ldb_context *ldb, /* * search for matching records */ -static int lsqlite3_search(struct ldb_module *module, const char *base, - enum ldb_scope scope, const char *expression, - const char * const *attrs, struct ldb_message ***res) +static int +lsqlite3_search(struct ldb_module *module, + const char *base, + enum ldb_scope scope, + const char *expression, + const char * const *attrs, + struct ldb_message ***res) { - struct ldb_context *ldb = module->ldb; - struct lsqlite3_private *lsqlite3 = module->private_data; - int count, msg_count; + int count; + int msg_count; + struct ldb_context * ldb = module->ldb; + struct lsqlite3_private * lsqlite3 = module->private_data; if (base == NULL) { base = ""; @@ -316,16 +331,18 @@ failed: * Issue a series of SQL statements to implement the ADD/MODIFY/DELETE * requests in the ldb_message */ -static int lsqlite3_msg_to_sql(struct ldb_context *ldb, - const struct ldb_message *msg, - long long dn_id, - int use_flags) +static int +lsqlite3_msg_to_sql(struct ldb_context *ldb, + const struct ldb_message *msg, + long long dn_id, + int use_flags) { - int flags; - unsigned int i, j; - struct ldb_context *ldb = module->ldb; - struct lsqlite3_private *lsqlite3 = module->private_data; - sqlite3_stmt *stmt = NULL; + int flags; + unsigned int i; + unsigned int j; + sqlite3_stmt * stmt = NULL; + struct ldb_context * ldb = module->ldb; + struct lsqlite3_private * lsqlite3 = module->private_data; for (i = 0; i < msg->num_elements; i++) { const struct ldb_message_element *el = &msg->elements[i]; @@ -428,11 +445,13 @@ static int lsqlite3_msg_to_sql(struct ldb_context *ldb, /* * add a record */ -static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg) +static int +lsqlite3_add(struct ldb_module *module, + const struct ldb_message *msg) { - struct ldb_context *ldb = module->ldb; - struct lsqlite3_private *lsqlite3 = module->private_data; - int ret; + int ret; + struct ldb_context * ldb = module->ldb; + struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ if (msg->dn[0] == '@') { @@ -482,12 +501,13 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg /* * modify a record */ -static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) +static int +lsqlite3_modify(struct ldb_module *module, + const struct ldb_message *msg) { - struct ldb_context *ldb = module->ldb; - struct lsqlite3_private *lsqlite3 = module->private_data; - LDAPMod **mods; - int ret = 0; + int ret = 0; + struct ldb_context * ldb = module->ldb; + struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ if (msg->dn[0] == '@') { @@ -538,11 +558,13 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * return lsqlite3->last_rc == SQLITE_DONE && ret == 0 ? 0 : -1; } -static int lsqlite3_lock(struct ldb_module *module, const char *lockname) +static int +lsqlite3_lock(struct ldb_module *module, + const char *lockname) { - int ret = 0; - struct ldb_context *ldb = module->ldb; - struct lsqlite3_private *lsqlite3 = module->private_data; + int ret = 0; + struct ldb_context * ldb = module->ldb; + struct lsqlite3_private * lsqlite3 = module->private_data; if (lockname == NULL) { return -1; @@ -559,11 +581,13 @@ static int lsqlite3_lock(struct ldb_module *module, const char *lockname) return lsqlite3->last_rc == 0 ? 0 : -1; } -static int lsqlite3_unlock(struct ldb_module *module, const char *lockname) +static int +lsqlite3_unlock(struct ldb_module *module, + const char *lockname) { - int ret = 0; - struct ldb_context *ldb = module->ldb; - struct lsqlite3_private *lsqlite3 = module->private_data; + int ret = 0; + struct ldb_context * ldb = module->ldb; + struct lsqlite3_private * lsqlite3 = module->private_data; if (lockname == NULL) { return -1; @@ -587,9 +611,11 @@ static int lsqlite3_unlock(struct ldb_module *module, const char *lockname) /* * return extended error information */ -static const char *lsqlite3_errstring(struct ldb_module *module) +static const char * +lsqlite3_errstring(struct ldb_module *module) { - struct lsqlite3_private *lsqlite3 = module->private_data; + struct lsqlite3_private * lsqlite3 = module->private_data; + return sqlite3_errmsg(lsqlite3->sqlite3); } @@ -608,22 +634,25 @@ static const struct ldb_module_ops lsqlite3_ops = { }; -static int lsqlite3_destructor(void *p) +static int +lsqlite3_destructor(void *p) { - struct lsqlite3_private *lsqlite3 = p; + struct lsqlite3_private * lsqlite3 = p; + (void) sqlite3_close(lsqlite3->sqlite3); return 0; } -static int lsqlite3_initialize(lsqlite3_private *lsqlite3, - const char *url) +static int +lsqlite3_initialize(lsqlite3_private *lsqlite3, + const char *url) { - int bNewDatabase = False; - char *p; - char *pTail; - struct stat statbuf; - sqlite3_stmt *stmt; - const char *schema = + int bNewDatabase = False; + char * p; + char * pTail; + struct stat statbuf; + sqlite3_stmt * stmt; + const char * schema = " -- ------------------------------------------------------ @@ -983,13 +1012,14 @@ static int lsqlite3_initialize(lsqlite3_private *lsqlite3, /* * connect to the database */ -struct ldb_context *lsqlite3_connect(const char *url, - unsigned int flags, - const char *options[]) +struct ldb_context * +lsqlite3_connect(const char *url, + unsigned int flags, + const char *options[]) { - struct ldb_context *ldb = NULL; - struct lsqlite3_private *lsqlite3 = NULL; - int i; + int i; + struct ldb_context * ldb = NULL; + struct lsqlite3_private * lsqlite3 = NULL; ldb = talloc(NULL, struct ldb_context); if (!ldb) { diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema index d06d7d0c34..45be5b578f 100644 --- a/source4/lib/ldb/ldb_sqlite3/schema +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -12,110 +12,163 @@ SELECT 'LDB' AS database_type, '1.0' AS version; - CREATE TABLE ldb_distinguished_names + /* + * Get the next USN value with: + * BEGIN EXCLUSIVE; + * UPDATE usn SET value = value + 1; + * SELECT value FROM usn; + * COMMIT; + */ + CREATE TABLE usn ( - dn_id INTEGER PRIMARY KEY AUTOINCREMENT, - dn TEXT UNIQUE + value INTEGER ); - CREATE TABLE ldb_object_classes + CREATE TABLE ldb_object ( - class_name TEXT PRIMARY KEY, - tree_key TEXT, - max_child_num INTEGER - ); - - CREATE TABLE ldb_dn_object_classes - ( - dn_id INTEGER REFERENCES ldb_distinguished_names, - class_name TEXT REFERENCES ldb_object_classes + /* tree_key is auto-generated by the insert trigger */ + tree_key TEXT PRIMARY KEY, + + parent_tree_key TEXT, + full_path TEXT, + + attr_name TEXT REFERENCES ldb_attributes, + attr_value TEXT, + + /* + * object_type can take on these values (to date): + * 1: object is a node of a DN + * 2: object is an attribute/value pair of its parent DN + */ + object_type INTEGER, + + /* + * if object_type is 1, the node can have children. + * this tracks the maximum previously assigned child + * number so we can generate a new unique tree key for + * a new child object. note that this is always incremented, + * so if children are deleted, this will not represent + * the _number_ of children. + */ + max_child_num INTEGER, + + /* + * Automatically maintained meta-data (a gift for metze) + */ + object_guid TEXT UNIQUE, + timestamp INTEGER, -- originating_time + invoke_id TEXT, -- GUID: originating_invocation_id + usn INTEGER, -- hyper: originating_usn + + /* do not allow duplicate name/value pairs */ + UNIQUE (parent_tree_key, attr_name, attr_value, object_type) ); CREATE TABLE ldb_attributes ( attr_name TEXT PRIMARY KEY, - case_insensitive_p BOOLEAN DEFAULT FALSE, - wildcard_p BOOLEAN DEFAULT FALSE, - hidden_p BOOLEAN DEFAULT FALSE, - integer_p BOOLEAN DEFAULT FALSE - ); + parent_tree_key TEXT, - CREATE TABLE ldb_attr_value_pairs - ( - dn_id INTEGER REFERENCES ldb_distinguished_names, - attr_name TEXT, -- optionally REFERENCES ldb_attributes - attr_value TEXT, + objectclass_p BOOLEAN DEFAULT 0, + + case_insensitive_p BOOLEAN DEFAULT 0, + wildcard_p BOOLEAN DEFAULT 0, + hidden_p BOOLEAN DEFAULT 0, + integer_p BOOLEAN DEFAULT 0, - UNIQUE (dn_id, attr_name, attr_value) + /* tree_key is auto-generated by the insert trigger */ + tree_key TEXT, -- null if not a object/sub class + -- level 1 if an objectclass + -- level 1-n if a subclass + max_child_num INTEGER ); -- ------------------------------------------------------ - CREATE TRIGGER ldb_distinguished_names_delete_tr - AFTER DELETE - ON ldb_distinguished_names + CREATE INDEX ldb_object_full_path_idx + ON ldb_object (full_path); + + CREATE INDEX ldb_attributes_tree_key_ids + ON ldb_attributes (tree_key); + + -- ------------------------------------------------------ + + /* Gifts for metze. Automatically updated meta-data */ + CREATE TRIGGER ldb_object_insert_tr + AFTER INSERT + ON ldb_object FOR EACH ROW BEGIN - DELETE FROM ldb_attr_value_pairs - WHERE dn_id = old.dn_id; - DELETE FROM ldb_dn_object_classes - WHERE dn_id = old.dn_id; + UPDATE ldb_object + SET max_child_num = max_child_num + 1 + WHERE tree_key = new.parent_tree_key; + UPDATE usn SET value = value + 1; + UPDATE ldb_object + SET tree_key = + (SELECT + new.tree_key || + base160(SELECT max_child_num + FROM ldb_object + WHERE tree_key = + new.parent_tree_key)); + max_child_num = 0, + object_guid = random_guid(), + timestamp = strftime('%s', 'now'), + usn = (SELECT value FROM usn); + WHERE tree_key = new.tree_key; END; - CREATE TRIGGER ldb_attr_value_pairs_insert_tr - BEFORE INSERT - ON ldb_attr_value_pairs + CREATE TRIGGER ldb_object_update_tr + AFTER UPDATE + ON ldb_object FOR EACH ROW BEGIN - INSERT OR IGNORE INTO ldb_attributes - (attr_name) - VALUES - (new.attr_name); + UPDATE usn SET value = value + 1; + UPDATE ldb_object + SET timestamp = strftime('%s', 'now'), + usn = (SELECT value FROM usn); + WHERE tree_key = new.tree_key; END; - CREATE TRIGGER ldb_attr_value_pairs_delete_tr - AFTER DELETE - ON ldb_attr_value_pairs + CREATE TRIGGER ldb_attributes_insert_tr + AFTER INSERT + ON ldb_attributes FOR EACH ROW BEGIN - DELETE FROM ldb_attributes - WHERE (SELECT COUNT(*) - FROM ldb_attr_value_pairs - WHERE attr_name = old.attr_name) = 0 - AND attr_name = old.attr_name; + UPDATE ldb_attributes + SET max_child_num = max_child_num + 1 + WHERE tree_key = new.parent_tree_key; + UPDATE ldb_attributes + SET tree_key = + (SELECT + new.tree_key || + base160(SELECT max_child_num + FROM ldb_attributes + WHERE tree_key = + new.parent_tree_key)); + max_child_num = 0 + WHERE tree_key = new.tree_key; END; - -- ------------------------------------------------------ - - CREATE INDEX ldb_distinguished_names_dn_idx - ON ldb_distinguished_names (dn); - - CREATE INDEX ldb_object_classes_tree_key_idx - ON ldb_object_classes (tree_key); - - - CREATE INDEX ldb_dn_object_classes_dn_id_idx - ON ldb_dn_object_classes (dn_id); - - CREATE INDEX ldb_dn_object_classes_class_name_idx - ON ldb_dn_object_classes (class_name); - - - CREATE INDEX ldb_attr_value_pairs_dn_id_name_case_idx - ON ldb_attr_value_pairs (dn_id, attr_name); - - CREATE INDEX ldb_attr_value_pairs_dn_id_name_nocase_idx - ON ldb_attr_value_pairs (dn_id, attr_name COLLATE NOCASE); -- ------------------------------------------------------ - /* all defaults for dn, initially */ - INSERT INTO ldb_attributes (attr_name) - VALUES ('dn'); + /* Initialize usn */ + INSERT INTO usn (value) VALUES (0); + + /* Create root object */ + INSERT INTO ldb_object + (tree_key, parent_tree_key, + full_path, + object_type, max_child_num) + VALUES ('', NULL, + '', + 1, 0); /* We need an implicit "top" level object class */ - INSERT INTO ldb_object_classes (class_name, tree_key) - SELECT 'top', /* next_tree_key(NULL) */ '0001'; + INSERT INTO ldb_attributes (attr_name, + parent_tree_key) + SELECT 'top', ''; -- ------------------------------------------------------ @@ -129,63 +182,103 @@ * objectclass: domainRelatedObject */ -- newDN -INSERT INTO ldb_distinguished_names (dn_id, dn) - VALUES (1, 'o=University of Michigan,c=US'); +BEGIN; + +INSERT OR IGNORE INTO ldb_object + (parent_tree_key + full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('', + 'c=US', + 'c', 'US', 1, 0); + +INSERT INTO ldb_object + (parent_tree_key, + full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('0001', + 'o=University of Michigan,c=US', + 'o', 'University of Michigan', 1, 0); -- newObjectClass -INSERT OR IGNORE INTO ldb_object_classes (class_name, tree_key) - SELECT 'organization', /* next_tree_key(NULL) */ '0002'; - -INSERT OR IGNORE INTO ldb_object_classes (class_name, tree_key) - SELECT 'domainRelatedObject', /* next_tree_key(NULL) */ '0003'; +INSERT OR IGNORE INTO ldb_attributes + (attr_name, parent_tree_key, objectclass_p) + VALUES + ('objectclass', '', 1); + +INSERT INTO ldb_object + (parent_tree_key, + full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', + NULL, + 'objectclass', 'organization', 2, 0); + +INSERT OR IGNORE INTO ldb_attributes + (attr_name, parent_tree_key, objectclass_p) + VALUES + ('objectclass', '', 1); + +INSERT INTO ldb_object + (parent_tree_key, + full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', + NULL, + 'objectclass', 'domainRelatedObject', 2, 0); + +COMMIT; --- assignObjectClass -INSERT OR IGNORE INTO ldb_dn_object_classes (dn_id, class_name) - VALUES (1, 'organization'); - -INSERT OR IGNORE INTO ldb_dn_object_classes (dn_id, class_name) - VALUES (1, 'domainRelatedObject'); /* + * dn: o=University of Michigan,c=US * l: Ann Arbor, Michigan * st: Michigan * o: University of Michigan * o: UMICH - * o: UM - * o: U-M - * o: U of M - * description: The University of Michigan at Ann Arbor * seeAlso: - * postaladdress: University of Michigan $ 535 W. William St. $ Ann Arbor, MI 481 - * 09 $ US * telephonenumber: +1 313 764-1817 - * associateddomain: example.com */ -- addAttrValuePair -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'l', 'Ann Arbor, Michigan'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'st', 'Michigan'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'o', 'University of Michigan'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'o', 'UMICH'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'o', 'UM'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'o', 'U-M'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'o', 'U of M'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'description', 'The University of Michigan at Ann Arbor'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'seeAlso', ''); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'postaladdress', 'University of Michigan $ 535 W. William St. $ Ann Arbor, MI 48109 $ US'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'telephonenumber', '+1 313 764-1817'); -INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) - VALUES (1, 'associateddomain', 'example.com'); +BEGIN; + +INSERT INTO ldb_object + (parent_tree_key, full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'l', 'Ann Arbor, Michigan', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'st', 'Michigan', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'o', 'University of Michigan', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'o', 'UMICH', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'seeAlso', '', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, full_path, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'telephonenumber', '+1 313 764-1817', 2, 0); + +COMMIT; -- ---------------------------------------------------------------------- @@ -197,18 +290,41 @@ INSERT INTO ldb_attr_value_pairs (dn_id, attr_name, attr_value) * dn: CASE_INSENSITIVE */ -- newAttribute -INSERT OR REPLACE INTO ldb_attributes - (attr_name, case_insensitive_p, wildcard_p, hidden_p, integer_p) - VALUES ('uid', 1, 1, 0, 0); -INSERT OR REPLACE INTO ldb_attributes - (attr_name, case_insensitive_p, wildcard_p, hidden_p, integer_p) - VALUES ('cn', 1, 0, 0, 0); -INSERT OR REPLACE INTO ldb_attributes - (attr_name, case_insensitive_p, wildcard_p, hidden_p, integer_p) - VALUES ('ou', 1, 0, 0, 0); -INSERT OR REPLACE INTO ldb_attributes - (attr_name, case_insensitive_p, wildcard_p, hidden_p, integer_p) - VALUES ('dn', 1, 0, 0, 0); + +BEGIN; + +INSERT OR IGNORE INTO ldb_attributes + (attr_name, parent_tree_key, objectclass_p) + VALUES + ('uid', '', 0); + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 1, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'uid' + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 0, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'cn' + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 0, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'ou' + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 0, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'dn' -- ---------------------------------------------------------------------- @@ -224,6 +340,10 @@ INSERT OR REPLACE INTO ldb_attributes * user: computer */ -- insertSubclass + +/* NOT YET UPDATED!!! * + + INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) SELECT 'domain', /* next_tree_key('top') */ '00010001'; INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) @@ -240,3 +360,4 @@ INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) SELECT 'OpenLDAPperson', /* next_tree_key('organizationPerson') */ '0001000200010002'; INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) SELECT 'computer', /* next_tree_key('user') */ '0001000200010001'; + -- cgit From 6ade5fc245a6f56b991b1b66742509270d65479d Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 4 Jun 2005 02:31:45 +0000 Subject: r7260: save current schema before I blow it away to try something different (This used to be commit 676a9824934576056208d30ce34716cfb734ce58) --- source4/lib/ldb/ldb_sqlite3/schema | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema index 45be5b578f..08dc50de08 100644 --- a/source4/lib/ldb/ldb_sqlite3/schema +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -30,7 +30,7 @@ tree_key TEXT PRIMARY KEY, parent_tree_key TEXT, - full_path TEXT, + dn TEXT, attr_name TEXT REFERENCES ldb_attributes, attr_value TEXT, @@ -85,8 +85,8 @@ -- ------------------------------------------------------ - CREATE INDEX ldb_object_full_path_idx - ON ldb_object (full_path); + CREATE INDEX ldb_object_dn_idx + ON ldb_object (dn); CREATE INDEX ldb_attributes_tree_key_ids ON ldb_attributes (tree_key); @@ -159,7 +159,7 @@ /* Create root object */ INSERT INTO ldb_object (tree_key, parent_tree_key, - full_path, + dn, object_type, max_child_num) VALUES ('', NULL, '', @@ -186,7 +186,7 @@ BEGIN; INSERT OR IGNORE INTO ldb_object (parent_tree_key - full_path, + dn, attr_name, attr_value, object_type, max_child_num) VALUES ('', 'c=US', @@ -194,7 +194,7 @@ INSERT OR IGNORE INTO ldb_object INSERT INTO ldb_object (parent_tree_key, - full_path, + dn, attr_name, attr_value, object_type, max_child_num) VALUES ('0001', 'o=University of Michigan,c=US', @@ -208,7 +208,7 @@ INSERT OR IGNORE INTO ldb_attributes INSERT INTO ldb_object (parent_tree_key, - full_path, + dn, attr_name, attr_value, object_type, max_child_num) VALUES ('00010001', NULL, @@ -221,7 +221,7 @@ INSERT OR IGNORE INTO ldb_attributes INSERT INTO ldb_object (parent_tree_key, - full_path, + dn, attr_name, attr_value, object_type, max_child_num) VALUES ('00010001', NULL, @@ -243,37 +243,37 @@ COMMIT; BEGIN; INSERT INTO ldb_object - (parent_tree_key, full_path, + (parent_tree_key, dn, attr_name, attr_value, object_type, max_child_num) VALUES ('00010001', NULL, 'l', 'Ann Arbor, Michigan', 2, 0); INSERT INTO ldb_object - (parent_tree_key, full_path, + (parent_tree_key, dn, attr_name, attr_value, object_type, max_child_num) VALUES ('00010001', NULL, 'st', 'Michigan', 2, 0); INSERT INTO ldb_object - (parent_tree_key, full_path, + (parent_tree_key, dn, attr_name, attr_value, object_type, max_child_num) VALUES ('00010001', NULL, 'o', 'University of Michigan', 2, 0); INSERT INTO ldb_object - (parent_tree_key, full_path, + (parent_tree_key, dn, attr_name, attr_value, object_type, max_child_num) VALUES ('00010001', NULL, 'o', 'UMICH', 2, 0); INSERT INTO ldb_object - (parent_tree_key, full_path, + (parent_tree_key, dn, attr_name, attr_value, object_type, max_child_num) VALUES ('00010001', NULL, 'seeAlso', '', 2, 0); INSERT INTO ldb_object - (parent_tree_key, full_path, + (parent_tree_key, dn, attr_name, attr_value, object_type, max_child_num) VALUES ('00010001', NULL, 'telephonenumber', '+1 313 764-1817', 2, 0); -- cgit From a1ba224107fbcf6f8a9a3091f42cde2a0c47f85e Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 4 Jun 2005 17:13:43 +0000 Subject: r7276: - moved static tdb function ltdb_dn_fold() into common/ so that it can be called from multiple backends. (ldb_sqlite3 needs it too.) Added parameter for a callback function that determines whether an attribute needs case folding. - begin to prepare for sqlite3 in build process - work-in-progress updates, on ldb_sqlite3 (This used to be commit a80bced0b96ffb655559a43cf7f4d7a34deb5a7d) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 669 +++++++++++------------------- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 18 - source4/lib/ldb/ldb_sqlite3/schema | 207 ++++----- 3 files changed, 327 insertions(+), 567 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index d36ced2667..0bce078a85 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -37,15 +37,16 @@ #include "ldb/include/ldb_private.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" -#undef SQL_EXEC /* just in case; not expected to be defined */ -#define SQL_EXEC(lsqlite3, query, reset) \ - do { \ - lsqlite3->last_rc = \ - sqlite3_step(lsqlite3->queries.query); \ - if (lsqlite3->last_rc == SQLITE_BUSY || reset) \ - (void) sqlite3_reset(lsqlite3->queries.query); \ - } while lsqlite3->last_rc == SQLITE_BUSY; - +#define QUERY(lsqlite3, pppValues, pNumRows, bRollbackOnError, sql...) \ + do \ + { \ + if (query(lsqlite3, pppValues, pNumRows, sql) != 0) { \ + if (bRollbackOnError) { \ + query(lsqlite3, NULL, NULL, "ROLLBACK;"); \ + } \ + return -1; \ + } \ + } while (0) #if 0 @@ -93,28 +94,8 @@ lsqlite3_rename(struct ldb_module *module, return 0; } - /* Bind old distinguished names */ - column = sqlite3_bind_parameter_index(lsqlite3->queries.renameDN, - ":oldDN"); - if (sqlite3_bind_text(lsqlite3->queries.renameDN, column, - olddn, strlen(olddn), - SQLITE_STATIC) != SQLITE_OK) { - return -1; - } - - /* Bind new distinguished names */ - column = sqlite3_bind_parameter_index(lsqlite3->queries.renameDN, - ":newDN"); - if (sqlite3_bind_text(lsqlite3->queries.renameDN, column, - newdn, strlen(newdn), - SQLITE_STATIC) != SQLITE_OK) { - return -1; - } - - /* Execute the query. This sets lsqlite3->last_rc */ - SQL_EXEC(lsqlite3, renameDN, TRUE); - - return lsqlite3->last_rc == 0 ? 0 : -1; +#warning "rename() is not yet supported" + return -1; } /* @@ -133,19 +114,7 @@ lsqlite3_delete(struct ldb_module *module, return 0; } - /* Bind distinguished names */ - column = sqlite3_bind_parameter_index(lsqlite3->queries.deleteDN, - ":dn"); - if (sqlite3_bind_text(lsqlite3->queries.deleteDN, column, - dn, strlen(dn), - SQLITE_STATIC) != SQLITE_OK) { - return -1; - } - - /* Execute the query. This sets lsqlite3->last_rc */ - SQL_EXEC(lsqlite3, deleteDN, TRUE); - - return lsqlite3->last_rc == 0 ? 0 : -1; + return -1; } /* @@ -332,9 +301,9 @@ failed: * requests in the ldb_message */ static int -lsqlite3_msg_to_sql(struct ldb_context *ldb, +lsqlite3_msg_to_sql(struct ldb_module *module, const struct ldb_message *msg, - long long dn_id, + long long eid, int use_flags) { int flags; @@ -353,88 +322,75 @@ lsqlite3_msg_to_sql(struct ldb_context *ldb, flags = el->flags & LDB_FLAG_MOD_MASK; } - /* Determine which query to use */ - switch (flags) { - case LDB_FLAG_MOD_ADD: - stmt = lsqlite3->queries.addAttrValuePair; - break; - - case LDB_FLAG_MOD_DELETE: - stmt = lsqlite3->queries.deleteAttrValuePairs; - break; - - case LDB_FLAG_MOD_REPLACE: - stmt = lsqlite3->queries.replaceAttrValuePairs; - break; - } - - /* - * All queries use dn id and attribute name. Bind them now. - */ - - /* Bind distinguished name id */ - column = - sqlite3_bind_parameter_index( - stmt, - ":dn_id"); - if (sqlite3_bind_int64(stmt, - column, - dn_id) != SQLITE_OK) { - - return -1; - } - - /* Bind attribute name */ - column = - sqlite3_bind_parameter_index( - stmt, - ":attr_name"); - if (sqlite3_bind_text(lsqlite3->queries.deleteDN, column, - el->name, strlen(el->name), - SQLITE_STATIC) != SQLITE_OK) { - - return -1; + if (flags == LDB_FLAG_MOD_ADD) { + /* Create the attribute table if it doesn't exist */ + if (create_attr_table(module, el->name) != 0) { + return -1; + } } - /* For each value of the specified attribute name... */ for (j = 0; j < el->num_values; j++) { /* ... bind the attribute value, if necessary */ switch (flags) { case LDB_FLAG_MOD_ADD: - case LDB_FLAG_MOD_REPLACE: - /* Bind attribute value */ - column = - sqlite3_bind_parameter_index( - stmt, - ":attr_value"); - if (sqlite3_bind_text( - stmt, column, - el->values[j].data, - el->values[j].length, - SQLITE_STATIC) != SQLITE_OK) { - - return -1; - } + QUERY(lsqlite3, + NULL, NULL, + FALSE, + "INSERT INTO ldb_attr_%q " + " (eid, attr_value) " + " VALUES " + " (%lld, %Q);", + eid, el->data); + QUERY(lsqlite3, + NULL, NULL, + FALSE, + "UPDATE ldb_entry " + " SET entry_data = " + " add_attr(entry_data, %Q, %Q) " + " WHERE eid = %lld;", + el->name, el->data, eid); + + break; + case LDB_FLAG_MOD_REPLACE: + QUERY(lsqlite3, + NULL, NULL, + FALSE, + "UPDATE ldb_attr_%q " + " SET attr_value = %Q " + " WHERE eid = %lld;", + el->data, eid); + QUERY(lsqlite3, + NULL, NULL, + FALSE, + "UPDATE ldb_entry " + " SET entry_data = " + " mod_attr(entry_data, %Q, %Q) " + " WHERE eid = %lld;", + el->name, el->data, eid); break; case LDB_FLAG_MOD_DELETE: /* No additional parameters to this query */ + QUERY(lsqlite3, + NULL, NULL, + FALSE, + "DELETE FROM ldb_attr_%q " + " WHERE eid = %lld " + " AND attr_value = %Q;", + eid, el->data); + QUERY(lsqlite3, + NULL, NULL, + FALSE, + "UPDATE ldb_entry " + " SET entry_data = " + " del_attr(entry_data, %Q, %Q) " + " WHERE eid = %lld;", + el->name, el->data, eid); break; } - - /* Execute the query */ - do { - lsqlite3->last_rc = sqlite3_step(stmt); - (void) sqlite3_reset(stmt); - } while lsqlite3->last_rc == SQLITE_BUSY; - - /* Make sure we succeeded */ - if (lsqlite3->last_rc != SQLITE_OK) { - return -1; - } } } @@ -442,6 +398,35 @@ lsqlite3_msg_to_sql(struct ldb_context *ldb, } +static char * +lsqlite3_normalize_dn(struct ldb_context * ldb, + char * pDN) +{ + char * pSrc; + char * pDest; + char * pNormalized; + + pNormalized = talloc_size(ldb, strlen(pDN) + 1); + if (pNormalized == NULL) { + errno = ENOMEM; + return -1; + } + + for (pSrc = pDN, pDest = pNormalized; *pSrc != '\0'; ) { + + } +} + + +static int +lsqlite3_insert_dn_recursive(struct lsqlite3_private * lsqlite3, + char * pDN, + long long * pEID) +{ + +} + + /* * add a record */ @@ -450,6 +435,7 @@ lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg) { int ret; + long long eid; struct ldb_context * ldb = module->ldb; struct lsqlite3_private * lsqlite3 = module->private_data; @@ -459,42 +445,28 @@ lsqlite3_add(struct ldb_module *module, } /* Begin a transaction */ - SQL_EXEC(lsqlite3, begin, TRUE); + QUERY(lsqlite3, NULL, NULL< FALSE, "BEGIN EXCLUSIVE;"); - /* This is a new DN. Bind new distinguished name */ - column = sqlite3_bind_parameter_index(lsqlite3->queries.newDN, ":dn"); - if (sqlite3_bind_text(lsqlite3->queries.newDN, column, - msg->dn, strlen(msg->dn), - SQLITE_STATIC) != SQLITE_OK) { - return -1; - } - - /* Add this new DN. This sets lsqlite3->last_rc */ - SQL_EXEC(lsqlite3, newDN, TRUE); - - if (lsqlite3->last_rc != SQLITE_DONE) { + /* + * Build any portions of the directory tree that don't exist. If the + * final component already exists, it's an error. + */ + if (lsqlite3_insert_dn_recursive(lsqlite3, + lsqlite3_normalize_dn(ldb, msg->dn), + &eid) != 0) { + QUERY(lsqlite3, NULL, NULL, FALSE, "ROLLBACK;"); return -1; } - - /* Get the id of the just-added DN */ - dn_id = sqlite3_last_insert_rowid(lsqlite3->sqlite3); - - ret = lsqlite3_msg_to_sql(ldb, msg, dn_id, FALSE); - /* Did the attribute additions (if any) succeeded? */ - if (ret == 0) - { - /* Yup. Commit the transaction */ - SQL_EXEC(lsqlite3, commit, TRUE); - } - else - { - /* Attribute addition failed. Rollback the transaction */ - SQL_EXEC(lsqlite3, rollback, TRUE); + /* Add attributes to this new entry */ + if (lsqlite3_msg_to_sql(module, msg, eid, FALSE) != 0) { + QUERY(lsqlite3, NULL, NULL, FALSE, "ROLLBACK;"); + return -1; } - /* If everything succeeded, return success */ - return lsqlite3->last_rc == SQLITE_DONE && ret == 0 ? 0 : -1; + /* Everything worked. Commit it! */ + QUERY(lsqlite3, NULL, NULL, TRUE, "COMMIT;"); + return 0; } @@ -506,6 +478,8 @@ lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) { int ret = 0; + int numRows; + char ** ppValues; struct ldb_context * ldb = module->ldb; struct lsqlite3_private * lsqlite3 = module->private_data; @@ -515,47 +489,37 @@ lsqlite3_modify(struct ldb_module *module, } /* Begin a transaction */ - SQL_EXEC(lsqlite3, begin, TRUE); - - /* Get the dn_id for the specified DN */ - column = - sqlite3_bind_parameter_index( - lsqlite3->queries.getDNID, - ":dn"); - if (sqlite3_bind_text(lsqlite3->queries.getDNID, - column, - msg->dn, strlen(msg->dn), - SQLITE_STATIC) != SQLITE_OK) { + QUERY(lsqlite3, NULL, NULL, FALSE, "BEGIN EXCLUSIVE;"); + + /* Get the id of this DN. */ + QUERY(lsqlite3, + &ppValues, + &numRows, + TRUE, + "SELECT eid " + " FROM ldb_entry " + " WHERE dn = %Q;", + lsqlite3_normalize_dn(ldb, msg->dn)); + + /* Did it exist? */ + if (numRows != 1) { + /* Nope. See ya! */ + sqlite_free_table(ppValues); return -1; } - /* Get the id of this DN. This sets lsqlite3->last_rc */ - SQL_EXEC(lsqlite3, getDNID, FALSE); - - if (lsqlite3->last_rc != SQLITE_ROW) { - return -1; - } - - dn_id = sqlite3_column_int64(lsqlite3->queries.getDNID, - column); - (void) sqlite3_reset(lsqlite3->queries.getDNID); - - ret = lsqlite3_msg_to_sql(ldb, msg, dn_id, FALSE); + /* Retrieve the eid */ + eid = strtoll(ppValues[1], NULL, 10); - /* Did the attribute additions (if any) succeeded? */ - if (ret == 0) - { - /* Yup. Commit the transaction */ - SQL_EXEC(lsqlite3, commit, TRUE); - } - else - { - /* Attribute addition failed. Rollback the transaction */ - SQL_EXEC(lsqlite3, rollback, TRUE); + /* Modify attributes as specified */ + if (lsqlite3_msg_to_sql(module, msg, eid, FALSE) != 0) { + QUERY(lsqlite3, NULL, NULL, FALSE, "ROLLBACK;"); + return -1; } - /* If everything succeeded, return success */ - return lsqlite3->last_rc == SQLITE_DONE && ret == 0 ? 0 : -1; + /* Everything worked. Commit it! */ + QUERY(lsqlite3, NULL, NULL, TRUE, "COMMIT;"); + return 0 ; } static int @@ -570,15 +534,9 @@ lsqlite3_lock(struct ldb_module *module, return -1; } - /* If we're already locked, just update lock count */ - if (++lsqlite3->lock_count > 1) { - return -1; - } - - /* Write-lock (but not read-lock) the database */ - SQL_EXEC(lsqlite3, begin, TRUE); + /* TODO implement a local locking mechanism here */ - return lsqlite3->last_rc == 0 ? 0 : -1; + return 0; } static int @@ -593,19 +551,9 @@ lsqlite3_unlock(struct ldb_module *module, return -1; } - /* If we're not already locked, there's nothing to do */ - if (lsqlite3->lock_count == 0) { - return 0; - } + /* TODO implement a local locking mechanism here */ - /* Decrement lock count */ - if (--lsqlite3->lock_count == 0) { - - /* Final unlock. Unlock the database */ - SQL_EXEC(lsqlite3, commit, TRUE); - } - - return lsqlite3->last_rc == 0 ? 0 : -1; + return 0; } /* @@ -647,6 +595,7 @@ static int lsqlite3_initialize(lsqlite3_private *lsqlite3, const char *url) { + int ret; int bNewDatabase = False; char * p; char * pTail; @@ -668,110 +617,124 @@ lsqlite3_initialize(lsqlite3_private *lsqlite3, SELECT 'LDB' AS database_type, '1.0' AS version; - CREATE TABLE ldb_distinguished_names - ( - dn_id INTEGER PRIMARY KEY AUTOINCREMENT, - dn TEXT UNIQUE - ); + -- ------------------------------------------------------ + -- Schema - CREATE TABLE ldb_object_classes + /* + * The entry table holds the information about an entry. This + * table is used to obtain the EID of the entry and to support + * scope=one and scope=base. The parent and child table + * is included in the entry table since all the other + * attributes on EID. + */ + CREATE TABLE ldb_entry ( - class_name TEXT PRIMARY KEY, - tree_key TEXT, - max_child_num INTEGER + -- Unique identifier of this LDB entry + eid INTEGER PRIMARY KEY, + + -- Unique identifier of the parent LDB entry + peid INTEGER REFERENCES ldb_entry, + + -- Distinguished name of this entry + dn TEXT, + + -- Time when the entry was created + create_timestamp INTEGER, + + -- Time when the entry was last modified + modify_timestamp INTEGER, + + -- Attributes of this entry, in the form + -- attr\1value\0[attr\1value\0]*\0 + entry_data TEXT ); - CREATE TABLE ldb_dn_object_classes + + /* + * The purpose of the descendant table is to support the + * subtree search feature. For each LDB entry with a unique + * ID (AEID), this table contains the unique identifiers + * (DEID) of the descendant entries. + * + * For evern entry in the directory, a row exists in this + * table for each of its ancestors including itself. The size + * of the table depends on the depth of each entry. In the + * worst case, if all the entries were at the same depth, the + * number of rows in the table is O(nm) where n is the number + * of nodes in the directory and m is the depth of the tree. + */ + CREATE TABLE ldb_descendants ( - dn_id INTEGER REFERENCES ldb_distinguished_names, - class_name TEXT REFERENCES ldb_object_classes + -- The unique identifier of the ancestor LDB entry + aeid INTEGER REFERENCES ldb_entry, + + -- The unique identifier of the descendant LDB entry + deid INTEGER REFERENCES ldb_entry ); - CREATE TABLE ldb_attributes + + CREATE TABLE ldb_object_classes ( - attr_name TEXT PRIMARY KEY, - case_insensitive_p BOOLEAN DEFAULT FALSE, - wildcard_p BOOLEAN DEFAULT FALSE, - hidden_p BOOLEAN DEFAULT FALSE, - integer_p BOOLEAN DEFAULT FALSE + -- Object classes are inserted into this table to track + -- their class hierarchy. 'top' is the top-level class + -- of which all other classes are subclasses. + class_name TEXT PRIMARY KEY, + + -- tree_key tracks the position of the class in + -- the hierarchy + tree_key TEXT UNIQUE ); - CREATE TABLE ldb_attr_value_pairs + /* + * There is one attribute table per searchable attribute. + */ +/* + CREATE TABLE ldb_attr_ATTRIBUTE_NAME ( - dn_id INTEGER REFERENCES ldb_distinguished_names, - attr_name TEXT, -- optionally REFERENCES ldb_attributes - attr_value TEXT, + -- The unique identifier of the LDB entry + eid INTEGER REFERENCES ldb_entry, - UNIQUE (dn_id, attr_name, attr_value) + -- Normalized attribute value + attr_value TEXT ); +*/ + -- ------------------------------------------------------ + -- Indexes - CREATE TRIGGER ldb_distinguished_names_delete_tr - AFTER DELETE - ON ldb_distinguished_names - FOR EACH ROW - BEGIN - DELETE FROM ldb_attr_value_pairs - WHERE dn_id = old.dn_id; - DELETE FROM ldb_dn_object_classes - WHERE dn_id = old.dn_id; - END; - CREATE TRIGGER ldb_attr_value_pairs_insert_tr - BEFORE INSERT - ON ldb_attr_value_pairs + -- ------------------------------------------------------ + -- Triggers + + CREATE TRIGGER ldb_entry_insert_tr + AFTER INSERT + ON ldb_entry FOR EACH ROW BEGIN - INSERT OR IGNORE INTO ldb_attributes - (attr_name) - VALUES - (new.attr_name); + UPDATE ldb_entry + SET create_timestamp = strftime('%s', 'now'), + modify_timestamp = strftime('%s', 'now') + WHERE eid = new.eid; END; - CREATE TRIGGER ldb_attr_value_pairs_delete_tr - AFTER DELETE - ON ldb_attr_value_pairs + CREATE TRIGGER ldb_entry_update_tr + AFTER UPDATE + ON ldb_entry FOR EACH ROW BEGIN - DELETE FROM ldb_attributes - WHERE (SELECT COUNT(*) - FROM ldb_attr_value_pairs - WHERE attr_name = old.attr_name) = 0 - AND attr_name = old.attr_name; + UPDATE ldb_entry + SET modify_timestamp = strftime('%s', 'now') + WHERE eid = old.eid; END; -- ------------------------------------------------------ + -- Table initialization - CREATE INDEX ldb_distinguished_names_dn_idx - ON ldb_distinguished_names (dn); - - CREATE INDEX ldb_object_classes_tree_key_idx - ON ldb_object_classes (tree_key); - - - CREATE INDEX ldb_dn_object_classes_dn_id_idx - ON ldb_dn_object_classes (dn_id); - - CREATE INDEX ldb_dn_object_classes_class_name_idx - ON ldb_dn_object_classes (class_name); - - - CREATE INDEX ldb_attr_value_pairs_dn_id_name_case_idx - ON ldb_attr_value_pairs (dn_id, attr_name); - - CREATE INDEX ldb_attr_value_pairs_dn_id_name_nocase_idx - ON ldb_attr_value_pairs (dn_id, attr_name COLLATE NOCASE); - - -- ------------------------------------------------------ - - /* all defaults for dn, initially */ - INSERT INTO ldb_attributes (attr_name) - VALUES ('dn'); - - /* We need an implicit 'top' level object class */ - INSERT INTO ldb_object_classes (class_name, tree_key) - SELECT 'top', /* next_tree_key(NULL) */ '0001'; + /* We need an implicit "top" level object class */ + INSERT INTO ldb_attributes (attr_name, + parent_tree_key) + SELECT 'top', ''; -- ------------------------------------------------------ @@ -797,7 +760,7 @@ lsqlite3_initialize(lsqlite3_private *lsqlite3, } /* Try to open the (possibly empty/non-existent) database */ - if ((lsqlite3->last_rc = sqlite3_open(p, &lsqlite3->sqlite3)) != SQLITE_SUCCESS) { + if ((ret = sqlite3_open(p, &lsqlite3->sqlite3)) != SQLITE_SUCCESS) { return ret; } @@ -831,18 +794,15 @@ lsqlite3_initialize(lsqlite3_private *lsqlite3, " WHERE type = 'table' " " AND name IN " " (" - " 'ldb_info', " - " 'ldb_distinguished_names', " - " 'ldb_object_classes', " - " 'ldb_dn_object_classes', " - " 'ldb_attributes', " - " 'ldb_attr_value_pairs' " + " 'ldb_entry', " + " 'ldb_descendants', " + " 'ldb_object_classes' " " );", -1, &stmt, &pTail)) != SQLITE_SUCCESS || (lsqlite3->last_rc = sqlite3_step(stmt)) != SQLITE_ROW || - sqlite3_column_int(stmt, 0) != 6 || + sqlite3_column_int(stmt, 0) != 3 || (lsqlite3->last_rc = sqlite_finalize(stmt)) != SQLITE_SUCCESS || (lsqlite3->last_rc = sqlite3_prepare( @@ -863,149 +823,6 @@ lsqlite3_initialize(lsqlite3_private *lsqlite3, } } - /* - * Pre-compile each of the queries we'll be using. - */ - - if ((lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "BEGIN IMMEDIATE;", - -1, - &lsqlite3->queries.begin, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "COMMIT;", - -1, - &lsqlite3->queries.commit, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "ROLLBACK;", - -1, - &lsqlite3->queries.rollback, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "INSERT INTO ldb_distinguished_names (dn_id, dn) " - " VALUES (:dn_id, :dn);", - -1, - &lsqlite3->queries.newDN, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "UPDATE ldb_distinguished_names " - " SET dn = :newDN " - " WHERE dn = :oldDN;", - -1, - &lsqlite3->queries.renameDN, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "DELETE FROM ldb_distinguished_names " - " WHERE dn = :dn;", - -1, - &lsqlite3->queries.deleteDN, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "INSERT OR IGNORE INTO ldb_object_classes " - " (class_name, tree_key)" - " SELECT :class_name, next_tree_key(NULL);", - -1, - &lsqlite3->queries.newObjectClass, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "INSERT OR REPLACE INTO ldb_dn_object_classes " - " (dn_id, class_name) " - " VALUES (:dn_id, :class_name);", - -1, - &lsqlite3->queries.assignObjectClass, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "INSERT OR IGNORE INTO ldb_attributes (name) " - " VALUES (:name);", - -1, - &lsqlite3->queries.newAttributeUseDefaults, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "INSERT OR REPLACE INTO ldb_attributes " - " (name, " - " case_insensitive_p, " - " wildcard_p, " - " hidden_p, " - " integer_p) " - " VALUES (:name, " - " :case_insensitive_p, " - " :wildcard_p, " - " :hidden_p, " - " :integer_p);", - -1, - &lsqlite3->queries.newAttribute, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "INSERT INTO ldb_attr_value_pairs " - " (dn_id, attr_name, attr_value) " - " VALUES (:dn_id, :attr_name, :attr_value);", - -1, - &lsqlite3->queries.addAttrValuePair, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "UPDATE ldb_attr_value_pairs " - " SET attr_value = :attr_value " - " WHERE dn_id = :dn_id " - " AND attr_name = :attr_name;", - -1, - &lsqlite3->queries.addAttrValuePair, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "DELETE FROM ldb_attr_value_pairs " - " WHERE dn_id = :dn_id " - " AND attr_name = :attr_name;" - -1, - &lsqlite3->queries.deleteAttrValuePair, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "INSERT OR REPLACE INTO ldb_object_classes " - " (class_name, tree_key) " - " SELECT :child_class, next_tree_key(:parent_class);" - -1, - &lsqlite3->queries.insertSubclass, - &pTail)) != SQLITE_SUCCESS || - - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, - "SELECT dn_id " - " FROM ldb_distinguished_names " - " WHERE dn = :dn;" - -1, - &lsqlite3->queries.getDNID, - &pTail)) != SQLITE_SUCCESS) { - - (void) sqlite3_close(lsqlite3->sqlite3); - return ret; - } - return SQLITE_SUCCESS; } diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h index 2fa08fdcb7..192e28f3dc 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h @@ -5,24 +5,6 @@ struct lsqlite3_private { const char *basedn; sqlite3 * sqlite; int lock_count; - int last_rc; - struct { - sqlite3_stmt *begin; - sqlite3_stmt *commit; - sqlite3_stmt *rollback; - sqlite3_stmt *newDN; - sqlite3_stmt *renameDN; - sqlite3_stmt *deleteDN; - sqlite3_stmt *newObjectClass; - sqlite3_stmt *assignObjectClass; - sqlite3_stmt *newAttributeUseDefaults; - sqlite3_stmt *newAttribute; - sqlite3_stmt *addAttrValuePair; - sqlite3_stmt *replaceAttrValuePairs; - sqlite3_stmt *deleteAttrValuePairs; - sqlite3_stmt *insertSubclass; - sqlite3_stmt *getDNID; - } queries; }; void diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema index 08dc50de08..78550985d4 100644 --- a/source4/lib/ldb/ldb_sqlite3/schema +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -12,158 +12,119 @@ SELECT 'LDB' AS database_type, '1.0' AS version; + -- ------------------------------------------------------ + -- Schema + /* - * Get the next USN value with: - * BEGIN EXCLUSIVE; - * UPDATE usn SET value = value + 1; - * SELECT value FROM usn; - * COMMIT; + * The entry table holds the information about an entry. This + * table is used to obtain the EID of the entry and to support + * scope="one" and scope="base". The parent and child table + * is included in the entry table since all the other + * attributes on EID. */ - CREATE TABLE usn + CREATE TABLE ldb_entry ( - value INTEGER + -- Unique identifier of this LDB entry + eid INTEGER PRIMARY KEY, + + -- Unique identifier of the parent LDB entry + peid INTEGER REFERENCES ldb_entry, + + -- Distinguished name of this entry + dn TEXT, + + -- Time when the entry was created + create_timestamp INTEGER, + + -- Time when the entry was last modified + modify_timestamp INTEGER, + + -- Attributes of this entry, in the form + -- attr\1value\0[attr\1value\0]*\0 + entry_data TEXT ); - CREATE TABLE ldb_object + + /* + * The purpose of the descendant table is to support the + * subtree search feature. For each LDB entry with a unique + * ID (AEID), this table contains the unique identifiers + * (DEID) of the descendant entries. + * + * For evern entry in the directory, a row exists in this + * table for each of its ancestors including itself. The size + * of the table depends on the depth of each entry. In the + * worst case, if all the entries were at the same depth, the + * number of rows in the table is O(nm) where n is the number + * of nodes in the directory and m is the depth of the tree. + */ + CREATE TABLE ldb_descendants ( - /* tree_key is auto-generated by the insert trigger */ - tree_key TEXT PRIMARY KEY, - - parent_tree_key TEXT, - dn TEXT, - - attr_name TEXT REFERENCES ldb_attributes, - attr_value TEXT, - - /* - * object_type can take on these values (to date): - * 1: object is a node of a DN - * 2: object is an attribute/value pair of its parent DN - */ - object_type INTEGER, - - /* - * if object_type is 1, the node can have children. - * this tracks the maximum previously assigned child - * number so we can generate a new unique tree key for - * a new child object. note that this is always incremented, - * so if children are deleted, this will not represent - * the _number_ of children. - */ - max_child_num INTEGER, - - /* - * Automatically maintained meta-data (a gift for metze) - */ - object_guid TEXT UNIQUE, - timestamp INTEGER, -- originating_time - invoke_id TEXT, -- GUID: originating_invocation_id - usn INTEGER, -- hyper: originating_usn - - /* do not allow duplicate name/value pairs */ - UNIQUE (parent_tree_key, attr_name, attr_value, object_type) + -- The unique identifier of the ancestor LDB entry + aeid INTEGER REFERENCES ldb_entry, + + -- The unique identifier of the descendant LDB entry + deid INTEGER REFERENCES ldb_entry ); - CREATE TABLE ldb_attributes - ( - attr_name TEXT PRIMARY KEY, - parent_tree_key TEXT, - objectclass_p BOOLEAN DEFAULT 0, + CREATE TABLE ldb_object_classes + ( + -- Object classes are inserted into this table to track + -- their class hierarchy. 'top' is the top-level class + -- of which all other classes are subclasses. + class_name TEXT PRIMARY KEY, + + -- tree_key tracks the position of the class in + -- the hierarchy + tree_key TEXT UNIQUE + ); - case_insensitive_p BOOLEAN DEFAULT 0, - wildcard_p BOOLEAN DEFAULT 0, - hidden_p BOOLEAN DEFAULT 0, - integer_p BOOLEAN DEFAULT 0, + /* + * There is one attribute table per searchable attribute. + */ +/* + CREATE TABLE ldb_attr_ATTRIBUTE_NAME + ( + -- The unique identifier of the LDB entry + eid INTEGER REFERENCES ldb_entry, - /* tree_key is auto-generated by the insert trigger */ - tree_key TEXT, -- null if not a object/sub class - -- level 1 if an objectclass - -- level 1-n if a subclass - max_child_num INTEGER + -- Normalized attribute value + attr_value TEXT ); +*/ - -- ------------------------------------------------------ - CREATE INDEX ldb_object_dn_idx - ON ldb_object (dn); + -- ------------------------------------------------------ + -- Indexes - CREATE INDEX ldb_attributes_tree_key_ids - ON ldb_attributes (tree_key); -- ------------------------------------------------------ + -- Triggers - /* Gifts for metze. Automatically updated meta-data */ - CREATE TRIGGER ldb_object_insert_tr + CREATE TRIGGER ldb_entry_insert_tr AFTER INSERT - ON ldb_object + ON ldb_entry FOR EACH ROW BEGIN - UPDATE ldb_object - SET max_child_num = max_child_num + 1 - WHERE tree_key = new.parent_tree_key; - UPDATE usn SET value = value + 1; - UPDATE ldb_object - SET tree_key = - (SELECT - new.tree_key || - base160(SELECT max_child_num - FROM ldb_object - WHERE tree_key = - new.parent_tree_key)); - max_child_num = 0, - object_guid = random_guid(), - timestamp = strftime('%s', 'now'), - usn = (SELECT value FROM usn); - WHERE tree_key = new.tree_key; + UPDATE ldb_entry + SET create_timestamp = strftime('%s', 'now'), + modify_timestamp = strftime('%s', 'now') + WHERE eid = new.eid; END; - CREATE TRIGGER ldb_object_update_tr + CREATE TRIGGER ldb_entry_update_tr AFTER UPDATE - ON ldb_object + ON ldb_entry FOR EACH ROW BEGIN - UPDATE usn SET value = value + 1; - UPDATE ldb_object - SET timestamp = strftime('%s', 'now'), - usn = (SELECT value FROM usn); - WHERE tree_key = new.tree_key; + UPDATE ldb_entry + SET modify_timestamp = strftime('%s', 'now') + WHERE eid = old.eid; END; - CREATE TRIGGER ldb_attributes_insert_tr - AFTER INSERT - ON ldb_attributes - FOR EACH ROW - BEGIN - UPDATE ldb_attributes - SET max_child_num = max_child_num + 1 - WHERE tree_key = new.parent_tree_key; - UPDATE ldb_attributes - SET tree_key = - (SELECT - new.tree_key || - base160(SELECT max_child_num - FROM ldb_attributes - WHERE tree_key = - new.parent_tree_key)); - max_child_num = 0 - WHERE tree_key = new.tree_key; - END; - - -- ------------------------------------------------------ - - /* Initialize usn */ - INSERT INTO usn (value) VALUES (0); - - /* Create root object */ - INSERT INTO ldb_object - (tree_key, parent_tree_key, - dn, - object_type, max_child_num) - VALUES ('', NULL, - '', - 1, 0); + -- Table initialization /* We need an implicit "top" level object class */ INSERT INTO ldb_attributes (attr_name, -- cgit From ec9bdca186d1378d327e0f84da60fa18c1fc787a Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 4 Jun 2005 18:33:21 +0000 Subject: r7280: taking advantage of previous research. this is documentation on which latest schema is based (This used to be commit 603faa9cabd6d83c2e0fcfea476c5bda3f76b741) --- source4/lib/ldb/ldb_sqlite3/shi.pdf | Bin 0 -> 1084939 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 source4/lib/ldb/ldb_sqlite3/shi.pdf (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/shi.pdf b/source4/lib/ldb/ldb_sqlite3/shi.pdf new file mode 100644 index 0000000000..1437ce87f1 Binary files /dev/null and b/source4/lib/ldb/ldb_sqlite3/shi.pdf differ -- cgit From 150f127aa3d489cb44486450807517b7cd248ef4 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 4 Jun 2005 20:30:49 +0000 Subject: r7281: removing document (This used to be commit 6867d56796ce4dd85c69107c6a0a5cf4bf93f585) --- source4/lib/ldb/ldb_sqlite3/shi.pdf | Bin 1084939 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 source4/lib/ldb/ldb_sqlite3/shi.pdf (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/shi.pdf b/source4/lib/ldb/ldb_sqlite3/shi.pdf deleted file mode 100644 index 1437ce87f1..0000000000 Binary files a/source4/lib/ldb/ldb_sqlite3/shi.pdf and /dev/null differ -- cgit From 217a8cfe6677c0d435992f96996d5415824f598b Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 4 Jun 2005 21:16:54 +0000 Subject: r7282: ldb_sqlite3 work in progress. (This used to be commit d934c42b00b68e8f4ac9d0583ac307818aeb494f) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 519 ++++++++++++++++-------------- source4/lib/ldb/ldb_sqlite3/schema | 4 +- 2 files changed, 273 insertions(+), 250 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 0bce078a85..6dfaa0627b 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -37,20 +37,49 @@ #include "ldb/include/ldb_private.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" +#ifndef False +# define False (0) +# define True (! False) +#endif + #define QUERY(lsqlite3, pppValues, pNumRows, bRollbackOnError, sql...) \ do \ { \ - if (query(lsqlite3, pppValues, pNumRows, sql) != 0) { \ + if (lsqlite3_query(lsqlite3, \ + pppValues, \ + pNumRows, \ + sql) != 0) { \ if (bRollbackOnError) { \ - query(lsqlite3, NULL, NULL, "ROLLBACK;"); \ + lsqlite3_query(lsqlite3, \ + NULL, \ + NULL, \ + "ROLLBACK;"); \ } \ return -1; \ } \ } while (0) +static int +lsqlite3_query(const struct lsqlite3_private *lsqlite3, + char ***pppValues, + int *pNumRows, + const char *pSql, + ...) +{ + +} + +static int +lsqlite3_create_attr_table(struct ldb_module *module, + char * pAttr) +{ + +} + + #if 0 -/* +p/* * we don't need this right now, but will once we add some backend options * * find an option in an option list (a null terminated list of strings) @@ -78,6 +107,18 @@ lsqlite3_option_find(const struct lsqlite3_private *lsqlite3, } #endif +/* + callback function used in call to ldb_dn_fold() for determining whether an + attribute type requires case folding. +*/ +static int lsqlite3_case_fold_attr_required(struct ldb_module *module, + char *attr) +{ +#warning "currently, all attributes require case folding" + return True; +} + + /* * rename a record */ @@ -86,15 +127,12 @@ lsqlite3_rename(struct ldb_module *module, const char *olddn, const char *newdn) { - int column; - struct lsqlite3_private * lsqlite3 = module->private_data; - /* ignore ltdb specials */ if (olddn[0] == '@' ||newdn[0] == '@') { return 0; } -#warning "rename() is not yet supported" +#warning "lsqlite3_rename() is not yet supported" return -1; } @@ -105,10 +143,6 @@ static int lsqlite3_delete(struct ldb_module *module, const char *dn) { - int ret = 0; - int column; - struct lsqlite3_private * lsqlite3 = module->private_data; - /* ignore ltdb specials */ if (dn[0] == '@') { return 0; @@ -117,6 +151,7 @@ lsqlite3_delete(struct ldb_module *module, return -1; } +#if 0 /* not currently used * / /* * free a search result */ @@ -127,11 +162,21 @@ lsqlite3_search_free(struct ldb_module *module, talloc_free(res); return 0; } +#endif /* * add a single set of ldap message values to a ldb_message */ + +/* get things to compile before we actually implement this function */ +struct berval +{ + int x; +}; + +#warning "lsqlite3_add_msg_attr() not yet implemented or used" +#if 0 static int lsqlite3_add_msg_attr(struct ldb_context *ldb, struct ldb_message *msg, @@ -186,6 +231,7 @@ lsqlite3_add_msg_attr(struct ldb_context *ldb, return 0; } +#endif /* * search for matching records @@ -195,9 +241,11 @@ lsqlite3_search(struct ldb_module *module, const char *base, enum ldb_scope scope, const char *expression, - const char * const *attrs, + const char * const attrs[], struct ldb_message ***res) { +#warning "lsqlite3_search() not yet implemented" +#if 0 int count; int msg_count; struct ldb_context * ldb = module->ldb; @@ -293,6 +341,9 @@ lsqlite3_search(struct ldb_module *module, failed: if (*res) lsqlite3_search_free(module, *res); return -1; +#else + return 0; +#endif } @@ -309,8 +360,6 @@ lsqlite3_msg_to_sql(struct ldb_module *module, int flags; unsigned int i; unsigned int j; - sqlite3_stmt * stmt = NULL; - struct ldb_context * ldb = module->ldb; struct lsqlite3_private * lsqlite3 = module->private_data; for (i = 0; i < msg->num_elements; i++) { @@ -324,7 +373,8 @@ lsqlite3_msg_to_sql(struct ldb_module *module, if (flags == LDB_FLAG_MOD_ADD) { /* Create the attribute table if it doesn't exist */ - if (create_attr_table(module, el->name) != 0) { + if (lsqlite3_create_attr_table(module, + el->name) != 0) { return -1; } } @@ -337,58 +387,58 @@ lsqlite3_msg_to_sql(struct ldb_module *module, case LDB_FLAG_MOD_ADD: QUERY(lsqlite3, NULL, NULL, - FALSE, + False, "INSERT INTO ldb_attr_%q " " (eid, attr_value) " " VALUES " " (%lld, %Q);", - eid, el->data); + eid, el->values[j].data); QUERY(lsqlite3, NULL, NULL, - FALSE, + False, "UPDATE ldb_entry " " SET entry_data = " " add_attr(entry_data, %Q, %Q) " " WHERE eid = %lld;", - el->name, el->data, eid); + el->name, el->values[j].data, eid); break; case LDB_FLAG_MOD_REPLACE: QUERY(lsqlite3, NULL, NULL, - FALSE, + False, "UPDATE ldb_attr_%q " " SET attr_value = %Q " " WHERE eid = %lld;", - el->data, eid); + el->values[j].data, eid); QUERY(lsqlite3, NULL, NULL, - FALSE, + False, "UPDATE ldb_entry " " SET entry_data = " " mod_attr(entry_data, %Q, %Q) " " WHERE eid = %lld;", - el->name, el->data, eid); + el->name, el->values[j].data, eid); break; case LDB_FLAG_MOD_DELETE: /* No additional parameters to this query */ QUERY(lsqlite3, NULL, NULL, - FALSE, + False, "DELETE FROM ldb_attr_%q " " WHERE eid = %lld " " AND attr_value = %Q;", - eid, el->data); + eid, el->values[j].data); QUERY(lsqlite3, NULL, NULL, - FALSE, + False, "UPDATE ldb_entry " " SET entry_data = " " del_attr(entry_data, %Q, %Q) " " WHERE eid = %lld;", - el->name, el->data, eid); + el->name, el->values[j].data, eid); break; } } @@ -398,32 +448,12 @@ lsqlite3_msg_to_sql(struct ldb_module *module, } -static char * -lsqlite3_normalize_dn(struct ldb_context * ldb, - char * pDN) -{ - char * pSrc; - char * pDest; - char * pNormalized; - - pNormalized = talloc_size(ldb, strlen(pDN) + 1); - if (pNormalized == NULL) { - errno = ENOMEM; - return -1; - } - - for (pSrc = pDN, pDest = pNormalized; *pSrc != '\0'; ) { - - } -} - - static int -lsqlite3_insert_dn_recursive(struct lsqlite3_private * lsqlite3, - char * pDN, - long long * pEID) +lsqlite3_insert_dn(struct lsqlite3_private * lsqlite3, + char * pDN, + long long * pEID) { - + } @@ -434,9 +464,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg) { - int ret; long long eid; - struct ldb_context * ldb = module->ldb; struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ @@ -445,27 +473,29 @@ lsqlite3_add(struct ldb_module *module, } /* Begin a transaction */ - QUERY(lsqlite3, NULL, NULL< FALSE, "BEGIN EXCLUSIVE;"); + QUERY(lsqlite3, NULL, NULL, False, "BEGIN EXCLUSIVE;"); /* * Build any portions of the directory tree that don't exist. If the * final component already exists, it's an error. */ - if (lsqlite3_insert_dn_recursive(lsqlite3, - lsqlite3_normalize_dn(ldb, msg->dn), + if (lsqlite3_insert_dn(lsqlite3, + ldb_dn_fold(module, + msg->dn, + lsqlite3_case_fold_attr_required), &eid) != 0) { - QUERY(lsqlite3, NULL, NULL, FALSE, "ROLLBACK;"); + QUERY(lsqlite3, NULL, NULL, False, "ROLLBACK;"); return -1; } /* Add attributes to this new entry */ - if (lsqlite3_msg_to_sql(module, msg, eid, FALSE) != 0) { - QUERY(lsqlite3, NULL, NULL, FALSE, "ROLLBACK;"); + if (lsqlite3_msg_to_sql(module, msg, eid, False) != 0) { + QUERY(lsqlite3, NULL, NULL, False, "ROLLBACK;"); return -1; } /* Everything worked. Commit it! */ - QUERY(lsqlite3, NULL, NULL, TRUE, "COMMIT;"); + QUERY(lsqlite3, NULL, NULL, True, "COMMIT;"); return 0; } @@ -477,10 +507,9 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) { - int ret = 0; int numRows; + long long eid; char ** ppValues; - struct ldb_context * ldb = module->ldb; struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ @@ -489,22 +518,24 @@ lsqlite3_modify(struct ldb_module *module, } /* Begin a transaction */ - QUERY(lsqlite3, NULL, NULL, FALSE, "BEGIN EXCLUSIVE;"); + QUERY(lsqlite3, NULL, NULL, False, "BEGIN EXCLUSIVE;"); /* Get the id of this DN. */ QUERY(lsqlite3, &ppValues, &numRows, - TRUE, + True, "SELECT eid " " FROM ldb_entry " " WHERE dn = %Q;", - lsqlite3_normalize_dn(ldb, msg->dn)); + ldb_dn_fold(module, + msg->dn, + lsqlite3_case_fold_attr_required)); /* Did it exist? */ if (numRows != 1) { /* Nope. See ya! */ - sqlite_free_table(ppValues); + sqlite3_free_table(ppValues); return -1; } @@ -512,13 +543,13 @@ lsqlite3_modify(struct ldb_module *module, eid = strtoll(ppValues[1], NULL, 10); /* Modify attributes as specified */ - if (lsqlite3_msg_to_sql(module, msg, eid, FALSE) != 0) { - QUERY(lsqlite3, NULL, NULL, FALSE, "ROLLBACK;"); + if (lsqlite3_msg_to_sql(module, msg, eid, False) != 0) { + QUERY(lsqlite3, NULL, NULL, False, "ROLLBACK;"); return -1; } /* Everything worked. Commit it! */ - QUERY(lsqlite3, NULL, NULL, TRUE, "COMMIT;"); + QUERY(lsqlite3, NULL, NULL, True, "COMMIT;"); return 0 ; } @@ -526,10 +557,6 @@ static int lsqlite3_lock(struct ldb_module *module, const char *lockname) { - int ret = 0; - struct ldb_context * ldb = module->ldb; - struct lsqlite3_private * lsqlite3 = module->private_data; - if (lockname == NULL) { return -1; } @@ -543,10 +570,6 @@ static int lsqlite3_unlock(struct ldb_module *module, const char *lockname) { - int ret = 0; - struct ldb_context * ldb = module->ldb; - struct lsqlite3_private * lsqlite3 = module->private_data; - if (lockname == NULL) { return -1; } @@ -564,14 +587,13 @@ lsqlite3_errstring(struct ldb_module *module) { struct lsqlite3_private * lsqlite3 = module->private_data; - return sqlite3_errmsg(lsqlite3->sqlite3); + return sqlite3_errmsg(lsqlite3->sqlite); } static const struct ldb_module_ops lsqlite3_ops = { "sqlite", lsqlite3_search, - lsqlite3_search_free, lsqlite3_add, lsqlite3_modify, lsqlite3_delete, @@ -587,162 +609,162 @@ lsqlite3_destructor(void *p) { struct lsqlite3_private * lsqlite3 = p; - (void) sqlite3_close(lsqlite3->sqlite3); + (void) sqlite3_close(lsqlite3->sqlite); return 0; } static int -lsqlite3_initialize(lsqlite3_private *lsqlite3, +lsqlite3_initialize(struct lsqlite3_private *lsqlite3, const char *url) { int ret; int bNewDatabase = False; char * p; - char * pTail; + const char * pTail; struct stat statbuf; sqlite3_stmt * stmt; const char * schema = - " - -- ------------------------------------------------------ - - PRAGMA auto_vacuum=1; - - -- ------------------------------------------------------ - - BEGIN EXCLUSIVE; - - -- ------------------------------------------------------ - - CREATE TABLE ldb_info AS - SELECT 'LDB' AS database_type, - '1.0' AS version; - - -- ------------------------------------------------------ - -- Schema - - /* - * The entry table holds the information about an entry. This - * table is used to obtain the EID of the entry and to support - * scope=one and scope=base. The parent and child table - * is included in the entry table since all the other - * attributes on EID. - */ - CREATE TABLE ldb_entry - ( - -- Unique identifier of this LDB entry - eid INTEGER PRIMARY KEY, - - -- Unique identifier of the parent LDB entry - peid INTEGER REFERENCES ldb_entry, - - -- Distinguished name of this entry - dn TEXT, - - -- Time when the entry was created - create_timestamp INTEGER, - - -- Time when the entry was last modified - modify_timestamp INTEGER, - - -- Attributes of this entry, in the form - -- attr\1value\0[attr\1value\0]*\0 - entry_data TEXT - ); - - - /* - * The purpose of the descendant table is to support the - * subtree search feature. For each LDB entry with a unique - * ID (AEID), this table contains the unique identifiers - * (DEID) of the descendant entries. - * - * For evern entry in the directory, a row exists in this - * table for each of its ancestors including itself. The size - * of the table depends on the depth of each entry. In the - * worst case, if all the entries were at the same depth, the - * number of rows in the table is O(nm) where n is the number - * of nodes in the directory and m is the depth of the tree. - */ - CREATE TABLE ldb_descendants - ( - -- The unique identifier of the ancestor LDB entry - aeid INTEGER REFERENCES ldb_entry, - - -- The unique identifier of the descendant LDB entry - deid INTEGER REFERENCES ldb_entry - ); - - - CREATE TABLE ldb_object_classes - ( - -- Object classes are inserted into this table to track - -- their class hierarchy. 'top' is the top-level class - -- of which all other classes are subclasses. - class_name TEXT PRIMARY KEY, - - -- tree_key tracks the position of the class in - -- the hierarchy - tree_key TEXT UNIQUE - ); - - /* - * There is one attribute table per searchable attribute. - */ -/* - CREATE TABLE ldb_attr_ATTRIBUTE_NAME - ( - -- The unique identifier of the LDB entry - eid INTEGER REFERENCES ldb_entry, - - -- Normalized attribute value - attr_value TEXT - ); -*/ - - - -- ------------------------------------------------------ - -- Indexes - - - -- ------------------------------------------------------ - -- Triggers - - CREATE TRIGGER ldb_entry_insert_tr - AFTER INSERT - ON ldb_entry - FOR EACH ROW - BEGIN - UPDATE ldb_entry - SET create_timestamp = strftime('%s', 'now'), - modify_timestamp = strftime('%s', 'now') - WHERE eid = new.eid; - END; - - CREATE TRIGGER ldb_entry_update_tr - AFTER UPDATE - ON ldb_entry - FOR EACH ROW - BEGIN - UPDATE ldb_entry - SET modify_timestamp = strftime('%s', 'now') - WHERE eid = old.eid; - END; - - -- ------------------------------------------------------ - -- Table initialization - - /* We need an implicit "top" level object class */ - INSERT INTO ldb_attributes (attr_name, - parent_tree_key) - SELECT 'top', ''; - - -- ------------------------------------------------------ - - COMMIT; - - -- ------------------------------------------------------ - "; - + "-- ------------------------------------------------------" + + "PRAGMA auto_vacuum=1;" + + "-- ------------------------------------------------------" + + "BEGIN EXCLUSIVE;" + + "-- ------------------------------------------------------" + + "CREATE TABLE ldb_info AS" + " SELECT 'LDB' AS database_type," + " '1.0' AS version;" + + "-- ------------------------------------------------------" + "-- Schema" + + "/*" + " * The entry table holds the information about an entry. " + " * This table is used to obtain the EID of the entry and to " + " * support scope=one and scope=base. The parent and child" + " * table is included in the entry table since all the other" + " * attributes are dependent on EID." + " */" + "CREATE TABLE ldb_entry" + "(" + " -- Unique identifier of this LDB entry" + " eid INTEGER PRIMARY KEY," + + " -- Unique identifier of the parent LDB entry" + " peid INTEGER REFERENCES ldb_entry," + + " -- Distinguished name of this entry" + " dn TEXT," + + " -- Time when the entry was created" + " create_timestamp INTEGER," + + " -- Time when the entry was last modified" + " modify_timestamp INTEGER," + + " -- Attributes of this entry, in the form" + " -- attr\1value\0[attr\1value\0]*\0" + " entry_data TEXT" + ");" + + + "/*" + " * The purpose of the descendant table is to support the" + " * subtree search feature. For each LDB entry with a unique" + " * ID (AEID), this table contains the unique identifiers" + " * (DEID) of the descendant entries." + " *" + " * For evern entry in the directory, a row exists in this" + " * table for each of its ancestors including itself. The " + " * size of the table depends on the depth of each entry. In " + " * the worst case, if all the entries were at the same " + " * depth, the number of rows in the table is O(nm) where " + " * n is the number of nodes in the directory and m is the " + " * depth of the tree. " + " */" + "CREATE TABLE ldb_descendants" + "(" + " -- The unique identifier of the ancestor LDB entry" + " aeid INTEGER REFERENCES ldb_entry," + + " -- The unique identifier of the descendant LDB entry" + " deid INTEGER REFERENCES ldb_entry" + ");" + + + "CREATE TABLE ldb_object_classes" + "(" + " -- Object classes are inserted into this table to track" + " -- their class hierarchy. 'top' is the top-level class" + " -- of which all other classes are subclasses." + " class_name TEXT PRIMARY KEY," + + " -- tree_key tracks the position of the class in" + " -- the hierarchy" + " tree_key TEXT UNIQUE" + ");" + + "/*" + " * There is one attribute table per searchable attribute." + " */" + "/*" + "CREATE TABLE ldb_attr_ATTRIBUTE_NAME" + "(" + " -- The unique identifier of the LDB entry" + " eid INTEGER REFERENCES ldb_entry," + + " -- Normalized attribute value" + " attr_value TEXT" + ");" + "*/" + + + "-- ------------------------------------------------------" + "-- Indexes" + + + "-- ------------------------------------------------------" + "-- Triggers" + + "CREATE TRIGGER ldb_entry_insert_tr" + " AFTER INSERT" + " ON ldb_entry" + " FOR EACH ROW" + " BEGIN" + " UPDATE ldb_entry" + " SET create_timestamp = strftime('%s', 'now')," + " modify_timestamp = strftime('%s', 'now')" + " WHERE eid = new.eid;" + " END;" + + "CREATE TRIGGER ldb_entry_update_tr" + " AFTER UPDATE" + " ON ldb_entry" + " FOR EACH ROW" + " BEGIN" + " UPDATE ldb_entry" + " SET modify_timestamp = strftime('%s', 'now')" + " WHERE eid = old.eid;" + " END;" + + "-- ------------------------------------------------------" + "-- Table initialization" + + "/* We need an implicit 'top' level object class */" + "INSERT INTO ldb_attributes (attr_name," + " parent_tree_key)" + " SELECT 'top', '';" + + "-- ------------------------------------------------------" + + "COMMIT;" + + "-- ------------------------------------------------------" + ; + /* Skip protocol indicator of url */ if ((p = strchr(url, ':')) == NULL) { return SQLITE_MISUSE; @@ -760,7 +782,7 @@ lsqlite3_initialize(lsqlite3_private *lsqlite3, } /* Try to open the (possibly empty/non-existent) database */ - if ((ret = sqlite3_open(p, &lsqlite3->sqlite3)) != SQLITE_SUCCESS) { + if ((ret = sqlite3_open(p, &lsqlite3->sqlite)) != SQLITE_OK) { return ret; } @@ -768,18 +790,18 @@ lsqlite3_initialize(lsqlite3_private *lsqlite3, /* * Create the database schema */ - for (pTail = schema; pTail != NULL; ) { + for (pTail = discard_const_p(char, schema); pTail != NULL; ) { - if ((lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, + if ((ret = sqlite3_prepare( + lsqlite3->sqlite, pTail, -1, &stmt, - &pTail)) != SQLITE_SUCCESS || - (lsqlite3->last_rc = sqlite3_step(stmt)) != SQLITE_DONE || - (lsqlite3->last_rc = sqlite_finalize(stmt)) != SQLITE_SUCCESS) { + &pTail)) != SQLITE_OK || + (ret = sqlite3_step(stmt)) != SQLITE_DONE || + (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { - (void) sqlite3_close(lsqlite3->sqlite3); + (void) sqlite3_close(lsqlite3->sqlite); return ret; } } @@ -787,8 +809,8 @@ lsqlite3_initialize(lsqlite3_private *lsqlite3, /* * Ensure that the database we opened is one of ours */ - if ((lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, + if ((ret = sqlite3_prepare( + lsqlite3->sqlite, "SELECT COUNT(*) " " FROM sqlite_master " " WHERE type = 'table' " @@ -800,30 +822,30 @@ lsqlite3_initialize(lsqlite3_private *lsqlite3, " );", -1, &stmt, - &pTail)) != SQLITE_SUCCESS || - (lsqlite3->last_rc = sqlite3_step(stmt)) != SQLITE_ROW || + &pTail)) != SQLITE_OK || + (ret = sqlite3_step(stmt)) != SQLITE_ROW || sqlite3_column_int(stmt, 0) != 3 || - (lsqlite3->last_rc = sqlite_finalize(stmt)) != SQLITE_SUCCESS || + (ret = sqlite3_finalize(stmt)) != SQLITE_OK || - (lsqlite3->last_rc = sqlite3_prepare( - lsqlite3->sqlite3, + (ret = sqlite3_prepare( + lsqlite3->sqlite, "SELECT 1 " " FROM ldb_info " " WHERE database_type = 'LDB' " " AND version = '1.0';", -1, &stmt, - &pTail)) != SQLITE_SUCCESS || - (lsqlite3->last_rc = sqlite3_step(stmt)) != SQLITE_ROW || - (lsqlite3->last_rc = sqlite_finalize(stmt)) != SQLITE_SUCCESS) { + &pTail)) != SQLITE_OK || + (ret = sqlite3_step(stmt)) != SQLITE_ROW || + (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { /* It's not one that we created. See ya! */ - (void) sqlite3_close(lsqlite3->sqlite3); + (void) sqlite3_close(lsqlite3->sqlite); return SQLITE_MISUSE; } } - return SQLITE_SUCCESS; + return SQLITE_OK; } /* @@ -835,6 +857,7 @@ lsqlite3_connect(const char *url, const char *options[]) { int i; + int ret; struct ldb_context * ldb = NULL; struct lsqlite3_private * lsqlite3 = NULL; @@ -850,12 +873,12 @@ lsqlite3_connect(const char *url, goto failed; } - lsqlite3->sqlite3 = NULL; + lsqlite3->sqlite = NULL; lsqlite3->options = NULL; lsqlite3->lock_count = 0; - lsqlite3->last_rc = lsqlite3_initialize(&lsqlite3->sqlite3, url); - if (lsqlite3->last_rc != SQLITE_SUCCESS) { + ret = lsqlite3_initialize(&lsqlite3, url); + if (ret != SQLITE_OK) { goto failed; } @@ -897,8 +920,8 @@ lsqlite3_connect(const char *url, return ldb; failed: - if (lsqlite3->sqlite3 != NULL) { - (void) sqlite3_close(lsqlite3->sqlite3); + if (lsqlite3->sqlite != NULL) { + (void) sqlite3_close(lsqlite3->sqlite); } talloc_free(ldb); return NULL; diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema index 78550985d4..dddca8d48f 100644 --- a/source4/lib/ldb/ldb_sqlite3/schema +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -20,7 +20,7 @@ * table is used to obtain the EID of the entry and to support * scope="one" and scope="base". The parent and child table * is included in the entry table since all the other - * attributes on EID. + * attributes are dependent on EID. */ CREATE TABLE ldb_entry ( @@ -126,7 +126,7 @@ -- ------------------------------------------------------ -- Table initialization - /* We need an implicit "top" level object class */ + /* We need an implicit 'top' level object class */ INSERT INTO ldb_attributes (attr_name, parent_tree_key) SELECT 'top', ''; -- cgit From 06cc74a66cef3944573e4390af0ee101517835df Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 4 Jun 2005 23:19:41 +0000 Subject: r7287: work in progress. no more time to work on this right now. save latest changes. (This used to be commit 94cbef9211597d8cdd6b5ab7bc9b655026be283a) --- source4/lib/ldb/ldb_sqlite3/README | 3 ++ source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 58 +++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 6 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/README b/source4/lib/ldb/ldb_sqlite3/README index a0b3dcb16d..6cda0a7759 100644 --- a/source4/lib/ldb/ldb_sqlite3/README +++ b/source4/lib/ldb/ldb_sqlite3/README @@ -2,3 +2,6 @@ trees.ps contains an explanation of the Genealogical Representation of Trees in Databases which is being used in ldb_sqlite3. Note that we use fgID representation with 4 bytes per level, so we can represent 6.5E+08 subclasses of any object class. This should be adequate for our purposes. :-) + +The following document is the primary basis for the schema currently being +used here: http://www.research.ibm.com/journal/sj/392/shi.html diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 6dfaa0627b..3fddbe85d4 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2,6 +2,7 @@ ldb database library Copyright (C) Andrew Tridgell 2004 + Copyright (C) Derrell Lipman 2005 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -32,6 +33,7 @@ * Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend) */ +#include #include "includes.h" #include "ldb/include/ldb.h" #include "ldb/include/ldb_private.h" @@ -67,19 +69,62 @@ lsqlite3_query(const struct lsqlite3_private *lsqlite3, const char *pSql, ...) { +// int i; +// int retval; + int numRows; +// int numColumns; + int bFreeTable = False; +// char errorBuf[4096]; + char * p; +// char * pError = NULL; + char ** ppValues; + va_list args; + + /* Begin access to variable argument list */ + va_start(args, pSql); + + /* + * If they didn't give us a place to put returned values, use our own + */ + if (pppValues == NULL) + { + pppValues = &ppValues; + bFreeTable = True; + } + /* Similarly for number of rows in result set */ + if (pNumRows == NULL) + { + pNumRows = &numRows; + } + + /* Format the query */ + if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { + return -1; + } + + +#warning "*** FINISH QUERY FUNCTION. Catch timeouts, schema changed, etc. ***" + + + /* All done with variable argument list */ + va_end(args); + + /* Success! */ + return 0; } static int lsqlite3_create_attr_table(struct ldb_module *module, char * pAttr) { - +#warning "*** lsqlite3_create_attr_table() not yet written ***" + return -1; } #if 0 -p/* +/* * we don't need this right now, but will once we add some backend options * * find an option in an option list (a null terminated list of strings) @@ -151,7 +196,7 @@ lsqlite3_delete(struct ldb_module *module, return -1; } -#if 0 /* not currently used * / +#if 0 /* not currently used */ /* * free a search result */ @@ -342,7 +387,7 @@ failed: if (*res) lsqlite3_search_free(module, *res); return -1; #else - return 0; + return -1; #endif } @@ -453,7 +498,8 @@ lsqlite3_insert_dn(struct lsqlite3_private * lsqlite3, char * pDN, long long * pEID) { - +#warning "*** lsqlite3_insert_dn() not yet implemented ***" + return -1; } @@ -877,7 +923,7 @@ lsqlite3_connect(const char *url, lsqlite3->options = NULL; lsqlite3->lock_count = 0; - ret = lsqlite3_initialize(&lsqlite3, url); + ret = lsqlite3_initialize(lsqlite3, url); if (ret != SQLITE_OK) { goto failed; } -- cgit From c88d65a862cefe832f3b5f38844829372a926e33 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Sun, 5 Jun 2005 04:18:57 +0000 Subject: r7292: Fix up the build system support for derrell's sqlite3 ldb backend. It is on by default, so I've also fixed a build issue in it. I'll show how to make it off be default in the next commit. Andrew Bartlett (This used to be commit 5a1ef888100e8ef803100a6341133d96e8a400b0) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 3fddbe85d4..b82c0ac6a9 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -35,6 +35,7 @@ #include #include "includes.h" +#include "system/filesys.h" #include "ldb/include/ldb.h" #include "ldb/include/ldb_private.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" -- cgit From 34ffdb12fc519dd5232082103bbe2f44d11f9ae8 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Mon, 6 Jun 2005 03:01:50 +0000 Subject: r7316: work in progress (This used to be commit 84a2b4049fde7db0d563e639e99364f40a47ace9) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 384 ++++++++++++++++++------------ 1 file changed, 237 insertions(+), 147 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index b82c0ac6a9..569978e343 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -35,92 +35,107 @@ #include #include "includes.h" -#include "system/filesys.h" #include "ldb/include/ldb.h" #include "ldb/include/ldb_private.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" -#ifndef False -# define False (0) -# define True (! False) +#ifndef FALSE +# define FALSE (0) +# define TRUE (! FALSE) #endif -#define QUERY(lsqlite3, pppValues, pNumRows, bRollbackOnError, sql...) \ - do \ - { \ - if (lsqlite3_query(lsqlite3, \ - pppValues, \ - pNumRows, \ - sql) != 0) { \ - if (bRollbackOnError) { \ - lsqlite3_query(lsqlite3, \ - NULL, \ - NULL, \ - "ROLLBACK;"); \ - } \ - return -1; \ - } \ +#define QUERY_NOROWS(lsqlite3, bRollbackOnError, sql...) \ + do { \ + if (lsqlite3_query_norows(lsqlite3, sql) != 0) { \ + if (bRollbackOnError) { \ + lsqlite3_query_norows(lsqlite3, \ + "ROLLBACK;"); \ + } \ + return -1; \ + } \ } while (0) +/* + * lsqlite3_query_norows() + * + * This function is used for queries that are not expected to return any rows, + * e.g. BEGIN, COMMIT, ROLLBACK, CREATE TABLE, INSERT, UPDATE, DELETE, etc. + * There are no provisions here for returning data from rows in a table, so do + * not pass SELECT queries to this function. + */ static int -lsqlite3_query(const struct lsqlite3_private *lsqlite3, - char ***pppValues, - int *pNumRows, - const char *pSql, - ...) +lsqlite3_query_norows(const struct lsqlite3_private *lsqlite3, + const char *pSql, + ...) { -// int i; -// int retval; - int numRows; -// int numColumns; - int bFreeTable = False; -// char errorBuf[4096]; + int ret; + int bLoop; char * p; -// char * pError = NULL; - char ** ppValues; + const char * pTail; + sqlite3_stmt * pStmt; va_list args; /* Begin access to variable argument list */ va_start(args, pSql); - /* - * If they didn't give us a place to put returned values, use our own - */ - if (pppValues == NULL) - { - pppValues = &ppValues; - bFreeTable = True; - } - - /* Similarly for number of rows in result set */ - if (pNumRows == NULL) - { - pNumRows = &numRows; - } - /* Format the query */ if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { return -1; } + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { + + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + pTail, + -1, + &pStmt, + &pTail)) != SQLITE_OK) { + ret = -1; + break; + } + + /* No rows expected, so just step through machine code once */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_DONE) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } -#warning "*** FINISH QUERY FUNCTION. Catch timeouts, schema changed, etc. ***" + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + ret = 0; + bLoop = FALSE; + } /* All done with variable argument list */ va_end(args); - /* Success! */ - return 0; -} + /* Free the memory we allocated for our query string */ + sqlite3_free(p); -static int -lsqlite3_create_attr_table(struct ldb_module *module, - char * pAttr) -{ -#warning "*** lsqlite3_create_attr_table() not yet written ***" - return -1; + return ret; } @@ -161,7 +176,7 @@ static int lsqlite3_case_fold_attr_required(struct ldb_module *module, char *attr) { #warning "currently, all attributes require case folding" - return True; + return TRUE; } @@ -393,6 +408,22 @@ failed: } +static int +lsqlite3_new_attr(struct lsqlite3_private * lsqlite3, + char * pAttrName) +{ + QUERY_NOROWS(lsqlite3, + FALSE, + "CREATE TABLE ldb_attr_%q " + "(" + " eid INTEGER REFERENCES ldb_entry, " + " attr_value TEXT" + ");", + pAttrName); + + return 0; +} + /* * Issue a series of SQL statements to implement the ADD/MODIFY/DELETE * requests in the ldb_message @@ -419,8 +450,7 @@ lsqlite3_msg_to_sql(struct ldb_module *module, if (flags == LDB_FLAG_MOD_ADD) { /* Create the attribute table if it doesn't exist */ - if (lsqlite3_create_attr_table(module, - el->name) != 0) { + if (lsqlite3_new_attr(lsqlite3, el->name) != 0) { return -1; } } @@ -431,60 +461,62 @@ lsqlite3_msg_to_sql(struct ldb_module *module, /* ... bind the attribute value, if necessary */ switch (flags) { case LDB_FLAG_MOD_ADD: - QUERY(lsqlite3, - NULL, NULL, - False, - "INSERT INTO ldb_attr_%q " - " (eid, attr_value) " - " VALUES " - " (%lld, %Q);", - eid, el->values[j].data); - QUERY(lsqlite3, - NULL, NULL, - False, - "UPDATE ldb_entry " - " SET entry_data = " - " add_attr(entry_data, %Q, %Q) " - " WHERE eid = %lld;", - el->name, el->values[j].data, eid); + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT INTO ldb_attr_%q " + " (eid, attr_value) " + " VALUES " + " (%lld, %Q);", + eid, el->values[j].data); + QUERY_NOROWS(lsqlite3, + FALSE, + "UPDATE ldb_entry " + " SET entry_data = " + " add_attr(entry_data, " + " %Q, %Q) " + " WHERE eid = %lld;", + el->name, el->values[j].data, + eid); break; case LDB_FLAG_MOD_REPLACE: - QUERY(lsqlite3, - NULL, NULL, - False, - "UPDATE ldb_attr_%q " - " SET attr_value = %Q " - " WHERE eid = %lld;", - el->values[j].data, eid); - QUERY(lsqlite3, - NULL, NULL, - False, - "UPDATE ldb_entry " - " SET entry_data = " - " mod_attr(entry_data, %Q, %Q) " - " WHERE eid = %lld;", - el->name, el->values[j].data, eid); + QUERY_NOROWS(lsqlite3, + FALSE, + "UPDATE ldb_attr_%q " + " SET attr_value = %Q " + " WHERE eid = %lld;", + el->values[j].data, + eid); + QUERY_NOROWS(lsqlite3, + FALSE, + "UPDATE ldb_entry " + " SET entry_data = " + " mod_attr(entry_data, " + " %Q, %Q) " + " WHERE eid = %lld;", + el->name, el->values[j].data, + eid); break; case LDB_FLAG_MOD_DELETE: /* No additional parameters to this query */ - QUERY(lsqlite3, - NULL, NULL, - False, - "DELETE FROM ldb_attr_%q " - " WHERE eid = %lld " - " AND attr_value = %Q;", - eid, el->values[j].data); - QUERY(lsqlite3, - NULL, NULL, - False, - "UPDATE ldb_entry " - " SET entry_data = " - " del_attr(entry_data, %Q, %Q) " - " WHERE eid = %lld;", - el->name, el->values[j].data, eid); + QUERY_NOROWS(lsqlite3, + FALSE, + "DELETE FROM ldb_attr_%q " + " WHERE eid = %lld " + " AND attr_value = %Q;", + eid, + el->values[j].data); + QUERY_NOROWS(lsqlite3, + FALSE, + "UPDATE ldb_entry " + " SET entry_data = " + " del_attr(entry_data, " + " %Q, %Q) " + " WHERE eid = %lld;", + el->name, el->values[j].data, + eid); break; } } @@ -495,11 +527,32 @@ lsqlite3_msg_to_sql(struct ldb_module *module, static int -lsqlite3_insert_dn(struct lsqlite3_private * lsqlite3, - char * pDN, - long long * pEID) +lsqlite3_new_dn(struct ldb_module *module, + char * pDN, + long long * pEID) { -#warning "*** lsqlite3_insert_dn() not yet implemented ***" + char * pName; + char * pValue; + + /* Normalize the distinguished name */ + pDN = ldb_dn_fold(module, pDN, lsqlite3_case_fold_attr_required); + + /* Parse the DN into its constituent components */ +#warning "this simple parse of DN ignores escaped '=' and ','. fix it." + while (pDN != NULL) { + pName = strsep(&pDN, ","); + + if (pDN == NULL) { + /* Attribute name with value? Should not occur. */ + return -1; + } + + pValue = pName; + strsep(&pValue, "="); + +#warning "*** lsqlite3_new_dn() not yet fully implemented ***" + } + return -1; } @@ -520,29 +573,25 @@ lsqlite3_add(struct ldb_module *module, } /* Begin a transaction */ - QUERY(lsqlite3, NULL, NULL, False, "BEGIN EXCLUSIVE;"); + QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); /* * Build any portions of the directory tree that don't exist. If the * final component already exists, it's an error. */ - if (lsqlite3_insert_dn(lsqlite3, - ldb_dn_fold(module, - msg->dn, - lsqlite3_case_fold_attr_required), - &eid) != 0) { - QUERY(lsqlite3, NULL, NULL, False, "ROLLBACK;"); + if (lsqlite3_new_dn(module, msg->dn, &eid) != 0) { + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); return -1; } /* Add attributes to this new entry */ - if (lsqlite3_msg_to_sql(module, msg, eid, False) != 0) { - QUERY(lsqlite3, NULL, NULL, False, "ROLLBACK;"); + if (lsqlite3_msg_to_sql(module, msg, eid, FALSE) != 0) { + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); return -1; } /* Everything worked. Commit it! */ - QUERY(lsqlite3, NULL, NULL, True, "COMMIT;"); + QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); return 0; } @@ -554,9 +603,12 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) { - int numRows; + int ret; + int bLoop; + char * p; + const char * pTail; long long eid; - char ** ppValues; + sqlite3_stmt * pStmt; struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ @@ -565,38 +617,76 @@ lsqlite3_modify(struct ldb_module *module, } /* Begin a transaction */ - QUERY(lsqlite3, NULL, NULL, False, "BEGIN EXCLUSIVE;"); + QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); - /* Get the id of this DN. */ - QUERY(lsqlite3, - &ppValues, - &numRows, - True, - "SELECT eid " - " FROM ldb_entry " - " WHERE dn = %Q;", - ldb_dn_fold(module, - msg->dn, - lsqlite3_case_fold_attr_required)); - - /* Did it exist? */ - if (numRows != 1) { - /* Nope. See ya! */ - sqlite3_free_table(ppValues); + /* Format the query */ + if ((p = sqlite3_mprintf( + "SELECT eid " + " FROM ldb_entry " + " WHERE dn = %Q;", + ldb_dn_fold(module, + msg->dn, + lsqlite3_case_fold_attr_required))) == NULL) { return -1; } - /* Retrieve the eid */ - eid = strtoll(ppValues[1], NULL, 10); + /* Get the id of this DN. */ + for (bLoop = TRUE; bLoop; ) { + + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + pTail, + -1, + &pStmt, + &pTail)) != SQLITE_OK) { + ret = -1; + break; + } + + /* One row expected */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_ROW) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* Retrieve the EID */ + eid = sqlite3_column_int64(pStmt, 0); + + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* Modify attributes as specified */ + if (lsqlite3_msg_to_sql(module, msg, eid, FALSE) != 0) { + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + return -1; + } + + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + ret = 0; + bLoop = FALSE; + } - /* Modify attributes as specified */ - if (lsqlite3_msg_to_sql(module, msg, eid, False) != 0) { - QUERY(lsqlite3, NULL, NULL, False, "ROLLBACK;"); + if (ret != 0) { + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); return -1; } /* Everything worked. Commit it! */ - QUERY(lsqlite3, NULL, NULL, True, "COMMIT;"); + QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); return 0 ; } @@ -665,7 +755,7 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3, const char *url) { int ret; - int bNewDatabase = False; + int bNewDatabase = FALSE; char * p; const char * pTail; struct stat statbuf; @@ -825,7 +915,7 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3, if ((stat(p, &statbuf) < 0 && errno == ENOENT) || statbuf.st_size == 0) { - bNewDatabase = True; + bNewDatabase = TRUE; } /* Try to open the (possibly empty/non-existent) database */ -- cgit From b8e8e5ed4e8436c4ad00eac8d72dd1157b770ab6 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Mon, 6 Jun 2005 13:11:06 +0000 Subject: r7332: added note to self for required modification (This used to be commit 8fa340c1d4423673e5a935f815491534413d9536) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 569978e343..602bd05fa2 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -912,6 +912,7 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3, /* * See if we'll be creating a new database, or opening an existing one */ +#warning "eliminate stat() here; concurrent processes could conflict" if ((stat(p, &statbuf) < 0 && errno == ENOENT) || statbuf.st_size == 0) { -- cgit From ca7baa3c9fc4814b7033f68a88ddac8072d62e2a Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 6 Jun 2005 15:19:49 +0000 Subject: r7343: handle url like ldb_tdb does (This used to be commit d36fde5c0cfe20d03dd99e2ffffdd13acf9f76f3) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 602bd05fa2..9ed137c4f5 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -903,11 +903,16 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3, ; /* Skip protocol indicator of url */ - if ((p = strchr(url, ':')) == NULL) { - return SQLITE_MISUSE; - } else { - ++p; - } + if (strchr(url, ':')) { + if (strncmp(url, "sqlite://", 9) != 0) { + errno = EINVAL; + return SQLITE_MISUSE; + } + p = url + 9; + } else { + p = url; + } + /* * See if we'll be creating a new database, or opening an existing one -- cgit From f08fafc49270022e3cca1a89c04b7dc014b9e12b Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Tue, 7 Jun 2005 03:01:46 +0000 Subject: r7349: work in progress (This used to be commit 0e4d9729d99a1a148a951878188fe1955713aea4) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 405 ++++++++++++++++++++++-------- 1 file changed, 299 insertions(+), 106 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 9ed137c4f5..25efc8ced2 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1,7 +1,6 @@ /* ldb database library - Copyright (C) Andrew Tridgell 2004 Copyright (C) Derrell Lipman 2005 ** NOTE! The following LGPL license applies to the ldb @@ -37,6 +36,7 @@ #include "includes.h" #include "ldb/include/ldb.h" #include "ldb/include/ldb_private.h" +#include "ldb/include/ldb_parse.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" #ifndef FALSE @@ -294,124 +294,314 @@ lsqlite3_add_msg_attr(struct ldb_context *ldb, } #endif -/* - * search for matching records - */ -static int -lsqlite3_search(struct ldb_module *module, - const char *base, - enum ldb_scope scope, - const char *expression, - const char * const attrs[], - struct ldb_message ***res) +static char * +lsqlite3_parsetree_to_sql(struct ldb_module *module, + char * hTalloc, + const struct ldb_parse_tree *t) { -#warning "lsqlite3_search() not yet implemented" -#if 0 - int count; - int msg_count; - struct ldb_context * ldb = module->ldb; - struct lsqlite3_private * lsqlite3 = module->private_data; + int i; + char * child; + char * p; + char * ret = NULL; + char * pAttrName; + - if (base == NULL) { - base = ""; - } + switch(t->operation) { + case LDB_OP_SIMPLE: + break; - lsqlite3->last_rc = ldap_search_s(lsqlite3->ldap, base, (int)scope, - expression, - discard_const_p(char *, attrs), - 0, &ldapres); - if (lsqlite3->last_rc != LDAP_SUCCESS) { - return -1; - } + case LDB_OP_AND: + ret = lsqlite3_parsetree_to_sql(module, + hTalloc, + t->u.list.elements[0]); + + for (i = 1; i < t->u.list.num_elements; i++) { + child = + lsqlite3_parsetree_to_sql( + module, + hTalloc, + t->u.list.elements[i]); + ret = talloc_asprintf_append(ret, + "INTERSECT\n" + "%s\n", + child); + talloc_free(child); + } - count = ldap_count_entries(lsqlite3->ldap, ldapres); - if (count == -1 || count == 0) { - ldap_msgfree(ldapres); - return count; - } + child = ret; + ret = talloc_asprintf("(\n" + "%s\n" + ")\n", + child); + talloc_free(child); + return ret; + + case LDB_OP_OR: + child = + lsqlite3_parsetree_to_sql( + module, + hTalloc, + t->u.list.elements[0]); + + for (i = 1; i < t->u.list.num_elements; i++) { + child = + lsqlite3_parsetree_to_sql( + module, + hTalloc, + t->u.list.elements[i]); + ret = talloc_asprintf_append(ret, + "UNION\n" + "%s\n", + child); + talloc_free(child); + } + child = ret; + ret = talloc_asprintf("(\n" + "%s\n" + ")\n", + child); + talloc_free(child); + return ret; + + case LDB_OP_NOT: + child = + lsqlite3_parsetree_to_sql( + module, + hTalloc, + t->u.not.child); + ret = talloc_asprintf(hTalloc, + "(\n" + " SELECT eid\n" + " FROM ldb_entry\n" + " WHERE eid NOT IN %s\n" + ")\n", + child); + talloc_free(child); + return ret; + + default: + /* should never occur */ + abort(); + }; + + /* Get a case-folded copy of the attribute name */ + pAttrName = ldb_casefold((struct ldb_context *) module, + t->u.simple.attr); - (*res) = talloc_array(lsqlite3, struct ldb_message *, count+1); - if (! *res) { - ldap_msgfree(ldapres); - errno = ENOMEM; - return -1; - } + /* + * For simple searches, we want to retrieve the list of EIDs that + * match the criteria. We accomplish this by searching the + * appropriate table, ldb_attr_, for the eid + * corresponding to all matching values. + */ + if (t->u.simple.value.length == 1 && + (*(const char *) t->u.simple.value.data) == '*') { + /* + * Special case for "attr_name=*". In this case, we want the + * eid corresponding to all values in the specified attribute + * table. + */ + if ((p = sqlite3_mprintf("(\n" + " SELECT eid\n" + " FROM ldb_attr_%q\n" + ")\n", + pAttrName)) == NULL) { + return NULL; + } - (*res)[0] = NULL; + ret = talloc_strdup(hTalloc, p); + sqlite3_free(p); - msg_count = 0; + } else if (strcasecmp(t->u.simple.attr, "objectclass") == 0) { + /* + * For object classes, we want to search for all objectclasses + * that are subclasses as well. + */ + if ((p = sqlite3_mprintf( + "(\n" + " SELECT eid\n" + " FROM ldb_attr_objectclass\n" + " WHERE attr_name IN\n" + " (SELECT class_name\n" + " FROM ldb_objectclasses\n" + " WHERE tree_key GLOB\n" + " (SELECT tree_key\n" + " FROM ldb_objectclasses\n" + " WHERE class_name = %Q) || '*')\n" + ")\n", + t->u.simple.value.data)) == NULL) { + return NULL; + } - /* loop over all messages */ - for (msg=ldap_first_entry(lsqlite3->ldap, ldapres); - msg; - msg=ldap_next_entry(lsqlite3->ldap, msg)) { - BerElement *berptr = NULL; - char *attr, *dn; + ret = talloc_strdup(hTalloc, p); + sqlite3_free(p); - if (msg_count == count) { - /* hmm, got too many? */ - ldb_debug(ldb, LDB_DEBUG_FATAL, "Fatal: ldap message count inconsistent\n"); - break; - } + } else { + /* A normal query. */ + if ((p = sqlite3_mprintf("(\n" + " SELECT eid\n" + " FROM ldb_attr_%q\n" + " WHERE attr_value = %Q\n" + ")\n", + pAttrName, + t->u.simple.value.data)) == NULL) { + return NULL; + } - (*res)[msg_count] = talloc(*res, struct ldb_message); - if (!(*res)[msg_count]) { - goto failed; - } - (*res)[msg_count+1] = NULL; + ret = talloc_strdup(hTalloc, p); + sqlite3_free(p); + } + return ret; +} - dn = ldap_get_dn(lsqlite3->ldap, msg); - if (!dn) { - goto failed; - } - (*res)[msg_count]->dn = talloc_strdup((*res)[msg_count], dn); - ldap_memfree(dn); - if (!(*res)[msg_count]->dn) { - goto failed; - } +static char * +lsqlite3_parsetree_to_tablelist(struct ldb_module *module, + char * hTalloc, + const struct ldb_parse_tree *t) +{ +#warning "obtain talloc'ed array of attribute names for table list" + return NULL; +} - (*res)[msg_count]->num_elements = 0; - (*res)[msg_count]->elements = NULL; - (*res)[msg_count]->private_data = NULL; +/* + * search for matching records + */ +static int +lsqlite3_search(struct ldb_module * module, + const char * pBaseDN, + enum ldb_scope scope, + const char * pExpression, + const char * const attrs[], + struct ldb_message *** res) +{ + int ret; + int bLoop; + long long eid; + char * sql; + char * sql_constraints; + char * table_list; + char * hTalloc; + const char * pTail; + sqlite3_stmt * pStmt; + struct ldb_parse_tree * pTree; + struct lsqlite3_private * lsqlite3 = module->private_data; + + if (pBaseDN == NULL) { + pBaseDN = ""; + } - /* loop over all attributes */ - for (attr=ldap_first_attribute(lsqlite3->ldap, msg, &berptr); - attr; - attr=ldap_next_attribute(lsqlite3->ldap, msg, berptr)) { - struct berval **bval; - bval = ldap_get_values_len(lsqlite3->ldap, msg, attr); + /* + * Obtain the eid of the base DN + */ + if ((pTail = sqlite3_mprintf("SELECT eid " + " FROM ldb_attr_dn " + " WHERE attr_value = %Q;", + pBaseDN)) == NULL) { + return -1; + } - if (bval) { - lsqlite3_add_msg_attr(ldb, (*res)[msg_count], attr, bval); - ldap_value_free_len(bval); - } - - ldap_memfree(attr); - } - if (berptr) ber_free(berptr, 0); + for (bLoop = TRUE; bLoop; ) { - msg_count++; - } + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + pTail, + -1, + &pStmt, + &pTail)) != SQLITE_OK) { + ret = -1; + break; + } + + /* One row expected */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_ROW) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* Retrieve the EID */ + eid = sqlite3_column_int64(pStmt, 0); + + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } - ldap_msgfree(ldapres); + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + ret = 0; + bLoop = FALSE; + } - return msg_count; + /* Parse the filter expression into a tree we can work with */ + if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { + return -1; + } + + /* Allocate a temporary talloc context */ + hTalloc = talloc_new(module); -failed: - if (*res) lsqlite3_search_free(module, *res); - return -1; -#else - return -1; -#endif + /* Move the parse tree to our temporary context */ + talloc_steal(hTalloc, pTree); + + /* Convert filter into a series of SQL statements (constraints) */ + sql_constraints = lsqlite3_parsetree_to_sql(module, hTalloc, pTree); + + /* Get the list of attribute names to use as our extra table list */ + table_list = lsqlite3_parsetree_to_tablelist(module, hTalloc, pTree); + + switch(scope) { + case LDB_SCOPE_DEFAULT: + case LDB_SCOPE_SUBTREE: + sql = sqlite3_mprintf( + "SELECT entry.entry_data\n" + " FROM ldb_entry AS entry\n" + " WHERE entry.eid IN\n" + " (SELECT ldb_entry.eid\n" + " FROM ldb_entry,\n" + " ldb_descendants,\n" + " %q\n" + " WHERE ldb_descendants.aeid = %lld\n" + " AND ldb_entry.eid = ldb_descendants.deid\n" + " AND ldap_entry.eid IN\n" + "%s);", + table_list, + sql_constraints); + break; + +#warning "scope BASE and ONLEVEL not yet implemented" + case LDB_SCOPE_BASE: + break; + + case LDB_SCOPE_ONELEVEL: + break; + } + + return ret; } static int -lsqlite3_new_attr(struct lsqlite3_private * lsqlite3, +lsqlite3_new_attr(struct ldb_module * module, char * pAttrName) { + struct lsqlite3_private * lsqlite3 = module->private_data; + + /* Get a case-folded copy of the attribute name */ + pAttrName = ldb_casefold((struct ldb_context *) module, pAttrName); + QUERY_NOROWS(lsqlite3, FALSE, "CREATE TABLE ldb_attr_%q " @@ -429,12 +619,13 @@ lsqlite3_new_attr(struct lsqlite3_private * lsqlite3, * requests in the ldb_message */ static int -lsqlite3_msg_to_sql(struct ldb_module *module, - const struct ldb_message *msg, +lsqlite3_msg_to_sql(struct ldb_module * module, + const struct ldb_message * msg, long long eid, int use_flags) { int flags; + char * pAttrName; unsigned int i; unsigned int j; struct lsqlite3_private * lsqlite3 = module->private_data; @@ -450,7 +641,7 @@ lsqlite3_msg_to_sql(struct ldb_module *module, if (flags == LDB_FLAG_MOD_ADD) { /* Create the attribute table if it doesn't exist */ - if (lsqlite3_new_attr(lsqlite3, el->name) != 0) { + if (lsqlite3_new_attr(module, el->name) != 0) { return -1; } } @@ -458,6 +649,10 @@ lsqlite3_msg_to_sql(struct ldb_module *module, /* For each value of the specified attribute name... */ for (j = 0; j < el->num_values; j++) { + /* Get a case-folded copy of the attribute name */ + pAttrName = ldb_casefold((struct ldb_context *) module, + el->name); + /* ... bind the attribute value, if necessary */ switch (flags) { case LDB_FLAG_MOD_ADD: @@ -467,6 +662,7 @@ lsqlite3_msg_to_sql(struct ldb_module *module, " (eid, attr_value) " " VALUES " " (%lld, %Q);", + pAttrName, eid, el->values[j].data); QUERY_NOROWS(lsqlite3, FALSE, @@ -486,6 +682,7 @@ lsqlite3_msg_to_sql(struct ldb_module *module, "UPDATE ldb_attr_%q " " SET attr_value = %Q " " WHERE eid = %lld;", + pAttrName, el->values[j].data, eid); QUERY_NOROWS(lsqlite3, @@ -506,6 +703,7 @@ lsqlite3_msg_to_sql(struct ldb_module *module, "DELETE FROM ldb_attr_%q " " WHERE eid = %lld " " AND attr_value = %Q;", + pAttrName, eid, el->values[j].data); QUERY_NOROWS(lsqlite3, @@ -903,16 +1101,11 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3, ; /* Skip protocol indicator of url */ - if (strchr(url, ':')) { - if (strncmp(url, "sqlite://", 9) != 0) { - errno = EINVAL; - return SQLITE_MISUSE; - } - p = url + 9; - } else { - p = url; - } - + if ((p = strchr(url, ':')) == NULL) { + return SQLITE_MISUSE; + } else { + ++p; + } /* * See if we'll be creating a new database, or opening an existing one -- cgit From 7fc1c3553cd3666c234ec302a54ebd331589c934 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Wed, 8 Jun 2005 19:49:49 +0000 Subject: r7408: added DN explode function, based on simo's ldap_parse_dn() function. simo, when you get a chance, please change your license so this can be linked with ldb. (This used to be commit 588a1d1451d4117cb6e427a293455f2a5657b604) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 55 +++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 14 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 25efc8ced2..147ee599a9 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -569,23 +569,52 @@ lsqlite3_search(struct ldb_module * module, "SELECT entry.entry_data\n" " FROM ldb_entry AS entry\n" " WHERE entry.eid IN\n" - " (SELECT ldb_entry.eid\n" + " (SELECT DISTINCT ldb_entry.eid\n" " FROM ldb_entry,\n" " ldb_descendants,\n" " %q\n" " WHERE ldb_descendants.aeid = %lld\n" " AND ldb_entry.eid = ldb_descendants.deid\n" " AND ldap_entry.eid IN\n" - "%s);", + "%s" + ");", table_list, + eid, sql_constraints); break; -#warning "scope BASE and ONLEVEL not yet implemented" case LDB_SCOPE_BASE: + sql = sqlite3_mprintf( + "SELECT entry.entry_data\n" + " FROM ldb_entry AS entry\n" + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM %q\n" + " WHERE ldb_entry.eid = %lld\n" + " AND ldb_entry.eid IN\n" + "%s" + ");", + table_list, + eid, + sql_constraints); break; case LDB_SCOPE_ONELEVEL: + sql = sqlite3_mprintf( + "SELECT entry.entry_data\n" + " FROM ldb_entry AS entry\n" + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry AS pchild, " + " %q\n" + " WHERE ldb_entry.eid = pchild.eid " + " AND pchild.peid = %lld " + " AND ldb_entry.eid IN\n" + "%s" + ");", + table_list, + eid, + sql_constraints); break; } @@ -599,9 +628,7 @@ lsqlite3_new_attr(struct ldb_module * module, { struct lsqlite3_private * lsqlite3 = module->private_data; - /* Get a case-folded copy of the attribute name */ - pAttrName = ldb_casefold((struct ldb_context *) module, pAttrName); - + /* NOTE: pAttrName is assumed to already be case-folded here! */ QUERY_NOROWS(lsqlite3, FALSE, "CREATE TABLE ldb_attr_%q " @@ -639,9 +666,13 @@ lsqlite3_msg_to_sql(struct ldb_module * module, flags = el->flags & LDB_FLAG_MOD_MASK; } + /* Get a case-folded copy of the attribute name */ + pAttrName = ldb_casefold((struct ldb_context *) module, + el->name); + if (flags == LDB_FLAG_MOD_ADD) { /* Create the attribute table if it doesn't exist */ - if (lsqlite3_new_attr(module, el->name) != 0) { + if (lsqlite3_new_attr(module, pAttrName) != 0) { return -1; } } @@ -649,10 +680,6 @@ lsqlite3_msg_to_sql(struct ldb_module * module, /* For each value of the specified attribute name... */ for (j = 0; j < el->num_values; j++) { - /* Get a case-folded copy of the attribute name */ - pAttrName = ldb_casefold((struct ldb_context *) module, - el->name); - /* ... bind the attribute value, if necessary */ switch (flags) { case LDB_FLAG_MOD_ADD: @@ -725,7 +752,7 @@ lsqlite3_msg_to_sql(struct ldb_module * module, static int -lsqlite3_new_dn(struct ldb_module *module, +lsqlite3_new_dn(struct ldb_module * module, char * pDN, long long * pEID) { @@ -738,10 +765,10 @@ lsqlite3_new_dn(struct ldb_module *module, /* Parse the DN into its constituent components */ #warning "this simple parse of DN ignores escaped '=' and ','. fix it." while (pDN != NULL) { - pName = strsep(&pDN, ","); + pName = strsep(&pValue, "="); if (pDN == NULL) { - /* Attribute name with value? Should not occur. */ + /* Attribute name without value? Should not occur. */ return -1; } -- cgit From a6717fae681f89cf427e282d645029ca0b3e4d44 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Thu, 9 Jun 2005 02:47:26 +0000 Subject: r7418: work in progress (This used to be commit 2a13e7655b1bce88694ddbb6a4d9349008ba42f0) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 58 ++++++++++++++++--------------- 1 file changed, 30 insertions(+), 28 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 147ee599a9..4f774efbae 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -37,6 +37,7 @@ #include "ldb/include/ldb.h" #include "ldb/include/ldb_private.h" #include "ldb/include/ldb_parse.h" +#include "ldb/include/ldb_explode_dn.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" #ifndef FALSE @@ -172,9 +173,11 @@ lsqlite3_option_find(const struct lsqlite3_private *lsqlite3, callback function used in call to ldb_dn_fold() for determining whether an attribute type requires case folding. */ -static int lsqlite3_case_fold_attr_required(struct ldb_module *module, - char *attr) +static int lsqlite3_case_fold_attr_required(void * hUserData, + char *attr) { +// struct ldb_module * module = hUserData; + #warning "currently, all attributes require case folding" return TRUE; } @@ -184,9 +187,9 @@ static int lsqlite3_case_fold_attr_required(struct ldb_module *module, * rename a record */ static int -lsqlite3_rename(struct ldb_module *module, - const char *olddn, - const char *newdn) +lsqlite3_rename(struct ldb_module * module, + const char * olddn, + const char * newdn) { /* ignore ltdb specials */ if (olddn[0] == '@' ||newdn[0] == '@') { @@ -478,7 +481,7 @@ lsqlite3_search(struct ldb_module * module, { int ret; int bLoop; - long long eid; + long long eid = 0; char * sql; char * sql_constraints; char * table_list; @@ -509,7 +512,7 @@ lsqlite3_search(struct ldb_module * module, pTail, -1, &pStmt, - &pTail)) != SQLITE_OK) { + NULL)) != SQLITE_OK) { ret = -1; break; } @@ -541,17 +544,24 @@ lsqlite3_search(struct ldb_module * module, * Normal condition is only one time through loop. Loop is * rerun in error conditions, via "continue", above. */ + sqlite3_free(discard_const_p(char, pTail)); ret = 0; bLoop = FALSE; } + if (ret != 0) { + sqlite3_free(discard_const_p(char, pTail)); + return -1; + } + /* Parse the filter expression into a tree we can work with */ if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { + sqlite3_free(discard_const_p(char, pTail)); return -1; } /* Allocate a temporary talloc context */ - hTalloc = talloc_new(module); + hTalloc = talloc_new(module->ldb); /* Move the parse tree to our temporary context */ talloc_steal(hTalloc, pTree); @@ -756,28 +766,20 @@ lsqlite3_new_dn(struct ldb_module * module, char * pDN, long long * pEID) { - char * pName; - char * pValue; - - /* Normalize the distinguished name */ - pDN = ldb_dn_fold(module, pDN, lsqlite3_case_fold_attr_required); - - /* Parse the DN into its constituent components */ -#warning "this simple parse of DN ignores escaped '=' and ','. fix it." - while (pDN != NULL) { - pName = strsep(&pValue, "="); - - if (pDN == NULL) { - /* Attribute name without value? Should not occur. */ - return -1; - } - - pValue = pName; - strsep(&pValue, "="); - -#warning "*** lsqlite3_new_dn() not yet fully implemented ***" + struct ldb_dn * pExplodedDN; + struct ldb_context * ldb = module->ldb; +// struct lsqlite3_private * lsqlite3 = module->private_data; + + /* Explode and normalize the DN */ + if ((pExplodedDN = + ldb_explode_dn(ldb, + pDN, + ldb, + lsqlite3_case_fold_attr_required)) == NULL) { + return -1; } +#warning "*** lsqlite3_new_dn() not yet fully implemented ***" return -1; } -- cgit From c63c28f5bd46e4a03e1cdd12b78934c0b88635a8 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Thu, 9 Jun 2005 14:15:09 +0000 Subject: r7437: Make Simo happy. I still think this URI syntax for a 'protocol' which has no network component is stupid; it should just be sqlite:local_file or sqlite:/full/path/to/file but there is enough precedent to warrant the behavior that Simo wants that it is not worth arguing. (This used to be commit 61dcb462f30a65256e263e87c192ed7f5280c7af) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 4f774efbae..54f8903231 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1130,7 +1130,7 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3, ; /* Skip protocol indicator of url */ - if ((p = strchr(url, ':')) == NULL) { + if (strncmp(url, "sqlite://", 9) != 0) { return SQLITE_MISUSE; } else { ++p; -- cgit From ee3f4b12d22459405372e1c72efe3079a052601d Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Thu, 9 Jun 2005 14:50:32 +0000 Subject: r7438: work in progress (This used to be commit 2fc5343f0637ef3109b079dbc33d6cf4e58c8d5e) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 323 ++++++++++++++---------------- 1 file changed, 149 insertions(+), 174 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 54f8903231..c0e3963743 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -56,6 +56,16 @@ } \ } while (0) +#define QUERY_INT(lsqlite3, result_var, bRollbackOnError, sql...) \ + do { \ + if (lsqlite3_query_int(lsqlite3, &result_var, sql) != 0) { \ + if (bRollbackOnError) { \ + lsqlite3_query_norows(lsqlite3, \ + "ROLLBACK;"); \ + } \ + return -1; \ + } \ + } while (0) /* * lsqlite3_query_norows() @@ -140,6 +150,94 @@ lsqlite3_query_norows(const struct lsqlite3_private *lsqlite3, } +/* + * lsqlite3_query_int() + * + * This function is used for the common case of queries that return a single + * integer value. + * + * NOTE: If more than one value is returned by the query, all but the first + * one will be ignored. + */ +static int +lsqlite3_query_int(const struct lsqlite3_private * lsqlite3, + long long * pRet, + const char * pSql, + ...) +{ + int ret; + int bLoop; + char * p; + const char * pTail; + sqlite3_stmt * pStmt; + va_list args; + + /* Begin access to variable argument list */ + va_start(args, pSql); + + /* Format the query */ + if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { + return -1; + } + + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { + + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + pTail, + -1, + &pStmt, + &pTail)) != SQLITE_OK) { + ret = -1; + break; + } + + /* No rows expected, so just step through machine code once */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_ROW) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* Get the value to be returned */ + *pRet = sqlite3_column_int64(pStmt, 0); + + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + ret = 0; + bLoop = FALSE; + } + + /* All done with variable argument list */ + va_end(args); + + /* Free the memory we allocated for our query string */ + sqlite3_free(p); + + return ret; +} + + #if 0 /* * we don't need this right now, but will once we add some backend options @@ -479,15 +577,11 @@ lsqlite3_search(struct ldb_module * module, const char * const attrs[], struct ldb_message *** res) { - int ret; - int bLoop; long long eid = 0; char * sql; char * sql_constraints; char * table_list; char * hTalloc; - const char * pTail; - sqlite3_stmt * pStmt; struct ldb_parse_tree * pTree; struct lsqlite3_private * lsqlite3 = module->private_data; @@ -495,68 +589,22 @@ lsqlite3_search(struct ldb_module * module, pBaseDN = ""; } + /* Begin a transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "BEGIN IMMEDIATE;"); + /* * Obtain the eid of the base DN */ - if ((pTail = sqlite3_mprintf("SELECT eid " - " FROM ldb_attr_dn " - " WHERE attr_value = %Q;", - pBaseDN)) == NULL) { - return -1; - } - - for (bLoop = TRUE; bLoop; ) { - - /* Compile the SQL statement into sqlite virtual machine */ - if ((ret = sqlite3_prepare(lsqlite3->sqlite, - pTail, - -1, - &pStmt, - NULL)) != SQLITE_OK) { - ret = -1; - break; - } - - /* One row expected */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_ROW) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* Retrieve the EID */ - eid = sqlite3_column_int64(pStmt, 0); - - /* Free the virtual machine */ - if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - sqlite3_free(discard_const_p(char, pTail)); - ret = 0; - bLoop = FALSE; - } - - if (ret != 0) { - sqlite3_free(discard_const_p(char, pTail)); - return -1; - } + QUERY_INT(lsqlite3, + eid, + TRUE, + "SELECT eid " + " FROM ldb_attr_dn " + " WHERE attr_value = %Q;", + pBaseDN); /* Parse the filter expression into a tree we can work with */ if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { - sqlite3_free(discard_const_p(char, pTail)); return -1; } @@ -628,7 +676,12 @@ lsqlite3_search(struct ldb_module * module, break; } - return ret; +#warning "retrieve and return the result set of the search here" + + /* End the transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;"); + + return 0; } @@ -830,12 +883,6 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) { - int ret; - int bLoop; - char * p; - const char * pTail; - long long eid; - sqlite3_stmt * pStmt; struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ @@ -846,72 +893,6 @@ lsqlite3_modify(struct ldb_module *module, /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); - /* Format the query */ - if ((p = sqlite3_mprintf( - "SELECT eid " - " FROM ldb_entry " - " WHERE dn = %Q;", - ldb_dn_fold(module, - msg->dn, - lsqlite3_case_fold_attr_required))) == NULL) { - return -1; - } - - /* Get the id of this DN. */ - for (bLoop = TRUE; bLoop; ) { - - /* Compile the SQL statement into sqlite virtual machine */ - if ((ret = sqlite3_prepare(lsqlite3->sqlite, - pTail, - -1, - &pStmt, - &pTail)) != SQLITE_OK) { - ret = -1; - break; - } - - /* One row expected */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_ROW) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* Retrieve the EID */ - eid = sqlite3_column_int64(pStmt, 0); - - /* Free the virtual machine */ - if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* Modify attributes as specified */ - if (lsqlite3_msg_to_sql(module, msg, eid, FALSE) != 0) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); - return -1; - } - - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - ret = 0; - bLoop = FALSE; - } - - if (ret != 0) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); - return -1; - } - /* Everything worked. Commit it! */ QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); return 0 ; @@ -982,10 +963,9 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3, const char *url) { int ret; - int bNewDatabase = FALSE; - char * p; + const char * p; + long long queryInt; const char * pTail; - struct stat statbuf; sqlite3_stmt * stmt; const char * schema = "-- ------------------------------------------------------" @@ -1133,25 +1113,29 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3, if (strncmp(url, "sqlite://", 9) != 0) { return SQLITE_MISUSE; } else { - ++p; + p = url + 9; } /* * See if we'll be creating a new database, or opening an existing one */ -#warning "eliminate stat() here; concurrent processes could conflict" - if ((stat(p, &statbuf) < 0 && errno == ENOENT) || - statbuf.st_size == 0) { - - bNewDatabase = TRUE; - } - /* Try to open the (possibly empty/non-existent) database */ if ((ret = sqlite3_open(p, &lsqlite3->sqlite)) != SQLITE_OK) { return ret; } - if (bNewDatabase) { + /* Begin a transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); + + /* Determine if this is a new database */ + QUERY_INT(lsqlite3, + queryInt, + TRUE, + "SELECT COUNT(*) " + " FROM sqlite_master " + " WHERE type = 'table';"); + + if (queryInt == 0) { /* * Create the database schema */ @@ -1174,35 +1158,26 @@ lsqlite3_initialize(struct lsqlite3_private *lsqlite3, /* * Ensure that the database we opened is one of ours */ - if ((ret = sqlite3_prepare( - lsqlite3->sqlite, - "SELECT COUNT(*) " - " FROM sqlite_master " - " WHERE type = 'table' " - " AND name IN " - " (" - " 'ldb_entry', " - " 'ldb_descendants', " - " 'ldb_object_classes' " - " );", - -1, - &stmt, - &pTail)) != SQLITE_OK || - (ret = sqlite3_step(stmt)) != SQLITE_ROW || - sqlite3_column_int(stmt, 0) != 3 || - (ret = sqlite3_finalize(stmt)) != SQLITE_OK || - - (ret = sqlite3_prepare( - lsqlite3->sqlite, - "SELECT 1 " - " FROM ldb_info " - " WHERE database_type = 'LDB' " - " AND version = '1.0';", - -1, - &stmt, - &pTail)) != SQLITE_OK || - (ret = sqlite3_step(stmt)) != SQLITE_ROW || - (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { + if (lsqlite3_query_int(lsqlite3, + &queryInt, + "SELECT " + " (SELECT COUNT(*) = 3" + " FROM sqlite_master " + " WHERE type = 'table' " + " AND name IN " + " (" + " 'ldb_entry', " + " 'ldb_descendants', " + " 'ldb_object_classes' " + " ) " + " ) " + " AND " + " (SELECT 1 " + " FROM ldb_info " + " WHERE database_type = 'LDB' " + " AND version = '1.0'" + " );") != 0 || + queryInt != 1) { /* It's not one that we created. See ya! */ (void) sqlite3_close(lsqlite3->sqlite); -- cgit From b501bf17ab89b0838cdd13d67f2e16fcc881e59d Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Thu, 9 Jun 2005 17:16:49 +0000 Subject: r7443: reorg functions for readability (This used to be commit 7543acfa9fe87b43cfee482cf02e56d73d29596b) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2061 +++++++++++++++-------------- 1 file changed, 1059 insertions(+), 1002 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index c0e3963743..c16708672d 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -40,6 +40,10 @@ #include "ldb/include/ldb_explode_dn.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" +/* + * Macros used throughout + */ + #ifndef FALSE # define FALSE (0) # define TRUE (! FALSE) @@ -47,9 +51,9 @@ #define QUERY_NOROWS(lsqlite3, bRollbackOnError, sql...) \ do { \ - if (lsqlite3_query_norows(lsqlite3, sql) != 0) { \ + if (query_norows(lsqlite3, sql) != 0) { \ if (bRollbackOnError) { \ - lsqlite3_query_norows(lsqlite3, \ + query_norows(lsqlite3, \ "ROLLBACK;"); \ } \ return -1; \ @@ -58,899 +62,689 @@ #define QUERY_INT(lsqlite3, result_var, bRollbackOnError, sql...) \ do { \ - if (lsqlite3_query_int(lsqlite3, &result_var, sql) != 0) { \ + if (query_int(lsqlite3, &result_var, sql) != 0) { \ if (bRollbackOnError) { \ - lsqlite3_query_norows(lsqlite3, \ + query_norows(lsqlite3, \ "ROLLBACK;"); \ } \ return -1; \ } \ } while (0) + /* - * lsqlite3_query_norows() - * - * This function is used for queries that are not expected to return any rows, - * e.g. BEGIN, COMMIT, ROLLBACK, CREATE TABLE, INSERT, UPDATE, DELETE, etc. - * There are no provisions here for returning data from rows in a table, so do - * not pass SELECT queries to this function. + * Forward declarations */ static int -lsqlite3_query_norows(const struct lsqlite3_private *lsqlite3, - const char *pSql, - ...) -{ - int ret; - int bLoop; - char * p; - const char * pTail; - sqlite3_stmt * pStmt; - va_list args; - - /* Begin access to variable argument list */ - va_start(args, pSql); - - /* Format the query */ - if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { - return -1; - } - - /* - * Prepare and execute the SQL statement. Loop allows retrying on - * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, - * requiring retrying the operation. - */ - for (bLoop = TRUE; bLoop; ) { +lsqlite3_rename(struct ldb_module * module, + const char * olddn, + const char * newdn); - /* Compile the SQL statement into sqlite virtual machine */ - if ((ret = sqlite3_prepare(lsqlite3->sqlite, - pTail, - -1, - &pStmt, - &pTail)) != SQLITE_OK) { - ret = -1; - break; - } - - /* No rows expected, so just step through machine code once */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_DONE) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } +static int +lsqlite3_delete(struct ldb_module *module, + const char *dn); - /* Free the virtual machine */ - if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } +static int +lsqlite3_search(struct ldb_module * module, + const char * pBaseDN, + enum ldb_scope scope, + const char * pExpression, + const char * const attrs[], + struct ldb_message *** res); - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - ret = 0; - bLoop = FALSE; - } +static int +lsqlite3_add(struct ldb_module *module, + const struct ldb_message *msg); - /* All done with variable argument list */ - va_end(args); +static int +lsqlite3_modify(struct ldb_module *module, + const struct ldb_message *msg); - /* Free the memory we allocated for our query string */ - sqlite3_free(p); +static int +lsqlite3_lock(struct ldb_module *module, + const char *lockname); - return ret; -} +static int +lsqlite3_unlock(struct ldb_module *module, + const char *lockname); +static const char * +lsqlite3_errstring(struct ldb_module *module); -/* - * lsqlite3_query_int() - * - * This function is used for the common case of queries that return a single - * integer value. - * - * NOTE: If more than one value is returned by the query, all but the first - * one will be ignored. - */ static int -lsqlite3_query_int(const struct lsqlite3_private * lsqlite3, - long long * pRet, - const char * pSql, - ...) -{ - int ret; - int bLoop; - char * p; - const char * pTail; - sqlite3_stmt * pStmt; - va_list args; - - /* Begin access to variable argument list */ - va_start(args, pSql); +initialize(struct lsqlite3_private *lsqlite3, + const char *url); - /* Format the query */ - if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { - return -1; - } +static int +destructor(void *p); - /* - * Prepare and execute the SQL statement. Loop allows retrying on - * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, - * requiring retrying the operation. - */ - for (bLoop = TRUE; bLoop; ) { +static int +query_norows(const struct lsqlite3_private *lsqlite3, + const char *pSql, + ...); - /* Compile the SQL statement into sqlite virtual machine */ - if ((ret = sqlite3_prepare(lsqlite3->sqlite, - pTail, - -1, - &pStmt, - &pTail)) != SQLITE_OK) { - ret = -1; - break; - } - - /* No rows expected, so just step through machine code once */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_ROW) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } +static int +query_int(const struct lsqlite3_private * lsqlite3, + long long * pRet, + const char * pSql, + ...); - /* Get the value to be returned */ - *pRet = sqlite3_column_int64(pStmt, 0); +static int case_fold_attr_required(void * hUserData, + char *attr); - /* Free the virtual machine */ - if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } +static char * +parsetree_to_sql(struct ldb_module *module, + char * hTalloc, + const struct ldb_parse_tree *t); - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - ret = 0; - bLoop = FALSE; - } +static char * +parsetree_to_tablelist(struct ldb_module *module, + char * hTalloc, + const struct ldb_parse_tree *t); - /* All done with variable argument list */ - va_end(args); +static int +new_attr(struct ldb_module * module, + char * pAttrName); - /* Free the memory we allocated for our query string */ - sqlite3_free(p); +static int +msg_to_sql(struct ldb_module * module, + const struct ldb_message * msg, + long long eid, + int use_flags); - return ret; -} +static int +new_dn(struct ldb_module * module, + char * pDN, + long long * pEID); -#if 0 /* - * we don't need this right now, but will once we add some backend options - * - * find an option in an option list (a null terminated list of strings) - * - * this assumes the list is short. If it ever gets long then we really should - * do this in some smarter way + * Table of operations for the sqlite3 backend */ -static const char * -lsqlite3_option_find(const struct lsqlite3_private *lsqlite3, - const char *name) -{ - int i; - size_t len = strlen(name); +static const struct ldb_module_ops lsqlite3_ops = { + "sqlite", + lsqlite3_search, + lsqlite3_add, + lsqlite3_modify, + lsqlite3_delete, + lsqlite3_rename, + lsqlite3_lock, + lsqlite3_unlock, + lsqlite3_errstring +}; - if (!lsqlite3->options) return NULL; - for (i=0;lsqlite3->options[i];i++) { - if (strncmp(lsqlite3->options[i], name, len) == 0 && - lsqlite3->options[i][len] == '=') { - return &lsqlite3->options[i][len+1]; - } - } - return NULL; -} -#endif /* - callback function used in call to ldb_dn_fold() for determining whether an - attribute type requires case folding. -*/ -static int lsqlite3_case_fold_attr_required(void * hUserData, - char *attr) -{ -// struct ldb_module * module = hUserData; - -#warning "currently, all attributes require case folding" - return TRUE; -} + * Public functions + */ /* - * rename a record + * connect to the database */ -static int -lsqlite3_rename(struct ldb_module * module, - const char * olddn, - const char * newdn) +struct ldb_context * +lsqlite3_connect(const char *url, + unsigned int flags, + const char *options[]) { - /* ignore ltdb specials */ - if (olddn[0] == '@' ||newdn[0] == '@') { - return 0; - } + int i; + int ret; + struct ldb_context * ldb = NULL; + struct lsqlite3_private * lsqlite3 = NULL; -#warning "lsqlite3_rename() is not yet supported" - return -1; -} + ldb = talloc(NULL, struct ldb_context); + if (!ldb) { + errno = ENOMEM; + goto failed; + } -/* - * delete a record - */ -static int -lsqlite3_delete(struct ldb_module *module, - const char *dn) -{ - /* ignore ltdb specials */ - if (dn[0] == '@') { - return 0; + lsqlite3 = talloc(ldb, struct lsqlite3_private); + if (!lsqlite3) { + errno = ENOMEM; + goto failed; } - - return -1; -} -#if 0 /* not currently used */ -/* - * free a search result - */ -static int -lsqlite3_search_free(struct ldb_module *module, - struct ldb_message **res) -{ - talloc_free(res); - return 0; -} -#endif + lsqlite3->sqlite = NULL; + lsqlite3->options = NULL; + lsqlite3->lock_count = 0; + + ret = initialize(lsqlite3, url); + if (ret != SQLITE_OK) { + goto failed; + } + + talloc_set_destructor(lsqlite3, destructor); + + ldb->modules = talloc(ldb, struct ldb_module); + if (!ldb->modules) { + errno = ENOMEM; + goto failed; + } + ldb->modules->ldb = ldb; + ldb->modules->prev = ldb->modules->next = NULL; + ldb->modules->private_data = lsqlite3; + ldb->modules->ops = &lsqlite3_ops; + + if (options) { + /* + * take a copy of the options array, so we don't have to rely + * on the caller keeping it around (it might be dynamic) + */ + for (i=0;options[i];i++) ; + + lsqlite3->options = talloc_array(lsqlite3, char *, i+1); + if (!lsqlite3->options) { + goto failed; + } + + for (i=0;options[i];i++) { + + lsqlite3->options[i+1] = NULL; + lsqlite3->options[i] = + talloc_strdup(lsqlite3->options, options[i]); + if (!lsqlite3->options[i]) { + goto failed; + } + } + } + + return ldb; + +failed: + if (lsqlite3->sqlite != NULL) { + (void) sqlite3_close(lsqlite3->sqlite); + } + talloc_free(ldb); + return NULL; +} /* - * add a single set of ldap message values to a ldb_message + * Interface functions referenced by lsqlite3_ops */ -/* get things to compile before we actually implement this function */ -struct berval -{ - int x; -}; - -#warning "lsqlite3_add_msg_attr() not yet implemented or used" -#if 0 +/* rename a record */ static int -lsqlite3_add_msg_attr(struct ldb_context *ldb, - struct ldb_message *msg, - const char *attr, - struct berval **bval) +lsqlite3_rename(struct ldb_module * module, + const char * olddn, + const char * newdn) { - int i; - int count; - struct ldb_message_element * el; + /* ignore ltdb specials */ + if (olddn[0] == '@' ||newdn[0] == '@') { + return 0; + } - count = ldap_count_values_len(bval); +#warning "lsqlite3_rename() is not yet supported" + return -1; +} - if (count <= 0) { - return -1; +/* delete a record */ +static int +lsqlite3_delete(struct ldb_module *module, + const char *dn) +{ + /* ignore ltdb specials */ + if (dn[0] == '@') { + return 0; } + + return -1; +} - el = talloc_realloc(msg, msg->elements, struct ldb_message_element, - msg->num_elements + 1); - if (!el) { - errno = ENOMEM; - return -1; +/* search for matching records */ +static int +lsqlite3_search(struct ldb_module * module, + const char * pBaseDN, + enum ldb_scope scope, + const char * pExpression, + const char * const attrs[], + struct ldb_message *** res) +{ + long long eid = 0; + char * sql; + char * sql_constraints; + char * table_list; + char * hTalloc; + struct ldb_parse_tree * pTree; + struct lsqlite3_private * lsqlite3 = module->private_data; + + if (pBaseDN == NULL) { + pBaseDN = ""; } - msg->elements = el; + /* Begin a transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "BEGIN IMMEDIATE;"); - el = &msg->elements[msg->num_elements]; + /* + * Obtain the eid of the base DN + */ + QUERY_INT(lsqlite3, + eid, + TRUE, + "SELECT eid " + " FROM ldb_attr_dn " + " WHERE attr_value = %Q;", + pBaseDN); - el->name = talloc_strdup(msg->elements, attr); - if (!el->name) { - errno = ENOMEM; + /* Parse the filter expression into a tree we can work with */ + if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { return -1; } - el->flags = 0; + + /* Allocate a temporary talloc context */ + hTalloc = talloc_new(module->ldb); - el->num_values = 0; - el->values = talloc_array(msg->elements, struct ldb_val, count); - if (!el->values) { - errno = ENOMEM; - return -1; - } + /* Move the parse tree to our temporary context */ + talloc_steal(hTalloc, pTree); + + /* Convert filter into a series of SQL statements (constraints) */ + sql_constraints = parsetree_to_sql(module, hTalloc, pTree); + + /* Get the list of attribute names to use as our extra table list */ + table_list = parsetree_to_tablelist(module, hTalloc, pTree); - for (i=0;ivalues[i].data = talloc_memdup(el->values, bval[i]->bv_val, bval[i]->bv_len); - if (!el->values[i].data) { - return -1; - } - el->values[i].length = bval[i]->bv_len; - el->num_values++; - } + switch(scope) { + case LDB_SCOPE_DEFAULT: + case LDB_SCOPE_SUBTREE: + sql = sqlite3_mprintf( + "SELECT entry.entry_data\n" + " FROM ldb_entry AS entry\n" + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry,\n" + " ldb_descendants,\n" + " %q\n" + " WHERE ldb_descendants.aeid = %lld\n" + " AND ldb_entry.eid = ldb_descendants.deid\n" + " AND ldap_entry.eid IN\n" + "%s" + ");", + table_list, + eid, + sql_constraints); + break; - msg->num_elements++; + case LDB_SCOPE_BASE: + sql = sqlite3_mprintf( + "SELECT entry.entry_data\n" + " FROM ldb_entry AS entry\n" + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM %q\n" + " WHERE ldb_entry.eid = %lld\n" + " AND ldb_entry.eid IN\n" + "%s" + ");", + table_list, + eid, + sql_constraints); + break; + + case LDB_SCOPE_ONELEVEL: + sql = sqlite3_mprintf( + "SELECT entry.entry_data\n" + " FROM ldb_entry AS entry\n" + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry AS pchild, " + " %q\n" + " WHERE ldb_entry.eid = pchild.eid " + " AND pchild.peid = %lld " + " AND ldb_entry.eid IN\n" + "%s" + ");", + table_list, + eid, + sql_constraints); + break; + } + +#warning "retrieve and return the result set of the search here" + + /* End the transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;"); return 0; } -#endif -static char * -lsqlite3_parsetree_to_sql(struct ldb_module *module, - char * hTalloc, - const struct ldb_parse_tree *t) + +/* add a record */ +static int +lsqlite3_add(struct ldb_module *module, + const struct ldb_message *msg) { - int i; - char * child; - char * p; - char * ret = NULL; - char * pAttrName; - + long long eid; + struct lsqlite3_private * lsqlite3 = module->private_data; - switch(t->operation) { - case LDB_OP_SIMPLE: - break; + /* ignore ltdb specials */ + if (msg->dn[0] == '@') { + return 0; + } - case LDB_OP_AND: - ret = lsqlite3_parsetree_to_sql(module, - hTalloc, - t->u.list.elements[0]); + /* Begin a transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); - for (i = 1; i < t->u.list.num_elements; i++) { - child = - lsqlite3_parsetree_to_sql( - module, - hTalloc, - t->u.list.elements[i]); - ret = talloc_asprintf_append(ret, - "INTERSECT\n" - "%s\n", - child); - talloc_free(child); - } + /* + * Build any portions of the directory tree that don't exist. If the + * final component already exists, it's an error. + */ + if (new_dn(module, msg->dn, &eid) != 0) { + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + return -1; + } - child = ret; - ret = talloc_asprintf("(\n" - "%s\n" - ")\n", - child); - talloc_free(child); - return ret; + /* Add attributes to this new entry */ + if (msg_to_sql(module, msg, eid, FALSE) != 0) { + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + return -1; + } - case LDB_OP_OR: - child = - lsqlite3_parsetree_to_sql( - module, - hTalloc, - t->u.list.elements[0]); + /* Everything worked. Commit it! */ + QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); + return 0; +} - for (i = 1; i < t->u.list.num_elements; i++) { - child = - lsqlite3_parsetree_to_sql( - module, - hTalloc, - t->u.list.elements[i]); - ret = talloc_asprintf_append(ret, - "UNION\n" - "%s\n", - child); - talloc_free(child); - } - child = ret; - ret = talloc_asprintf("(\n" - "%s\n" - ")\n", - child); - talloc_free(child); - return ret; - case LDB_OP_NOT: - child = - lsqlite3_parsetree_to_sql( - module, - hTalloc, - t->u.not.child); - ret = talloc_asprintf(hTalloc, - "(\n" - " SELECT eid\n" - " FROM ldb_entry\n" - " WHERE eid NOT IN %s\n" - ")\n", - child); - talloc_free(child); - return ret; +/* modify a record */ +static int +lsqlite3_modify(struct ldb_module *module, + const struct ldb_message *msg) +{ + struct lsqlite3_private * lsqlite3 = module->private_data; - default: - /* should never occur */ - abort(); - }; - - /* Get a case-folded copy of the attribute name */ - pAttrName = ldb_casefold((struct ldb_context *) module, - t->u.simple.attr); + /* ignore ltdb specials */ + if (msg->dn[0] == '@') { + return 0; + } - /* - * For simple searches, we want to retrieve the list of EIDs that - * match the criteria. We accomplish this by searching the - * appropriate table, ldb_attr_, for the eid - * corresponding to all matching values. - */ - if (t->u.simple.value.length == 1 && - (*(const char *) t->u.simple.value.data) == '*') { - /* - * Special case for "attr_name=*". In this case, we want the - * eid corresponding to all values in the specified attribute - * table. - */ - if ((p = sqlite3_mprintf("(\n" - " SELECT eid\n" - " FROM ldb_attr_%q\n" - ")\n", - pAttrName)) == NULL) { - return NULL; - } + /* Begin a transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); - ret = talloc_strdup(hTalloc, p); - sqlite3_free(p); + /* Everything worked. Commit it! */ + QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); + return 0 ; +} - } else if (strcasecmp(t->u.simple.attr, "objectclass") == 0) { - /* - * For object classes, we want to search for all objectclasses - * that are subclasses as well. - */ - if ((p = sqlite3_mprintf( - "(\n" - " SELECT eid\n" - " FROM ldb_attr_objectclass\n" - " WHERE attr_name IN\n" - " (SELECT class_name\n" - " FROM ldb_objectclasses\n" - " WHERE tree_key GLOB\n" - " (SELECT tree_key\n" - " FROM ldb_objectclasses\n" - " WHERE class_name = %Q) || '*')\n" - ")\n", - t->u.simple.value.data)) == NULL) { - return NULL; - } +/* obtain a named lock */ +static int +lsqlite3_lock(struct ldb_module *module, + const char *lockname) +{ + if (lockname == NULL) { + return -1; + } - ret = talloc_strdup(hTalloc, p); - sqlite3_free(p); + /* TODO implement a local locking mechanism here */ - } else { - /* A normal query. */ - if ((p = sqlite3_mprintf("(\n" - " SELECT eid\n" - " FROM ldb_attr_%q\n" - " WHERE attr_value = %Q\n" - ")\n", - pAttrName, - t->u.simple.value.data)) == NULL) { - return NULL; - } + return 0; +} - ret = talloc_strdup(hTalloc, p); - sqlite3_free(p); +/* release a named lock */ +static int +lsqlite3_unlock(struct ldb_module *module, + const char *lockname) +{ + if (lockname == NULL) { + return -1; } - return ret; -} + /* TODO implement a local locking mechanism here */ + + return 0; +} -static char * -lsqlite3_parsetree_to_tablelist(struct ldb_module *module, - char * hTalloc, - const struct ldb_parse_tree *t) +/* return extended error information */ +static const char * +lsqlite3_errstring(struct ldb_module *module) { -#warning "obtain talloc'ed array of attribute names for table list" - return NULL; + struct lsqlite3_private * lsqlite3 = module->private_data; + + return sqlite3_errmsg(lsqlite3->sqlite); } + + /* - * search for matching records + * Static functions */ + static int -lsqlite3_search(struct ldb_module * module, - const char * pBaseDN, - enum ldb_scope scope, - const char * pExpression, - const char * const attrs[], - struct ldb_message *** res) +initialize(struct lsqlite3_private *lsqlite3, + const char *url) { - long long eid = 0; - char * sql; - char * sql_constraints; - char * table_list; - char * hTalloc; - struct ldb_parse_tree * pTree; - struct lsqlite3_private * lsqlite3 = module->private_data; - - if (pBaseDN == NULL) { - pBaseDN = ""; - } + int ret; + long long queryInt; + const char * pTail; + sqlite3_stmt * stmt; + const char * schema = + "-- ------------------------------------------------------" - /* Begin a transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "BEGIN IMMEDIATE;"); + "PRAGMA auto_vacuum=1;" - /* - * Obtain the eid of the base DN - */ - QUERY_INT(lsqlite3, - eid, - TRUE, - "SELECT eid " - " FROM ldb_attr_dn " - " WHERE attr_value = %Q;", - pBaseDN); + "-- ------------------------------------------------------" - /* Parse the filter expression into a tree we can work with */ - if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { - return -1; - } - - /* Allocate a temporary talloc context */ - hTalloc = talloc_new(module->ldb); + "BEGIN EXCLUSIVE;" - /* Move the parse tree to our temporary context */ - talloc_steal(hTalloc, pTree); - - /* Convert filter into a series of SQL statements (constraints) */ - sql_constraints = lsqlite3_parsetree_to_sql(module, hTalloc, pTree); - - /* Get the list of attribute names to use as our extra table list */ - table_list = lsqlite3_parsetree_to_tablelist(module, hTalloc, pTree); + "-- ------------------------------------------------------" - switch(scope) { - case LDB_SCOPE_DEFAULT: - case LDB_SCOPE_SUBTREE: - sql = sqlite3_mprintf( - "SELECT entry.entry_data\n" - " FROM ldb_entry AS entry\n" - " WHERE entry.eid IN\n" - " (SELECT DISTINCT ldb_entry.eid\n" - " FROM ldb_entry,\n" - " ldb_descendants,\n" - " %q\n" - " WHERE ldb_descendants.aeid = %lld\n" - " AND ldb_entry.eid = ldb_descendants.deid\n" - " AND ldap_entry.eid IN\n" - "%s" - ");", - table_list, - eid, - sql_constraints); - break; + "CREATE TABLE ldb_info AS" + " SELECT 'LDB' AS database_type," + " '1.0' AS version;" - case LDB_SCOPE_BASE: - sql = sqlite3_mprintf( - "SELECT entry.entry_data\n" - " FROM ldb_entry AS entry\n" - " WHERE entry.eid IN\n" - " (SELECT DISTINCT ldb_entry.eid\n" - " FROM %q\n" - " WHERE ldb_entry.eid = %lld\n" - " AND ldb_entry.eid IN\n" - "%s" - ");", - table_list, - eid, - sql_constraints); - break; + "-- ------------------------------------------------------" + "-- Schema" - case LDB_SCOPE_ONELEVEL: - sql = sqlite3_mprintf( - "SELECT entry.entry_data\n" - " FROM ldb_entry AS entry\n" - " WHERE entry.eid IN\n" - " (SELECT DISTINCT ldb_entry.eid\n" - " FROM ldb_entry AS pchild, " - " %q\n" - " WHERE ldb_entry.eid = pchild.eid " - " AND pchild.peid = %lld " - " AND ldb_entry.eid IN\n" - "%s" - ");", - table_list, - eid, - sql_constraints); - break; - } - -#warning "retrieve and return the result set of the search here" - - /* End the transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;"); + "/*" + " * The entry table holds the information about an entry. " + " * This table is used to obtain the EID of the entry and to " + " * support scope=one and scope=base. The parent and child" + " * table is included in the entry table since all the other" + " * attributes are dependent on EID." + " */" + "CREATE TABLE ldb_entry" + "(" + " -- Unique identifier of this LDB entry" + " eid INTEGER PRIMARY KEY," - return 0; -} + " -- Unique identifier of the parent LDB entry" + " peid INTEGER REFERENCES ldb_entry," + " -- Distinguished name of this entry" + " dn TEXT," -static int -lsqlite3_new_attr(struct ldb_module * module, - char * pAttrName) -{ - struct lsqlite3_private * lsqlite3 = module->private_data; + " -- Time when the entry was created" + " create_timestamp INTEGER," - /* NOTE: pAttrName is assumed to already be case-folded here! */ - QUERY_NOROWS(lsqlite3, - FALSE, - "CREATE TABLE ldb_attr_%q " - "(" - " eid INTEGER REFERENCES ldb_entry, " - " attr_value TEXT" - ");", - pAttrName); + " -- Time when the entry was last modified" + " modify_timestamp INTEGER," - return 0; -} + " -- Attributes of this entry, in the form" + " -- attr\1value\0[attr\1value\0]*\0" + " entry_data TEXT" + ");" -/* - * Issue a series of SQL statements to implement the ADD/MODIFY/DELETE - * requests in the ldb_message - */ -static int -lsqlite3_msg_to_sql(struct ldb_module * module, - const struct ldb_message * msg, - long long eid, - int use_flags) -{ - int flags; - char * pAttrName; - unsigned int i; - unsigned int j; - struct lsqlite3_private * lsqlite3 = module->private_data; - for (i = 0; i < msg->num_elements; i++) { - const struct ldb_message_element *el = &msg->elements[i]; + "/*" + " * The purpose of the descendant table is to support the" + " * subtree search feature. For each LDB entry with a unique" + " * ID (AEID), this table contains the unique identifiers" + " * (DEID) of the descendant entries." + " *" + " * For evern entry in the directory, a row exists in this" + " * table for each of its ancestors including itself. The " + " * size of the table depends on the depth of each entry. In " + " * the worst case, if all the entries were at the same " + " * depth, the number of rows in the table is O(nm) where " + " * n is the number of nodes in the directory and m is the " + " * depth of the tree. " + " */" + "CREATE TABLE ldb_descendants" + "(" + " -- The unique identifier of the ancestor LDB entry" + " aeid INTEGER REFERENCES ldb_entry," - if (! use_flags) { - flags = LDB_FLAG_MOD_ADD; - } else { - flags = el->flags & LDB_FLAG_MOD_MASK; - } + " -- The unique identifier of the descendant LDB entry" + " deid INTEGER REFERENCES ldb_entry" + ");" - /* Get a case-folded copy of the attribute name */ - pAttrName = ldb_casefold((struct ldb_context *) module, - el->name); - if (flags == LDB_FLAG_MOD_ADD) { - /* Create the attribute table if it doesn't exist */ - if (lsqlite3_new_attr(module, pAttrName) != 0) { - return -1; - } - } + "CREATE TABLE ldb_object_classes" + "(" + " -- Object classes are inserted into this table to track" + " -- their class hierarchy. 'top' is the top-level class" + " -- of which all other classes are subclasses." + " class_name TEXT PRIMARY KEY," - /* For each value of the specified attribute name... */ - for (j = 0; j < el->num_values; j++) { + " -- tree_key tracks the position of the class in" + " -- the hierarchy" + " tree_key TEXT UNIQUE" + ");" - /* ... bind the attribute value, if necessary */ - switch (flags) { - case LDB_FLAG_MOD_ADD: - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT INTO ldb_attr_%q " - " (eid, attr_value) " - " VALUES " - " (%lld, %Q);", - pAttrName, - eid, el->values[j].data); - QUERY_NOROWS(lsqlite3, - FALSE, - "UPDATE ldb_entry " - " SET entry_data = " - " add_attr(entry_data, " - " %Q, %Q) " - " WHERE eid = %lld;", - el->name, el->values[j].data, - eid); - - break; + "/*" + " * There is one attribute table per searchable attribute." + " */" + "/*" + "CREATE TABLE ldb_attr_ATTRIBUTE_NAME" + "(" + " -- The unique identifier of the LDB entry" + " eid INTEGER REFERENCES ldb_entry," - case LDB_FLAG_MOD_REPLACE: - QUERY_NOROWS(lsqlite3, - FALSE, - "UPDATE ldb_attr_%q " - " SET attr_value = %Q " - " WHERE eid = %lld;", - pAttrName, - el->values[j].data, - eid); - QUERY_NOROWS(lsqlite3, - FALSE, - "UPDATE ldb_entry " - " SET entry_data = " - " mod_attr(entry_data, " - " %Q, %Q) " - " WHERE eid = %lld;", - el->name, el->values[j].data, - eid); - break; + " -- Normalized attribute value" + " attr_value TEXT" + ");" + "*/" - case LDB_FLAG_MOD_DELETE: - /* No additional parameters to this query */ - QUERY_NOROWS(lsqlite3, - FALSE, - "DELETE FROM ldb_attr_%q " - " WHERE eid = %lld " - " AND attr_value = %Q;", - pAttrName, - eid, - el->values[j].data); - QUERY_NOROWS(lsqlite3, - FALSE, - "UPDATE ldb_entry " - " SET entry_data = " - " del_attr(entry_data, " - " %Q, %Q) " - " WHERE eid = %lld;", - el->name, el->values[j].data, - eid); - break; - } - } - } - return 0; -} + "-- ------------------------------------------------------" + "-- Indexes" -static int -lsqlite3_new_dn(struct ldb_module * module, - char * pDN, - long long * pEID) -{ - struct ldb_dn * pExplodedDN; - struct ldb_context * ldb = module->ldb; -// struct lsqlite3_private * lsqlite3 = module->private_data; + "-- ------------------------------------------------------" + "-- Triggers" - /* Explode and normalize the DN */ - if ((pExplodedDN = - ldb_explode_dn(ldb, - pDN, - ldb, - lsqlite3_case_fold_attr_required)) == NULL) { - return -1; - } + "CREATE TRIGGER ldb_entry_insert_tr" + " AFTER INSERT" + " ON ldb_entry" + " FOR EACH ROW" + " BEGIN" + " UPDATE ldb_entry" + " SET create_timestamp = strftime('%s', 'now')," + " modify_timestamp = strftime('%s', 'now')" + " WHERE eid = new.eid;" + " END;" -#warning "*** lsqlite3_new_dn() not yet fully implemented ***" - return -1; -} + "CREATE TRIGGER ldb_entry_update_tr" + " AFTER UPDATE" + " ON ldb_entry" + " FOR EACH ROW" + " BEGIN" + " UPDATE ldb_entry" + " SET modify_timestamp = strftime('%s', 'now')" + " WHERE eid = old.eid;" + " END;" + "-- ------------------------------------------------------" + "-- Table initialization" -/* - * add a record - */ -static int -lsqlite3_add(struct ldb_module *module, - const struct ldb_message *msg) -{ - long long eid; - struct lsqlite3_private * lsqlite3 = module->private_data; + "/* We need an implicit 'top' level object class */" + "INSERT INTO ldb_attributes (attr_name," + " parent_tree_key)" + " SELECT 'top', '';" - /* ignore ltdb specials */ - if (msg->dn[0] == '@') { - return 0; - } + "-- ------------------------------------------------------" - /* Begin a transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); + "COMMIT;" - /* - * Build any portions of the directory tree that don't exist. If the - * final component already exists, it's an error. - */ - if (lsqlite3_new_dn(module, msg->dn, &eid) != 0) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); - return -1; + "-- ------------------------------------------------------" + ; + + /* Skip protocol indicator of url */ + if (strncmp(url, "sqlite://", 9) != 0) { + return SQLITE_MISUSE; } - /* Add attributes to this new entry */ - if (lsqlite3_msg_to_sql(module, msg, eid, FALSE) != 0) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); - return -1; + /* Update pointer to just after the protocol indicator */ + url += 9; + + /* Try to open the (possibly empty/non-existent) database */ + if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) { + return ret; } - /* Everything worked. Commit it! */ - QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); - return 0; -} - - -/* - * modify a record - */ -static int -lsqlite3_modify(struct ldb_module *module, - const struct ldb_message *msg) -{ - struct lsqlite3_private * lsqlite3 = module->private_data; - - /* ignore ltdb specials */ - if (msg->dn[0] == '@') { - return 0; - } - /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); - /* Everything worked. Commit it! */ - QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); - return 0 ; -} - -static int -lsqlite3_lock(struct ldb_module *module, - const char *lockname) -{ - if (lockname == NULL) { - return -1; - } - - /* TODO implement a local locking mechanism here */ - - return 0; -} + /* Determine if this is a new database. No tables means it is. */ + QUERY_INT(lsqlite3, + queryInt, + TRUE, + "SELECT COUNT(*) " + " FROM sqlite_master " + " WHERE type = 'table';"); -static int -lsqlite3_unlock(struct ldb_module *module, - const char *lockname) -{ - if (lockname == NULL) { - return -1; - } + if (queryInt == 0) { + /* + * Create the database schema + */ + for (pTail = discard_const_p(char, schema); pTail != NULL; ) { - /* TODO implement a local locking mechanism here */ + if ((ret = sqlite3_prepare( + lsqlite3->sqlite, + pTail, + -1, + &stmt, + &pTail)) != SQLITE_OK || + (ret = sqlite3_step(stmt)) != SQLITE_DONE || + (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { - return 0; -} + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + (void) sqlite3_close(lsqlite3->sqlite); + return ret; + } + } + } else { + /* + * Ensure that the database we opened is one of ours + */ + if (query_int(lsqlite3, + &queryInt, + "SELECT " + " (SELECT COUNT(*) = 3" + " FROM sqlite_master " + " WHERE type = 'table' " + " AND name IN " + " (" + " 'ldb_entry', " + " 'ldb_descendants', " + " 'ldb_object_classes' " + " ) " + " ) " + " AND " + " (SELECT 1 " + " FROM ldb_info " + " WHERE database_type = 'LDB' " + " AND version = '1.0'" + " );") != 0 || + queryInt != 1) { + + /* It's not one that we created. See ya! */ + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + (void) sqlite3_close(lsqlite3->sqlite); + return SQLITE_MISUSE; + } + } -/* - * return extended error information - */ -static const char * -lsqlite3_errstring(struct ldb_module *module) -{ - struct lsqlite3_private * lsqlite3 = module->private_data; + /* Commit the transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "COMMIT;"); - return sqlite3_errmsg(lsqlite3->sqlite); + return SQLITE_OK; } - -static const struct ldb_module_ops lsqlite3_ops = { - "sqlite", - lsqlite3_search, - lsqlite3_add, - lsqlite3_modify, - lsqlite3_delete, - lsqlite3_rename, - lsqlite3_lock, - lsqlite3_unlock, - lsqlite3_errstring -}; - - static int -lsqlite3_destructor(void *p) +destructor(void *p) { struct lsqlite3_private * lsqlite3 = p; @@ -958,312 +752,575 @@ lsqlite3_destructor(void *p) return 0; } + +/* + * query_norows() + * + * This function is used for queries that are not expected to return any rows, + * e.g. BEGIN, COMMIT, ROLLBACK, CREATE TABLE, INSERT, UPDATE, DELETE, etc. + * There are no provisions here for returning data from rows in a table, so do + * not pass SELECT queries to this function. + */ static int -lsqlite3_initialize(struct lsqlite3_private *lsqlite3, - const char *url) +query_norows(const struct lsqlite3_private *lsqlite3, + const char *pSql, + ...) { int ret; - const char * p; - long long queryInt; + int bLoop; + char * p; const char * pTail; - sqlite3_stmt * stmt; - const char * schema = - "-- ------------------------------------------------------" - - "PRAGMA auto_vacuum=1;" + sqlite3_stmt * pStmt; + va_list args; + + /* Begin access to variable argument list */ + va_start(args, pSql); - "-- ------------------------------------------------------" + /* Format the query */ + if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { + return -1; + } - "BEGIN EXCLUSIVE;" + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { - "-- ------------------------------------------------------" + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + pTail, + -1, + &pStmt, + &pTail)) != SQLITE_OK) { + ret = -1; + break; + } + + /* No rows expected, so just step through machine code once */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_DONE) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } - "CREATE TABLE ldb_info AS" - " SELECT 'LDB' AS database_type," - " '1.0' AS version;" + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } - "-- ------------------------------------------------------" - "-- Schema" + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + ret = 0; + bLoop = FALSE; + } - "/*" - " * The entry table holds the information about an entry. " - " * This table is used to obtain the EID of the entry and to " - " * support scope=one and scope=base. The parent and child" - " * table is included in the entry table since all the other" - " * attributes are dependent on EID." - " */" - "CREATE TABLE ldb_entry" - "(" - " -- Unique identifier of this LDB entry" - " eid INTEGER PRIMARY KEY," + /* All done with variable argument list */ + va_end(args); - " -- Unique identifier of the parent LDB entry" - " peid INTEGER REFERENCES ldb_entry," + /* Free the memory we allocated for our query string */ + sqlite3_free(p); - " -- Distinguished name of this entry" - " dn TEXT," + return ret; +} - " -- Time when the entry was created" - " create_timestamp INTEGER," - " -- Time when the entry was last modified" - " modify_timestamp INTEGER," +/* + * query_int() + * + * This function is used for the common case of queries that return a single + * integer value. + * + * NOTE: If more than one value is returned by the query, all but the first + * one will be ignored. + */ +static int +query_int(const struct lsqlite3_private * lsqlite3, + long long * pRet, + const char * pSql, + ...) +{ + int ret; + int bLoop; + char * p; + const char * pTail; + sqlite3_stmt * pStmt; + va_list args; + + /* Begin access to variable argument list */ + va_start(args, pSql); - " -- Attributes of this entry, in the form" - " -- attr\1value\0[attr\1value\0]*\0" - " entry_data TEXT" - ");" + /* Format the query */ + if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { + return -1; + } + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { - "/*" - " * The purpose of the descendant table is to support the" - " * subtree search feature. For each LDB entry with a unique" - " * ID (AEID), this table contains the unique identifiers" - " * (DEID) of the descendant entries." - " *" - " * For evern entry in the directory, a row exists in this" - " * table for each of its ancestors including itself. The " - " * size of the table depends on the depth of each entry. In " - " * the worst case, if all the entries were at the same " - " * depth, the number of rows in the table is O(nm) where " - " * n is the number of nodes in the directory and m is the " - " * depth of the tree. " - " */" - "CREATE TABLE ldb_descendants" - "(" - " -- The unique identifier of the ancestor LDB entry" - " aeid INTEGER REFERENCES ldb_entry," + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + pTail, + -1, + &pStmt, + &pTail)) != SQLITE_OK) { + ret = -1; + break; + } + + /* No rows expected, so just step through machine code once */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_ROW) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } - " -- The unique identifier of the descendant LDB entry" - " deid INTEGER REFERENCES ldb_entry" - ");" + /* Get the value to be returned */ + *pRet = sqlite3_column_int64(pStmt, 0); + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } - "CREATE TABLE ldb_object_classes" - "(" - " -- Object classes are inserted into this table to track" - " -- their class hierarchy. 'top' is the top-level class" - " -- of which all other classes are subclasses." - " class_name TEXT PRIMARY KEY," + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + ret = 0; + bLoop = FALSE; + } - " -- tree_key tracks the position of the class in" - " -- the hierarchy" - " tree_key TEXT UNIQUE" - ");" + /* All done with variable argument list */ + va_end(args); - "/*" - " * There is one attribute table per searchable attribute." - " */" - "/*" - "CREATE TABLE ldb_attr_ATTRIBUTE_NAME" - "(" - " -- The unique identifier of the LDB entry" - " eid INTEGER REFERENCES ldb_entry," + /* Free the memory we allocated for our query string */ + sqlite3_free(p); - " -- Normalized attribute value" - " attr_value TEXT" - ");" - "*/" + return ret; +} - "-- ------------------------------------------------------" - "-- Indexes" +/* + callback function used in call to ldb_dn_fold() for determining whether an + attribute type requires case folding. +*/ +static int +case_fold_attr_required(void * hUserData, + char *attr) +{ +// struct ldb_module * module = hUserData; + +#warning "currently, all attributes require case folding" + return TRUE; +} - "-- ------------------------------------------------------" - "-- Triggers" +/* + * add a single set of ldap message values to a ldb_message + */ - "CREATE TRIGGER ldb_entry_insert_tr" - " AFTER INSERT" - " ON ldb_entry" - " FOR EACH ROW" - " BEGIN" - " UPDATE ldb_entry" - " SET create_timestamp = strftime('%s', 'now')," - " modify_timestamp = strftime('%s', 'now')" - " WHERE eid = new.eid;" - " END;" +#warning "add_msg_attr() not yet implemented or used" +#if 0 +static int +add_msg_attr(struct ldb_context *ldb, + struct ldb_message *msg, + const char *attr, + struct berval **bval) +{ + int i; + int count; + struct ldb_message_element * el; - "CREATE TRIGGER ldb_entry_update_tr" - " AFTER UPDATE" - " ON ldb_entry" - " FOR EACH ROW" - " BEGIN" - " UPDATE ldb_entry" - " SET modify_timestamp = strftime('%s', 'now')" - " WHERE eid = old.eid;" - " END;" + count = ldap_count_values_len(bval); - "-- ------------------------------------------------------" - "-- Table initialization" + if (count <= 0) { + return -1; + } - "/* We need an implicit 'top' level object class */" - "INSERT INTO ldb_attributes (attr_name," - " parent_tree_key)" - " SELECT 'top', '';" + el = talloc_realloc(msg, msg->elements, struct ldb_message_element, + msg->num_elements + 1); + if (!el) { + errno = ENOMEM; + return -1; + } + + msg->elements = el; + + el = &msg->elements[msg->num_elements]; + + el->name = talloc_strdup(msg->elements, attr); + if (!el->name) { + errno = ENOMEM; + return -1; + } + el->flags = 0; + + el->num_values = 0; + el->values = talloc_array(msg->elements, struct ldb_val, count); + if (!el->values) { + errno = ENOMEM; + return -1; + } + + for (i=0;ivalues[i].data = talloc_memdup(el->values, bval[i]->bv_val, bval[i]->bv_len); + if (!el->values[i].data) { + return -1; + } + el->values[i].length = bval[i]->bv_len; + el->num_values++; + } + + msg->num_elements++; + + return 0; +} +#endif + +static char * +parsetree_to_sql(struct ldb_module *module, + char * hTalloc, + const struct ldb_parse_tree *t) +{ + int i; + char * child; + char * p; + char * ret = NULL; + char * pAttrName; + + + switch(t->operation) { + case LDB_OP_SIMPLE: + break; + + case LDB_OP_AND: + ret = parsetree_to_sql(module, + hTalloc, + t->u.list.elements[0]); + + for (i = 1; i < t->u.list.num_elements; i++) { + child = + parsetree_to_sql( + module, + hTalloc, + t->u.list.elements[i]); + ret = talloc_asprintf_append(ret, + "INTERSECT\n" + "%s\n", + child); + talloc_free(child); + } + + child = ret; + ret = talloc_asprintf("(\n" + "%s\n" + ")\n", + child); + talloc_free(child); + return ret; + + case LDB_OP_OR: + child = + parsetree_to_sql( + module, + hTalloc, + t->u.list.elements[0]); + + for (i = 1; i < t->u.list.num_elements; i++) { + child = + parsetree_to_sql( + module, + hTalloc, + t->u.list.elements[i]); + ret = talloc_asprintf_append(ret, + "UNION\n" + "%s\n", + child); + talloc_free(child); + } + child = ret; + ret = talloc_asprintf("(\n" + "%s\n" + ")\n", + child); + talloc_free(child); + return ret; + + case LDB_OP_NOT: + child = + parsetree_to_sql( + module, + hTalloc, + t->u.not.child); + ret = talloc_asprintf(hTalloc, + "(\n" + " SELECT eid\n" + " FROM ldb_entry\n" + " WHERE eid NOT IN %s\n" + ")\n", + child); + talloc_free(child); + return ret; + + default: + /* should never occur */ + abort(); + }; + + /* Get a case-folded copy of the attribute name */ + pAttrName = ldb_casefold((struct ldb_context *) module, + t->u.simple.attr); + + /* + * For simple searches, we want to retrieve the list of EIDs that + * match the criteria. We accomplish this by searching the + * appropriate table, ldb_attr_, for the eid + * corresponding to all matching values. + */ + if (t->u.simple.value.length == 1 && + (*(const char *) t->u.simple.value.data) == '*') { + /* + * Special case for "attr_name=*". In this case, we want the + * eid corresponding to all values in the specified attribute + * table. + */ + if ((p = sqlite3_mprintf("(\n" + " SELECT eid\n" + " FROM ldb_attr_%q\n" + ")\n", + pAttrName)) == NULL) { + return NULL; + } + + ret = talloc_strdup(hTalloc, p); + sqlite3_free(p); + + } else if (strcasecmp(t->u.simple.attr, "objectclass") == 0) { + /* + * For object classes, we want to search for all objectclasses + * that are subclasses as well. + */ + if ((p = sqlite3_mprintf( + "(\n" + " SELECT eid\n" + " FROM ldb_attr_objectclass\n" + " WHERE attr_name IN\n" + " (SELECT class_name\n" + " FROM ldb_objectclasses\n" + " WHERE tree_key GLOB\n" + " (SELECT tree_key\n" + " FROM ldb_objectclasses\n" + " WHERE class_name = %Q) || '*')\n" + ")\n", + t->u.simple.value.data)) == NULL) { + return NULL; + } - "-- ------------------------------------------------------" + ret = talloc_strdup(hTalloc, p); + sqlite3_free(p); - "COMMIT;" + } else { + /* A normal query. */ + if ((p = sqlite3_mprintf("(\n" + " SELECT eid\n" + " FROM ldb_attr_%q\n" + " WHERE attr_value = %Q\n" + ")\n", + pAttrName, + t->u.simple.value.data)) == NULL) { + return NULL; + } - "-- ------------------------------------------------------" - ; - - /* Skip protocol indicator of url */ - if (strncmp(url, "sqlite://", 9) != 0) { - return SQLITE_MISUSE; - } else { - p = url + 9; - } - - /* - * See if we'll be creating a new database, or opening an existing one - */ - /* Try to open the (possibly empty/non-existent) database */ - if ((ret = sqlite3_open(p, &lsqlite3->sqlite)) != SQLITE_OK) { - return ret; - } + ret = talloc_strdup(hTalloc, p); + sqlite3_free(p); + } + return ret; +} - /* Begin a transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); - /* Determine if this is a new database */ - QUERY_INT(lsqlite3, - queryInt, - TRUE, - "SELECT COUNT(*) " - " FROM sqlite_master " - " WHERE type = 'table';"); +static char * +parsetree_to_tablelist(struct ldb_module *module, + char * hTalloc, + const struct ldb_parse_tree *t) +{ +#warning "obtain talloc'ed array of attribute names for table list" + return NULL; +} - if (queryInt == 0) { - /* - * Create the database schema - */ - for (pTail = discard_const_p(char, schema); pTail != NULL; ) { - if ((ret = sqlite3_prepare( - lsqlite3->sqlite, - pTail, - -1, - &stmt, - &pTail)) != SQLITE_OK || - (ret = sqlite3_step(stmt)) != SQLITE_DONE || - (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { +static int +new_attr(struct ldb_module * module, + char * pAttrName) +{ + struct lsqlite3_private * lsqlite3 = module->private_data; - (void) sqlite3_close(lsqlite3->sqlite); - return ret; - } - } - } else { - /* - * Ensure that the database we opened is one of ours - */ - if (lsqlite3_query_int(lsqlite3, - &queryInt, - "SELECT " - " (SELECT COUNT(*) = 3" - " FROM sqlite_master " - " WHERE type = 'table' " - " AND name IN " - " (" - " 'ldb_entry', " - " 'ldb_descendants', " - " 'ldb_object_classes' " - " ) " - " ) " - " AND " - " (SELECT 1 " - " FROM ldb_info " - " WHERE database_type = 'LDB' " - " AND version = '1.0'" - " );") != 0 || - queryInt != 1) { - - /* It's not one that we created. See ya! */ - (void) sqlite3_close(lsqlite3->sqlite); - return SQLITE_MISUSE; - } - } + /* NOTE: pAttrName is assumed to already be case-folded here! */ + QUERY_NOROWS(lsqlite3, + FALSE, + "CREATE TABLE ldb_attr_%q " + "(" + " eid INTEGER REFERENCES ldb_entry, " + " attr_value TEXT" + ");", + pAttrName); - return SQLITE_OK; + return 0; } /* - * connect to the database + * Issue a series of SQL statements to implement the ADD/MODIFY/DELETE + * requests in the ldb_message */ -struct ldb_context * -lsqlite3_connect(const char *url, - unsigned int flags, - const char *options[]) +static int +msg_to_sql(struct ldb_module * module, + const struct ldb_message * msg, + long long eid, + int use_flags) { - int i; - int ret; - struct ldb_context * ldb = NULL; - struct lsqlite3_private * lsqlite3 = NULL; - - ldb = talloc(NULL, struct ldb_context); - if (!ldb) { - errno = ENOMEM; - goto failed; - } + int flags; + char * pAttrName; + unsigned int i; + unsigned int j; + struct lsqlite3_private * lsqlite3 = module->private_data; - lsqlite3 = talloc(ldb, struct lsqlite3_private); - if (!lsqlite3) { - errno = ENOMEM; - goto failed; - } + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_message_element *el = &msg->elements[i]; - lsqlite3->sqlite = NULL; - lsqlite3->options = NULL; - lsqlite3->lock_count = 0; + if (! use_flags) { + flags = LDB_FLAG_MOD_ADD; + } else { + flags = el->flags & LDB_FLAG_MOD_MASK; + } - ret = lsqlite3_initialize(lsqlite3, url); - if (ret != SQLITE_OK) { - goto failed; - } + /* Get a case-folded copy of the attribute name */ + pAttrName = ldb_casefold((struct ldb_context *) module, + el->name); - talloc_set_destructor(lsqlite3, lsqlite3_destructor); + if (flags == LDB_FLAG_MOD_ADD) { + /* Create the attribute table if it doesn't exist */ + if (new_attr(module, pAttrName) != 0) { + return -1; + } + } - ldb->modules = talloc(ldb, struct ldb_module); - if (!ldb->modules) { - errno = ENOMEM; - goto failed; - } - ldb->modules->ldb = ldb; - ldb->modules->prev = ldb->modules->next = NULL; - ldb->modules->private_data = lsqlite3; - ldb->modules->ops = &lsqlite3_ops; + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { - if (options) { - /* - * take a copy of the options array, so we don't have to rely - * on the caller keeping it around (it might be dynamic) - */ - for (i=0;options[i];i++) ; + /* ... bind the attribute value, if necessary */ + switch (flags) { + case LDB_FLAG_MOD_ADD: + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT INTO ldb_attr_%q " + " (eid, attr_value) " + " VALUES " + " (%lld, %Q);", + pAttrName, + eid, el->values[j].data); + QUERY_NOROWS(lsqlite3, + FALSE, + "UPDATE ldb_entry " + " SET entry_data = " + " add_attr(entry_data, " + " %Q, %Q) " + " WHERE eid = %lld;", + el->name, el->values[j].data, + eid); + + break; - lsqlite3->options = talloc_array(lsqlite3, char *, i+1); - if (!lsqlite3->options) { - goto failed; - } - - for (i=0;options[i];i++) { + case LDB_FLAG_MOD_REPLACE: + QUERY_NOROWS(lsqlite3, + FALSE, + "UPDATE ldb_attr_%q " + " SET attr_value = %Q " + " WHERE eid = %lld;", + pAttrName, + el->values[j].data, + eid); + QUERY_NOROWS(lsqlite3, + FALSE, + "UPDATE ldb_entry " + " SET entry_data = " + " mod_attr(entry_data, " + " %Q, %Q) " + " WHERE eid = %lld;", + el->name, el->values[j].data, + eid); + break; - lsqlite3->options[i+1] = NULL; - lsqlite3->options[i] = - talloc_strdup(lsqlite3->options, options[i]); - if (!lsqlite3->options[i]) { - goto failed; - } + case LDB_FLAG_MOD_DELETE: + /* No additional parameters to this query */ + QUERY_NOROWS(lsqlite3, + FALSE, + "DELETE FROM ldb_attr_%q " + " WHERE eid = %lld " + " AND attr_value = %Q;", + pAttrName, + eid, + el->values[j].data); + QUERY_NOROWS(lsqlite3, + FALSE, + "UPDATE ldb_entry " + " SET entry_data = " + " del_attr(entry_data, " + " %Q, %Q) " + " WHERE eid = %lld;", + el->name, el->values[j].data, + eid); + break; + } } } - return ldb; + return 0; +} -failed: - if (lsqlite3->sqlite != NULL) { - (void) sqlite3_close(lsqlite3->sqlite); + +static int +new_dn(struct ldb_module * module, + char * pDN, + long long * pEID) +{ + struct ldb_dn * pExplodedDN; + struct ldb_context * ldb = module->ldb; +// struct lsqlite3_private * lsqlite3 = module->private_data; + + /* Explode and normalize the DN */ + if ((pExplodedDN = + ldb_explode_dn(ldb, + pDN, + ldb, + case_fold_attr_required)) == NULL) { + return -1; } - talloc_free(ldb); - return NULL; + +#warning "*** new_dn() not yet fully implemented ***" + return -1; } + -- cgit From 5351ae59a0d7043f627fa066879cf7252451fbd9 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Thu, 9 Jun 2005 18:43:56 +0000 Subject: r7449: add ctype.h header to dn expand function (This used to be commit 0e3b872560d82e1a0f7b58fe7d210563d6d29daf) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 47 ++++++++++++++++--------------- 1 file changed, 24 insertions(+), 23 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index c16708672d..e491fba6e0 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -142,10 +142,6 @@ parsetree_to_tablelist(struct ldb_module *module, char * hTalloc, const struct ldb_parse_tree *t); -static int -new_attr(struct ldb_module * module, - char * pAttrName); - static int msg_to_sql(struct ldb_module * module, const struct ldb_message * msg, @@ -157,6 +153,10 @@ new_dn(struct ldb_module * module, char * pDN, long long * pEID); +static int +new_attr(struct ldb_module * module, + char * pAttrName); + /* * Table of operations for the sqlite3 backend @@ -1172,25 +1172,6 @@ parsetree_to_tablelist(struct ldb_module *module, } -static int -new_attr(struct ldb_module * module, - char * pAttrName) -{ - struct lsqlite3_private * lsqlite3 = module->private_data; - - /* NOTE: pAttrName is assumed to already be case-folded here! */ - QUERY_NOROWS(lsqlite3, - FALSE, - "CREATE TABLE ldb_attr_%q " - "(" - " eid INTEGER REFERENCES ldb_entry, " - " attr_value TEXT" - ");", - pAttrName); - - return 0; -} - /* * Issue a series of SQL statements to implement the ADD/MODIFY/DELETE * requests in the ldb_message @@ -1301,6 +1282,7 @@ msg_to_sql(struct ldb_module * module, } + static int new_dn(struct ldb_module * module, char * pDN, @@ -1324,3 +1306,22 @@ new_dn(struct ldb_module * module, } +static int +new_attr(struct ldb_module * module, + char * pAttrName) +{ + struct lsqlite3_private * lsqlite3 = module->private_data; + + /* NOTE: pAttrName is assumed to already be case-folded here! */ + QUERY_NOROWS(lsqlite3, + FALSE, + "CREATE TABLE ldb_attr_%q " + "(" + " eid INTEGER REFERENCES ldb_entry, " + " attr_value TEXT" + ");", + pAttrName); + + return 0; +} + -- cgit From 0264c1792d951eb212490b1d89d4ba9a635931d5 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 11 Jun 2005 03:20:26 +0000 Subject: r7480: ldb_sqlite3 work in progress (This used to be commit 510e7994da808ab12f51fa7a36c3f5f9244c51ac) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 113 ++++++++++++++++++++++++++---- 1 file changed, 101 insertions(+), 12 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index e491fba6e0..556702a21d 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1288,9 +1288,15 @@ new_dn(struct ldb_module * module, char * pDN, long long * pEID) { + int nComponent; + int bFirst; + char * p; + char * pPartialDN; + long long eid; struct ldb_dn * pExplodedDN; + struct ldb_dn_component * pComponent; struct ldb_context * ldb = module->ldb; -// struct lsqlite3_private * lsqlite3 = module->private_data; + struct lsqlite3_private * lsqlite3 = module->private_data; /* Explode and normalize the DN */ if ((pExplodedDN = @@ -1301,8 +1307,71 @@ new_dn(struct ldb_module * module, return -1; } -#warning "*** new_dn() not yet fully implemented ***" - return -1; + /* Allocate a string to hold the partial DN of each component */ + if ((pPartialDN = talloc_strdup(ldb, "")) == NULL) { + return -1; + } + + /* For each component of the DN (starting with the last one)... */ + eid = 0; + for (nComponent = pExplodedDN->comp_num - 1, bFirst = TRUE; + nComponent >= 0; + nComponent--, bFirst = FALSE) { + + /* Point to the component */ + pComponent = pExplodedDN->components[nComponent]; + + /* Add this component on to the partial DN to date */ + if ((p = talloc_asprintf(ldb, + "%s%s%s", + pComponent->component, + bFirst ? "" : ",", + pPartialDN)) == NULL) { + return -1; + } + + /* No need for the old partial DN any more */ + talloc_free(pPartialDN); + + /* Save the new partial DN */ + pPartialDN = p; + + /* + * Ensure that an entry is in the ldb_entry table for this + * component. Any component other than the last one + * (component 0) may already exist. It is an error if + * component 0 (the full DN requested to be be inserted) + * already exists. + */ + if (bFirst) { + /* This is a top-level entry. Parent EID is null. */ + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT %s INTO ldb_entry " + " (peid, dn) " + " VALUES " + " (NULL, %q);", + nComponent == 0 ? "" : "OR IGNORE", + pPartialDN); + } else { + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT %s INTO ldb_entry " + " (peid, dn) " + " VALUES " + " (%lld, %q);", + nComponent == 0 ? "" : "OR IGNORE", + eid, pPartialDN); + } + + /* Get the EID of the just inserted row (the next parent) */ + eid = sqlite3_last_insert_rowid(lsqlite3->sqlite); + } + + /* Give 'em what they came for! */ + *pEID = eid; + + return 0; } @@ -1310,18 +1379,38 @@ static int new_attr(struct ldb_module * module, char * pAttrName) { + long long bExists; struct lsqlite3_private * lsqlite3 = module->private_data; - /* NOTE: pAttrName is assumed to already be case-folded here! */ - QUERY_NOROWS(lsqlite3, - FALSE, - "CREATE TABLE ldb_attr_%q " - "(" - " eid INTEGER REFERENCES ldb_entry, " - " attr_value TEXT" - ");", - pAttrName); + /* + * NOTE: + * pAttrName is assumed to already be case-folded here! + */ + + /* See if the table already exists */ + QUERY_INT(lsqlite3, + bExists, + FALSE, + "SELECT COUNT(*) <> 0" + " FROM sqlite_master " + " WHERE type = 'table' " + " AND tbl_name = %Q;", + pAttrName); + + /* Did it exist? */ + if (! bExists) { + /* Nope. Create the table */ + QUERY_NOROWS(lsqlite3, + FALSE, + "CREATE TABLE ldb_attr_%q " + "(" + " eid INTEGER REFERENCES ldb_entry, " + " attr_value TEXT" + ");", + pAttrName); + } return 0; } + -- cgit From 2e1851e1acae4aba40fd38bc0f7b088599e9cba9 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sun, 12 Jun 2005 03:07:10 +0000 Subject: r7498: ldb_sqlite3 work in progress (This used to be commit 797263330b9eada019e432ff201bf5c872e35b5d) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 178 +++++++++++++++++++++++------- source4/lib/ldb/ldb_sqlite3/schema | 19 +++- 2 files changed, 153 insertions(+), 44 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 556702a21d..d9e72c8089 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -290,6 +290,7 @@ lsqlite3_delete(struct ldb_module *module, return 0; } +#warning "lsqlite3_delete() is not yet supported" return -1; } @@ -302,11 +303,18 @@ lsqlite3_search(struct ldb_module * module, const char * const attrs[], struct ldb_message *** res) { + int ret; + int bLoop; long long eid = 0; - char * sql; - char * sql_constraints; - char * table_list; + long long prevEID; + char * pSql = NULL; + char * pSqlConstraints; + char * pTableList; char * hTalloc; + const char * pDN; + const char * pAttrName; + const char * pAttrValue; + sqlite3_stmt * pStmt; struct ldb_parse_tree * pTree; struct lsqlite3_private * lsqlite3 = module->private_data; @@ -340,17 +348,21 @@ lsqlite3_search(struct ldb_module * module, talloc_steal(hTalloc, pTree); /* Convert filter into a series of SQL statements (constraints) */ - sql_constraints = parsetree_to_sql(module, hTalloc, pTree); + pSqlConstraints = parsetree_to_sql(module, hTalloc, pTree); /* Get the list of attribute names to use as our extra table list */ - table_list = parsetree_to_tablelist(module, hTalloc, pTree); + pTableList = parsetree_to_tablelist(module, hTalloc, pTree); switch(scope) { case LDB_SCOPE_DEFAULT: case LDB_SCOPE_SUBTREE: - sql = sqlite3_mprintf( - "SELECT entry.entry_data\n" - " FROM ldb_entry AS entry\n" + pSql = sqlite3_mprintf( + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry,\n" + " ldb_attribute_values AS av\n" " WHERE entry.eid IN\n" " (SELECT DISTINCT ldb_entry.eid\n" " FROM ldb_entry,\n" @@ -358,55 +370,133 @@ lsqlite3_search(struct ldb_module * module, " %q\n" " WHERE ldb_descendants.aeid = %lld\n" " AND ldb_entry.eid = ldb_descendants.deid\n" - " AND ldap_entry.eid IN\n" - "%s" - ");", - table_list, + " AND ldap_entry.eid IN\n%s\n" + " ) " + " AND av.eid = entry.eid " + " ORDER BY av.eid, av.attr_name;", + pTableList, eid, - sql_constraints); + pSqlConstraints); break; case LDB_SCOPE_BASE: - sql = sqlite3_mprintf( - "SELECT entry.entry_data\n" - " FROM ldb_entry AS entry\n" + pSql = sqlite3_mprintf( + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry,\n" + " ldb_attribute_values AS av\n" " WHERE entry.eid IN\n" " (SELECT DISTINCT ldb_entry.eid\n" " FROM %q\n" " WHERE ldb_entry.eid = %lld\n" - " AND ldb_entry.eid IN\n" - "%s" - ");", - table_list, + " AND ldb_entry.eid IN\n%s\n" + " ) " + " AND av.eid = entry.eid " + " ORDER BY av.eid, av.attr_name;", + pTableList, eid, - sql_constraints); + pSqlConstraints); break; case LDB_SCOPE_ONELEVEL: - sql = sqlite3_mprintf( - "SELECT entry.entry_data\n" - " FROM ldb_entry AS entry\n" + pSql = sqlite3_mprintf( + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry,\n" + " ldb_attribute_values AS av\n" " WHERE entry.eid IN\n" " (SELECT DISTINCT ldb_entry.eid\n" " FROM ldb_entry AS pchild, " " %q\n" " WHERE ldb_entry.eid = pchild.eid " " AND pchild.peid = %lld " - " AND ldb_entry.eid IN\n" - "%s" - ");", - table_list, + " AND ldb_entry.eid IN\n%s\n" + " ) " + " AND av.eid = entry.eid " + " ORDER BY av.eid, av.attr_name;", + pTableList, eid, - sql_constraints); + pSqlConstraints); break; } -#warning "retrieve and return the result set of the search here" + /* Initially, we have no old eid */ + prevEID = -1; + + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { + + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + pSql, + -1, + &pStmt, + NULL)) == SQLITE_SCHEMA) { + continue; + } else if (ret != SQLITE_OK) { + ret = -1; + break; + } + + /* Loop through the returned rows */ + do { + /* Get the next row */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_ROW) { + + /* Get the values from this row */ + eid = sqlite3_column_int64(pStmt, 0); + pDN = sqlite3_column_text(pStmt, 1); + pAttrName = sqlite3_column_text(pStmt, 2); + pAttrValue = sqlite3_column_text(pStmt, 3); + + /* Add this row data to the return results */ +#warning "finish returning the result set of the search here" + } + } while (ret == SQLITE_ROW); + + if (ret == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_DONE) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + ret = 0; + bLoop = FALSE; + } + /* End the transaction */ QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;"); - return 0; + /* We're alll done with this query */ + sqlite3_free(pSql); + + return ret; } @@ -559,11 +649,7 @@ initialize(struct lsqlite3_private *lsqlite3, " create_timestamp INTEGER," " -- Time when the entry was last modified" - " modify_timestamp INTEGER," - - " -- Attributes of this entry, in the form" - " -- attr\1value\0[attr\1value\0]*\0" - " entry_data TEXT" + " modify_timestamp INTEGER" ");" @@ -603,6 +689,16 @@ initialize(struct lsqlite3_private *lsqlite3, " tree_key TEXT UNIQUE" ");" + "/*" + " * We keep a full listing of attribute/value pairs here" + " */" + "CREATE TABLE ldb_attribute_values" + "(" + " eid INTEGER REFERENCES ldb_entry," + " attr_name TEXT, -- see ldb_attr_ATTRIBUTE_NAME" + " attr_value TEXT" + ");" + "/*" " * There is one attribute table per searchable attribute." " */" @@ -793,7 +889,9 @@ query_norows(const struct lsqlite3_private *lsqlite3, pTail, -1, &pStmt, - &pTail)) != SQLITE_OK) { + &pTail)) == SQLITE_SCHEMA) { + continue; + } else if (ret != SQLITE_OK) { ret = -1; break; } @@ -878,12 +976,14 @@ query_int(const struct lsqlite3_private * lsqlite3, pTail, -1, &pStmt, - &pTail)) != SQLITE_OK) { + &pTail)) == SQLITE_SCHEMA) { + continue; + } else if (ret != SQLITE_OK) { ret = -1; break; } - /* No rows expected, so just step through machine code once */ + /* One row expected */ if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { (void) sqlite3_finalize(pStmt); continue; diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema index dddca8d48f..b02b806150 100644 --- a/source4/lib/ldb/ldb_sqlite3/schema +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -37,11 +37,7 @@ create_timestamp INTEGER, -- Time when the entry was last modified - modify_timestamp INTEGER, - - -- Attributes of this entry, in the form - -- attr\1value\0[attr\1value\0]*\0 - entry_data TEXT + modify_timestamp INTEGER ); @@ -80,6 +76,19 @@ tree_key TEXT UNIQUE ); + /* + * We keep a full listing of attribute/value pairs here + */ + CREATE TABLE ldb_attribute_values + ( + eid INTEGER REFERENCES ldb_entry, + + attr_name TEXT, -- see ldb_attr_ATTRIBUTE_NAME + + attr_value TEXT + ); + + /* * There is one attribute table per searchable attribute. */ -- cgit From 4b0e5bd75373ffa2d847706a71fd0349dfa15e71 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 13 Jun 2005 09:10:17 +0000 Subject: r7527: - added a ldb_search_bytree() interface, which takes a ldb_parse_tree instead of a search expression. This allows our ldap server to pass its ASN.1 parsed search expressions straight to ldb, instead of going via strings. - updated all the ldb modules code to handle the new interface - got rid of the separate ldb_parse.h now that the ldb_parse structures are exposed externally - moved to C99 structure initialisation in ldb - switched ldap server to using ldb_search_bytree() (This used to be commit 96620ab2ee5d440bbbc51c1bc0cad9977770f897) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index d9e72c8089..747938116a 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -36,7 +36,6 @@ #include "includes.h" #include "ldb/include/ldb.h" #include "ldb/include/ldb_private.h" -#include "ldb/include/ldb_parse.h" #include "ldb/include/ldb_explode_dn.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" @@ -162,15 +161,16 @@ new_attr(struct ldb_module * module, * Table of operations for the sqlite3 backend */ static const struct ldb_module_ops lsqlite3_ops = { - "sqlite", - lsqlite3_search, - lsqlite3_add, - lsqlite3_modify, - lsqlite3_delete, - lsqlite3_rename, - lsqlite3_lock, - lsqlite3_unlock, - lsqlite3_errstring + .name = "sqlite", + .search = lsqlite3_search, + .search_bytree = lsqlite3_search_bytree, + .add_record = lsqlite3_add, + .modify_record = lsqlite3_modify, + .delete_record = lsqlite3_delete, + .rename_record = lsqlite3_rename, + .named_lock = lsqlite3_lock, + .named_unlock = lsqlite3_unlock, + .errstring = lsqlite3_errstring }; -- cgit From 4fec6356ea190d202783fe19013387462a22c441 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 14 Jun 2005 01:35:44 +0000 Subject: r7558: added support in ldb for extended ldap search requests. These are using to perform such things as bitop tests on integers. So far I have only added support for the 1.2.840.113556.1.4.803 and 1.2.840.113556.1.4.804 rules, which are for bitwise and/or (This used to be commit 5f773b065f1db959e59c02de68bcf30cef1a6c2c) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 747938116a..4089f0bdb5 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1117,6 +1117,10 @@ parsetree_to_sql(struct ldb_module *module, case LDB_OP_SIMPLE: break; + case LDB_OP_EXTENDED: +#warning "derrell, you'll need to work out how to handle bitops" + return NULL; + case LDB_OP_AND: ret = parsetree_to_sql(module, hTalloc, -- cgit From 81b4183e1c8f70f69b97a99265ee5020c207f9e4 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Tue, 14 Jun 2005 03:08:34 +0000 Subject: r7562: work in progress (This used to be commit d8a9ce78533639f510b60b48c8f305bd07f3f717) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 1022 ++++++++++++++++++++--------- 1 file changed, 699 insertions(+), 323 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 4089f0bdb5..dbbb775928 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -48,27 +48,30 @@ # define TRUE (! FALSE) #endif +#define FILTER_ATTR_TABLE "temp_filter_attrs" +#define RESULT_ATTR_TABLE "temp_result_attrs" + #define QUERY_NOROWS(lsqlite3, bRollbackOnError, sql...) \ - do { \ - if (query_norows(lsqlite3, sql) != 0) { \ - if (bRollbackOnError) { \ - query_norows(lsqlite3, \ - "ROLLBACK;"); \ + do { \ + if (query_norows(lsqlite3, sql) != 0) { \ + if (bRollbackOnError) { \ + query_norows(lsqlite3, \ + "ROLLBACK;"); \ + } \ + return -1; \ } \ - return -1; \ - } \ - } while (0) + } while (0) #define QUERY_INT(lsqlite3, result_var, bRollbackOnError, sql...) \ - do { \ - if (query_int(lsqlite3, &result_var, sql) != 0) { \ - if (bRollbackOnError) { \ - query_norows(lsqlite3, \ - "ROLLBACK;"); \ - } \ - return -1; \ - } \ - } while (0) + do { \ + if (query_int(lsqlite3, &result_var, sql) != 0) { \ + if (bRollbackOnError) { \ + query_norows(lsqlite3, \ + "ROLLBACK;"); \ + } \ + return -1; \ + } \ + } while (0) /* @@ -83,13 +86,21 @@ static int lsqlite3_delete(struct ldb_module *module, const char *dn); +static int +lsqlite3_search_bytree(struct ldb_module * module, + const char * pBaseDN, + enum ldb_scope scope, + struct ldb_parse_tree * pTree, + const char * const * attrs, + struct ldb_message *** pppRes); + static int lsqlite3_search(struct ldb_module * module, const char * pBaseDN, enum ldb_scope scope, const char * pExpression, const char * const attrs[], - struct ldb_message *** res); + struct ldb_message *** pppRes); static int lsqlite3_add(struct ldb_module *module, @@ -131,15 +142,28 @@ query_int(const struct lsqlite3_private * lsqlite3, static int case_fold_attr_required(void * hUserData, char *attr); +static int +add_msg_attr(void * hTalloc, + long long eid, + const char * pDN, + const char * pAttrName, + const char * pAttrValue, + long long prevEID, + int * pAllocated, + struct ldb_message *** pppRes); + static char * parsetree_to_sql(struct ldb_module *module, - char * hTalloc, + char * hTalloc, const struct ldb_parse_tree *t); +static int +parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, + const struct ldb_parse_tree * t); + static char * -parsetree_to_tablelist(struct ldb_module *module, - char * hTalloc, - const struct ldb_parse_tree *t); +build_attr_table_list(void * hTalloc, + struct lsqlite3_private * lsqlite3); static int msg_to_sql(struct ldb_module * module, @@ -193,54 +217,51 @@ lsqlite3_connect(const char *url, int ret; struct ldb_context * ldb = NULL; struct lsqlite3_private * lsqlite3 = NULL; - + ldb = talloc(NULL, struct ldb_context); if (!ldb) { - errno = ENOMEM; goto failed; } - + lsqlite3 = talloc(ldb, struct lsqlite3_private); if (!lsqlite3) { - errno = ENOMEM; goto failed; } - + lsqlite3->sqlite = NULL; lsqlite3->options = NULL; lsqlite3->lock_count = 0; - + ret = initialize(lsqlite3, url); if (ret != SQLITE_OK) { goto failed; } - + talloc_set_destructor(lsqlite3, destructor); - + ldb->modules = talloc(ldb, struct ldb_module); if (!ldb->modules) { - errno = ENOMEM; goto failed; } ldb->modules->ldb = ldb; ldb->modules->prev = ldb->modules->next = NULL; ldb->modules->private_data = lsqlite3; ldb->modules->ops = &lsqlite3_ops; - + if (options) { /* * take a copy of the options array, so we don't have to rely * on the caller keeping it around (it might be dynamic) */ for (i=0;options[i];i++) ; - + lsqlite3->options = talloc_array(lsqlite3, char *, i+1); if (!lsqlite3->options) { goto failed; } - + for (i=0;options[i];i++) { - + lsqlite3->options[i+1] = NULL; lsqlite3->options[i] = talloc_strdup(lsqlite3->options, options[i]); @@ -249,9 +270,9 @@ lsqlite3_connect(const char *url, } } } - + return ldb; - + failed: if (lsqlite3->sqlite != NULL) { (void) sqlite3_close(lsqlite3->sqlite); @@ -275,7 +296,7 @@ lsqlite3_rename(struct ldb_module * module, if (olddn[0] == '@' ||newdn[0] == '@') { return 0; } - + #warning "lsqlite3_rename() is not yet supported" return -1; } @@ -289,42 +310,44 @@ lsqlite3_delete(struct ldb_module *module, if (dn[0] == '@') { return 0; } - + #warning "lsqlite3_delete() is not yet supported" return -1; } -/* search for matching records */ +/* search for matching records, by tree */ static int -lsqlite3_search(struct ldb_module * module, - const char * pBaseDN, - enum ldb_scope scope, - const char * pExpression, - const char * const attrs[], - struct ldb_message *** res) +lsqlite3_search_bytree(struct ldb_module * module, + const char * pBaseDN, + enum ldb_scope scope, + struct ldb_parse_tree * pTree, + const char * const * attrs, + struct ldb_message *** pppRes) { + int i; int ret; + int allocated; int bLoop; long long eid = 0; long long prevEID; char * pSql = NULL; char * pSqlConstraints; char * pTableList; - char * hTalloc; + char * hTalloc = NULL; const char * pDN; const char * pAttrName; const char * pAttrValue; + const char * const * pRequestedAttrs; sqlite3_stmt * pStmt; - struct ldb_parse_tree * pTree; struct lsqlite3_private * lsqlite3 = module->private_data; - + if (pBaseDN == NULL) { pBaseDN = ""; } - + /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN IMMEDIATE;"); - + /* * Obtain the eid of the base DN */ @@ -335,24 +358,60 @@ lsqlite3_search(struct ldb_module * module, " FROM ldb_attr_dn " " WHERE attr_value = %Q;", pBaseDN); - - /* Parse the filter expression into a tree we can work with */ - if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { - return -1; - } - + /* Allocate a temporary talloc context */ - hTalloc = talloc_new(module->ldb); - - /* Move the parse tree to our temporary context */ - talloc_steal(hTalloc, pTree); - - /* Convert filter into a series of SQL statements (constraints) */ + if ((hTalloc = talloc_new(module->ldb)) == NULL) { + ret = -1; + talloc_free(pTree); + goto cleanup; + } + + /* Convert filter into a series of SQL conditions (constraints) */ pSqlConstraints = parsetree_to_sql(module, hTalloc, pTree); - - /* Get the list of attribute names to use as our extra table list */ - pTableList = parsetree_to_tablelist(module, hTalloc, pTree); - + + /* Ensure we're starting with an empty result attribute table */ + QUERY_NOROWS(lsqlite3, + FALSE, + "DELETE FROM " RESULT_ATTR_TABLE " " + " WHERE 1;");/* avoid a schema change with WHERE 1 */ + + /* Insert the list of requested attributes into this table */ + for (pRequestedAttrs = (const char * const *) attrs; + pRequestedAttrs != NULL; + pRequestedAttrs++) { + + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT OR IGNORE INTO " RESULT_ATTR_TABLE " " + " (attr_name) " + " VALUES " + " (%Q);", + *pRequestedAttrs); + } + + /* Ensure we're starting with an empty filter attribute table */ + QUERY_NOROWS(lsqlite3, + FALSE, + "DELETE FROM " FILTER_ATTR_TABLE " " + " WHERE 1;");/* avoid a schema change with WHERE 1 */ + + /* + * Create a table of unique attribute names for our extra table list + */ + if (parsetree_to_attrlist(lsqlite3, pTree) != 0) { + ret = -1; + goto cleanup; + } + + /* + * Build the attribute table list from the list of unique names. + */ + + if ((pTableList = build_attr_table_list(hTalloc, lsqlite3)) == NULL) { + ret = -1; + goto cleanup; + } + switch(scope) { case LDB_SCOPE_DEFAULT: case LDB_SCOPE_SUBTREE: @@ -373,12 +432,15 @@ lsqlite3_search(struct ldb_module * module, " AND ldap_entry.eid IN\n%s\n" " ) " " AND av.eid = entry.eid " + " AND av.attr_name IN " + " (SELECT attr_name " + " FROM " RESULT_ATTR_TABLE ") " " ORDER BY av.eid, av.attr_name;", pTableList, eid, pSqlConstraints); break; - + case LDB_SCOPE_BASE: pSql = sqlite3_mprintf( "SELECT entry.eid,\n" @@ -394,12 +456,15 @@ lsqlite3_search(struct ldb_module * module, " AND ldb_entry.eid IN\n%s\n" " ) " " AND av.eid = entry.eid " + " AND av.attr_name IN " + " (SELECT attr_name " + " FROM " RESULT_ATTR_TABLE ") " " ORDER BY av.eid, av.attr_name;", pTableList, eid, pSqlConstraints); break; - + case LDB_SCOPE_ONELEVEL: pSql = sqlite3_mprintf( "SELECT entry.eid,\n" @@ -417,70 +482,96 @@ lsqlite3_search(struct ldb_module * module, " AND ldb_entry.eid IN\n%s\n" " ) " " AND av.eid = entry.eid " + " AND av.attr_name IN " + " (SELECT attr_name " + " FROM " RESULT_ATTR_TABLE ") " " ORDER BY av.eid, av.attr_name;", pTableList, eid, pSqlConstraints); break; } - - /* Initially, we have no old eid */ - prevEID = -1; - + /* * Prepare and execute the SQL statement. Loop allows retrying on * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, * requiring retrying the operation. */ for (bLoop = TRUE; bLoop; ) { - + /* There are no allocate message structures yet */ + allocated = 0; + + for (i = 0; i < allocated; i++) { + (*pppRes)[i] = NULL; + } + /* Compile the SQL statement into sqlite virtual machine */ if ((ret = sqlite3_prepare(lsqlite3->sqlite, pSql, -1, &pStmt, NULL)) == SQLITE_SCHEMA) { + talloc_free(*pppRes); continue; } else if (ret != SQLITE_OK) { ret = -1; break; } + /* Initially, we have no previous eid */ + prevEID = -1; + /* Loop through the returned rows */ - do { + for (ret = SQLITE_ROW; ret == SQLITE_ROW; ) { + /* Get the next row */ if ((ret = sqlite3_step(pStmt)) == SQLITE_ROW) { - + /* Get the values from this row */ eid = sqlite3_column_int64(pStmt, 0); pDN = sqlite3_column_text(pStmt, 1); pAttrName = sqlite3_column_text(pStmt, 2); pAttrValue = sqlite3_column_text(pStmt, 3); - /* Add this row data to the return results */ -#warning "finish returning the result set of the search here" + /* Add this result to the result set */ + if ((ret = add_msg_attr(hTalloc, + eid, + pDN, + pAttrName, + pAttrValue, + prevEID, + &allocated, + pppRes)) != 0) { + + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } } - } while (ret == SQLITE_ROW); - +#warning "finish returning the result set of the search here" + } + if (ret == SQLITE_SCHEMA) { (void) sqlite3_finalize(pStmt); + talloc_free(*pppRes); continue; } else if (ret != SQLITE_DONE) { (void) sqlite3_finalize(pStmt); ret = -1; break; } - + /* Free the virtual machine */ if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { (void) sqlite3_finalize(pStmt); + talloc_free(*pppRes); continue; } else if (ret != SQLITE_OK) { (void) sqlite3_finalize(pStmt); ret = -1; break; } - + /* * Normal condition is only one time through loop. Loop is * rerun in error conditions, via "continue", above. @@ -488,15 +579,66 @@ lsqlite3_search(struct ldb_module * module, ret = 0; bLoop = FALSE; } - - + /* End the transaction */ QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;"); - + /* We're alll done with this query */ sqlite3_free(pSql); + + /* Were there any results? */ + if (ret != 0 || allocated == 0) { + /* Nope. We can free the results. */ + talloc_free(pppRes); + } + +cleanup: + /* Clean up our temporary tables */ + QUERY_NOROWS(lsqlite3, + FALSE, + "DELETE FROM " RESULT_ATTR_TABLE " " + " WHERE 1;");/* avoid a schema change with WHERE 1 */ + + QUERY_NOROWS(lsqlite3, + FALSE, + "DELETE FROM " FILTER_ATTR_TABLE " " + " WHERE 1;");/* avoid a schema change with WHERE 1 */ + + + if (hTalloc != NULL) { + talloc_free(hTalloc); + } + + /* If error, return error code; otherwise return number of results */ + return ret == 0 ? allocated : ret; +} - return ret; +/* search for matching records, by expression */ +static int +lsqlite3_search(struct ldb_module * module, + const char * pBaseDN, + enum ldb_scope scope, + const char * pExpression, + const char * const * attrs, + struct ldb_message *** pppRes) +{ + int ret; + struct ldb_parse_tree * pTree; + + /* Parse the filter expression into a tree we can work with */ + if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { + return -1; + } + + /* Now use the bytree function for the remainder of processing */ + ret = lsqlite3_search_bytree(module, pBaseDN, scope, + pTree, attrs, pppRes); + + /* Free the parse tree */ + talloc_free(pTree); + + /* All done. */ + return ret; } @@ -507,15 +649,15 @@ lsqlite3_add(struct ldb_module *module, { long long eid; struct lsqlite3_private * lsqlite3 = module->private_data; - + /* ignore ltdb specials */ if (msg->dn[0] == '@') { return 0; } - + /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); - + /* * Build any portions of the directory tree that don't exist. If the * final component already exists, it's an error. @@ -524,13 +666,13 @@ lsqlite3_add(struct ldb_module *module, QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); return -1; } - + /* Add attributes to this new entry */ if (msg_to_sql(module, msg, eid, FALSE) != 0) { QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); return -1; } - + /* Everything worked. Commit it! */ QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); return 0; @@ -543,15 +685,15 @@ lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) { struct lsqlite3_private * lsqlite3 = module->private_data; - + /* ignore ltdb specials */ if (msg->dn[0] == '@') { return 0; } - + /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); - + /* Everything worked. Commit it! */ QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); return 0 ; @@ -565,9 +707,9 @@ lsqlite3_lock(struct ldb_module *module, if (lockname == NULL) { return -1; } - + /* TODO implement a local locking mechanism here */ - + return 0; } @@ -579,9 +721,9 @@ lsqlite3_unlock(struct ldb_module *module, if (lockname == NULL) { return -1; } - + /* TODO implement a local locking mechanism here */ - + return 0; } @@ -590,7 +732,7 @@ static const char * lsqlite3_errstring(struct ldb_module *module) { struct lsqlite3_private * lsqlite3 = module->private_data; - + return sqlite3_errmsg(lsqlite3->sqlite); } @@ -611,22 +753,22 @@ initialize(struct lsqlite3_private *lsqlite3, sqlite3_stmt * stmt; const char * schema = "-- ------------------------------------------------------" - + "PRAGMA auto_vacuum=1;" - + "-- ------------------------------------------------------" - + "BEGIN EXCLUSIVE;" - + "-- ------------------------------------------------------" - + "CREATE TABLE ldb_info AS" " SELECT 'LDB' AS database_type," " '1.0' AS version;" - + "-- ------------------------------------------------------" "-- Schema" - + "/*" " * The entry table holds the information about an entry. " " * This table is used to obtain the EID of the entry and to " @@ -638,21 +780,21 @@ initialize(struct lsqlite3_private *lsqlite3, "(" " -- Unique identifier of this LDB entry" " eid INTEGER PRIMARY KEY," - + " -- Unique identifier of the parent LDB entry" " peid INTEGER REFERENCES ldb_entry," - + " -- Distinguished name of this entry" " dn TEXT," - + " -- Time when the entry was created" " create_timestamp INTEGER," - + " -- Time when the entry was last modified" " modify_timestamp INTEGER" ");" - - + + "/*" " * The purpose of the descendant table is to support the" " * subtree search feature. For each LDB entry with a unique" @@ -671,24 +813,24 @@ initialize(struct lsqlite3_private *lsqlite3, "(" " -- The unique identifier of the ancestor LDB entry" " aeid INTEGER REFERENCES ldb_entry," - + " -- The unique identifier of the descendant LDB entry" " deid INTEGER REFERENCES ldb_entry" ");" - - + + "CREATE TABLE ldb_object_classes" "(" " -- Object classes are inserted into this table to track" " -- their class hierarchy. 'top' is the top-level class" " -- of which all other classes are subclasses." " class_name TEXT PRIMARY KEY," - + " -- tree_key tracks the position of the class in" " -- the hierarchy" " tree_key TEXT UNIQUE" ");" - + "/*" " * We keep a full listing of attribute/value pairs here" " */" @@ -698,7 +840,7 @@ initialize(struct lsqlite3_private *lsqlite3, " attr_name TEXT, -- see ldb_attr_ATTRIBUTE_NAME" " attr_value TEXT" ");" - + "/*" " * There is one attribute table per searchable attribute." " */" @@ -707,20 +849,20 @@ initialize(struct lsqlite3_private *lsqlite3, "(" " -- The unique identifier of the LDB entry" " eid INTEGER REFERENCES ldb_entry," - + " -- Normalized attribute value" " attr_value TEXT" ");" "*/" - - + + "-- ------------------------------------------------------" "-- Indexes" - - + + "-- ------------------------------------------------------" "-- Triggers" - + "CREATE TRIGGER ldb_entry_insert_tr" " AFTER INSERT" " ON ldb_entry" @@ -731,7 +873,7 @@ initialize(struct lsqlite3_private *lsqlite3, " modify_timestamp = strftime('%s', 'now')" " WHERE eid = new.eid;" " END;" - + "CREATE TRIGGER ldb_entry_update_tr" " AFTER UPDATE" " ON ldb_entry" @@ -741,19 +883,19 @@ initialize(struct lsqlite3_private *lsqlite3, " SET modify_timestamp = strftime('%s', 'now')" " WHERE eid = old.eid;" " END;" - + "-- ------------------------------------------------------" "-- Table initialization" - + "/* We need an implicit 'top' level object class */" "INSERT INTO ldb_attributes (attr_name," " parent_tree_key)" " SELECT 'top', '';" - + "-- ------------------------------------------------------" - + "COMMIT;" - + "-- ------------------------------------------------------" ; @@ -761,18 +903,18 @@ initialize(struct lsqlite3_private *lsqlite3, if (strncmp(url, "sqlite://", 9) != 0) { return SQLITE_MISUSE; } - + /* Update pointer to just after the protocol indicator */ url += 9; - + /* Try to open the (possibly empty/non-existent) database */ if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) { return ret; } - + /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); - + /* Determine if this is a new database. No tables means it is. */ QUERY_INT(lsqlite3, queryInt, @@ -780,13 +922,13 @@ initialize(struct lsqlite3_private *lsqlite3, "SELECT COUNT(*) " " FROM sqlite_master " " WHERE type = 'table';"); - + if (queryInt == 0) { /* * Create the database schema */ for (pTail = discard_const_p(char, schema); pTail != NULL; ) { - + if ((ret = sqlite3_prepare( lsqlite3->sqlite, pTail, @@ -795,7 +937,7 @@ initialize(struct lsqlite3_private *lsqlite3, &pTail)) != SQLITE_OK || (ret = sqlite3_step(stmt)) != SQLITE_DONE || (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { - + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); (void) sqlite3_close(lsqlite3->sqlite); return ret; @@ -825,17 +967,39 @@ initialize(struct lsqlite3_private *lsqlite3, " AND version = '1.0'" " );") != 0 || queryInt != 1) { - + /* It's not one that we created. See ya! */ QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); (void) sqlite3_close(lsqlite3->sqlite); return SQLITE_MISUSE; } } - + + /* + * Create a temporary table to hold attributes requested in the result + * set of a search. + */ + QUERY_NOROWS(lsqlite3, + FALSE, + "CREATE TEMPORARY TABLE " RESULT_ATTR_TABLE " " + " (" + " attr_name TEXT PRIMARY KEY " + " );"); + + /* + * Create a temporary table to hold the attributes used by filters + * during a search. + */ + QUERY_NOROWS(lsqlite3, + FALSE, + "CREATE TEMPORARY TABLE " FILTER_ATTR_TABLE " " + " (" + " attr_name TEXT PRIMARY KEY " + " );"); + /* Commit the transaction */ QUERY_NOROWS(lsqlite3, FALSE, "COMMIT;"); - + return SQLITE_OK; } @@ -843,7 +1007,7 @@ static int destructor(void *p) { struct lsqlite3_private * lsqlite3 = p; - + (void) sqlite3_close(lsqlite3->sqlite); return 0; } @@ -871,19 +1035,19 @@ query_norows(const struct lsqlite3_private *lsqlite3, /* Begin access to variable argument list */ va_start(args, pSql); - + /* Format the query */ if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { return -1; } - + /* * Prepare and execute the SQL statement. Loop allows retrying on * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, * requiring retrying the operation. */ for (bLoop = TRUE; bLoop; ) { - + /* Compile the SQL statement into sqlite virtual machine */ if ((ret = sqlite3_prepare(lsqlite3->sqlite, pTail, @@ -905,7 +1069,7 @@ query_norows(const struct lsqlite3_private *lsqlite3, ret = -1; break; } - + /* Free the virtual machine */ if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { (void) sqlite3_finalize(pStmt); @@ -915,7 +1079,7 @@ query_norows(const struct lsqlite3_private *lsqlite3, ret = -1; break; } - + /* * Normal condition is only one time through loop. Loop is * rerun in error conditions, via "continue", above. @@ -923,13 +1087,13 @@ query_norows(const struct lsqlite3_private *lsqlite3, ret = 0; bLoop = FALSE; } - + /* All done with variable argument list */ va_end(args); - + /* Free the memory we allocated for our query string */ sqlite3_free(p); - + return ret; } @@ -958,19 +1122,19 @@ query_int(const struct lsqlite3_private * lsqlite3, /* Begin access to variable argument list */ va_start(args, pSql); - + /* Format the query */ if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { return -1; } - + /* * Prepare and execute the SQL statement. Loop allows retrying on * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, * requiring retrying the operation. */ for (bLoop = TRUE; bLoop; ) { - + /* Compile the SQL statement into sqlite virtual machine */ if ((ret = sqlite3_prepare(lsqlite3->sqlite, pTail, @@ -992,10 +1156,10 @@ query_int(const struct lsqlite3_private * lsqlite3, ret = -1; break; } - + /* Get the value to be returned */ *pRet = sqlite3_column_int64(pStmt, 0); - + /* Free the virtual machine */ if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { (void) sqlite3_finalize(pStmt); @@ -1005,7 +1169,7 @@ query_int(const struct lsqlite3_private * lsqlite3, ret = -1; break; } - + /* * Normal condition is only one time through loop. Loop is * rerun in error conditions, via "continue", above. @@ -1013,13 +1177,13 @@ query_int(const struct lsqlite3_private * lsqlite3, ret = 0; bLoop = FALSE; } - + /* All done with variable argument list */ va_end(args); - + /* Free the memory we allocated for our query string */ sqlite3_free(p); - + return ret; } @@ -1043,162 +1207,210 @@ case_fold_attr_required(void * hUserData, * add a single set of ldap message values to a ldb_message */ -#warning "add_msg_attr() not yet implemented or used" -#if 0 static int -add_msg_attr(struct ldb_context *ldb, - struct ldb_message *msg, - const char *attr, - struct berval **bval) +add_msg_attr(void * hTalloc, + long long eid, + const char * pDN, + const char * pAttrName, + const char * pAttrValue, + long long prevEID, + int * pAllocated, + struct ldb_message *** pppRes) { - int i; - int count; + void * x; + struct ldb_message * msg; struct ldb_message_element * el; - - count = ldap_count_values_len(bval); - - if (count <= 0) { - return -1; - } - - el = talloc_realloc(msg, msg->elements, struct ldb_message_element, - msg->num_elements + 1); - if (!el) { - errno = ENOMEM; - return -1; - } - - msg->elements = el; - - el = &msg->elements[msg->num_elements]; - - el->name = talloc_strdup(msg->elements, attr); - if (!el->name) { - errno = ENOMEM; - return -1; - } - el->flags = 0; - - el->num_values = 0; - el->values = talloc_array(msg->elements, struct ldb_val, count); - if (!el->values) { - errno = ENOMEM; - return -1; - } - - for (i=0;ivalues[i].data = talloc_memdup(el->values, bval[i]->bv_val, bval[i]->bv_len); - if (!el->values[i].data) { - return -1; - } - el->values[i].length = bval[i]->bv_len; - el->num_values++; - } - - msg->num_elements++; - + + /* Is this a different EID than the previous one? */ + if (eid != prevEID) { + /* Yup. Add another result to the result array */ + if ((x = talloc_realloc(hTalloc, + *pAllocated == 0 ? NULL : pppRes, + struct ldb_message *, + *pAllocated + 1)) == NULL) { + + return -1; + } + + /* Save the new result list */ + *pppRes = x; + + /* We've allocated one more result */ + *pAllocated++; + + /* Ensure that the message is initialized */ + msg = x; + msg->dn = NULL; + msg->num_elements = 0; + msg->elements = NULL; + msg->private_data = NULL; + } else { + /* Same EID. Point to the previous most-recent message */ + msg = *pppRes[*pAllocated - 1]; + } + + /* + * Point to the most recent previous element. (If there are none, + * this will point to non-allocated memory, but the pointer will never + * be dereferenced.) + */ + el = &msg->elements[msg->num_elements - 1]; + + /* See if the most recent previous element has the same attr_name */ + if (msg->num_elements == 0 || strcmp(el->name, pAttrName) != 0) { + + /* It's a new attr_name. Allocate another message element */ + if ((el = talloc_realloc(msg, + msg->elements, + struct ldb_message_element, + msg->num_elements + 1)) == NULL) { + return -1; + } + + /* Save the new element */ + msg->elements = el; + + /* There's now one additional element */ + msg->num_elements++; + + /* Save the attribute name */ + if ((el->name = + talloc_strdup(msg->elements, pAttrName)) == NULL) { + + return -1; + } + + /* No flags */ + el->flags = 0; + + /* Initialize number of attribute values for this type */ + el->num_values = 0; + el->values = NULL; + } + + /* Increase the value array size by 1 */ + if ((el->values = + talloc_realloc(el, + el->num_values == 0 ? NULL : el->values, + struct ldb_val, + el->num_values)) == NULL) { + return -1; + } + + /* Save the new attribute value length */ + el->values[el->num_values].length = strlen(pAttrValue) + 1; + + /* Copy the new attribute value */ + if (talloc_memdup(el->values[el->num_values].data, + pAttrValue, + el->values[el->num_values].length) == NULL) { + return -1; + } + + /* We now have one additional value of this type */ + el->num_values++; + return 0; } -#endif static char * parsetree_to_sql(struct ldb_module *module, - char * hTalloc, - const struct ldb_parse_tree *t) + char * hTalloc, + const struct ldb_parse_tree *t) { int i; char * child; char * p; char * ret = NULL; char * pAttrName; - - + + switch(t->operation) { - case LDB_OP_SIMPLE: - break; - - case LDB_OP_EXTENDED: -#warning "derrell, you'll need to work out how to handle bitops" - return NULL; - - case LDB_OP_AND: - ret = parsetree_to_sql(module, - hTalloc, - t->u.list.elements[0]); - - for (i = 1; i < t->u.list.num_elements; i++) { - child = - parsetree_to_sql( - module, - hTalloc, - t->u.list.elements[i]); - ret = talloc_asprintf_append(ret, - "INTERSECT\n" - "%s\n", - child); - talloc_free(child); - } - - child = ret; - ret = talloc_asprintf("(\n" - "%s\n" - ")\n", - child); - talloc_free(child); - return ret; - - case LDB_OP_OR: - child = + case LDB_OP_SIMPLE: + break; + + case LDB_OP_EXTENDED: +#warning "work out how to handle bitops" + return NULL; + + case LDB_OP_AND: + ret = parsetree_to_sql(module, + hTalloc, + t->u.list.elements[0]); + + for (i = 1; i < t->u.list.num_elements; i++) { + child = parsetree_to_sql( module, hTalloc, - t->u.list.elements[0]); - - for (i = 1; i < t->u.list.num_elements; i++) { - child = - parsetree_to_sql( - module, - hTalloc, - t->u.list.elements[i]); - ret = talloc_asprintf_append(ret, - "UNION\n" - "%s\n", - child); - talloc_free(child); - } - child = ret; - ret = talloc_asprintf("(\n" - "%s\n" - ")\n", - child); + t->u.list.elements[i]); + ret = talloc_asprintf_append(ret, + "INTERSECT\n" + "%s\n", + child); talloc_free(child); - return ret; - - case LDB_OP_NOT: - child = + } + + child = ret; + ret = talloc_asprintf("(\n" + "%s\n" + ")\n", + child); + talloc_free(child); + return ret; + + case LDB_OP_OR: + child = + parsetree_to_sql( + module, + hTalloc, + t->u.list.elements[0]); + + for (i = 1; i < t->u.list.num_elements; i++) { + child = parsetree_to_sql( module, hTalloc, - t->u.not.child); - ret = talloc_asprintf(hTalloc, - "(\n" - " SELECT eid\n" - " FROM ldb_entry\n" - " WHERE eid NOT IN %s\n" - ")\n", - child); - talloc_free(child); - return ret; - - default: - /* should never occur */ - abort(); + t->u.list.elements[i]); + ret = talloc_asprintf_append(ret, + "UNION\n" + "%s\n", + child); + talloc_free(child); + } + child = ret; + ret = talloc_asprintf("(\n" + "%s\n" + ")\n", + child); + talloc_free(child); + return ret; + + case LDB_OP_NOT: + child = + parsetree_to_sql( + module, + hTalloc, + t->u.not.child); + ret = talloc_asprintf(hTalloc, + "(\n" + " SELECT eid\n" + " FROM ldb_entry\n" + " WHERE eid NOT IN %s\n" + ")\n", + child); + talloc_free(child); + return ret; + + default: + /* should never occur */ + abort(); }; - + /* Get a case-folded copy of the attribute name */ pAttrName = ldb_casefold((struct ldb_context *) module, t->u.simple.attr); - + /* * For simple searches, we want to retrieve the list of EIDs that * match the criteria. We accomplish this by searching the @@ -1219,10 +1431,10 @@ parsetree_to_sql(struct ldb_module *module, pAttrName)) == NULL) { return NULL; } - + ret = talloc_strdup(hTalloc, p); sqlite3_free(p); - + } else if (strcasecmp(t->u.simple.attr, "objectclass") == 0) { /* * For object classes, we want to search for all objectclasses @@ -1243,10 +1455,10 @@ parsetree_to_sql(struct ldb_module *module, t->u.simple.value.data)) == NULL) { return NULL; } - + ret = talloc_strdup(hTalloc, p); sqlite3_free(p); - + } else { /* A normal query. */ if ((p = sqlite3_mprintf("(\n" @@ -1258,7 +1470,7 @@ parsetree_to_sql(struct ldb_module *module, t->u.simple.value.data)) == NULL) { return NULL; } - + ret = talloc_strdup(hTalloc, p); sqlite3_free(p); } @@ -1266,13 +1478,177 @@ parsetree_to_sql(struct ldb_module *module, } +static int +parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, + const struct ldb_parse_tree * t) +{ + int i; + + switch(t->operation) { + case LDB_OP_SIMPLE: + break; + + case LDB_OP_EXTENDED: +#warning "work out how to handle bitops" + return -1; + + case LDB_OP_AND: + if (parsetree_to_attrlist( + lsqlite3, + t->u.list.elements[0]) != 0) { + return -1; + } + + for (i = 1; i < t->u.list.num_elements; i++) { + if (parsetree_to_attrlist( + lsqlite3, + t->u.list.elements[i]) != 0) { + return -1; + } + } + + return 0; + + case LDB_OP_OR: + if (parsetree_to_attrlist( + lsqlite3, + t->u.list.elements[0]) != 0) { + return -1; + } + + for (i = 1; i < t->u.list.num_elements; i++) { + if (parsetree_to_attrlist( + lsqlite3, + t->u.list.elements[i]) != 0) { + return -1; + } + } + + return 0; + + case LDB_OP_NOT: + if (parsetree_to_attrlist(lsqlite3, + t->u.not.child) != 0) { + return -1; + } + + return 0; + + default: + /* should never occur */ + abort(); + }; + + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT OR IGNORE INTO " FILTER_ATTR_TABLE " " + " (attr_name) " + " VALUES " + " (%Q);", + t->u.simple.attr); + return 0; +} + + +/* + * Use the already-generated FILTER_ATTR_TABLE to create a list of attribute + * table names that will be used in search queries. + */ static char * -parsetree_to_tablelist(struct ldb_module *module, - char * hTalloc, - const struct ldb_parse_tree *t) +build_attr_table_list(void * hTalloc, + struct lsqlite3_private * lsqlite3) { -#warning "obtain talloc'ed array of attribute names for table list" - return NULL; + int ret; + int bLoop; + char * p; + char * pTableList; + sqlite3_stmt * pStmt; + + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { + /* Initialize a string to which we'll append each table name */ + if ((pTableList = talloc_strdup(hTalloc, "")) == NULL) { + return NULL; + } + + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + "SELECT attr_name " + " FROM " FILTER_ATTR_TABLE ";", + -1, + &pStmt, + NULL)) == SQLITE_SCHEMA) { + continue; + } else if (ret != SQLITE_OK) { + ret = -1; + break; + } + + /* Loop through the returned rows */ + for (ret = SQLITE_ROW; ret == SQLITE_ROW; ) { + + /* Get the next row */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_ROW) { + + /* + * Get value from this row and append to table + * list + */ + p = discard_const_p(char, + sqlite3_column_text(pStmt, + 0)); + + /* Append it to the table list */ + if ((p = talloc_asprintf( + hTalloc, + "%s%s", + *pTableList == '\0' ? "" : ",", + sqlite3_column_text(pStmt, + 0))) == NULL) { + + talloc_free(pTableList); + return NULL; + } + + /* We have a new table list */ + talloc_free(pTableList); + pTableList = p; + } + } + + if (ret == SQLITE_SCHEMA) { + talloc_free(pTableList); + continue; + } + + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + ret = 0; + bLoop = FALSE; + } + + if (ret != 0) { + talloc_free(pTableList); + pTableList = NULL; + } + + return pTableList; } @@ -1291,30 +1667,30 @@ msg_to_sql(struct ldb_module * module, unsigned int i; unsigned int j; struct lsqlite3_private * lsqlite3 = module->private_data; - + for (i = 0; i < msg->num_elements; i++) { const struct ldb_message_element *el = &msg->elements[i]; - + if (! use_flags) { flags = LDB_FLAG_MOD_ADD; } else { flags = el->flags & LDB_FLAG_MOD_MASK; } - + /* Get a case-folded copy of the attribute name */ pAttrName = ldb_casefold((struct ldb_context *) module, el->name); - + if (flags == LDB_FLAG_MOD_ADD) { /* Create the attribute table if it doesn't exist */ if (new_attr(module, pAttrName) != 0) { return -1; } } - + /* For each value of the specified attribute name... */ for (j = 0; j < el->num_values; j++) { - + /* ... bind the attribute value, if necessary */ switch (flags) { case LDB_FLAG_MOD_ADD: @@ -1335,9 +1711,9 @@ msg_to_sql(struct ldb_module * module, " WHERE eid = %lld;", el->name, el->values[j].data, eid); - + break; - + case LDB_FLAG_MOD_REPLACE: QUERY_NOROWS(lsqlite3, FALSE, @@ -1357,7 +1733,7 @@ msg_to_sql(struct ldb_module * module, el->name, el->values[j].data, eid); break; - + case LDB_FLAG_MOD_DELETE: /* No additional parameters to this query */ QUERY_NOROWS(lsqlite3, @@ -1381,7 +1757,7 @@ msg_to_sql(struct ldb_module * module, } } } - + return 0; } @@ -1401,7 +1777,7 @@ new_dn(struct ldb_module * module, struct ldb_dn_component * pComponent; struct ldb_context * ldb = module->ldb; struct lsqlite3_private * lsqlite3 = module->private_data; - + /* Explode and normalize the DN */ if ((pExplodedDN = ldb_explode_dn(ldb, @@ -1410,12 +1786,12 @@ new_dn(struct ldb_module * module, case_fold_attr_required)) == NULL) { return -1; } - + /* Allocate a string to hold the partial DN of each component */ if ((pPartialDN = talloc_strdup(ldb, "")) == NULL) { return -1; } - + /* For each component of the DN (starting with the last one)... */ eid = 0; for (nComponent = pExplodedDN->comp_num - 1, bFirst = TRUE; @@ -1424,7 +1800,7 @@ new_dn(struct ldb_module * module, /* Point to the component */ pComponent = pExplodedDN->components[nComponent]; - + /* Add this component on to the partial DN to date */ if ((p = talloc_asprintf(ldb, "%s%s%s", @@ -1433,13 +1809,13 @@ new_dn(struct ldb_module * module, pPartialDN)) == NULL) { return -1; } - + /* No need for the old partial DN any more */ talloc_free(pPartialDN); - + /* Save the new partial DN */ pPartialDN = p; - + /* * Ensure that an entry is in the ldb_entry table for this * component. Any component other than the last one @@ -1467,30 +1843,30 @@ new_dn(struct ldb_module * module, nComponent == 0 ? "" : "OR IGNORE", eid, pPartialDN); } - + /* Get the EID of the just inserted row (the next parent) */ eid = sqlite3_last_insert_rowid(lsqlite3->sqlite); } - + /* Give 'em what they came for! */ *pEID = eid; - + return 0; } static int new_attr(struct ldb_module * module, - char * pAttrName) + char * pAttrName) { long long bExists; struct lsqlite3_private * lsqlite3 = module->private_data; - + /* * NOTE: * pAttrName is assumed to already be case-folded here! */ - + /* See if the table already exists */ QUERY_INT(lsqlite3, bExists, @@ -1500,7 +1876,7 @@ new_attr(struct ldb_module * module, " WHERE type = 'table' " " AND tbl_name = %Q;", pAttrName); - + /* Did it exist? */ if (! bExists) { /* Nope. Create the table */ @@ -1513,7 +1889,7 @@ new_attr(struct ldb_module * module, ");", pAttrName); } - + return 0; } -- cgit From c2747479e04761d86f0de4aa90b4d793856d0fb7 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Tue, 14 Jun 2005 21:52:35 +0000 Subject: r7586: ldb_sqlite3 making progress. add and search have indicated a willingness to operate properly on initial testing (This used to be commit 86ca8639e0ddc2525f8ed0ca9879d9f98c0cd00e) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 522 +++++++++++++++++------------- source4/lib/ldb/ldb_sqlite3/schema | 151 +-------- 2 files changed, 300 insertions(+), 373 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index dbbb775928..09ba24022f 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -74,6 +74,12 @@ } while (0) +/* + * Static variables + */ +static int lsqlite3_debug = TRUE; + + /* * Forward declarations */ @@ -298,6 +304,7 @@ lsqlite3_rename(struct ldb_module * module, } #warning "lsqlite3_rename() is not yet supported" + return -1; } @@ -306,13 +313,23 @@ static int lsqlite3_delete(struct ldb_module *module, const char *dn) { + struct lsqlite3_private * lsqlite3 = module->private_data; + /* ignore ltdb specials */ if (dn[0] == '@') { return 0; } + /* Begin a transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); + + #warning "lsqlite3_delete() is not yet supported" - return -1; + + /* Commit the transaction */ + QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); + + return 0; } /* search for matching records, by tree */ @@ -324,7 +341,6 @@ lsqlite3_search_bytree(struct ldb_module * module, const char * const * attrs, struct ldb_message *** pppRes) { - int i; int ret; int allocated; int bLoop; @@ -337,6 +353,7 @@ lsqlite3_search_bytree(struct ldb_module * module, const char * pDN; const char * pAttrName; const char * pAttrValue; + const char * pResultAttrList; const char * const * pRequestedAttrs; sqlite3_stmt * pStmt; struct lsqlite3_private * lsqlite3 = module->private_data; @@ -351,13 +368,18 @@ lsqlite3_search_bytree(struct ldb_module * module, /* * Obtain the eid of the base DN */ - QUERY_INT(lsqlite3, - eid, - TRUE, - "SELECT eid " - " FROM ldb_attr_dn " - " WHERE attr_value = %Q;", - pBaseDN); + if ((ret = query_int(lsqlite3, + &eid, + "SELECT eid\n" + " FROM ldb_attr_DN\n" + " WHERE attr_value = %Q;", + pBaseDN)) == SQLITE_DONE) { + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + return 0; + } else if (ret != SQLITE_OK) { + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + return -1; + } /* Allocate a temporary talloc context */ if ((hTalloc = talloc_new(module->ldb)) == NULL) { @@ -372,33 +394,61 @@ lsqlite3_search_bytree(struct ldb_module * module, /* Ensure we're starting with an empty result attribute table */ QUERY_NOROWS(lsqlite3, FALSE, - "DELETE FROM " RESULT_ATTR_TABLE " " + "DELETE FROM " RESULT_ATTR_TABLE "\n" " WHERE 1;");/* avoid a schema change with WHERE 1 */ + /* Initially, we don't know what the requested attributes are */ + if (attrs == NULL) { + /* but they didn't give us any so we'll retrieve all of 'em */ + pResultAttrList = ""; + } else { + /* Discover the list of attributes */ + pResultAttrList = NULL; + } + /* Insert the list of requested attributes into this table */ for (pRequestedAttrs = (const char * const *) attrs; - pRequestedAttrs != NULL; + pRequestedAttrs != NULL && *pRequestedAttrs != NULL; pRequestedAttrs++) { - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT OR IGNORE INTO " RESULT_ATTR_TABLE " " - " (attr_name) " - " VALUES " - " (%Q);", - *pRequestedAttrs); + /* If any attribute in the list is "*" then... */ + if (strcmp(*pRequestedAttrs, "*") == 0) { + /* we want all attribute types */ + pResultAttrList = ""; + break; + + } else { + /* otherwise, add this name to the resuult list */ + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT OR IGNORE\n" + " INTO " RESULT_ATTR_TABLE "\n" + " (attr_name)\n" + " VALUES\n" + " (%Q);", + *pRequestedAttrs); + } } + /* If we didn't get a "*" for all attributes in the result list... */ + if (pResultAttrList == NULL) { + /* ... then we'll use the result attribute table */ + pResultAttrList = + " AND av.attr_name IN\n" + " (SELECT attr_name\n" + " FROM " RESULT_ATTR_TABLE ") "; + } + /* Ensure we're starting with an empty filter attribute table */ QUERY_NOROWS(lsqlite3, FALSE, - "DELETE FROM " FILTER_ATTR_TABLE " " + "DELETE FROM " FILTER_ATTR_TABLE "\n" " WHERE 1;");/* avoid a schema change with WHERE 1 */ /* * Create a table of unique attribute names for our extra table list */ - if (parsetree_to_attrlist(lsqlite3, pTree) != 0) { + if ((ret = parsetree_to_attrlist(lsqlite3, pTree)) != 0) { ret = -1; goto cleanup; } @@ -425,20 +475,17 @@ lsqlite3_search_bytree(struct ldb_module * module, " WHERE entry.eid IN\n" " (SELECT DISTINCT ldb_entry.eid\n" " FROM ldb_entry,\n" - " ldb_descendants,\n" - " %q\n" + " ldb_descendants\n" " WHERE ldb_descendants.aeid = %lld\n" " AND ldb_entry.eid = ldb_descendants.deid\n" - " AND ldap_entry.eid IN\n%s\n" - " ) " - " AND av.eid = entry.eid " - " AND av.attr_name IN " - " (SELECT attr_name " - " FROM " RESULT_ATTR_TABLE ") " + " AND ldb_entry.eid IN\n%s\n" + " )\n" + " AND av.eid = entry.eid\n" + " %s\n" " ORDER BY av.eid, av.attr_name;", - pTableList, eid, - pSqlConstraints); + pSqlConstraints, + pResultAttrList); break; case LDB_SCOPE_BASE: @@ -451,18 +498,16 @@ lsqlite3_search_bytree(struct ldb_module * module, " ldb_attribute_values AS av\n" " WHERE entry.eid IN\n" " (SELECT DISTINCT ldb_entry.eid\n" - " FROM %q\n" + " FROM ldb_entry\n" " WHERE ldb_entry.eid = %lld\n" " AND ldb_entry.eid IN\n%s\n" - " ) " - " AND av.eid = entry.eid " - " AND av.attr_name IN " - " (SELECT attr_name " - " FROM " RESULT_ATTR_TABLE ") " + " )\n" + " AND av.eid = entry.eid\n" + " %s\n" " ORDER BY av.eid, av.attr_name;", - pTableList, eid, - pSqlConstraints); + pSqlConstraints, + pResultAttrList); break; case LDB_SCOPE_ONELEVEL: @@ -475,23 +520,24 @@ lsqlite3_search_bytree(struct ldb_module * module, " ldb_attribute_values AS av\n" " WHERE entry.eid IN\n" " (SELECT DISTINCT ldb_entry.eid\n" - " FROM ldb_entry AS pchild, " - " %q\n" - " WHERE ldb_entry.eid = pchild.eid " - " AND pchild.peid = %lld " + " FROM ldb_entry AS pchild\n" + " WHERE ldb_entry.eid = pchild.eid\n" + " AND pchild.peid = %lld\n" " AND ldb_entry.eid IN\n%s\n" - " ) " - " AND av.eid = entry.eid " - " AND av.attr_name IN " - " (SELECT attr_name " - " FROM " RESULT_ATTR_TABLE ") " - " ORDER BY av.eid, av.attr_name;", - pTableList, + " )\n" + " AND av.eid = entry.eid\n" + " %s\n" + " ORDER BY av.eid, av.attr_name;\n", eid, - pSqlConstraints); + pSqlConstraints, + pResultAttrList); break; } + if (lsqlite3_debug) { + printf("%s\n", pSql); + } + /* * Prepare and execute the SQL statement. Loop allows retrying on * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, @@ -500,9 +546,8 @@ lsqlite3_search_bytree(struct ldb_module * module, for (bLoop = TRUE; bLoop; ) { /* There are no allocate message structures yet */ allocated = 0; - - for (i = 0; i < allocated; i++) { - (*pppRes)[i] = NULL; + if (pppRes != NULL) { + *pppRes = NULL; } /* Compile the SQL statement into sqlite virtual machine */ @@ -511,7 +556,9 @@ lsqlite3_search_bytree(struct ldb_module * module, -1, &pStmt, NULL)) == SQLITE_SCHEMA) { - talloc_free(*pppRes); + if (pppRes != NULL && *pppRes != NULL) { + talloc_free(*pppRes); + } continue; } else if (ret != SQLITE_OK) { ret = -1; @@ -548,12 +595,13 @@ lsqlite3_search_bytree(struct ldb_module * module, break; } } -#warning "finish returning the result set of the search here" } if (ret == SQLITE_SCHEMA) { (void) sqlite3_finalize(pStmt); - talloc_free(*pppRes); + if (pppRes != NULL && *pppRes != NULL) { + talloc_free(*pppRes); + } continue; } else if (ret != SQLITE_DONE) { (void) sqlite3_finalize(pStmt); @@ -564,7 +612,9 @@ lsqlite3_search_bytree(struct ldb_module * module, /* Free the virtual machine */ if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { (void) sqlite3_finalize(pStmt); - talloc_free(*pppRes); + if (pppRes != NULL && *pppRes != NULL) { + talloc_free(*pppRes); + } continue; } else if (ret != SQLITE_OK) { (void) sqlite3_finalize(pStmt); @@ -589,19 +639,21 @@ lsqlite3_search_bytree(struct ldb_module * module, /* Were there any results? */ if (ret != 0 || allocated == 0) { /* Nope. We can free the results. */ - talloc_free(pppRes); + if (pppRes != NULL && *pppRes != NULL) { + talloc_free(*pppRes); + } } cleanup: /* Clean up our temporary tables */ QUERY_NOROWS(lsqlite3, FALSE, - "DELETE FROM " RESULT_ATTR_TABLE " " + "DELETE FROM " RESULT_ATTR_TABLE "\n" " WHERE 1;");/* avoid a schema change with WHERE 1 */ QUERY_NOROWS(lsqlite3, FALSE, - "DELETE FROM " FILTER_ATTR_TABLE " " + "DELETE FROM " FILTER_ATTR_TABLE "\n" " WHERE 1;");/* avoid a schema change with WHERE 1 */ @@ -694,6 +746,8 @@ lsqlite3_modify(struct ldb_module *module, /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); +#warning "modify() not yet implemented" + /* Everything worked. Commit it! */ QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); return 0 ; @@ -752,116 +806,105 @@ initialize(struct lsqlite3_private *lsqlite3, const char * pTail; sqlite3_stmt * stmt; const char * schema = - "-- ------------------------------------------------------" - - "PRAGMA auto_vacuum=1;" - - "-- ------------------------------------------------------" - "BEGIN EXCLUSIVE;" - "-- ------------------------------------------------------" - - "CREATE TABLE ldb_info AS" + "CREATE TABLE ldb_info AS " " SELECT 'LDB' AS database_type," " '1.0' AS version;" - "-- ------------------------------------------------------" - "-- Schema" - - "/*" - " * The entry table holds the information about an entry. " - " * This table is used to obtain the EID of the entry and to " - " * support scope=one and scope=base. The parent and child" - " * table is included in the entry table since all the other" - " * attributes are dependent on EID." - " */" - "CREATE TABLE ldb_entry" + /* + * The entry table holds the information about an entry. + * This table is used to obtain the EID of the entry and to + * support scope=one and scope=base. The parent and child + * table is included in the entry table since all the other + * attributes are dependent on EID. + */ + "CREATE TABLE ldb_entry " "(" - " -- Unique identifier of this LDB entry" " eid INTEGER PRIMARY KEY," - - " -- Unique identifier of the parent LDB entry" " peid INTEGER REFERENCES ldb_entry," - - " -- Distinguished name of this entry" - " dn TEXT," - - " -- Time when the entry was created" + " dn TEXT UNIQUE," " create_timestamp INTEGER," - - " -- Time when the entry was last modified" " modify_timestamp INTEGER" ");" - - "/*" - " * The purpose of the descendant table is to support the" - " * subtree search feature. For each LDB entry with a unique" - " * ID (AEID), this table contains the unique identifiers" - " * (DEID) of the descendant entries." - " *" - " * For evern entry in the directory, a row exists in this" - " * table for each of its ancestors including itself. The " - " * size of the table depends on the depth of each entry. In " - " * the worst case, if all the entries were at the same " - " * depth, the number of rows in the table is O(nm) where " - " * n is the number of nodes in the directory and m is the " - " * depth of the tree. " - " */" - "CREATE TABLE ldb_descendants" - "(" - " -- The unique identifier of the ancestor LDB entry" + + /* + * The purpose of the descendant table is to support the + * subtree search feature. For each LDB entry with a unique + * ID (AEID), this table contains the unique identifiers + * (DEID) of the descendant entries. + * + * For evern entry in the directory, a row exists in this + * table for each of its ancestors including itself. The + * size of the table depends on the depth of each entry. In + * the worst case, if all the entries were at the same + * depth, the number of rows in the table is O(nm) where + * n is the number of nodes in the directory and m is the + * depth of the tree. + */ + "CREATE TABLE ldb_descendants " + "( " " aeid INTEGER REFERENCES ldb_entry," - - " -- The unique identifier of the descendant LDB entry" " deid INTEGER REFERENCES ldb_entry" ");" "CREATE TABLE ldb_object_classes" "(" - " -- Object classes are inserted into this table to track" - " -- their class hierarchy. 'top' is the top-level class" - " -- of which all other classes are subclasses." " class_name TEXT PRIMARY KEY," - - " -- tree_key tracks the position of the class in" - " -- the hierarchy" " tree_key TEXT UNIQUE" ");" - "/*" - " * We keep a full listing of attribute/value pairs here" - " */" + /* + * We keep a full listing of attribute/value pairs here + */ "CREATE TABLE ldb_attribute_values" "(" " eid INTEGER REFERENCES ldb_entry," - " attr_name TEXT, -- see ldb_attr_ATTRIBUTE_NAME" + " attr_name TEXT," " attr_value TEXT" ");" - "/*" - " * There is one attribute table per searchable attribute." - " */" - "/*" + /* + * There is one attribute table per searchable attribute. + */ + /* "CREATE TABLE ldb_attr_ATTRIBUTE_NAME" "(" - " -- The unique identifier of the LDB entry" " eid INTEGER REFERENCES ldb_entry," + " attr_value TEXT" + ");" + */ - " -- Normalized attribute value" + /* + * We pre-create the dn attribute table + */ + "CREATE TABLE ldb_attr_DN" + "(" + " eid INTEGER REFERENCES ldb_entry," " attr_value TEXT" ");" - "*/" + + /* + * We pre-create the objectclass attribute table + */ + "CREATE TABLE ldb_attr_OBJECTCLASS" + "(" + " eid INTEGER REFERENCES ldb_entry," + " attr_value TEXT" + ");" + - "-- ------------------------------------------------------" - "-- Indexes" + /* + * Indexes + */ - "-- ------------------------------------------------------" - "-- Triggers" + /* + * Triggers + */ "CREATE TRIGGER ldb_entry_insert_tr" " AFTER INSERT" @@ -884,19 +927,22 @@ initialize(struct lsqlite3_private *lsqlite3, " WHERE eid = old.eid;" " END;" - "-- ------------------------------------------------------" - "-- Table initialization" - - "/* We need an implicit 'top' level object class */" - "INSERT INTO ldb_attributes (attr_name," - " parent_tree_key)" - " SELECT 'top', '';" - - "-- ------------------------------------------------------" - - "COMMIT;" - - "-- ------------------------------------------------------" + /* + * Table initialization + */ + + /* The root node */ + "INSERT INTO ldb_entry " + " (eid, peid, dn) " + " VALUES " + " (0, NULL, '');" + + /* And the root node "dn" attribute */ + "INSERT INTO ldb_attr_DN " + " (eid, attr_value) " + " VALUES " + " (0, '');" + ; /* Skip protocol indicator of url */ @@ -912,6 +958,9 @@ initialize(struct lsqlite3_private *lsqlite3, return ret; } + /* In case this is a new database, enable auto_vacuum */ + QUERY_NOROWS(lsqlite3, FALSE, "PRAGMA auto_vacuum=1;"); + /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); @@ -919,15 +968,21 @@ initialize(struct lsqlite3_private *lsqlite3, QUERY_INT(lsqlite3, queryInt, TRUE, - "SELECT COUNT(*) " - " FROM sqlite_master " + "SELECT COUNT(*)\n" + " FROM sqlite_master\n" " WHERE type = 'table';"); if (queryInt == 0) { /* * Create the database schema */ - for (pTail = discard_const_p(char, schema); pTail != NULL; ) { + for (pTail = discard_const_p(char, schema); + pTail != NULL && *pTail != '\0'; + ) { + + if (lsqlite3_debug) { + printf("Execute first query in:\n%s\n", pTail); + } if ((ret = sqlite3_prepare( lsqlite3->sqlite, @@ -981,9 +1036,9 @@ initialize(struct lsqlite3_private *lsqlite3, */ QUERY_NOROWS(lsqlite3, FALSE, - "CREATE TEMPORARY TABLE " RESULT_ATTR_TABLE " " - " (" - " attr_name TEXT PRIMARY KEY " + "CREATE TEMPORARY TABLE " RESULT_ATTR_TABLE "\n" + " (\n" + " attr_name TEXT PRIMARY KEY\n" " );"); /* @@ -992,9 +1047,9 @@ initialize(struct lsqlite3_private *lsqlite3, */ QUERY_NOROWS(lsqlite3, FALSE, - "CREATE TEMPORARY TABLE " FILTER_ATTR_TABLE " " - " (" - " attr_name TEXT PRIMARY KEY " + "CREATE TEMPORARY TABLE " FILTER_ATTR_TABLE "\n" + " (\n" + " attr_name TEXT PRIMARY KEY\n" " );"); /* Commit the transaction */ @@ -1029,7 +1084,6 @@ query_norows(const struct lsqlite3_private *lsqlite3, int ret; int bLoop; char * p; - const char * pTail; sqlite3_stmt * pStmt; va_list args; @@ -1041,6 +1095,10 @@ query_norows(const struct lsqlite3_private *lsqlite3, return -1; } + if (lsqlite3_debug) { + printf("%s\n", p); + } + /* * Prepare and execute the SQL statement. Loop allows retrying on * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, @@ -1050,10 +1108,10 @@ query_norows(const struct lsqlite3_private *lsqlite3, /* Compile the SQL statement into sqlite virtual machine */ if ((ret = sqlite3_prepare(lsqlite3->sqlite, - pTail, + p, -1, &pStmt, - &pTail)) == SQLITE_SCHEMA) { + NULL)) == SQLITE_SCHEMA) { continue; } else if (ret != SQLITE_OK) { ret = -1; @@ -1116,7 +1174,6 @@ query_int(const struct lsqlite3_private * lsqlite3, int ret; int bLoop; char * p; - const char * pTail; sqlite3_stmt * pStmt; va_list args; @@ -1125,9 +1182,13 @@ query_int(const struct lsqlite3_private * lsqlite3, /* Format the query */ if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { - return -1; + return SQLITE_NOMEM; } + if (lsqlite3_debug) { + printf("%s\n", p); + } + /* * Prepare and execute the SQL statement. Loop allows retrying on * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, @@ -1137,13 +1198,12 @@ query_int(const struct lsqlite3_private * lsqlite3, /* Compile the SQL statement into sqlite virtual machine */ if ((ret = sqlite3_prepare(lsqlite3->sqlite, - pTail, + p, -1, &pStmt, - &pTail)) == SQLITE_SCHEMA) { + NULL)) == SQLITE_SCHEMA) { continue; } else if (ret != SQLITE_OK) { - ret = -1; break; } @@ -1153,7 +1213,6 @@ query_int(const struct lsqlite3_private * lsqlite3, continue; } else if (ret != SQLITE_ROW) { (void) sqlite3_finalize(pStmt); - ret = -1; break; } @@ -1166,7 +1225,6 @@ query_int(const struct lsqlite3_private * lsqlite3, continue; } else if (ret != SQLITE_OK) { (void) sqlite3_finalize(pStmt); - ret = -1; break; } @@ -1174,7 +1232,6 @@ query_int(const struct lsqlite3_private * lsqlite3, * Normal condition is only one time through loop. Loop is * rerun in error conditions, via "continue", above. */ - ret = 0; bLoop = FALSE; } @@ -1432,6 +1489,10 @@ parsetree_to_sql(struct ldb_module *module, return NULL; } + if (lsqlite3_debug) { + printf("%s\n", p); + } + ret = talloc_strdup(hTalloc, p); sqlite3_free(p); @@ -1443,7 +1504,7 @@ parsetree_to_sql(struct ldb_module *module, if ((p = sqlite3_mprintf( "(\n" " SELECT eid\n" - " FROM ldb_attr_objectclass\n" + " FROM ldb_attr_OBJECTCLASS\n" " WHERE attr_name IN\n" " (SELECT class_name\n" " FROM ldb_objectclasses\n" @@ -1456,6 +1517,10 @@ parsetree_to_sql(struct ldb_module *module, return NULL; } + if (lsqlite3_debug) { + printf("%s\n", p); + } + ret = talloc_strdup(hTalloc, p); sqlite3_free(p); @@ -1471,6 +1536,10 @@ parsetree_to_sql(struct ldb_module *module, return NULL; } + if (lsqlite3_debug) { + printf("%s\n", p); + } + ret = talloc_strdup(hTalloc, p); sqlite3_free(p); } @@ -1541,9 +1610,9 @@ parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, QUERY_NOROWS(lsqlite3, FALSE, - "INSERT OR IGNORE INTO " FILTER_ATTR_TABLE " " - " (attr_name) " - " VALUES " + "INSERT OR IGNORE INTO " FILTER_ATTR_TABLE "\n" + " (attr_name)\n" + " VALUES\n" " (%Q);", t->u.simple.attr); return 0; @@ -1561,6 +1630,7 @@ build_attr_table_list(void * hTalloc, int ret; int bLoop; char * p; + char * pAttrName; char * pTableList; sqlite3_stmt * pStmt; @@ -1602,13 +1672,17 @@ build_attr_table_list(void * hTalloc, sqlite3_column_text(pStmt, 0)); + pAttrName = + ldb_casefold( + hTalloc, + sqlite3_column_text(pStmt, 0)); + /* Append it to the table list */ if ((p = talloc_asprintf( hTalloc, - "%s%s", + "%sldb_attr_%s", *pTableList == '\0' ? "" : ",", - sqlite3_column_text(pStmt, - 0))) == NULL) { + pAttrName)) == NULL) { talloc_free(pTableList); return NULL; @@ -1696,63 +1770,63 @@ msg_to_sql(struct ldb_module * module, case LDB_FLAG_MOD_ADD: QUERY_NOROWS(lsqlite3, FALSE, - "INSERT INTO ldb_attr_%q " - " (eid, attr_value) " - " VALUES " + "INSERT INTO ldb_attr_%q\n" + " (eid, attr_value)\n" + " VALUES\n" " (%lld, %Q);", pAttrName, eid, el->values[j].data); QUERY_NOROWS(lsqlite3, FALSE, - "UPDATE ldb_entry " - " SET entry_data = " - " add_attr(entry_data, " - " %Q, %Q) " - " WHERE eid = %lld;", - el->name, el->values[j].data, - eid); + "INSERT INTO ldb_attribute_values" + " (eid, attr_name, attr_value)" + " VALUES " + " (%lld, %Q, %Q);", + eid, + el->name, + el->values[j].data); break; case LDB_FLAG_MOD_REPLACE: QUERY_NOROWS(lsqlite3, FALSE, - "UPDATE ldb_attr_%q " - " SET attr_value = %Q " + "UPDATE ldb_attr_%q\n" + " SET attr_value = %Q\n" " WHERE eid = %lld;", pAttrName, el->values[j].data, eid); QUERY_NOROWS(lsqlite3, FALSE, - "UPDATE ldb_entry " - " SET entry_data = " - " mod_attr(entry_data, " - " %Q, %Q) " - " WHERE eid = %lld;", - el->name, el->values[j].data, - eid); + "UPDATE ldb_attribute_values " + " SET attr_value = %Q " + " WHERE eid = %lld " + " AND attr_name = %Q;", + el->values[j].data, + eid, + el->name); break; case LDB_FLAG_MOD_DELETE: /* No additional parameters to this query */ QUERY_NOROWS(lsqlite3, FALSE, - "DELETE FROM ldb_attr_%q " - " WHERE eid = %lld " + "DELETE FROM ldb_attr_%q\n" + " WHERE eid = %lld\n" " AND attr_value = %Q;", pAttrName, eid, el->values[j].data); QUERY_NOROWS(lsqlite3, FALSE, - "UPDATE ldb_entry " - " SET entry_data = " - " del_attr(entry_data, " - " %Q, %Q) " - " WHERE eid = %lld;", - el->name, el->values[j].data, - eid); + "DELETE FROM ldb_attribute_values" + " WHERE eid = %lld " + " AND attr_name = %Q " + " AND attr_value = %Q;", + eid, + el->name, + el->values[j].data); break; } } @@ -1823,29 +1897,29 @@ new_dn(struct ldb_module * module, * component 0 (the full DN requested to be be inserted) * already exists. */ - if (bFirst) { - /* This is a top-level entry. Parent EID is null. */ - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT %s INTO ldb_entry " - " (peid, dn) " - " VALUES " - " (NULL, %q);", - nComponent == 0 ? "" : "OR IGNORE", - pPartialDN); - } else { + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT %s INTO ldb_entry\n" + " (peid, dn)\n" + " VALUES\n" + " (%lld, %Q);", + nComponent == 0 ? "" : "OR IGNORE", + eid, pPartialDN); + + /* Get the EID of the just inserted row (the next parent) */ + eid = sqlite3_last_insert_rowid(lsqlite3->sqlite); + + /* If this is the final component, also add DN attribute */ + if (nComponent == 0) { QUERY_NOROWS(lsqlite3, FALSE, - "INSERT %s INTO ldb_entry " - " (peid, dn) " + "INSERT %s INTO ldb_attr_DN\n" + " (eid, attr_value) " " VALUES " - " (%lld, %q);", + " (%lld, %Q);", nComponent == 0 ? "" : "OR IGNORE", eid, pPartialDN); } - - /* Get the EID of the just inserted row (the next parent) */ - eid = sqlite3_last_insert_rowid(lsqlite3->sqlite); } /* Give 'em what they came for! */ @@ -1871,10 +1945,10 @@ new_attr(struct ldb_module * module, QUERY_INT(lsqlite3, bExists, FALSE, - "SELECT COUNT(*) <> 0" - " FROM sqlite_master " - " WHERE type = 'table' " - " AND tbl_name = %Q;", + "SELECT COUNT(*) <> 0\n" + " FROM sqlite_master\n" + " WHERE type = 'table'\n" + " AND tbl_name = 'ldb_attr_%q';", pAttrName); /* Did it exist? */ @@ -1882,10 +1956,10 @@ new_attr(struct ldb_module * module, /* Nope. Create the table */ QUERY_NOROWS(lsqlite3, FALSE, - "CREATE TABLE ldb_attr_%q " - "(" - " eid INTEGER REFERENCES ldb_entry, " - " attr_value TEXT" + "CREATE TABLE ldb_attr_%q\n" + "(\n" + " eid INTEGER REFERENCES ldb_entry,\n" + " attr_value TEXT\n" ");", pAttrName); } diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema index b02b806150..c44351c543 100644 --- a/source4/lib/ldb/ldb_sqlite3/schema +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -146,58 +146,13 @@ -- ------------------------------------------------------ +/*** TESTS ***/ + /* * dn: o=University of Michigan,c=US * objectclass: organization * objectclass: domainRelatedObject */ --- newDN -BEGIN; - -INSERT OR IGNORE INTO ldb_object - (parent_tree_key - dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('', - 'c=US', - 'c', 'US', 1, 0); - -INSERT INTO ldb_object - (parent_tree_key, - dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('0001', - 'o=University of Michigan,c=US', - 'o', 'University of Michigan', 1, 0); - --- newObjectClass -INSERT OR IGNORE INTO ldb_attributes - (attr_name, parent_tree_key, objectclass_p) - VALUES - ('objectclass', '', 1); - -INSERT INTO ldb_object - (parent_tree_key, - dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('00010001', - NULL, - 'objectclass', 'organization', 2, 0); - -INSERT OR IGNORE INTO ldb_attributes - (attr_name, parent_tree_key, objectclass_p) - VALUES - ('objectclass', '', 1); - -INSERT INTO ldb_object - (parent_tree_key, - dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('00010001', - NULL, - 'objectclass', 'domainRelatedObject', 2, 0); - -COMMIT; /* @@ -209,48 +164,6 @@ COMMIT; * seeAlso: * telephonenumber: +1 313 764-1817 */ --- addAttrValuePair -BEGIN; - -INSERT INTO ldb_object - (parent_tree_key, dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('00010001', NULL, - 'l', 'Ann Arbor, Michigan', 2, 0); - -INSERT INTO ldb_object - (parent_tree_key, dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('00010001', NULL, - 'st', 'Michigan', 2, 0); - -INSERT INTO ldb_object - (parent_tree_key, dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('00010001', NULL, - 'o', 'University of Michigan', 2, 0); - -INSERT INTO ldb_object - (parent_tree_key, dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('00010001', NULL, - 'o', 'UMICH', 2, 0); - -INSERT INTO ldb_object - (parent_tree_key, dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('00010001', NULL, - 'seeAlso', '', 2, 0); - -INSERT INTO ldb_object - (parent_tree_key, dn, - attr_name, attr_value, object_type, max_child_num) - VALUES ('00010001', NULL, - 'telephonenumber', '+1 313 764-1817', 2, 0); - -COMMIT; - --- ---------------------------------------------------------------------- /* * dn: @ATTRIBUTES @@ -259,44 +172,6 @@ COMMIT; * ou: CASE_INSENSITIVE * dn: CASE_INSENSITIVE */ --- newAttribute - -BEGIN; - -INSERT OR IGNORE INTO ldb_attributes - (attr_name, parent_tree_key, objectclass_p) - VALUES - ('uid', '', 0); - -UPDATE ldb_attributes - SET case_insensitive_p = 1, - wildcard_p = 1, - hidden_p = 0, - integer_p = 0 - WHERE attr_name = 'uid' - -UPDATE ldb_attributes - SET case_insensitive_p = 1, - wildcard_p = 0, - hidden_p = 0, - integer_p = 0 - WHERE attr_name = 'cn' - -UPDATE ldb_attributes - SET case_insensitive_p = 1, - wildcard_p = 0, - hidden_p = 0, - integer_p = 0 - WHERE attr_name = 'ou' - -UPDATE ldb_attributes - SET case_insensitive_p = 1, - wildcard_p = 0, - hidden_p = 0, - integer_p = 0 - WHERE attr_name = 'dn' - --- ---------------------------------------------------------------------- /* * dn: @SUBCLASSES @@ -309,25 +184,3 @@ UPDATE ldb_attributes * organizationalPerson: OpenLDAPperson * user: computer */ --- insertSubclass - -/* NOT YET UPDATED!!! * - - -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'domain', /* next_tree_key('top') */ '00010001'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'person', /* next_tree_key('top') */ '00010002'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'domainDNS', /* next_tree_key('domain') */ '000100010001'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'organizationalPerson', /* next_tree_key('person') */ '000100020001'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'fooPerson', /* next_tree_key('person') */ '000100020002'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'user', /* next_tree_key('organizationalPerson') */ '0001000200010001'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'OpenLDAPperson', /* next_tree_key('organizationPerson') */ '0001000200010002'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'computer', /* next_tree_key('user') */ '0001000200010001'; - -- cgit From f021dffb6991138213967521c743f03f474f9af9 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Wed, 15 Jun 2005 02:43:42 +0000 Subject: r7601: ldb_sqlite3 work in progress (This used to be commit 0a64948152a446b5e127578d49b1ed8a90a1a222) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 243 +++++++++++++++++++++++++----- 1 file changed, 208 insertions(+), 35 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 09ba24022f..51830db94c 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -167,9 +167,11 @@ static int parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, const struct ldb_parse_tree * t); +#ifdef NEED_TABLE_LIST static char * build_attr_table_list(void * hTalloc, struct lsqlite3_private * lsqlite3); +#endif static int msg_to_sql(struct ldb_module * module, @@ -295,36 +297,140 @@ failed: /* rename a record */ static int lsqlite3_rename(struct ldb_module * module, - const char * olddn, - const char * newdn) + const char * pOldDN, + const char * pNewDN) { - /* ignore ltdb specials */ - if (olddn[0] == '@' ||newdn[0] == '@') { - return 0; - } - -#warning "lsqlite3_rename() is not yet supported" + struct lsqlite3_private * lsqlite3 = module->private_data; + + /* Case-fold each of the DNs */ + pOldDN = ldb_dn_fold(module->ldb, pOldDN, + module, case_fold_attr_required); + pNewDN = ldb_dn_fold(module->ldb, pNewDN, + module, case_fold_attr_required); - return -1; + QUERY_NOROWS(lsqlite3, + FALSE, + "UPDATE ldb_entry " + " SET dn = %Q " + " WHERE dn = %Q;", + pNewDN, pOldDN); + + return 0; } /* delete a record */ static int -lsqlite3_delete(struct ldb_module *module, - const char *dn) +lsqlite3_delete(struct ldb_module * module, + const char * pDN) { + int ret; + int bLoop; + long long eid; + char * pSql; + const char * pAttrName; + sqlite3_stmt * pStmt; struct lsqlite3_private * lsqlite3 = module->private_data; - /* ignore ltdb specials */ - if (dn[0] == '@') { - return 0; - } - /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); + /* Determine the eid of the DN being deleted */ + QUERY_INT(lsqlite3, + eid, + TRUE, + "SELECT eid\n" + " FROM ldb_entry\n" + " WHERE dn = %Q;", + pDN); + + /* Obtain the list of attribute names in use by this DN */ + if ((pSql = talloc_asprintf(module->ldb, + "SELECT attr_name " + " FROM ldb_attribute_values " + " WHERE eid = %lld;", + eid)) == NULL) { + return -1; + } + + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + pSql, + -1, + &pStmt, + NULL)) == SQLITE_SCHEMA) { + continue; + } else if (ret != SQLITE_OK) { + ret = -1; + break; + } + + /* Loop through the returned rows */ + for (ret = SQLITE_ROW; ret == SQLITE_ROW; ) { + + /* Get the next row */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_ROW) { + + /* Get the values from this row */ + pAttrName = sqlite3_column_text(pStmt, 0); + + /* + * Delete any entries from the specified + * attribute table that pertain to this eid. + */ + QUERY_NOROWS(lsqlite3, + TRUE, + "DELETE FROM ldb_attr_%q " + " WHERE eid = %lld;", + pAttrName, eid); + } + } + + if (ret == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_DONE) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + ret = -1; + break; + } + + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + ret = 0; + bLoop = FALSE; + } + + /* Delete the descendants records */ + QUERY_NOROWS(lsqlite3, + TRUE, + "DELETE FROM ldb_descendants " + " WHERE deid = %lld;", + eid); -#warning "lsqlite3_delete() is not yet supported" + /* Delete attribute/value table entries pertaining to this DN */ + QUERY_NOROWS(lsqlite3, + TRUE, + "DELETE FROM ldb_attribute_value " + " WHERE eid = %lld;", + eid); /* Commit the transaction */ QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); @@ -348,7 +454,9 @@ lsqlite3_search_bytree(struct ldb_module * module, long long prevEID; char * pSql = NULL; char * pSqlConstraints; +#ifdef NEED_TABLE_LIST char * pTableList; +#endif char * hTalloc = NULL; const char * pDN; const char * pAttrName; @@ -362,6 +470,18 @@ lsqlite3_search_bytree(struct ldb_module * module, pBaseDN = ""; } + /* Allocate a temporary talloc context */ + if ((hTalloc = talloc_new(module->ldb)) == NULL) { + return -1; + } + + /* Case-fold the base DN */ + if ((pBaseDN = ldb_dn_fold(hTalloc, pBaseDN, + module, case_fold_attr_required)) == NULL) { + talloc_free(hTalloc); + return -1; + } + /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN IMMEDIATE;"); @@ -375,19 +495,14 @@ lsqlite3_search_bytree(struct ldb_module * module, " WHERE attr_value = %Q;", pBaseDN)) == SQLITE_DONE) { QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + talloc_free(hTalloc); return 0; } else if (ret != SQLITE_OK) { QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + talloc_free(hTalloc); return -1; } - /* Allocate a temporary talloc context */ - if ((hTalloc = talloc_new(module->ldb)) == NULL) { - ret = -1; - talloc_free(pTree); - goto cleanup; - } - /* Convert filter into a series of SQL conditions (constraints) */ pSqlConstraints = parsetree_to_sql(module, hTalloc, pTree); @@ -453,14 +568,15 @@ lsqlite3_search_bytree(struct ldb_module * module, goto cleanup; } +#ifdef NEED_TABLE_LIST /* * Build the attribute table list from the list of unique names. */ - if ((pTableList = build_attr_table_list(hTalloc, lsqlite3)) == NULL) { ret = -1; goto cleanup; } +#endif switch(scope) { case LDB_SCOPE_DEFAULT: @@ -534,6 +650,11 @@ lsqlite3_search_bytree(struct ldb_module * module, break; } + if (pSql == NULL) { + ret = -1; + goto cleanup; + } + if (lsqlite3_debug) { printf("%s\n", pSql); } @@ -630,12 +751,12 @@ lsqlite3_search_bytree(struct ldb_module * module, bLoop = FALSE; } - /* End the transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;"); - /* We're alll done with this query */ sqlite3_free(pSql); + /* End the transaction */ + QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;"); + /* Were there any results? */ if (ret != 0 || allocated == 0) { /* Nope. We can free the results. */ @@ -733,9 +854,11 @@ lsqlite3_add(struct ldb_module *module, /* modify a record */ static int -lsqlite3_modify(struct ldb_module *module, - const struct ldb_message *msg) +lsqlite3_modify(struct ldb_module * module, + const struct ldb_message * msg) { + char * pDN; + long long eid; struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ @@ -746,7 +869,25 @@ lsqlite3_modify(struct ldb_module *module, /* Begin a transaction */ QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); -#warning "modify() not yet implemented" + /* Case-fold the DN so we can compare it to what's in the database */ + pDN = ldb_dn_fold(module->ldb, msg->dn, + module, case_fold_attr_required); + + /* Determine the eid of the DN being deleted */ + QUERY_INT(lsqlite3, + eid, + TRUE, + "SELECT eid\n" + " FROM ldb_entry\n" + " WHERE dn = %Q;", + pDN); + + /* Apply the message attributes */ + if (msg_to_sql(module, msg, eid, TRUE) != 0) { + QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + return -1; + } + /* Everything worked. Commit it! */ QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); @@ -1409,7 +1550,8 @@ parsetree_to_sql(struct ldb_module *module, } child = ret; - ret = talloc_asprintf("(\n" + ret = talloc_asprintf(hTalloc, + "(\n" "%s\n" ")\n", child); @@ -1436,7 +1578,8 @@ parsetree_to_sql(struct ldb_module *module, talloc_free(child); } child = ret; - ret = talloc_asprintf("(\n" + ret = talloc_asprintf(hTalloc, + "(\n" "%s\n" ")\n", child); @@ -1495,7 +1638,7 @@ parsetree_to_sql(struct ldb_module *module, ret = talloc_strdup(hTalloc, p); sqlite3_free(p); - + } else if (strcasecmp(t->u.simple.attr, "objectclass") == 0) { /* * For object classes, we want to search for all objectclasses @@ -1543,6 +1686,7 @@ parsetree_to_sql(struct ldb_module *module, ret = talloc_strdup(hTalloc, p); sqlite3_free(p); } + return ret; } @@ -1619,6 +1763,7 @@ parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, } +#ifdef NEED_TABLE_LIST /* * Use the already-generated FILTER_ATTR_TABLE to create a list of attribute * table names that will be used in search queries. @@ -1724,6 +1869,7 @@ build_attr_table_list(void * hTalloc, return pTableList; } +#endif /* @@ -1847,6 +1993,7 @@ new_dn(struct ldb_module * module, char * p; char * pPartialDN; long long eid; + long long peid; struct ldb_dn * pExplodedDN; struct ldb_dn_component * pComponent; struct ldb_context * ldb = module->ldb; @@ -1906,9 +2053,35 @@ new_dn(struct ldb_module * module, nComponent == 0 ? "" : "OR IGNORE", eid, pPartialDN); - /* Get the EID of the just inserted row (the next parent) */ + /* Save the parent EID */ + peid = eid; + + /* Get the EID of the just inserted row */ eid = sqlite3_last_insert_rowid(lsqlite3->sqlite); + /* + * Popoulate the descendant table + */ + + /* This table has an entry for itself as well as descendants */ + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT INTO ldb_descendants " + " (aeid, deid) " + " VALUES " + " (%lld, %lld);", + eid, eid); + + /* Now insert rows for all of our ancestors */ + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT INTO ldb_descendants " + " (aeid, deid) " + " SELECT aeid, %lld " + " FROM ldb_descendants " + " WHERE aeid = %lld;", + eid, peid); + /* If this is the final component, also add DN attribute */ if (nComponent == 0) { QUERY_NOROWS(lsqlite3, -- cgit From ed3d8091ce2b2014350a2f7f22202dde6846a130 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 18 Jun 2005 07:42:21 +0000 Subject: r7709: - convert ldb to use popt, so that it can interact with the samba cmdline credentials code (which will be done soon) - added a ldb_init() call, and changed ldb_connect() to take a ldb context. This allows for much better error handling in ldb_connect(), and also made the popt conversion easier - fixed up all the existing backends with the new syntax - improved error handling in *_connect() - fixed a crash bug in the new case_fold_required() code - ensured that ltdb_rename() and all ltdb_search() paths get the read lock - added a ldb_oom() macro to make it easier to report out of memory situations in ldb code (This used to be commit f648fdf187669d6d87d01dd4e786b03cd420f220) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 51830db94c..3d36043044 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -216,21 +216,16 @@ static const struct ldb_module_ops lsqlite3_ops = { /* * connect to the database */ -struct ldb_context * -lsqlite3_connect(const char *url, - unsigned int flags, - const char *options[]) +int lsqlite3_connect(struct ldb_context *ldb, + const char *url, + unsigned int flags, + const char *options[]) { int i; int ret; struct ldb_context * ldb = NULL; struct lsqlite3_private * lsqlite3 = NULL; - ldb = talloc(NULL, struct ldb_context); - if (!ldb) { - goto failed; - } - lsqlite3 = talloc(ldb, struct lsqlite3_private); if (!lsqlite3) { goto failed; @@ -279,14 +274,14 @@ lsqlite3_connect(const char *url, } } - return ldb; + return 0; failed: if (lsqlite3->sqlite != NULL) { (void) sqlite3_close(lsqlite3->sqlite); } - talloc_free(ldb); - return NULL; + talloc_free(lsqlite3); + return -1; } @@ -1204,7 +1199,9 @@ destructor(void *p) { struct lsqlite3_private * lsqlite3 = p; - (void) sqlite3_close(lsqlite3->sqlite); + if (lsqlite3->sqlite) { + sqlite3_close(lsqlite3->sqlite); + } return 0; } -- cgit From fdc0450db25021eddcc65d032fd3fd8ca5976928 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Wed, 22 Jun 2005 02:39:07 +0000 Subject: r7828: Although there is still plenty to do, ldb_sqlite3 now passes the set of tests in tests/test-sqlite3.sh (tests/test-generic.sh). There are lots of optimizations still TBD, and some things are REALLY slow right now (e.g. each add() operation takes 1/3 - 1/2 second) but it's ready for interested parties to poke it and prod it and see how (un)reasonable it is. Play away. Still to be implemented or improved: - tdb specials (@MODULES, @SUBCLASSES, etc.) - all DNs are case-folded in their entirty right now (since doing otherwise would require @ATTRIBUTES to be implemented) - speed improvements and optimizations. I am quite confident that the excessively slow add() operation can be much improved, and other areas can be somewhat improved. (This used to be commit 1dd865005594671e7effe06fb088fa97fa08de0b) --- source4/lib/ldb/ldb_sqlite3/base160.c | 3 +- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 1102 ++++++++++++++++++++++------- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 8 +- source4/lib/ldb/ldb_sqlite3/schema | 367 +++++++--- 4 files changed, 1118 insertions(+), 362 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/base160.c b/source4/lib/ldb/ldb_sqlite3/base160.c index e7220433fc..4286979123 100644 --- a/source4/lib/ldb/ldb_sqlite3/base160.c +++ b/source4/lib/ldb/ldb_sqlite3/base160.c @@ -115,6 +115,7 @@ char * lsqlite3_base160Next(char base160[]) { int i; + int len; unsigned char * pTab; char * pBase160 = base160; @@ -122,7 +123,7 @@ lsqlite3_base160Next(char base160[]) * We need a minimum of four digits, and we will always get a multiple of * four digits. */ - if (*pBase160 != '\0') + if (len = strlen(pBase160)) >= 4) { pBase160 += strlen(pBase160) - 1; diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 3d36043044..ff19ff737a 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -51,34 +51,50 @@ #define FILTER_ATTR_TABLE "temp_filter_attrs" #define RESULT_ATTR_TABLE "temp_result_attrs" -#define QUERY_NOROWS(lsqlite3, bRollbackOnError, sql...) \ - do { \ - if (query_norows(lsqlite3, sql) != 0) { \ - if (bRollbackOnError) { \ - query_norows(lsqlite3, \ - "ROLLBACK;"); \ - } \ - return -1; \ - } \ +//#define TEMPTAB /* for testing, create non-temporary table */ +#define TEMPTAB "TEMPORARY" + +//#define DEBUG_LOCKS + +#ifndef DEBUG_LOCKS +# define LOCK_DB(mod, name) lsqlite3_lock(mod, name) +# define UNLOCK_DB(mod, name) lsqlite3_unlock(mod, name) +#else +# define LOCK_DB(mod, name) lock_debug(mod, name, __FILE__, __LINE__) +# define UNLOCK_DB(mod, name) unlock_debug(mod, name, __FILE__, __LINE__) +#endif + +#define QUERY_NOROWS(lsqlite3, bRollbackOnError, sql...) \ + do { \ + if (query_norows(lsqlite3, sql) != 0) { \ + if (bRollbackOnError) { \ + UNLOCK_DB(module, "rollback"); \ + } \ + return -1; \ + } \ } while (0) #define QUERY_INT(lsqlite3, result_var, bRollbackOnError, sql...) \ do { \ if (query_int(lsqlite3, &result_var, sql) != 0) { \ if (bRollbackOnError) { \ - query_norows(lsqlite3, \ - "ROLLBACK;"); \ + UNLOCK_DB(module, "rollback"); \ } \ return -1; \ } \ } while (0) +#define SQLITE3_DEBUG_QUERY (1 << 0) +#define SQLITE3_DEBUG_INIT (1 << 1) +#define SQLITE3_DEBUG_ADD (1 << 2) +#define SQLITE3_DEBUG_NEWDN (1 << 3) +#define SQLITE3_DEBUG_SEARCH (1 << 4) + /* * Static variables */ -static int lsqlite3_debug = TRUE; - +static int lsqlite3_debug = FALSE; /* * Forward declarations @@ -164,7 +180,7 @@ parsetree_to_sql(struct ldb_module *module, const struct ldb_parse_tree *t); static int -parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, +parsetree_to_attrlist(struct ldb_module *module, const struct ldb_parse_tree * t); #ifdef NEED_TABLE_LIST @@ -188,6 +204,28 @@ static int new_attr(struct ldb_module * module, char * pAttrName); +static void +base160_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv); + +static void +base160next_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv); + +#ifdef DEBUG_LOCKS +static int lock_debug(struct ldb_module * module, + const char * lockname, + const char * pFileName, + int linenum); + +static int unlock_debug(struct ldb_module * module, + const char * lockname, + const char * pFileName, + int linenum); +#endif + /* * Table of operations for the sqlite3 backend @@ -223,7 +261,6 @@ int lsqlite3_connect(struct ldb_context *ldb, { int i; int ret; - struct ldb_context * ldb = NULL; struct lsqlite3_private * lsqlite3 = NULL; lsqlite3 = talloc(ldb, struct lsqlite3_private); @@ -295,21 +332,55 @@ lsqlite3_rename(struct ldb_module * module, const char * pOldDN, const char * pNewDN) { + long long eid; struct lsqlite3_private * lsqlite3 = module->private_data; + /* ignore ltdb specials */ + if (*pOldDN == '@' || *pNewDN == '@') { + return 0; + } + /* Case-fold each of the DNs */ pOldDN = ldb_dn_fold(module->ldb, pOldDN, module, case_fold_attr_required); pNewDN = ldb_dn_fold(module->ldb, pNewDN, module, case_fold_attr_required); + /* Begin a transaction */ + if (LOCK_DB(module, "transaction") < 0) { + return -1; + } + + /* Determine the eid of the DN being deleted */ + QUERY_INT(lsqlite3, + eid, + TRUE, + "SELECT eid\n" + " FROM ldb_entry\n" + " WHERE dn = %Q;", + pOldDN); + QUERY_NOROWS(lsqlite3, - FALSE, + TRUE, "UPDATE ldb_entry " " SET dn = %Q " - " WHERE dn = %Q;", - pNewDN, pOldDN); + " WHERE eid = %lld;", + pNewDN, eid); + QUERY_NOROWS(lsqlite3, + TRUE, + "UPDATE ldb_attr_DN " + " SET attr_value = %Q " + " WHERE eid = %lld;", + pNewDN, + eid); + + /* Commit the transaction */ + if (UNLOCK_DB(module, "transaction") < 0) { + UNLOCK_DB(module, "rollback"); + return -1; + } + return 0; } @@ -326,8 +397,18 @@ lsqlite3_delete(struct ldb_module * module, sqlite3_stmt * pStmt; struct lsqlite3_private * lsqlite3 = module->private_data; + /* ignore ltdb specials */ + if (*pDN == '@') { + return 0; + } + /* Begin a transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); + if (LOCK_DB(module, "transaction") < 0) { + return -1; + } + + /* Case-fold the DNs */ + pDN = ldb_dn_fold(module->ldb, pDN, module, case_fold_attr_required); /* Determine the eid of the DN being deleted */ QUERY_INT(lsqlite3, @@ -340,7 +421,7 @@ lsqlite3_delete(struct ldb_module * module, /* Obtain the list of attribute names in use by this DN */ if ((pSql = talloc_asprintf(module->ldb, - "SELECT attr_name " + "SELECT upper(attr_name) " " FROM ldb_attribute_values " " WHERE eid = %lld;", eid)) == NULL) { @@ -413,22 +494,32 @@ lsqlite3_delete(struct ldb_module * module, bLoop = FALSE; } - /* Delete the descendants records */ + /* Delete the DN attribute entry */ QUERY_NOROWS(lsqlite3, TRUE, - "DELETE FROM ldb_descendants " - " WHERE deid = %lld;", + "DELETE FROM ldb_attr_DN " + " WHERE eid = %lld;", eid); /* Delete attribute/value table entries pertaining to this DN */ QUERY_NOROWS(lsqlite3, TRUE, - "DELETE FROM ldb_attribute_value " + "DELETE FROM ldb_attribute_values " + " WHERE eid = %lld;", + eid); + + /* Delete this entry */ + QUERY_NOROWS(lsqlite3, + TRUE, + "DELETE FROM ldb_entry " " WHERE eid = %lld;", eid); /* Commit the transaction */ - QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); + if (UNLOCK_DB(module, "transaction") < 0) { + UNLOCK_DB(module, "rollback"); + return -1; + } return 0; } @@ -478,7 +569,9 @@ lsqlite3_search_bytree(struct ldb_module * module, } /* Begin a transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "BEGIN IMMEDIATE;"); + if (LOCK_DB(module, "transaction") < 0) { + return -1; + } /* * Obtain the eid of the base DN @@ -489,11 +582,11 @@ lsqlite3_search_bytree(struct ldb_module * module, " FROM ldb_attr_DN\n" " WHERE attr_value = %Q;", pBaseDN)) == SQLITE_DONE) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + UNLOCK_DB(module, "rollback"); talloc_free(hTalloc); return 0; } else if (ret != SQLITE_OK) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + UNLOCK_DB(module, "rollback"); talloc_free(hTalloc); return -1; } @@ -508,13 +601,7 @@ lsqlite3_search_bytree(struct ldb_module * module, " WHERE 1;");/* avoid a schema change with WHERE 1 */ /* Initially, we don't know what the requested attributes are */ - if (attrs == NULL) { - /* but they didn't give us any so we'll retrieve all of 'em */ - pResultAttrList = ""; - } else { - /* Discover the list of attributes */ - pResultAttrList = NULL; - } + pResultAttrList = NULL; /* Insert the list of requested attributes into this table */ for (pRequestedAttrs = (const char * const *) attrs; @@ -544,7 +631,7 @@ lsqlite3_search_bytree(struct ldb_module * module, if (pResultAttrList == NULL) { /* ... then we'll use the result attribute table */ pResultAttrList = - " AND av.attr_name IN\n" + " AND upper(av.attr_name) IN\n" " (SELECT attr_name\n" " FROM " RESULT_ATTR_TABLE ") "; } @@ -558,7 +645,7 @@ lsqlite3_search_bytree(struct ldb_module * module, /* * Create a table of unique attribute names for our extra table list */ - if ((ret = parsetree_to_attrlist(lsqlite3, pTree)) != 0) { + if ((ret = parsetree_to_attrlist(module, pTree)) != 0) { ret = -1; goto cleanup; } @@ -581,22 +668,31 @@ lsqlite3_search_bytree(struct ldb_module * module, " entry.dn,\n" " av.attr_name,\n" " av.attr_value\n" - " FROM ldb_entry AS entry,\n" - " ldb_attribute_values AS av\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + " %s\n" + " WHERE entry.eid IN\n" " (SELECT DISTINCT ldb_entry.eid\n" - " FROM ldb_entry,\n" - " ldb_descendants\n" - " WHERE ldb_descendants.aeid = %lld\n" - " AND ldb_entry.eid = ldb_descendants.deid\n" - " AND ldb_entry.eid IN\n%s\n" + " FROM ldb_entry\n" + " WHERE ldb_entry.tree_key >=\n" + " (SELECT tree_key\n" + " FROM ldb_entry\n" + " WHERE eid = %lld)\n" + " AND ldb_entry.tree_key <\n" + " (SELECT base160_next(tree_key)\n" + " FROM ldb_entry\n" + " WHERE eid = %lld)\n" + " AND ldb_entry.eid IN\n(%s)\n" " )\n" - " AND av.eid = entry.eid\n" - " %s\n" - " ORDER BY av.eid, av.attr_name;", + " ORDER BY entry.tree_key DESC,\n" + " COALESCE(av.attr_name, '');", + pResultAttrList, + eid, eid, - pSqlConstraints, - pResultAttrList); + pSqlConstraints); break; case LDB_SCOPE_BASE: @@ -605,20 +701,23 @@ lsqlite3_search_bytree(struct ldb_module * module, " entry.dn,\n" " av.attr_name,\n" " av.attr_value\n" - " FROM ldb_entry AS entry,\n" - " ldb_attribute_values AS av\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + " %s\n" + " WHERE entry.eid IN\n" " (SELECT DISTINCT ldb_entry.eid\n" " FROM ldb_entry\n" " WHERE ldb_entry.eid = %lld\n" - " AND ldb_entry.eid IN\n%s\n" + " AND ldb_entry.eid IN\n(%s)\n" " )\n" - " AND av.eid = entry.eid\n" - " %s\n" - " ORDER BY av.eid, av.attr_name;", + " ORDER BY entry.tree_key DESC,\n" + " COALESCE(av.attr_name, '');", + pResultAttrList, eid, - pSqlConstraints, - pResultAttrList); + pSqlConstraints); break; case LDB_SCOPE_ONELEVEL: @@ -627,21 +726,37 @@ lsqlite3_search_bytree(struct ldb_module * module, " entry.dn,\n" " av.attr_name,\n" " av.attr_value\n" - " FROM ldb_entry AS entry,\n" - " ldb_attribute_values AS av\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + " %s\n" + " WHERE entry.eid IN\n" " (SELECT DISTINCT ldb_entry.eid\n" - " FROM ldb_entry AS pchild\n" - " WHERE ldb_entry.eid = pchild.eid\n" - " AND pchild.peid = %lld\n" - " AND ldb_entry.eid IN\n%s\n" + " FROM ldb_entry\n" + " WHERE ldb_entry.tree_key >=\n" + " (SELECT tree_key\n" + " FROM ldb_entry\n" + " WHERE eid = %lld)\n" + " AND ldb_entry.tree_key <\n" + " (SELECT base160_next(tree_key)\n" + " FROM ldb_entry\n" + " WHERE eid = %lld)\n" + " AND length(ldb_entry.tree_key) =\n" + " (SELECT length(tree_key) + 4\n" + " FROM ldb_entry\n" + " WHERE eid = %lld)\n" + " AND ldb_entry.eid IN\n(%s)\n" " )\n" - " AND av.eid = entry.eid\n" - " %s\n" - " ORDER BY av.eid, av.attr_name;\n", + + " ORDER BY entry.tree_key DESC,\n" + " COALESCE(av.attr_name, '');\n", + pResultAttrList, + eid, + eid, eid, - pSqlConstraints, - pResultAttrList); + pSqlConstraints); break; } @@ -650,7 +765,7 @@ lsqlite3_search_bytree(struct ldb_module * module, goto cleanup; } - if (lsqlite3_debug) { + if (lsqlite3_debug & SQLITE3_DEBUG_SEARCH) { printf("%s\n", pSql); } @@ -697,19 +812,22 @@ lsqlite3_search_bytree(struct ldb_module * module, pAttrValue = sqlite3_column_text(pStmt, 3); /* Add this result to the result set */ - if ((ret = add_msg_attr(hTalloc, - eid, - pDN, - pAttrName, - pAttrValue, - prevEID, - &allocated, - pppRes)) != 0) { + if (add_msg_attr(hTalloc, + eid, + pDN, + pAttrName, + pAttrValue, + prevEID, + &allocated, + pppRes) != 0) { (void) sqlite3_finalize(pStmt); ret = -1; break; } + + /* Save the most recent EID */ + prevEID = eid; } } @@ -750,7 +868,7 @@ lsqlite3_search_bytree(struct ldb_module * module, sqlite3_free(pSql); /* End the transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;"); + UNLOCK_DB(module, "rollback"); /* Were there any results? */ if (ret != 0 || allocated == 0) { @@ -793,6 +911,17 @@ lsqlite3_search(struct ldb_module * module, int ret; struct ldb_parse_tree * pTree; + /* Handle tdb specials */ + if (pBaseDN != NULL && *pBaseDN == '@') { +#warning "handle tdb specials" + return 0; + } + + /* Handle the special case of requesting all */ + if (pExpression != NULL && *pExpression == '\0') { + pExpression = "dn=*"; + } + /* Parse the filter expression into a tree we can work with */ if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { return -1; @@ -816,33 +945,48 @@ lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg) { long long eid; - struct lsqlite3_private * lsqlite3 = module->private_data; - - /* ignore ltdb specials */ - if (msg->dn[0] == '@') { - return 0; - } + /* See if this is an ltdb special */ + if (*msg->dn == '@') { + /* Yup. We handle a few of these and ignore others */ + if (strcmp(msg->dn, "@SUBCLASSES") == 0) { +#warning "insert subclasses into object class tree" + } + + if (strcmp(msg->dn, "@INDEXLIST") == 0) { + /* explicitly ignored */ + return 0; + } + + /* Others are implicitly ignored */ + return 0; + } + /* Begin a transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); + if (LOCK_DB(module, "transaction") < 0) { + return -1; + } /* * Build any portions of the directory tree that don't exist. If the * final component already exists, it's an error. */ if (new_dn(module, msg->dn, &eid) != 0) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + UNLOCK_DB(module, "rollback"); return -1; } /* Add attributes to this new entry */ if (msg_to_sql(module, msg, eid, FALSE) != 0) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + UNLOCK_DB(module, "rollback"); return -1; } /* Everything worked. Commit it! */ - QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); + if (UNLOCK_DB(module, "transaction") < 0) { + UNLOCK_DB(module, "rollback"); + return -1; + } return 0; } @@ -856,13 +1000,15 @@ lsqlite3_modify(struct ldb_module * module, long long eid; struct lsqlite3_private * lsqlite3 = module->private_data; - /* ignore ltdb specials */ - if (msg->dn[0] == '@') { - return 0; - } - + /* ignore ltdb specials */ + if (*msg->dn == '@') { + return 0; + } + /* Begin a transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); + if (LOCK_DB(module, "transaction") < 0) { + return -1; + } /* Case-fold the DN so we can compare it to what's in the database */ pDN = ldb_dn_fold(module->ldb, msg->dn, @@ -879,26 +1025,38 @@ lsqlite3_modify(struct ldb_module * module, /* Apply the message attributes */ if (msg_to_sql(module, msg, eid, TRUE) != 0) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + UNLOCK_DB(module, "rollback"); return -1; } /* Everything worked. Commit it! */ - QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;"); + if (UNLOCK_DB(module, "transaction") < 0) { + UNLOCK_DB(module, "rollback"); + return -1; + } return 0 ; } /* obtain a named lock */ static int -lsqlite3_lock(struct ldb_module *module, - const char *lockname) +lsqlite3_lock(struct ldb_module * module, + const char * lockname) { + struct lsqlite3_private * lsqlite3 = module->private_data; + if (lockname == NULL) { return -1; } - /* TODO implement a local locking mechanism here */ + if (strcmp(lockname, "transaction") == 0) { + if (lsqlite3->lock_count == 0) { + if (query_norows(lsqlite3, "BEGIN EXCLUSIVE;") != 0) { + return -1; + } + } + ++lsqlite3->lock_count; + } return 0; } @@ -908,11 +1066,23 @@ static int lsqlite3_unlock(struct ldb_module *module, const char *lockname) { + struct lsqlite3_private * lsqlite3 = module->private_data; + if (lockname == NULL) { return -1; } - /* TODO implement a local locking mechanism here */ + if (strcmp(lockname, "transaction") == 0) { + if (lsqlite3->lock_count == 1) { + if (query_norows(lsqlite3, "COMMIT;") != 0) { + query_norows(lsqlite3, "ROLLBACK;"); + } + } else if (lsqlite3->lock_count > 0) { + --lsqlite3->lock_count; + } + } else if (strcmp(lockname, "rollback") == 0) { + query_norows(lsqlite3, "ROLLBACK;"); + } return 0; } @@ -959,37 +1129,20 @@ initialize(struct lsqlite3_private *lsqlite3, "(" " eid INTEGER PRIMARY KEY," " peid INTEGER REFERENCES ldb_entry," - " dn TEXT UNIQUE," + " dn TEXT UNIQUE NOT NULL," + " tree_key TEXT UNIQUE," + " max_child_num INTEGER DEFAULT 0," " create_timestamp INTEGER," " modify_timestamp INTEGER" ");" - /* - * The purpose of the descendant table is to support the - * subtree search feature. For each LDB entry with a unique - * ID (AEID), this table contains the unique identifiers - * (DEID) of the descendant entries. - * - * For evern entry in the directory, a row exists in this - * table for each of its ancestors including itself. The - * size of the table depends on the depth of each entry. In - * the worst case, if all the entries were at the same - * depth, the number of rows in the table is O(nm) where - * n is the number of nodes in the directory and m is the - * depth of the tree. - */ - "CREATE TABLE ldb_descendants " - "( " - " aeid INTEGER REFERENCES ldb_entry," - " deid INTEGER REFERENCES ldb_entry" - ");" - - "CREATE TABLE ldb_object_classes" "(" " class_name TEXT PRIMARY KEY," - " tree_key TEXT UNIQUE" + " parent_class_name TEXT," + " tree_key TEXT UNIQUE," + " max_child_num INTEGER DEFAULT 0" ");" /* @@ -1018,8 +1171,8 @@ initialize(struct lsqlite3_private *lsqlite3, */ "CREATE TABLE ldb_attr_DN" "(" - " eid INTEGER REFERENCES ldb_entry," - " attr_value TEXT" + " eid INTEGER PRIMARY KEY REFERENCES ldb_entry," + " attr_value TEXT" ");" @@ -1036,8 +1189,16 @@ initialize(struct lsqlite3_private *lsqlite3, /* * Indexes */ + "CREATE INDEX ldb_entry_tree_key_idx " + " ON ldb_entry (tree_key);" + + "CREATE INDEX ldb_attribute_values_eid_idx " + " ON ldb_attribute_values (eid);" + "CREATE INDEX ldb_attr_DN_attr_value_idx " + " ON ldb_attr_DN (attr_value);" + /* * Triggers */ @@ -1047,10 +1208,23 @@ initialize(struct lsqlite3_private *lsqlite3, " ON ldb_entry" " FOR EACH ROW" " BEGIN" + " UPDATE ldb_entry" " SET create_timestamp = strftime('%s', 'now')," " modify_timestamp = strftime('%s', 'now')" - " WHERE eid = new.eid;" + " ," + " tree_key = COALESCE(tree_key, " + " (" + " SELECT tree_key || " + " (SELECT base160(max_child_num + 1)" + " FROM ldb_entry" + " WHERE eid = new.peid)" + " FROM ldb_entry " + " WHERE eid = new.peid " + " ));" + " UPDATE ldb_entry " + " SET max_child_num = max_child_num + 1" + " WHERE eid = new.peid;" " END;" "CREATE TRIGGER ldb_entry_update_tr" @@ -1063,15 +1237,36 @@ initialize(struct lsqlite3_private *lsqlite3, " WHERE eid = old.eid;" " END;" + "CREATE TRIGGER ldb_object_classes_insert_tr" + " AFTER INSERT" + " ON ldb_object_classes" + " FOR EACH ROW" + " BEGIN" + " UPDATE ldb_object_classes" + " SET tree_key = COALESCE(tree_key, " + " (" + " SELECT tree_key || " + " (SELECT base160(max_child_num + 1)" + " FROM ldb_object_classes" + " WHERE class_name = " + " new.parent_class_name)" + " FROM ldb_object_classes " + " WHERE class_name = new.parent_class_name " + " ));" + " UPDATE ldb_object_classes " + " SET max_child_num = max_child_num + 1" + " WHERE class_name = new.parent_class_name;" + " END;" + /* * Table initialization */ /* The root node */ "INSERT INTO ldb_entry " - " (eid, peid, dn) " + " (eid, peid, dn, tree_key) " " VALUES " - " (0, NULL, '');" + " (0, NULL, '', '0001');" /* And the root node "dn" attribute */ "INSERT INTO ldb_attr_DN " @@ -1079,6 +1274,11 @@ initialize(struct lsqlite3_private *lsqlite3, " VALUES " " (0, '');" + "INSERT INTO ldb_object_classes " + " (class_name, tree_key) " + " VALUES " + " ('TOP', '0001');" + ; /* Skip protocol indicator of url */ @@ -1095,18 +1295,58 @@ initialize(struct lsqlite3_private *lsqlite3, } /* In case this is a new database, enable auto_vacuum */ - QUERY_NOROWS(lsqlite3, FALSE, "PRAGMA auto_vacuum=1;"); + if (query_norows(lsqlite3, "PRAGMA auto_vacuum=1;") != 0) { + return -1; + } + /* Establish a busy timeout of 30 seconds */ + if ((ret = sqlite3_busy_timeout(lsqlite3->sqlite, + 30000)) != SQLITE_OK) { + return ret; + } + + /* Create a function, callable from sql, to increment a tree_key */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite,/* handle */ + "base160_next", /* function name */ + 1, /* number of args */ + SQLITE_ANY, /* preferred text type */ + NULL, /* user data */ + base160next_sql, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } + + /* Create a function, callable from sql, to convert int to base160 */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite,/* handle */ + "base160", /* function name */ + 1, /* number of args */ + SQLITE_ANY, /* preferred text type */ + NULL, /* user data */ + base160_sql, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } + /* Begin a transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;"); + if ((ret = query_norows(lsqlite3, "BEGIN EXCLUSIVE;")) != 0) { + return ret; + } /* Determine if this is a new database. No tables means it is. */ - QUERY_INT(lsqlite3, - queryInt, - TRUE, - "SELECT COUNT(*)\n" - " FROM sqlite_master\n" - " WHERE type = 'table';"); + if (query_int(lsqlite3, + &queryInt, + "SELECT COUNT(*)\n" + " FROM sqlite_master\n" + " WHERE type = 'table';") != 0) { + query_norows(lsqlite3, "ROLLBACK;"); + return -1; + } if (queryInt == 0) { /* @@ -1116,7 +1356,7 @@ initialize(struct lsqlite3_private *lsqlite3, pTail != NULL && *pTail != '\0'; ) { - if (lsqlite3_debug) { + if (lsqlite3_debug & SQLITE3_DEBUG_INIT) { printf("Execute first query in:\n%s\n", pTail); } @@ -1129,7 +1369,13 @@ initialize(struct lsqlite3_private *lsqlite3, (ret = sqlite3_step(stmt)) != SQLITE_DONE || (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + if (lsqlite3_debug & SQLITE3_DEBUG_INIT) { + printf("%s\n", + sqlite3_errmsg(lsqlite3->sqlite)); + printf("pTail = [%s]\n", pTail); + } + + query_norows(lsqlite3, "ROLLBACK;"); (void) sqlite3_close(lsqlite3->sqlite); return ret; } @@ -1141,13 +1387,14 @@ initialize(struct lsqlite3_private *lsqlite3, if (query_int(lsqlite3, &queryInt, "SELECT " - " (SELECT COUNT(*) = 3" + " (SELECT COUNT(*) = 4" " FROM sqlite_master " " WHERE type = 'table' " " AND name IN " " (" " 'ldb_entry', " - " 'ldb_descendants', " + " 'ldb_attr_DN', " + " 'ldb_attr_OBJECTCLASS', " " 'ldb_object_classes' " " ) " " ) " @@ -1160,7 +1407,7 @@ initialize(struct lsqlite3_private *lsqlite3, queryInt != 1) { /* It's not one that we created. See ya! */ - QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;"); + query_norows(lsqlite3, "ROLLBACK;"); (void) sqlite3_close(lsqlite3->sqlite); return SQLITE_MISUSE; } @@ -1170,26 +1417,37 @@ initialize(struct lsqlite3_private *lsqlite3, * Create a temporary table to hold attributes requested in the result * set of a search. */ - QUERY_NOROWS(lsqlite3, - FALSE, - "CREATE TEMPORARY TABLE " RESULT_ATTR_TABLE "\n" - " (\n" - " attr_name TEXT PRIMARY KEY\n" - " );"); - + query_norows(lsqlite3, "DROP TABLE " RESULT_ATTR_TABLE ";\n"); + if ((ret = + query_norows(lsqlite3, + "CREATE " TEMPTAB " TABLE " RESULT_ATTR_TABLE "\n" + " (\n" + " attr_name TEXT PRIMARY KEY\n" + " );")) != 0) { + query_norows(lsqlite3, "ROLLBACK;"); + return ret; + } + /* * Create a temporary table to hold the attributes used by filters * during a search. */ - QUERY_NOROWS(lsqlite3, - FALSE, - "CREATE TEMPORARY TABLE " FILTER_ATTR_TABLE "\n" - " (\n" - " attr_name TEXT PRIMARY KEY\n" - " );"); - + query_norows(lsqlite3, "DROP TABLE " FILTER_ATTR_TABLE ";\n"); + if ((ret = + query_norows(lsqlite3, + "CREATE " TEMPTAB " TABLE " FILTER_ATTR_TABLE "\n" + " (\n" + " attr_name TEXT PRIMARY KEY\n" + " );")) != 0) { + query_norows(lsqlite3, "ROLLBACK;"); + return ret; + } + /* Commit the transaction */ - QUERY_NOROWS(lsqlite3, FALSE, "COMMIT;"); + if ((ret = query_norows(lsqlite3, "COMMIT;")) != 0) { + query_norows(lsqlite3, "ROLLBACK;"); + return ret; + } return SQLITE_OK; } @@ -1224,7 +1482,14 @@ query_norows(const struct lsqlite3_private *lsqlite3, char * p; sqlite3_stmt * pStmt; va_list args; + double t0; + double t1; + struct timeval tv; + struct timezone tz; + gettimeofday(&tv, &tz); + t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + /* Begin access to variable argument list */ va_start(args, pSql); @@ -1233,10 +1498,6 @@ query_norows(const struct lsqlite3_private *lsqlite3, return -1; } - if (lsqlite3_debug) { - printf("%s\n", p); - } - /* * Prepare and execute the SQL statement. Loop allows retrying on * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, @@ -1287,6 +1548,15 @@ query_norows(const struct lsqlite3_private *lsqlite3, /* All done with variable argument list */ va_end(args); + gettimeofday(&tv, NULL); + t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + + if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { + printf("%1.6lf %s\n%s\n\n", t1 - t0, + ret == 0 ? "SUCCESS" : "FAIL", + p); + } + /* Free the memory we allocated for our query string */ sqlite3_free(p); @@ -1314,7 +1584,14 @@ query_int(const struct lsqlite3_private * lsqlite3, char * p; sqlite3_stmt * pStmt; va_list args; + double t0; + double t1; + struct timeval tv; + struct timezone tz; + gettimeofday(&tv, &tz); + t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + /* Begin access to variable argument list */ va_start(args, pSql); @@ -1323,7 +1600,7 @@ query_int(const struct lsqlite3_private * lsqlite3, return SQLITE_NOMEM; } - if (lsqlite3_debug) { + if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { printf("%s\n", p); } @@ -1376,6 +1653,15 @@ query_int(const struct lsqlite3_private * lsqlite3, /* All done with variable argument list */ va_end(args); + gettimeofday(&tv, NULL); + t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + + if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { + printf("%1.6lf %s\n%s\n\n", t1 - t0, + ret == 0 ? "SUCCESS" : "FAIL", + p); + } + /* Free the memory we allocated for our query string */ sqlite3_free(p); @@ -1420,7 +1706,7 @@ add_msg_attr(void * hTalloc, if (eid != prevEID) { /* Yup. Add another result to the result array */ if ((x = talloc_realloc(hTalloc, - *pAllocated == 0 ? NULL : pppRes, + *pAllocated == 0 ? NULL : *pppRes, struct ldb_message *, *pAllocated + 1)) == NULL) { @@ -1429,81 +1715,99 @@ add_msg_attr(void * hTalloc, /* Save the new result list */ *pppRes = x; - + + /* Allocate a new result structure */ + if ((x = talloc(*pppRes, struct ldb_message)) == NULL) { + return -1; + } + + /* Save the new result */ + (*pppRes)[*pAllocated] = x; + + /* Steal the initial result and put it in its own context */ + talloc_steal(NULL, *pppRes); + /* We've allocated one more result */ - *pAllocated++; + ++*pAllocated; /* Ensure that the message is initialized */ msg = x; - msg->dn = NULL; + if ((msg->dn = talloc_strdup(msg, pDN)) == NULL) { + return -1; + } msg->num_elements = 0; msg->elements = NULL; msg->private_data = NULL; } else { /* Same EID. Point to the previous most-recent message */ - msg = *pppRes[*pAllocated - 1]; + msg = (*pppRes)[*pAllocated - 1]; } - /* - * Point to the most recent previous element. (If there are none, - * this will point to non-allocated memory, but the pointer will never - * be dereferenced.) - */ - el = &msg->elements[msg->num_elements - 1]; + if (pAttrName != NULL && pAttrValue != NULL) { + /* + * Point to the most recent previous element. (If there are none, + * this will point to non-allocated memory, but the pointer will + * never be dereferenced.) + */ + el = &msg->elements[msg->num_elements - 1]; - /* See if the most recent previous element has the same attr_name */ - if (msg->num_elements == 0 || strcmp(el->name, pAttrName) != 0) { + /* + * See if the most recent previous element has the same attr_name + */ + if (msg->num_elements == 0 || strcmp(el->name, pAttrName) != 0) { /* It's a new attr_name. Allocate another message element */ if ((el = talloc_realloc(msg, msg->elements, struct ldb_message_element, msg->num_elements + 1)) == NULL) { - return -1; + return -1; } /* Save the new element */ msg->elements = el; - /* There's now one additional element */ - msg->num_elements++; - /* Save the attribute name */ if ((el->name = talloc_strdup(msg->elements, pAttrName)) == NULL) { - return -1; + return -1; } + /* There's now one additional element */ + msg->num_elements++; + /* No flags */ el->flags = 0; /* Initialize number of attribute values for this type */ el->num_values = 0; el->values = NULL; - } + } - /* Increase the value array size by 1 */ - if ((el->values = - talloc_realloc(el, - el->num_values == 0 ? NULL : el->values, - struct ldb_val, - el->num_values)) == NULL) { + /* Increase the value array size by 1 */ + if ((el->values = + talloc_realloc(el, + el->num_values == 0 ? NULL : el->values, + struct ldb_val, + el->num_values + 1)) == NULL) { return -1; - } + } - /* Save the new attribute value length */ - el->values[el->num_values].length = strlen(pAttrValue) + 1; + /* Save the new attribute value length */ + el->values[el->num_values].length = strlen(pAttrValue); - /* Copy the new attribute value */ - if (talloc_memdup(el->values[el->num_values].data, - pAttrValue, - el->values[el->num_values].length) == NULL) { + /* Copy the new attribute value */ + if ((el->values[el->num_values].data = + talloc_memdup(el->values, + pAttrValue, + el->values[el->num_values].length)) == NULL) { return -1; - } + } - /* We now have one additional value of this type */ - el->num_values++; + /* We now have one additional value of this type */ + el->num_values++; + } return 0; } @@ -1514,6 +1818,7 @@ parsetree_to_sql(struct ldb_module *module, const struct ldb_parse_tree *t) { int i; + char * pDN; char * child; char * p; char * ret = NULL; @@ -1548,7 +1853,7 @@ parsetree_to_sql(struct ldb_module *module, child = ret; ret = talloc_asprintf(hTalloc, - "(\n" + "SELECT * FROM (\n" "%s\n" ")\n", child); @@ -1556,11 +1861,9 @@ parsetree_to_sql(struct ldb_module *module, return ret; case LDB_OP_OR: - child = - parsetree_to_sql( - module, - hTalloc, - t->u.list.elements[0]); + ret = parsetree_to_sql(module, + hTalloc, + t->u.list.elements[0]); for (i = 1; i < t->u.list.num_elements; i++) { child = @@ -1576,7 +1879,7 @@ parsetree_to_sql(struct ldb_module *module, } child = ret; ret = talloc_asprintf(hTalloc, - "(\n" + "SELECT * FROM (\n" "%s\n" ")\n", child); @@ -1590,11 +1893,9 @@ parsetree_to_sql(struct ldb_module *module, hTalloc, t->u.not.child); ret = talloc_asprintf(hTalloc, - "(\n" " SELECT eid\n" " FROM ldb_entry\n" - " WHERE eid NOT IN %s\n" - ")\n", + " WHERE eid NOT IN (%s)\n", child); talloc_free(child); return ret; @@ -1621,15 +1922,13 @@ parsetree_to_sql(struct ldb_module *module, * eid corresponding to all values in the specified attribute * table. */ - if ((p = sqlite3_mprintf("(\n" - " SELECT eid\n" - " FROM ldb_attr_%q\n" - ")\n", + if ((p = sqlite3_mprintf(" SELECT eid\n" + " FROM ldb_attr_%q\n", pAttrName)) == NULL) { return NULL; } - if (lsqlite3_debug) { + if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { printf("%s\n", p); } @@ -1642,41 +1941,55 @@ parsetree_to_sql(struct ldb_module *module, * that are subclasses as well. */ if ((p = sqlite3_mprintf( - "(\n" " SELECT eid\n" " FROM ldb_attr_OBJECTCLASS\n" - " WHERE attr_name IN\n" + " WHERE attr_value IN\n" " (SELECT class_name\n" - " FROM ldb_objectclasses\n" + " FROM ldb_object_classes\n" " WHERE tree_key GLOB\n" " (SELECT tree_key\n" - " FROM ldb_objectclasses\n" - " WHERE class_name = %Q) || '*')\n" - ")\n", + " FROM ldb_object_classes\n" + " WHERE class_name = upper(%Q)) " + " || '*')\n", t->u.simple.value.data)) == NULL) { return NULL; } - if (lsqlite3_debug) { + if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { printf("%s\n", p); } ret = talloc_strdup(hTalloc, p); sqlite3_free(p); + } else if (strcasecmp(t->u.simple.attr, "dn") == 0) { + pDN = ldb_dn_fold(module->ldb, t->u.simple.value.data, + module, case_fold_attr_required); + if ((p = sqlite3_mprintf(" SELECT eid\n" + " FROM ldb_attr_%q\n" + " WHERE attr_value = %Q\n", + pAttrName, + pDN)) == NULL) { + return NULL; + } + + if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { + printf("%s\n", p); + } + + ret = talloc_strdup(hTalloc, p); + sqlite3_free(p); } else { /* A normal query. */ - if ((p = sqlite3_mprintf("(\n" - " SELECT eid\n" + if ((p = sqlite3_mprintf(" SELECT eid\n" " FROM ldb_attr_%q\n" - " WHERE attr_value = %Q\n" - ")\n", + " WHERE attr_value = %Q\n", pAttrName, t->u.simple.value.data)) == NULL) { return NULL; } - if (lsqlite3_debug) { + if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { printf("%s\n", p); } @@ -1689,10 +2002,11 @@ parsetree_to_sql(struct ldb_module *module, static int -parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, +parsetree_to_attrlist(struct ldb_module *module, const struct ldb_parse_tree * t) { int i; + struct lsqlite3_private * lsqlite3 = module->private_data; switch(t->operation) { case LDB_OP_SIMPLE: @@ -1704,14 +2018,14 @@ parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, case LDB_OP_AND: if (parsetree_to_attrlist( - lsqlite3, + module, t->u.list.elements[0]) != 0) { return -1; } for (i = 1; i < t->u.list.num_elements; i++) { if (parsetree_to_attrlist( - lsqlite3, + module, t->u.list.elements[i]) != 0) { return -1; } @@ -1721,14 +2035,14 @@ parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, case LDB_OP_OR: if (parsetree_to_attrlist( - lsqlite3, + module, t->u.list.elements[0]) != 0) { return -1; } for (i = 1; i < t->u.list.num_elements; i++) { if (parsetree_to_attrlist( - lsqlite3, + module, t->u.list.elements[i]) != 0) { return -1; } @@ -1737,7 +2051,7 @@ parsetree_to_attrlist(struct lsqlite3_private * lsqlite3, return 0; case LDB_OP_NOT: - if (parsetree_to_attrlist(lsqlite3, + if (parsetree_to_attrlist(module, t->u.not.child) != 0) { return -1; } @@ -1929,6 +2243,25 @@ msg_to_sql(struct ldb_module * module, el->name, el->values[j].data); + + /* Is this a special "objectclass"? */ + if (strcasecmp(pAttrName, + "objectclass") != 0) { + /* Nope. */ + break; + } + + /* Handle special "objectclass" type */ + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT OR IGNORE " + " INTO ldb_object_classes " + " (class_name, " + " parent_class_name) " + " VALUES " + " (upper(%Q), 'TOP');", + ldb_casefold(module, + el->values[j].data)); break; case LDB_FLAG_MOD_REPLACE: @@ -1991,11 +2324,20 @@ new_dn(struct ldb_module * module, char * pPartialDN; long long eid; long long peid; + double t0 = 0; + double t1 = 0; + struct timeval tv; + struct timezone tz; struct ldb_dn * pExplodedDN; struct ldb_dn_component * pComponent; struct ldb_context * ldb = module->ldb; struct lsqlite3_private * lsqlite3 = module->private_data; + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, &tz); + t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + } + /* Explode and normalize the DN */ if ((pExplodedDN = ldb_explode_dn(ldb, @@ -2005,17 +2347,34 @@ new_dn(struct ldb_module * module, return -1; } + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, NULL); + t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + printf("%1.6lf loc 1\n", t1 - t0); + t0 = t1; + } + /* Allocate a string to hold the partial DN of each component */ if ((pPartialDN = talloc_strdup(ldb, "")) == NULL) { return -1; } /* For each component of the DN (starting with the last one)... */ +#warning "convert this loop to recursive, and search backwards instead" eid = 0; + for (nComponent = pExplodedDN->comp_num - 1, bFirst = TRUE; nComponent >= 0; nComponent--, bFirst = FALSE) { + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, NULL); + t1 = ((double) tv.tv_sec + + ((double) tv.tv_usec / 1000000.0)); + printf("%1.6lf loc 2\n", t1 - t0); + t0 = t1; + } + /* Point to the component */ pComponent = pExplodedDN->components[nComponent]; @@ -2028,12 +2387,28 @@ new_dn(struct ldb_module * module, return -1; } + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, NULL); + t1 = ((double) tv.tv_sec + + ((double) tv.tv_usec / 1000000.0)); + printf("%1.6lf loc 3\n", t1 - t0); + t0 = t1; + } + /* No need for the old partial DN any more */ talloc_free(pPartialDN); /* Save the new partial DN */ pPartialDN = p; + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, NULL); + t1 = ((double) tv.tv_sec + + ((double) tv.tv_usec / 1000000.0)); + printf("%1.6lf loc 4\n", t1 - t0); + t0 = t1; + } + /* * Ensure that an entry is in the ldb_entry table for this * component. Any component other than the last one @@ -2053,45 +2428,50 @@ new_dn(struct ldb_module * module, /* Save the parent EID */ peid = eid; + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, NULL); + t1 = ((double) tv.tv_sec + + ((double) tv.tv_usec / 1000000.0)); + printf("%1.6lf loc 5\n", t1 - t0); + t0 = t1; + } + /* Get the EID of the just inserted row */ - eid = sqlite3_last_insert_rowid(lsqlite3->sqlite); - - /* - * Popoulate the descendant table - */ - - /* This table has an entry for itself as well as descendants */ - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT INTO ldb_descendants " - " (aeid, deid) " - " VALUES " - " (%lld, %lld);", - eid, eid); + QUERY_INT(lsqlite3, + eid, + FALSE, + "SELECT eid " + " FROM ldb_entry " + " WHERE dn = %Q;", + pPartialDN); + + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, NULL); + t1 = ((double) tv.tv_sec + + ((double) tv.tv_usec / 1000000.0)); + printf("%1.6lf loc 8\n", t1 - t0); + t0 = t1; + } - /* Now insert rows for all of our ancestors */ + /* Also add DN attribute */ QUERY_NOROWS(lsqlite3, FALSE, - "INSERT INTO ldb_descendants " - " (aeid, deid) " - " SELECT aeid, %lld " - " FROM ldb_descendants " - " WHERE aeid = %lld;", - eid, peid); - - /* If this is the final component, also add DN attribute */ - if (nComponent == 0) { - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT %s INTO ldb_attr_DN\n" - " (eid, attr_value) " - " VALUES " - " (%lld, %Q);", - nComponent == 0 ? "" : "OR IGNORE", - eid, pPartialDN); - } + "INSERT %s INTO ldb_attr_DN\n" + " (eid, attr_value) " + " VALUES " + " (%lld, %Q);", + nComponent == 0 ? "" : "OR IGNORE", + eid, pPartialDN); } + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, NULL); + t1 = ((double) tv.tv_sec + + ((double) tv.tv_usec / 1000000.0)); + printf("%1.6lf loc 9\n", t1 - t0); + t0 = t1; + } + /* Give 'em what they came for! */ *pEID = eid; @@ -2132,9 +2512,207 @@ new_attr(struct ldb_module * module, " attr_value TEXT\n" ");", pAttrName); + + QUERY_NOROWS(lsqlite3, + FALSE, + "CREATE INDEX ldb_attr_%q_eid_idx\n" + " ON ldb_attr_%q (eid);", + pAttrName, + pAttrName); + + QUERY_NOROWS(lsqlite3, + FALSE, + "CREATE INDEX ldb_attr_%q_attr_value_idx " + " ON ldb_attr_%q (attr_value);", + pAttrName, + pAttrName); + } return 0; } +static unsigned char base160tab[161] = { + 48 ,49 ,50 ,51 ,52 ,53 ,54 ,55 ,56 ,57 , /* 0-9 */ + 58 ,59 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 , /* : ; A-H */ + 73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 , /* I-R */ + 83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 ,97 ,98 , /* S-Z , a-b */ + 99 ,100,101,102,103,104,105,106,107,108, /* c-l */ + 109,110,111,112,113,114,115,116,117,118, /* m-v */ + 119,120,121,122,160,161,162,163,164,165, /* w-z, latin1 */ + 166,167,168,169,170,171,172,173,174,175, /* latin1 */ + 176,177,178,179,180,181,182,183,184,185, /* latin1 */ + 186,187,188,189,190,191,192,193,194,195, /* latin1 */ + 196,197,198,199,200,201,202,203,204,205, /* latin1 */ + 206,207,208,209,210,211,212,213,214,215, /* latin1 */ + 216,217,218,219,220,221,222,223,224,225, /* latin1 */ + 226,227,228,229,230,231,232,233,234,235, /* latin1 */ + 236,237,238,239,240,241,242,243,244,245, /* latin1 */ + 246,247,248,249,250,251,252,253,254,255, /* latin1 */ + '\0' +}; + + +/* + * base160() + * + * Convert an unsigned long integer into a base160 representation of the + * number. + * + * Parameters: + * val -- + * value to be converted + * + * result -- + * character array, 5 bytes long, into which the base160 representation + * will be placed. The result will be a four-digit representation of the + * number (with leading zeros prepended as necessary), and null + * terminated. + * + * Returns: + * Nothing + */ +static void +base160_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv) +{ + int i; + long long val; + char result[5]; + + val = sqlite3_value_int64(argv[0]); + + for (i = 3; i >= 0; i--) { + + result[i] = base160tab[val % 160]; + val /= 160; + } + + result[4] = '\0'; + + sqlite3_result_text(hContext, result, -1, SQLITE_TRANSIENT); +} + + +/* + * base160next_sql() + * + * This function enhances sqlite by adding a "base160_next()" function which is + * accessible via queries. + * + * Retrieve the next-greater number in the base160 sequence for the terminal + * tree node (the last four digits). Only one tree level (four digits) is + * operated on. + * + * Input: + * A character string: either an empty string (in which case no operation is + * performed), or a string of base160 digits with a length of a multiple of + * four digits. + * + * Output: + * Upon return, the trailing four digits (one tree level) will have been + * incremented by 1. + */ +static void +base160next_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv) +{ + int i; + int len; + unsigned char * pTab; + unsigned char * pBase160 = + strdup(sqlite3_value_text(argv[0])); + unsigned char * pStart = pBase160; + + /* + * We need a minimum of four digits, and we will always get a multiple + * of four digits. + */ + if (pBase160 != NULL && + (len = strlen(pBase160)) >= 4 && + len % 4 == 0) { + + if (pBase160 == NULL) { + + sqlite3_result_null(hContext); + return; + } + + pBase160 += strlen(pBase160) - 1; + + /* We only carry through four digits: one level in the tree */ + for (i = 0; i < 4; i++) { + + /* What base160 value does this digit have? */ + pTab = strchr(base160tab, *pBase160); + + /* Is there a carry? */ + if (pTab < base160tab + sizeof(base160tab) - 1) { + + /* + * Nope. Just increment this value and we're + * done. + */ + *pBase160 = *++pTab; + break; + } else { + + /* + * There's a carry. This value gets + * base160tab[0], we decrement the buffer + * pointer to get the next higher-order digit, + * and continue in the loop. + */ + *pBase160-- = base160tab[0]; + } + } + + sqlite3_result_text(hContext, + pStart, + strlen(pStart), + free); + } else { + sqlite3_result_value(hContext, argv[0]); + if (pBase160 != NULL) { + free(pBase160); + } + } +} + + +#ifdef DEBUG_LOCKS +static int lock_debug(struct ldb_module * module, + const char * lockname, + const char * pFileName, + int linenum) +{ + int ret; + struct lsqlite3_private * lsqlite3 = module->private_data; + + printf("%s(%d): LOCK (%d) ", + pFileName, linenum, lsqlite3->lock_count); + ret = lsqlite3_lock(module, lockname); + printf("got %d\n", ret); + + return ret; +} + + +static int unlock_debug(struct ldb_module * module, + const char * lockname, + const char * pFileName, + int linenum) +{ + int ret; + struct lsqlite3_private * lsqlite3 = module->private_data; + + ret = lsqlite3_unlock(module, lockname); + printf("%s(%d): UNLOCK (%d) got %d\n", + pFileName, linenum, lsqlite3->lock_count, ret); + + return ret; +} +#endif diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h index 192e28f3dc..3d3c63397b 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h @@ -1,10 +1,10 @@ #include struct lsqlite3_private { - char **options; - const char *basedn; - sqlite3 * sqlite; - int lock_count; + char ** options; + const char * basedn; + sqlite3 * sqlite; + int lock_count; }; void diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema index c44351c543..08dc50de08 100644 --- a/source4/lib/ldb/ldb_sqlite3/schema +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -12,130 +12,160 @@ SELECT 'LDB' AS database_type, '1.0' AS version; - -- ------------------------------------------------------ - -- Schema - /* - * The entry table holds the information about an entry. This - * table is used to obtain the EID of the entry and to support - * scope="one" and scope="base". The parent and child table - * is included in the entry table since all the other - * attributes are dependent on EID. + * Get the next USN value with: + * BEGIN EXCLUSIVE; + * UPDATE usn SET value = value + 1; + * SELECT value FROM usn; + * COMMIT; */ - CREATE TABLE ldb_entry + CREATE TABLE usn ( - -- Unique identifier of this LDB entry - eid INTEGER PRIMARY KEY, - - -- Unique identifier of the parent LDB entry - peid INTEGER REFERENCES ldb_entry, - - -- Distinguished name of this entry - dn TEXT, - - -- Time when the entry was created - create_timestamp INTEGER, - - -- Time when the entry was last modified - modify_timestamp INTEGER + value INTEGER ); - - /* - * The purpose of the descendant table is to support the - * subtree search feature. For each LDB entry with a unique - * ID (AEID), this table contains the unique identifiers - * (DEID) of the descendant entries. - * - * For evern entry in the directory, a row exists in this - * table for each of its ancestors including itself. The size - * of the table depends on the depth of each entry. In the - * worst case, if all the entries were at the same depth, the - * number of rows in the table is O(nm) where n is the number - * of nodes in the directory and m is the depth of the tree. - */ - CREATE TABLE ldb_descendants + CREATE TABLE ldb_object ( - -- The unique identifier of the ancestor LDB entry - aeid INTEGER REFERENCES ldb_entry, - - -- The unique identifier of the descendant LDB entry - deid INTEGER REFERENCES ldb_entry - ); - - - CREATE TABLE ldb_object_classes - ( - -- Object classes are inserted into this table to track - -- their class hierarchy. 'top' is the top-level class - -- of which all other classes are subclasses. - class_name TEXT PRIMARY KEY, - - -- tree_key tracks the position of the class in - -- the hierarchy - tree_key TEXT UNIQUE + /* tree_key is auto-generated by the insert trigger */ + tree_key TEXT PRIMARY KEY, + + parent_tree_key TEXT, + dn TEXT, + + attr_name TEXT REFERENCES ldb_attributes, + attr_value TEXT, + + /* + * object_type can take on these values (to date): + * 1: object is a node of a DN + * 2: object is an attribute/value pair of its parent DN + */ + object_type INTEGER, + + /* + * if object_type is 1, the node can have children. + * this tracks the maximum previously assigned child + * number so we can generate a new unique tree key for + * a new child object. note that this is always incremented, + * so if children are deleted, this will not represent + * the _number_ of children. + */ + max_child_num INTEGER, + + /* + * Automatically maintained meta-data (a gift for metze) + */ + object_guid TEXT UNIQUE, + timestamp INTEGER, -- originating_time + invoke_id TEXT, -- GUID: originating_invocation_id + usn INTEGER, -- hyper: originating_usn + + /* do not allow duplicate name/value pairs */ + UNIQUE (parent_tree_key, attr_name, attr_value, object_type) ); - /* - * We keep a full listing of attribute/value pairs here - */ - CREATE TABLE ldb_attribute_values + CREATE TABLE ldb_attributes ( - eid INTEGER REFERENCES ldb_entry, - - attr_name TEXT, -- see ldb_attr_ATTRIBUTE_NAME + attr_name TEXT PRIMARY KEY, + parent_tree_key TEXT, - attr_value TEXT - ); + objectclass_p BOOLEAN DEFAULT 0, + case_insensitive_p BOOLEAN DEFAULT 0, + wildcard_p BOOLEAN DEFAULT 0, + hidden_p BOOLEAN DEFAULT 0, + integer_p BOOLEAN DEFAULT 0, - /* - * There is one attribute table per searchable attribute. - */ -/* - CREATE TABLE ldb_attr_ATTRIBUTE_NAME - ( - -- The unique identifier of the LDB entry - eid INTEGER REFERENCES ldb_entry, - - -- Normalized attribute value - attr_value TEXT + /* tree_key is auto-generated by the insert trigger */ + tree_key TEXT, -- null if not a object/sub class + -- level 1 if an objectclass + -- level 1-n if a subclass + max_child_num INTEGER ); -*/ - -- ------------------------------------------------------ - -- Indexes + CREATE INDEX ldb_object_dn_idx + ON ldb_object (dn); + + CREATE INDEX ldb_attributes_tree_key_ids + ON ldb_attributes (tree_key); -- ------------------------------------------------------ - -- Triggers - CREATE TRIGGER ldb_entry_insert_tr + /* Gifts for metze. Automatically updated meta-data */ + CREATE TRIGGER ldb_object_insert_tr AFTER INSERT - ON ldb_entry + ON ldb_object FOR EACH ROW BEGIN - UPDATE ldb_entry - SET create_timestamp = strftime('%s', 'now'), - modify_timestamp = strftime('%s', 'now') - WHERE eid = new.eid; + UPDATE ldb_object + SET max_child_num = max_child_num + 1 + WHERE tree_key = new.parent_tree_key; + UPDATE usn SET value = value + 1; + UPDATE ldb_object + SET tree_key = + (SELECT + new.tree_key || + base160(SELECT max_child_num + FROM ldb_object + WHERE tree_key = + new.parent_tree_key)); + max_child_num = 0, + object_guid = random_guid(), + timestamp = strftime('%s', 'now'), + usn = (SELECT value FROM usn); + WHERE tree_key = new.tree_key; END; - CREATE TRIGGER ldb_entry_update_tr + CREATE TRIGGER ldb_object_update_tr AFTER UPDATE - ON ldb_entry + ON ldb_object FOR EACH ROW BEGIN - UPDATE ldb_entry - SET modify_timestamp = strftime('%s', 'now') - WHERE eid = old.eid; + UPDATE usn SET value = value + 1; + UPDATE ldb_object + SET timestamp = strftime('%s', 'now'), + usn = (SELECT value FROM usn); + WHERE tree_key = new.tree_key; END; + CREATE TRIGGER ldb_attributes_insert_tr + AFTER INSERT + ON ldb_attributes + FOR EACH ROW + BEGIN + UPDATE ldb_attributes + SET max_child_num = max_child_num + 1 + WHERE tree_key = new.parent_tree_key; + UPDATE ldb_attributes + SET tree_key = + (SELECT + new.tree_key || + base160(SELECT max_child_num + FROM ldb_attributes + WHERE tree_key = + new.parent_tree_key)); + max_child_num = 0 + WHERE tree_key = new.tree_key; + END; + + -- ------------------------------------------------------ - -- Table initialization - /* We need an implicit 'top' level object class */ + /* Initialize usn */ + INSERT INTO usn (value) VALUES (0); + + /* Create root object */ + INSERT INTO ldb_object + (tree_key, parent_tree_key, + dn, + object_type, max_child_num) + VALUES ('', NULL, + '', + 1, 0); + + /* We need an implicit "top" level object class */ INSERT INTO ldb_attributes (attr_name, parent_tree_key) SELECT 'top', ''; @@ -146,13 +176,58 @@ -- ------------------------------------------------------ -/*** TESTS ***/ - /* * dn: o=University of Michigan,c=US * objectclass: organization * objectclass: domainRelatedObject */ +-- newDN +BEGIN; + +INSERT OR IGNORE INTO ldb_object + (parent_tree_key + dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('', + 'c=US', + 'c', 'US', 1, 0); + +INSERT INTO ldb_object + (parent_tree_key, + dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('0001', + 'o=University of Michigan,c=US', + 'o', 'University of Michigan', 1, 0); + +-- newObjectClass +INSERT OR IGNORE INTO ldb_attributes + (attr_name, parent_tree_key, objectclass_p) + VALUES + ('objectclass', '', 1); + +INSERT INTO ldb_object + (parent_tree_key, + dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', + NULL, + 'objectclass', 'organization', 2, 0); + +INSERT OR IGNORE INTO ldb_attributes + (attr_name, parent_tree_key, objectclass_p) + VALUES + ('objectclass', '', 1); + +INSERT INTO ldb_object + (parent_tree_key, + dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', + NULL, + 'objectclass', 'domainRelatedObject', 2, 0); + +COMMIT; /* @@ -164,6 +239,48 @@ * seeAlso: * telephonenumber: +1 313 764-1817 */ +-- addAttrValuePair +BEGIN; + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'l', 'Ann Arbor, Michigan', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'st', 'Michigan', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'o', 'University of Michigan', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'o', 'UMICH', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'seeAlso', '', 2, 0); + +INSERT INTO ldb_object + (parent_tree_key, dn, + attr_name, attr_value, object_type, max_child_num) + VALUES ('00010001', NULL, + 'telephonenumber', '+1 313 764-1817', 2, 0); + +COMMIT; + +-- ---------------------------------------------------------------------- /* * dn: @ATTRIBUTES @@ -172,6 +289,44 @@ * ou: CASE_INSENSITIVE * dn: CASE_INSENSITIVE */ +-- newAttribute + +BEGIN; + +INSERT OR IGNORE INTO ldb_attributes + (attr_name, parent_tree_key, objectclass_p) + VALUES + ('uid', '', 0); + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 1, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'uid' + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 0, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'cn' + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 0, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'ou' + +UPDATE ldb_attributes + SET case_insensitive_p = 1, + wildcard_p = 0, + hidden_p = 0, + integer_p = 0 + WHERE attr_name = 'dn' + +-- ---------------------------------------------------------------------- /* * dn: @SUBCLASSES @@ -184,3 +339,25 @@ * organizationalPerson: OpenLDAPperson * user: computer */ +-- insertSubclass + +/* NOT YET UPDATED!!! * + + +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'domain', /* next_tree_key('top') */ '00010001'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'person', /* next_tree_key('top') */ '00010002'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'domainDNS', /* next_tree_key('domain') */ '000100010001'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'organizationalPerson', /* next_tree_key('person') */ '000100020001'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'fooPerson', /* next_tree_key('person') */ '000100020002'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'user', /* next_tree_key('organizationalPerson') */ '0001000200010001'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'OpenLDAPperson', /* next_tree_key('organizationPerson') */ '0001000200010002'; +INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) + SELECT 'computer', /* next_tree_key('user') */ '0001000200010001'; + -- cgit From f1a853664ca143466ebd12958c1b1ac7f3c039dd Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Thu, 23 Jun 2005 04:26:23 +0000 Subject: r7844: eliminate superfluous attribute tables (This used to be commit 863beef35b769c5a531819c974754aea2a790921) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 473 ++++++------------------------ 1 file changed, 91 insertions(+), 382 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index ff19ff737a..b21365d3f8 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -200,10 +200,6 @@ new_dn(struct ldb_module * module, char * pDN, long long * pEID); -static int -new_attr(struct ldb_module * module, - char * pAttrName); - static void base160_sql(sqlite3_context * hContext, int argc, @@ -351,7 +347,7 @@ lsqlite3_rename(struct ldb_module * module, return -1; } - /* Determine the eid of the DN being deleted */ + /* Determine the eid of the DN being renamed */ QUERY_INT(lsqlite3, eid, TRUE, @@ -369,9 +365,12 @@ lsqlite3_rename(struct ldb_module * module, QUERY_NOROWS(lsqlite3, TRUE, - "UPDATE ldb_attr_DN " - " SET attr_value = %Q " - " WHERE eid = %lld;", + "UPDATE ldb_attribute_values " + " SET attr_value = %Q, " + " attr_value_normalized = upper(%Q) " + " WHERE eid = %lld " + " AND attr_name = 'DN';", + pNewDN, pNewDN, eid); @@ -389,12 +388,7 @@ static int lsqlite3_delete(struct ldb_module * module, const char * pDN) { - int ret; - int bLoop; long long eid; - char * pSql; - const char * pAttrName; - sqlite3_stmt * pStmt; struct lsqlite3_private * lsqlite3 = module->private_data; /* ignore ltdb specials */ @@ -415,92 +409,11 @@ lsqlite3_delete(struct ldb_module * module, eid, TRUE, "SELECT eid\n" - " FROM ldb_entry\n" - " WHERE dn = %Q;", + " FROM ldb_attribute_values\n" + " WHERE attr_name = 'DN'\n" + " AND attr_value_normalized = upper(%Q);", pDN); - /* Obtain the list of attribute names in use by this DN */ - if ((pSql = talloc_asprintf(module->ldb, - "SELECT upper(attr_name) " - " FROM ldb_attribute_values " - " WHERE eid = %lld;", - eid)) == NULL) { - return -1; - } - - /* - * Prepare and execute the SQL statement. Loop allows retrying on - * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, - * requiring retrying the operation. - */ - for (bLoop = TRUE; bLoop; ) { - /* Compile the SQL statement into sqlite virtual machine */ - if ((ret = sqlite3_prepare(lsqlite3->sqlite, - pSql, - -1, - &pStmt, - NULL)) == SQLITE_SCHEMA) { - continue; - } else if (ret != SQLITE_OK) { - ret = -1; - break; - } - - /* Loop through the returned rows */ - for (ret = SQLITE_ROW; ret == SQLITE_ROW; ) { - - /* Get the next row */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_ROW) { - - /* Get the values from this row */ - pAttrName = sqlite3_column_text(pStmt, 0); - - /* - * Delete any entries from the specified - * attribute table that pertain to this eid. - */ - QUERY_NOROWS(lsqlite3, - TRUE, - "DELETE FROM ldb_attr_%q " - " WHERE eid = %lld;", - pAttrName, eid); - } - } - - if (ret == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_DONE) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* Free the virtual machine */ - if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - ret = 0; - bLoop = FALSE; - } - - /* Delete the DN attribute entry */ - QUERY_NOROWS(lsqlite3, - TRUE, - "DELETE FROM ldb_attr_DN " - " WHERE eid = %lld;", - eid); - /* Delete attribute/value table entries pertaining to this DN */ QUERY_NOROWS(lsqlite3, TRUE, @@ -579,8 +492,9 @@ lsqlite3_search_bytree(struct ldb_module * module, if ((ret = query_int(lsqlite3, &eid, "SELECT eid\n" - " FROM ldb_attr_DN\n" - " WHERE attr_value = %Q;", + " FROM ldb_attribute_values\n" + " WHERE attr_name = 'DN'\n" + " AND attr_value_normalized = upper(%Q);", pBaseDN)) == SQLITE_DONE) { UNLOCK_DB(module, "rollback"); talloc_free(hTalloc); @@ -917,10 +831,13 @@ lsqlite3_search(struct ldb_module * module, return 0; } +#if 0 +/* (|(objectclass=*)(dn=*)) is passed by the command line tool now instead */ /* Handle the special case of requesting all */ if (pExpression != NULL && *pExpression == '\0') { pExpression = "dn=*"; } +#endif /* Parse the filter expression into a tree we can work with */ if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { @@ -1152,40 +1069,11 @@ initialize(struct lsqlite3_private *lsqlite3, "(" " eid INTEGER REFERENCES ldb_entry," " attr_name TEXT," - " attr_value TEXT" - ");" - - /* - * There is one attribute table per searchable attribute. - */ - /* - "CREATE TABLE ldb_attr_ATTRIBUTE_NAME" - "(" - " eid INTEGER REFERENCES ldb_entry," - " attr_value TEXT" + " attr_value TEXT," + " attr_value_normalized TEXT " ");" - */ - - /* - * We pre-create the dn attribute table - */ - "CREATE TABLE ldb_attr_DN" - "(" - " eid INTEGER PRIMARY KEY REFERENCES ldb_entry," - " attr_value TEXT" - ");" - - - /* - * We pre-create the objectclass attribute table - */ - "CREATE TABLE ldb_attr_OBJECTCLASS" - "(" - " eid INTEGER REFERENCES ldb_entry," - " attr_value TEXT" - ");" - + /* * Indexes */ @@ -1195,8 +1083,6 @@ initialize(struct lsqlite3_private *lsqlite3, "CREATE INDEX ldb_attribute_values_eid_idx " " ON ldb_attribute_values (eid);" - "CREATE INDEX ldb_attr_DN_attr_value_idx " - " ON ldb_attr_DN (attr_value);" /* @@ -1269,10 +1155,10 @@ initialize(struct lsqlite3_private *lsqlite3, " (0, NULL, '', '0001');" /* And the root node "dn" attribute */ - "INSERT INTO ldb_attr_DN " - " (eid, attr_value) " + "INSERT INTO ldb_attribute_values " + " (eid, attr_name, attr_value, attr_value_normalized) " " VALUES " - " (0, '');" + " (0, 'DN', '', '');" "INSERT INTO ldb_object_classes " " (class_name, tree_key) " @@ -1387,14 +1273,12 @@ initialize(struct lsqlite3_private *lsqlite3, if (query_int(lsqlite3, &queryInt, "SELECT " - " (SELECT COUNT(*) = 4" + " (SELECT COUNT(*) = 2" " FROM sqlite_master " " WHERE type = 'table' " " AND name IN " " (" " 'ldb_entry', " - " 'ldb_attr_DN', " - " 'ldb_attr_OBJECTCLASS', " " 'ldb_object_classes' " " ) " " ) " @@ -1911,9 +1795,7 @@ parsetree_to_sql(struct ldb_module *module, /* * For simple searches, we want to retrieve the list of EIDs that - * match the criteria. We accomplish this by searching the - * appropriate table, ldb_attr_, for the eid - * corresponding to all matching values. + * match the criteria. */ if (t->u.simple.value.length == 1 && (*(const char *) t->u.simple.value.data) == '*') { @@ -1923,8 +1805,9 @@ parsetree_to_sql(struct ldb_module *module, * table. */ if ((p = sqlite3_mprintf(" SELECT eid\n" - " FROM ldb_attr_%q\n", - pAttrName)) == NULL) { + " FROM ldb_attribute_values\n" + " WHERE attr_name = %Q", + pAttrName)) == NULL) { return NULL; } @@ -1942,8 +1825,9 @@ parsetree_to_sql(struct ldb_module *module, */ if ((p = sqlite3_mprintf( " SELECT eid\n" - " FROM ldb_attr_OBJECTCLASS\n" - " WHERE attr_value IN\n" + " FROM ldb_attribute_values\n" + " WHERE attr_name = 'OBJECTCLASS' " + " AND attr_value_normalized IN\n" " (SELECT class_name\n" " FROM ldb_object_classes\n" " WHERE tree_key GLOB\n" @@ -1965,11 +1849,13 @@ parsetree_to_sql(struct ldb_module *module, } else if (strcasecmp(t->u.simple.attr, "dn") == 0) { pDN = ldb_dn_fold(module->ldb, t->u.simple.value.data, module, case_fold_attr_required); - if ((p = sqlite3_mprintf(" SELECT eid\n" - " FROM ldb_attr_%q\n" - " WHERE attr_value = %Q\n", - pAttrName, - pDN)) == NULL) { + if ((p = sqlite3_mprintf( + " SELECT eid\n" + " FROM ldb_attribute_values\n" + " WHERE attr_name = %Q\n" + " AND attr_value_normalized = upper(%Q)\n", + pAttrName, + pDN)) == NULL) { return NULL; } @@ -1981,11 +1867,13 @@ parsetree_to_sql(struct ldb_module *module, sqlite3_free(p); } else { /* A normal query. */ - if ((p = sqlite3_mprintf(" SELECT eid\n" - " FROM ldb_attr_%q\n" - " WHERE attr_value = %Q\n", - pAttrName, - t->u.simple.value.data)) == NULL) { + if ((p = sqlite3_mprintf( + " SELECT eid\n" + " FROM ldb_attribute_values\n" + " WHERE attr_name = %Q\n" + " AND attr_value_normalized = upper(%Q)\n", + pAttrName, + t->u.simple.value.data)) == NULL) { return NULL; } @@ -2074,115 +1962,6 @@ parsetree_to_attrlist(struct ldb_module *module, } -#ifdef NEED_TABLE_LIST -/* - * Use the already-generated FILTER_ATTR_TABLE to create a list of attribute - * table names that will be used in search queries. - */ -static char * -build_attr_table_list(void * hTalloc, - struct lsqlite3_private * lsqlite3) -{ - int ret; - int bLoop; - char * p; - char * pAttrName; - char * pTableList; - sqlite3_stmt * pStmt; - - /* - * Prepare and execute the SQL statement. Loop allows retrying on - * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, - * requiring retrying the operation. - */ - for (bLoop = TRUE; bLoop; ) { - /* Initialize a string to which we'll append each table name */ - if ((pTableList = talloc_strdup(hTalloc, "")) == NULL) { - return NULL; - } - - /* Compile the SQL statement into sqlite virtual machine */ - if ((ret = sqlite3_prepare(lsqlite3->sqlite, - "SELECT attr_name " - " FROM " FILTER_ATTR_TABLE ";", - -1, - &pStmt, - NULL)) == SQLITE_SCHEMA) { - continue; - } else if (ret != SQLITE_OK) { - ret = -1; - break; - } - - /* Loop through the returned rows */ - for (ret = SQLITE_ROW; ret == SQLITE_ROW; ) { - - /* Get the next row */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_ROW) { - - /* - * Get value from this row and append to table - * list - */ - p = discard_const_p(char, - sqlite3_column_text(pStmt, - 0)); - - pAttrName = - ldb_casefold( - hTalloc, - sqlite3_column_text(pStmt, 0)); - - /* Append it to the table list */ - if ((p = talloc_asprintf( - hTalloc, - "%sldb_attr_%s", - *pTableList == '\0' ? "" : ",", - pAttrName)) == NULL) { - - talloc_free(pTableList); - return NULL; - } - - /* We have a new table list */ - talloc_free(pTableList); - pTableList = p; - } - } - - if (ret == SQLITE_SCHEMA) { - talloc_free(pTableList); - continue; - } - - /* Free the virtual machine */ - if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - ret = 0; - bLoop = FALSE; - } - - if (ret != 0) { - talloc_free(pTableList); - pTableList = NULL; - } - - return pTableList; -} -#endif - - /* * Issue a series of SQL statements to implement the ADD/MODIFY/DELETE * requests in the ldb_message @@ -2212,37 +1991,26 @@ msg_to_sql(struct ldb_module * module, pAttrName = ldb_casefold((struct ldb_context *) module, el->name); - if (flags == LDB_FLAG_MOD_ADD) { - /* Create the attribute table if it doesn't exist */ - if (new_attr(module, pAttrName) != 0) { - return -1; - } - } - /* For each value of the specified attribute name... */ for (j = 0; j < el->num_values; j++) { /* ... bind the attribute value, if necessary */ switch (flags) { case LDB_FLAG_MOD_ADD: - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT INTO ldb_attr_%q\n" - " (eid, attr_value)\n" - " VALUES\n" - " (%lld, %Q);", - pAttrName, - eid, el->values[j].data); - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT INTO ldb_attribute_values" - " (eid, attr_name, attr_value)" - " VALUES " - " (%lld, %Q, %Q);", - eid, - el->name, - el->values[j].data); - + QUERY_NOROWS( + lsqlite3, + FALSE, + "INSERT INTO ldb_attribute_values\n" + " (eid,\n" + " attr_name,\n" + " attr_value,\n" + " attr_value_normalized)\n" + " VALUES\n" + " (%lld, %Q, %Q, upper(%Q));", + eid, + pAttrName, + el->values[j].data, /* FIX ME */ + el->values[j].data); /* Is this a special "objectclass"? */ if (strcasecmp(pAttrName, @@ -2265,44 +2033,34 @@ msg_to_sql(struct ldb_module * module, break; case LDB_FLAG_MOD_REPLACE: - QUERY_NOROWS(lsqlite3, - FALSE, - "UPDATE ldb_attr_%q\n" - " SET attr_value = %Q\n" - " WHERE eid = %lld;", - pAttrName, - el->values[j].data, - eid); - QUERY_NOROWS(lsqlite3, - FALSE, - "UPDATE ldb_attribute_values " - " SET attr_value = %Q " - " WHERE eid = %lld " - " AND attr_name = %Q;", - el->values[j].data, - eid, - el->name); + QUERY_NOROWS( + lsqlite3, + FALSE, + "UPDATE ldb_attribute_values\n" + " SET attr_value = %Q,\n" + " attr_value_normalized =\n" + " upper(%Q)\n" + " WHERE eid = %lld\n" + " AND attr_name = %Q;", + el->values[j].data, /* FIX ME */ + el->values[j].data, + eid, + pAttrName); break; case LDB_FLAG_MOD_DELETE: /* No additional parameters to this query */ - QUERY_NOROWS(lsqlite3, - FALSE, - "DELETE FROM ldb_attr_%q\n" - " WHERE eid = %lld\n" - " AND attr_value = %Q;", - pAttrName, - eid, - el->values[j].data); - QUERY_NOROWS(lsqlite3, - FALSE, - "DELETE FROM ldb_attribute_values" - " WHERE eid = %lld " - " AND attr_name = %Q " - " AND attr_value = %Q;", - eid, - el->name, - el->values[j].data); + QUERY_NOROWS( + lsqlite3, + FALSE, + "DELETE FROM ldb_attribute_values" + " WHERE eid = %lld " + " AND attr_name = %Q " + " AND attr_value_normalized =\n" + " upper(%Q);", + eid, + el->name, + el->values[j].data); break; } } @@ -2456,12 +2214,17 @@ new_dn(struct ldb_module * module, /* Also add DN attribute */ QUERY_NOROWS(lsqlite3, FALSE, - "INSERT %s INTO ldb_attr_DN\n" - " (eid, attr_value) " + "INSERT %s INTO ldb_attribute_values\n" + " (eid,\n" + " attr_name,\n" + " attr_value,\n" + " attr_value_normalized) " " VALUES " - " (%lld, %Q);", + " (%lld, 'DN', %Q, upper(%Q));", nComponent == 0 ? "" : "OR IGNORE", - eid, pPartialDN); + eid, + pPartialDN, /* FIX ME */ + pPartialDN); } if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { @@ -2479,60 +2242,6 @@ new_dn(struct ldb_module * module, } -static int -new_attr(struct ldb_module * module, - char * pAttrName) -{ - long long bExists; - struct lsqlite3_private * lsqlite3 = module->private_data; - - /* - * NOTE: - * pAttrName is assumed to already be case-folded here! - */ - - /* See if the table already exists */ - QUERY_INT(lsqlite3, - bExists, - FALSE, - "SELECT COUNT(*) <> 0\n" - " FROM sqlite_master\n" - " WHERE type = 'table'\n" - " AND tbl_name = 'ldb_attr_%q';", - pAttrName); - - /* Did it exist? */ - if (! bExists) { - /* Nope. Create the table */ - QUERY_NOROWS(lsqlite3, - FALSE, - "CREATE TABLE ldb_attr_%q\n" - "(\n" - " eid INTEGER REFERENCES ldb_entry,\n" - " attr_value TEXT\n" - ");", - pAttrName); - - QUERY_NOROWS(lsqlite3, - FALSE, - "CREATE INDEX ldb_attr_%q_eid_idx\n" - " ON ldb_attr_%q (eid);", - pAttrName, - pAttrName); - - QUERY_NOROWS(lsqlite3, - FALSE, - "CREATE INDEX ldb_attr_%q_attr_value_idx " - " ON ldb_attr_%q (attr_value);", - pAttrName, - pAttrName); - - } - - return 0; -} - - static unsigned char base160tab[161] = { 48 ,49 ,50 ,51 ,52 ,53 ,54 ,55 ,56 ,57 , /* 0-9 */ 58 ,59 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 , /* : ; A-H */ -- cgit From ce2e35309e26d7fc23ba54f1caeb8aeeefa7ccc2 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 23 Jun 2005 23:19:31 +0000 Subject: r7851: We are case preserving let the DN be returned the same the user put it into. sss (This used to be commit 5b41e3202456549250e6e5b1c63bd45ea7500fa3) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 138 +++++++++++++++--------------- 1 file changed, 70 insertions(+), 68 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index b21365d3f8..019c0eebf1 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -164,6 +164,9 @@ query_int(const struct lsqlite3_private * lsqlite3, static int case_fold_attr_required(void * hUserData, char *attr); +static int case_fold_attr_not_required(void * hUserData, + char *attr); + static int add_msg_attr(void * hTalloc, long long eid, @@ -183,12 +186,6 @@ static int parsetree_to_attrlist(struct ldb_module *module, const struct ldb_parse_tree * t); -#ifdef NEED_TABLE_LIST -static char * -build_attr_table_list(void * hTalloc, - struct lsqlite3_private * lsqlite3); -#endif - static int msg_to_sql(struct ldb_module * module, const struct ldb_message * msg, @@ -328,6 +325,8 @@ lsqlite3_rename(struct ldb_module * module, const char * pOldDN, const char * pNewDN) { + const char *pOldNormalizedDN; + const char *pNewNormalizedDN; long long eid; struct lsqlite3_private * lsqlite3 = module->private_data; @@ -337,9 +336,9 @@ lsqlite3_rename(struct ldb_module * module, } /* Case-fold each of the DNs */ - pOldDN = ldb_dn_fold(module->ldb, pOldDN, + pOldNormalizedDN = ldb_dn_fold(module->ldb, pOldDN, module, case_fold_attr_required); - pNewDN = ldb_dn_fold(module->ldb, pNewDN, + pNewNormalizedDN = ldb_dn_fold(module->ldb, pNewDN, module, case_fold_attr_required); /* Begin a transaction */ @@ -353,25 +352,26 @@ lsqlite3_rename(struct ldb_module * module, TRUE, "SELECT eid\n" " FROM ldb_entry\n" - " WHERE dn = %Q;", - pOldDN); + " WHERE normalized_dn = %Q;", + pOldNormalizedDN); QUERY_NOROWS(lsqlite3, TRUE, "UPDATE ldb_entry " - " SET dn = %Q " + " SET dn = %Q, " + " normalized_dn = %Q " " WHERE eid = %lld;", - pNewDN, eid); + pNewDN, pNewNormalizedDN, eid); QUERY_NOROWS(lsqlite3, TRUE, "UPDATE ldb_attribute_values " " SET attr_value = %Q, " - " attr_value_normalized = upper(%Q) " + " attr_value_normalized = %Q " " WHERE eid = %lld " " AND attr_name = 'DN';", pNewDN, - pNewDN, + pNewNormalizedDN, eid); /* Commit the transaction */ @@ -388,6 +388,7 @@ static int lsqlite3_delete(struct ldb_module * module, const char * pDN) { + char *pNormalizedDN; long long eid; struct lsqlite3_private * lsqlite3 = module->private_data; @@ -402,7 +403,7 @@ lsqlite3_delete(struct ldb_module * module, } /* Case-fold the DNs */ - pDN = ldb_dn_fold(module->ldb, pDN, module, case_fold_attr_required); + pNormalizedDN = ldb_dn_fold(module->ldb, pDN, module, case_fold_attr_required); /* Determine the eid of the DN being deleted */ QUERY_INT(lsqlite3, @@ -411,8 +412,8 @@ lsqlite3_delete(struct ldb_module * module, "SELECT eid\n" " FROM ldb_attribute_values\n" " WHERE attr_name = 'DN'\n" - " AND attr_value_normalized = upper(%Q);", - pDN); + " AND attr_value_normalized = %Q;", + pNormalizedDN); /* Delete attribute/value table entries pertaining to this DN */ QUERY_NOROWS(lsqlite3, @@ -453,11 +454,9 @@ lsqlite3_search_bytree(struct ldb_module * module, long long prevEID; char * pSql = NULL; char * pSqlConstraints; -#ifdef NEED_TABLE_LIST - char * pTableList; -#endif char * hTalloc = NULL; const char * pDN; + const char * pNormalizedBaseDN; const char * pAttrName; const char * pAttrValue; const char * pResultAttrList; @@ -465,17 +464,13 @@ lsqlite3_search_bytree(struct ldb_module * module, sqlite3_stmt * pStmt; struct lsqlite3_private * lsqlite3 = module->private_data; - if (pBaseDN == NULL) { - pBaseDN = ""; - } - /* Allocate a temporary talloc context */ if ((hTalloc = talloc_new(module->ldb)) == NULL) { return -1; } /* Case-fold the base DN */ - if ((pBaseDN = ldb_dn_fold(hTalloc, pBaseDN, + if ((pNormalizedBaseDN = ldb_dn_fold(hTalloc, pBaseDN?pBaseDN:"", module, case_fold_attr_required)) == NULL) { talloc_free(hTalloc); return -1; @@ -492,10 +487,9 @@ lsqlite3_search_bytree(struct ldb_module * module, if ((ret = query_int(lsqlite3, &eid, "SELECT eid\n" - " FROM ldb_attribute_values\n" - " WHERE attr_name = 'DN'\n" - " AND attr_value_normalized = upper(%Q);", - pBaseDN)) == SQLITE_DONE) { + " FROM ldb_entry\n" + " WHERE normalized_dn = %Q;", + pNormalizedBaseDN)) == SQLITE_DONE) { UNLOCK_DB(module, "rollback"); talloc_free(hTalloc); return 0; @@ -564,16 +558,6 @@ lsqlite3_search_bytree(struct ldb_module * module, goto cleanup; } -#ifdef NEED_TABLE_LIST - /* - * Build the attribute table list from the list of unique names. - */ - if ((pTableList = build_attr_table_list(hTalloc, lsqlite3)) == NULL) { - ret = -1; - goto cleanup; - } -#endif - switch(scope) { case LDB_SCOPE_DEFAULT: case LDB_SCOPE_SUBTREE: @@ -913,7 +897,7 @@ static int lsqlite3_modify(struct ldb_module * module, const struct ldb_message * msg) { - char * pDN; + char * pNormalizedDN; long long eid; struct lsqlite3_private * lsqlite3 = module->private_data; @@ -928,7 +912,7 @@ lsqlite3_modify(struct ldb_module * module, } /* Case-fold the DN so we can compare it to what's in the database */ - pDN = ldb_dn_fold(module->ldb, msg->dn, + pNormalizedDN = ldb_dn_fold(module->ldb, msg->dn, module, case_fold_attr_required); /* Determine the eid of the DN being deleted */ @@ -937,8 +921,8 @@ lsqlite3_modify(struct ldb_module * module, TRUE, "SELECT eid\n" " FROM ldb_entry\n" - " WHERE dn = %Q;", - pDN); + " WHERE normalized_dn = %Q;", + pNormalizedDN); /* Apply the message attributes */ if (msg_to_sql(module, msg, eid, TRUE) != 0) { @@ -1047,6 +1031,7 @@ initialize(struct lsqlite3_private *lsqlite3, " eid INTEGER PRIMARY KEY," " peid INTEGER REFERENCES ldb_entry," " dn TEXT UNIQUE NOT NULL," + " normalized_dn TEXT UNIQUE NOT NULL," " tree_key TEXT UNIQUE," " max_child_num INTEGER DEFAULT 0," " create_timestamp INTEGER," @@ -1150,9 +1135,9 @@ initialize(struct lsqlite3_private *lsqlite3, /* The root node */ "INSERT INTO ldb_entry " - " (eid, peid, dn, tree_key) " + " (eid, peid, dn, normalized_dn, tree_key) " " VALUES " - " (0, NULL, '', '0001');" + " (0, NULL, '', '', '0001');" /* And the root node "dn" attribute */ "INSERT INTO ldb_attribute_values " @@ -1371,8 +1356,10 @@ query_norows(const struct lsqlite3_private *lsqlite3, struct timeval tv; struct timezone tz; - gettimeofday(&tv, &tz); - t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { + gettimeofday(&tv, &tz); + t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + } /* Begin access to variable argument list */ va_start(args, pSql); @@ -1432,10 +1419,9 @@ query_norows(const struct lsqlite3_private *lsqlite3, /* All done with variable argument list */ va_end(args); - gettimeofday(&tv, NULL); - t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { + gettimeofday(&tv, NULL); + t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); printf("%1.6lf %s\n%s\n\n", t1 - t0, ret == 0 ? "SUCCESS" : "FAIL", p); @@ -1473,8 +1459,10 @@ query_int(const struct lsqlite3_private * lsqlite3, struct timeval tv; struct timezone tz; - gettimeofday(&tv, &tz); - t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { + gettimeofday(&tv, &tz); + t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + } /* Begin access to variable argument list */ va_start(args, pSql); @@ -1537,10 +1525,10 @@ query_int(const struct lsqlite3_private * lsqlite3, /* All done with variable argument list */ va_end(args); - gettimeofday(&tv, NULL); - t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { + gettimeofday(&tv, NULL); + t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); printf("%1.6lf %s\n%s\n\n", t1 - t0, ret == 0 ? "SUCCESS" : "FAIL", p); @@ -1563,10 +1551,18 @@ case_fold_attr_required(void * hUserData, { // struct ldb_module * module = hUserData; -#warning "currently, all attributes require case folding" return TRUE; } +static int +case_fold_attr_not_required(void * hUserData, + char *attr) +{ +// struct ldb_module * module = hUserData; + + return FALSE; +} + /* * add a single set of ldap message values to a ldb_message @@ -1702,7 +1698,7 @@ parsetree_to_sql(struct ldb_module *module, const struct ldb_parse_tree *t) { int i; - char * pDN; + char * pNormalizedDN; char * child; char * p; char * ret = NULL; @@ -1847,15 +1843,15 @@ parsetree_to_sql(struct ldb_module *module, sqlite3_free(p); } else if (strcasecmp(t->u.simple.attr, "dn") == 0) { - pDN = ldb_dn_fold(module->ldb, t->u.simple.value.data, + pNormalizedDN = ldb_dn_fold(module->ldb, t->u.simple.value.data, module, case_fold_attr_required); if ((p = sqlite3_mprintf( " SELECT eid\n" " FROM ldb_attribute_values\n" " WHERE attr_name = %Q\n" - " AND attr_value_normalized = upper(%Q)\n", + " AND attr_value_normalized = %Q\n", pAttrName, - pDN)) == NULL) { + pNormalizedDN)) == NULL) { return NULL; } @@ -2080,6 +2076,7 @@ new_dn(struct ldb_module * module, int bFirst; char * p; char * pPartialDN; + char * pPartialNormalizedDN; long long eid; long long peid; double t0 = 0; @@ -2096,12 +2093,12 @@ new_dn(struct ldb_module * module, t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); } - /* Explode and normalize the DN */ + /* Explode the DN */ if ((pExplodedDN = ldb_explode_dn(ldb, pDN, ldb, - case_fold_attr_required)) == NULL) { + case_fold_attr_not_required)) == NULL) { return -1; } @@ -2117,6 +2114,10 @@ new_dn(struct ldb_module * module, return -1; } + if ((pPartialNormalizedDN = talloc_strdup(pPartialDN, "")) == NULL) { + return -1; + } + /* For each component of the DN (starting with the last one)... */ #warning "convert this loop to recursive, and search backwards instead" eid = 0; @@ -2158,6 +2159,7 @@ new_dn(struct ldb_module * module, /* Save the new partial DN */ pPartialDN = p; + pPartialNormalizedDN = ldb_dn_fold(pPartialDN, p, module, case_fold_attr_required); if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { gettimeofday(&tv, NULL); @@ -2177,11 +2179,11 @@ new_dn(struct ldb_module * module, QUERY_NOROWS(lsqlite3, FALSE, "INSERT %s INTO ldb_entry\n" - " (peid, dn)\n" + " (peid, dn, normalized_dn)\n" " VALUES\n" - " (%lld, %Q);", + " (%lld, %Q, %Q);", nComponent == 0 ? "" : "OR IGNORE", - eid, pPartialDN); + eid, pPartialDN, pPartialNormalizedDN); /* Save the parent EID */ peid = eid; @@ -2200,8 +2202,8 @@ new_dn(struct ldb_module * module, FALSE, "SELECT eid " " FROM ldb_entry " - " WHERE dn = %Q;", - pPartialDN); + " WHERE normalized_dn = %Q;", + pPartialNormalizedDN); if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { gettimeofday(&tv, NULL); @@ -2220,11 +2222,11 @@ new_dn(struct ldb_module * module, " attr_value,\n" " attr_value_normalized) " " VALUES " - " (%lld, 'DN', %Q, upper(%Q));", + " (%lld, 'DN', %Q, %Q);", nComponent == 0 ? "" : "OR IGNORE", eid, pPartialDN, /* FIX ME */ - pPartialDN); + pPartialNormalizedDN); } if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { -- cgit From 1603fd94666d3175e9df12652f9ff4e1d14de064 Mon Sep 17 00:00:00 2001 From: Derrell Lipman Date: Sat, 25 Jun 2005 03:43:33 +0000 Subject: r7897: work in progress (This used to be commit 8e1431efcf0df797bc50ef584c38fce6a03429b3) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 312 +++++++++++++++++++++--------- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 8 - 2 files changed, 219 insertions(+), 101 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 019c0eebf1..76ef703ca5 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -84,6 +84,16 @@ } \ } while (0) +#define GET_EID(lsqlite3, result_var, bRollbackOnError, pDN) \ + do { \ + if (getEID(lsqlite3, &result_var, pDN) != 0) { \ + if (bRollbackOnError) { \ + UNLOCK_DB(module, "rollback"); \ + } \ + return -1; \ + } \ + } while (0) + #define SQLITE3_DEBUG_QUERY (1 << 0) #define SQLITE3_DEBUG_INIT (1 << 1) @@ -95,6 +105,7 @@ * Static variables */ static int lsqlite3_debug = FALSE; +sqlite3_stmt * stmtGetEID = NULL; /* * Forward declarations @@ -161,6 +172,11 @@ query_int(const struct lsqlite3_private * lsqlite3, const char * pSql, ...); +static int +getEID(const struct lsqlite3_private * lsqlite3, + long long * pRet, + const char * pNormalizedDN); + static int case_fold_attr_required(void * hUserData, char *attr); @@ -336,10 +352,10 @@ lsqlite3_rename(struct ldb_module * module, } /* Case-fold each of the DNs */ - pOldNormalizedDN = ldb_dn_fold(module->ldb, pOldDN, - module, case_fold_attr_required); - pNewNormalizedDN = ldb_dn_fold(module->ldb, pNewDN, - module, case_fold_attr_required); + pOldNormalizedDN = + ldb_dn_fold(module->ldb, pOldDN, module, case_fold_attr_required); + pNewNormalizedDN = + ldb_dn_fold(module->ldb, pNewDN, module, case_fold_attr_required); /* Begin a transaction */ if (LOCK_DB(module, "transaction") < 0) { @@ -347,13 +363,7 @@ lsqlite3_rename(struct ldb_module * module, } /* Determine the eid of the DN being renamed */ - QUERY_INT(lsqlite3, - eid, - TRUE, - "SELECT eid\n" - " FROM ldb_entry\n" - " WHERE normalized_dn = %Q;", - pOldNormalizedDN); + GET_EID(lsqlite3, eid, TRUE, pOldNormalizedDN); QUERY_NOROWS(lsqlite3, TRUE, @@ -403,17 +413,11 @@ lsqlite3_delete(struct ldb_module * module, } /* Case-fold the DNs */ - pNormalizedDN = ldb_dn_fold(module->ldb, pDN, module, case_fold_attr_required); + pNormalizedDN = + ldb_dn_fold(module->ldb, pDN, module, case_fold_attr_required); /* Determine the eid of the DN being deleted */ - QUERY_INT(lsqlite3, - eid, - TRUE, - "SELECT eid\n" - " FROM ldb_attribute_values\n" - " WHERE attr_name = 'DN'\n" - " AND attr_value_normalized = %Q;", - pNormalizedDN); + GET_EID(lsqlite3, eid, TRUE, pNormalizedDN); /* Delete attribute/value table entries pertaining to this DN */ QUERY_NOROWS(lsqlite3, @@ -470,26 +474,26 @@ lsqlite3_search_bytree(struct ldb_module * module, } /* Case-fold the base DN */ - if ((pNormalizedBaseDN = ldb_dn_fold(hTalloc, pBaseDN?pBaseDN:"", - module, case_fold_attr_required)) == NULL) { + if ((pNormalizedBaseDN = + ldb_dn_fold(hTalloc, + pBaseDN == NULL ? "" : pBaseDN, + module, + case_fold_attr_required)) == NULL) { + talloc_free(hTalloc); return -1; } /* Begin a transaction */ if (LOCK_DB(module, "transaction") < 0) { + talloc_free(hTalloc); return -1; } /* * Obtain the eid of the base DN */ - if ((ret = query_int(lsqlite3, - &eid, - "SELECT eid\n" - " FROM ldb_entry\n" - " WHERE normalized_dn = %Q;", - pNormalizedBaseDN)) == SQLITE_DONE) { + if ((ret = getEID(lsqlite3, &eid, pNormalizedBaseDN)) == SQLITE_DONE) { UNLOCK_DB(module, "rollback"); talloc_free(hTalloc); return 0; @@ -685,9 +689,15 @@ lsqlite3_search_bytree(struct ldb_module * module, -1, &pStmt, NULL)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + if (pppRes != NULL && *pppRes != NULL) { talloc_free(*pppRes); } + continue; } else if (ret != SQLITE_OK) { ret = -1; @@ -730,6 +740,11 @@ lsqlite3_search_bytree(struct ldb_module * module, } if (ret == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + (void) sqlite3_finalize(pStmt); if (pppRes != NULL && *pppRes != NULL) { talloc_free(*pppRes); @@ -743,7 +758,11 @@ lsqlite3_search_bytree(struct ldb_module * module, /* Free the virtual machine */ if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + if (pppRes != NULL && *pppRes != NULL) { talloc_free(*pppRes); } @@ -916,13 +935,7 @@ lsqlite3_modify(struct ldb_module * module, module, case_fold_attr_required); /* Determine the eid of the DN being deleted */ - QUERY_INT(lsqlite3, - eid, - TRUE, - "SELECT eid\n" - " FROM ldb_entry\n" - " WHERE normalized_dn = %Q;", - pNormalizedDN); + GET_EID(lsqlite3, eid, TRUE, pNormalizedDN); /* Apply the message attributes */ if (msg_to_sql(module, msg, eid, TRUE) != 0) { @@ -1068,6 +1081,9 @@ initialize(struct lsqlite3_private *lsqlite3, "CREATE INDEX ldb_attribute_values_eid_idx " " ON ldb_attribute_values (eid);" + "CREATE INDEX ldb_attribute_values_name_value_idx " + " ON ldb_attribute_values (attr_name, attr_value_normalized);" + /* @@ -1351,7 +1367,7 @@ query_norows(const struct lsqlite3_private *lsqlite3, char * p; sqlite3_stmt * pStmt; va_list args; - double t0; + double t0 = 0; double t1; struct timeval tv; struct timezone tz; @@ -1382,6 +1398,10 @@ query_norows(const struct lsqlite3_private *lsqlite3, -1, &pStmt, NULL)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } continue; } else if (ret != SQLITE_OK) { ret = -1; @@ -1390,6 +1410,10 @@ query_norows(const struct lsqlite3_private *lsqlite3, /* No rows expected, so just step through machine code once */ if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } (void) sqlite3_finalize(pStmt); continue; } else if (ret != SQLITE_DONE) { @@ -1400,7 +1424,10 @@ query_norows(const struct lsqlite3_private *lsqlite3, /* Free the virtual machine */ if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } continue; } else if (ret != SQLITE_OK) { (void) sqlite3_finalize(pStmt); @@ -1454,7 +1481,7 @@ query_int(const struct lsqlite3_private * lsqlite3, char * p; sqlite3_stmt * pStmt; va_list args; - double t0; + double t0 = 0; double t1; struct timeval tv; struct timezone tz; @@ -1489,6 +1516,10 @@ query_int(const struct lsqlite3_private * lsqlite3, -1, &pStmt, NULL)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } continue; } else if (ret != SQLITE_OK) { break; @@ -1496,6 +1527,10 @@ query_int(const struct lsqlite3_private * lsqlite3, /* One row expected */ if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } (void) sqlite3_finalize(pStmt); continue; } else if (ret != SQLITE_ROW) { @@ -1508,7 +1543,10 @@ query_int(const struct lsqlite3_private * lsqlite3, /* Free the virtual machine */ if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(pStmt); + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } continue; } else if (ret != SQLITE_OK) { (void) sqlite3_finalize(pStmt); @@ -1541,6 +1579,92 @@ query_int(const struct lsqlite3_private * lsqlite3, } +/* + * getEID() + * + * This function is used for the very common case of retrieving an EID value + * given a normalized DN. + * + * NOTE: If more than one value is returned by the query, all but the first + * one will be ignored. + */ +static int +getEID(const struct lsqlite3_private * lsqlite3, + long long * pRet, + const char * pNormalizedDN) +{ + int ret; + int bLoop; + const char * query = + "SELECT eid\n" + " FROM ldb_attribute_values\n" + " WHERE attr_name = 'DN'\n" + " AND attr_value_normalized = :dn;"; + + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { + + /* Compile the SQL statement into sqlite virtual machine */ + ret = SQLITE_OK; + if (stmtGetEID == NULL && + (ret = sqlite3_prepare(lsqlite3->sqlite, + query, + -1, + &stmtGetEID, + NULL)) == SQLITE_SCHEMA) { + continue; + } else if (ret != SQLITE_OK) { + break; + } + + /* Bind our parameter */ + if ((ret = sqlite3_bind_text(stmtGetEID, + 1, + pNormalizedDN, + -1, + SQLITE_STATIC)) != SQLITE_OK) { + break; + } + + /* One row expected */ + if ((ret = sqlite3_step(stmtGetEID)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + continue; + } else if (ret != SQLITE_ROW) { + (void) sqlite3_reset(stmtGetEID); + break; + } + + /* Get the value to be returned */ + *pRet = sqlite3_column_int64(stmtGetEID, 0); + + /* Free the virtual machine */ + if ((ret = sqlite3_reset(stmtGetEID)) == SQLITE_SCHEMA) { + (void) sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + break; + } + + /* + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. + */ + bLoop = FALSE; + } + + return ret; +} + + /* callback function used in call to ldb_dn_fold() for determining whether an attribute type requires case folding. @@ -2072,8 +2196,9 @@ new_dn(struct ldb_module * module, char * pDN, long long * pEID) { - int nComponent; + int ret; int bFirst; + int nComponent; char * p; char * pPartialDN; char * pPartialNormalizedDN; @@ -2159,7 +2284,10 @@ new_dn(struct ldb_module * module, /* Save the new partial DN */ pPartialDN = p; - pPartialNormalizedDN = ldb_dn_fold(pPartialDN, p, module, case_fold_attr_required); + pPartialNormalizedDN = ldb_dn_fold(pPartialDN, + p, + module, + case_fold_attr_required); if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { gettimeofday(&tv, NULL); @@ -2171,62 +2299,60 @@ new_dn(struct ldb_module * module, /* * Ensure that an entry is in the ldb_entry table for this - * component. Any component other than the last one - * (component 0) may already exist. It is an error if - * component 0 (the full DN requested to be be inserted) - * already exists. + * component. */ - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT %s INTO ldb_entry\n" - " (peid, dn, normalized_dn)\n" - " VALUES\n" - " (%lld, %Q, %Q);", - nComponent == 0 ? "" : "OR IGNORE", - eid, pPartialDN, pPartialNormalizedDN); - - /* Save the parent EID */ - peid = eid; + if ((ret = getEID(lsqlite3, + &eid, + pPartialNormalizedDN)) == SQLITE_DONE) { + + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT INTO ldb_entry\n" + " (peid, dn, normalized_dn)\n" + " VALUES\n" + " (%lld, %Q, %Q);", + eid, pPartialDN, pPartialNormalizedDN); + + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, NULL); + t1 = ((double) tv.tv_sec + + ((double) tv.tv_usec / 1000000.0)); + printf("%1.6lf loc 5\n", t1 - t0); + t0 = t1; + } - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, NULL); - t1 = ((double) tv.tv_sec + - ((double) tv.tv_usec / 1000000.0)); - printf("%1.6lf loc 5\n", t1 - t0); - t0 = t1; - } + /* Get the EID of the just inserted row */ + eid = sqlite3_last_insert_rowid(lsqlite3->sqlite); + + if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { + gettimeofday(&tv, NULL); + t1 = ((double) tv.tv_sec + + ((double) tv.tv_usec / 1000000.0)); + printf("%1.6lf loc 8\n", t1 - t0); + t0 = t1; + } - /* Get the EID of the just inserted row */ - QUERY_INT(lsqlite3, - eid, - FALSE, - "SELECT eid " - " FROM ldb_entry " - " WHERE normalized_dn = %Q;", - pPartialNormalizedDN); + /* Also add DN attribute */ + QUERY_NOROWS(lsqlite3, + FALSE, + "INSERT INTO ldb_attribute_values\n" + " (eid,\n" + " attr_name,\n" + " attr_value,\n" + " attr_value_normalized) " + " VALUES " + " (%lld, 'DN', %Q, %Q);", + eid, + pPartialDN, /* FIX ME */ + pPartialNormalizedDN); - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, NULL); - t1 = ((double) tv.tv_sec + - ((double) tv.tv_usec / 1000000.0)); - printf("%1.6lf loc 8\n", t1 - t0); - t0 = t1; + } else if (ret != SQLITE_OK) { + UNLOCK_DB(module, "rollback"); + return -1; } - - /* Also add DN attribute */ - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT %s INTO ldb_attribute_values\n" - " (eid,\n" - " attr_name,\n" - " attr_value,\n" - " attr_value_normalized) " - " VALUES " - " (%lld, 'DN', %Q, %Q);", - nComponent == 0 ? "" : "OR IGNORE", - eid, - pPartialDN, /* FIX ME */ - pPartialNormalizedDN); + + /* Save the parent EID */ + peid = eid; } if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h index 3d3c63397b..46ee1e93ba 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h @@ -2,14 +2,6 @@ struct lsqlite3_private { char ** options; - const char * basedn; sqlite3 * sqlite; int lock_count; }; - -void -lsqlite3_base160(unsigned long val, - unsigned char result[5]); - -char * -lsqlite3_base160Next(char base160[]); -- cgit From 38b04883fe07fe92ef52aaff51eb7f1ea041008a Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 14 Sep 2005 22:45:49 +0000 Subject: r10232: Some work on ldb_sqlite3. It is still far from being usable in samba4 but I want to commit so that the work does not get lost by mistake. This is also a good way to get comments if somebody is interested. Sorry Derrell I ended up rewriting large parts of the code but I find this style much more readable. Thanks for the hard work done. Your work was a good reference for me. ah the current code also shows some good numbers sqlite3 generic test: uid search took 0.05 seconds real 0m12.492s user 0m0.492s sys 0m0.345s with tdb we still get better numbers: uid search took 0.46 seconds real 0m0.892s user 0m0.360s sys 0m0.468s but most of the time is spent in adding operations and I think there's still a lot of space for improvement. Simo. (This used to be commit ace9990060c10d0931f418934b2121aea9512ff7) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 3787 ++++++++++++----------------- 1 file changed, 1563 insertions(+), 2224 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 76ef703ca5..e283e6b0c1 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -36,7 +36,6 @@ #include "includes.h" #include "ldb/include/ldb.h" #include "ldb/include/ldb_private.h" -#include "ldb/include/ldb_explode_dn.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" /* @@ -48,644 +47,436 @@ # define TRUE (! FALSE) #endif -#define FILTER_ATTR_TABLE "temp_filter_attrs" #define RESULT_ATTR_TABLE "temp_result_attrs" //#define TEMPTAB /* for testing, create non-temporary table */ #define TEMPTAB "TEMPORARY" -//#define DEBUG_LOCKS +/* + * Static variables + */ +sqlite3_stmt * stmtGetEID = NULL; -#ifndef DEBUG_LOCKS -# define LOCK_DB(mod, name) lsqlite3_lock(mod, name) -# define UNLOCK_DB(mod, name) lsqlite3_unlock(mod, name) -#else -# define LOCK_DB(mod, name) lock_debug(mod, name, __FILE__, __LINE__) -# define UNLOCK_DB(mod, name) unlock_debug(mod, name, __FILE__, __LINE__) -#endif +static char *lsqlite3_tprintf(TALLOC_CTX *mem_ctx, const char *fmt, ...) +{ + char *str, *ret; + va_list ap; + + va_start(ap, fmt); + str = sqlite3_vmprintf(fmt, ap); + va_end(ap); + + if (str == NULL) return NULL; + + ret = talloc_strdup(mem_ctx, str); + if (ret == NULL) { + sqlite3_free(str); + return NULL; + } + + sqlite3_free(str); + return ret; +} + +static unsigned char base160tab[161] = { + 48 ,49 ,50 ,51 ,52 ,53 ,54 ,55 ,56 ,57 , /* 0-9 */ + 58 ,59 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 , /* : ; A-H */ + 73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 , /* I-R */ + 83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 ,97 ,98 , /* S-Z , a-b */ + 99 ,100,101,102,103,104,105,106,107,108, /* c-l */ + 109,110,111,112,113,114,115,116,117,118, /* m-v */ + 119,120,121,122,160,161,162,163,164,165, /* w-z, latin1 */ + 166,167,168,169,170,171,172,173,174,175, /* latin1 */ + 176,177,178,179,180,181,182,183,184,185, /* latin1 */ + 186,187,188,189,190,191,192,193,194,195, /* latin1 */ + 196,197,198,199,200,201,202,203,204,205, /* latin1 */ + 206,207,208,209,210,211,212,213,214,215, /* latin1 */ + 216,217,218,219,220,221,222,223,224,225, /* latin1 */ + 226,227,228,229,230,231,232,233,234,235, /* latin1 */ + 236,237,238,239,240,241,242,243,244,245, /* latin1 */ + 246,247,248,249,250,251,252,253,254,255, /* latin1 */ + '\0' +}; -#define QUERY_NOROWS(lsqlite3, bRollbackOnError, sql...) \ - do { \ - if (query_norows(lsqlite3, sql) != 0) { \ - if (bRollbackOnError) { \ - UNLOCK_DB(module, "rollback"); \ - } \ - return -1; \ - } \ - } while (0) - -#define QUERY_INT(lsqlite3, result_var, bRollbackOnError, sql...) \ - do { \ - if (query_int(lsqlite3, &result_var, sql) != 0) { \ - if (bRollbackOnError) { \ - UNLOCK_DB(module, "rollback"); \ - } \ - return -1; \ - } \ - } while (0) - -#define GET_EID(lsqlite3, result_var, bRollbackOnError, pDN) \ - do { \ - if (getEID(lsqlite3, &result_var, pDN) != 0) { \ - if (bRollbackOnError) { \ - UNLOCK_DB(module, "rollback"); \ - } \ - return -1; \ - } \ - } while (0) - - -#define SQLITE3_DEBUG_QUERY (1 << 0) -#define SQLITE3_DEBUG_INIT (1 << 1) -#define SQLITE3_DEBUG_ADD (1 << 2) -#define SQLITE3_DEBUG_NEWDN (1 << 3) -#define SQLITE3_DEBUG_SEARCH (1 << 4) /* - * Static variables + * base160() + * + * Convert an unsigned long integer into a base160 representation of the + * number. + * + * Parameters: + * val -- + * value to be converted + * + * result -- + * character array, 5 bytes long, into which the base160 representation + * will be placed. The result will be a four-digit representation of the + * number (with leading zeros prepended as necessary), and null + * terminated. + * + * Returns: + * Nothing */ -static int lsqlite3_debug = FALSE; -sqlite3_stmt * stmtGetEID = NULL; +static void +base160_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv) +{ + int i; + long long val; + char result[5]; + + val = sqlite3_value_int64(argv[0]); + + for (i = 3; i >= 0; i--) { + + result[i] = base160tab[val % 160]; + val /= 160; + } + + result[4] = '\0'; + + sqlite3_result_text(hContext, result, -1, SQLITE_TRANSIENT); +} + /* - * Forward declarations + * base160next_sql() + * + * This function enhances sqlite by adding a "base160_next()" function which is + * accessible via queries. + * + * Retrieve the next-greater number in the base160 sequence for the terminal + * tree node (the last four digits). Only one tree level (four digits) is + * operated on. + * + * Input: + * A character string: either an empty string (in which case no operation is + * performed), or a string of base160 digits with a length of a multiple of + * four digits. + * + * Output: + * Upon return, the trailing four digits (one tree level) will have been + * incremented by 1. */ -static int -lsqlite3_rename(struct ldb_module * module, - const char * olddn, - const char * newdn); +static void +base160next_sql(sqlite3_context * hContext, + int argc, + sqlite3_value ** argv) +{ + int i; + int len; + unsigned char * pTab; + unsigned char * pBase160 = + strdup(sqlite3_value_text(argv[0])); + unsigned char * pStart = pBase160; -static int -lsqlite3_delete(struct ldb_module *module, - const char *dn); + /* + * We need a minimum of four digits, and we will always get a multiple + * of four digits. + */ + if (pBase160 != NULL && + (len = strlen(pBase160)) >= 4 && + len % 4 == 0) { -static int -lsqlite3_search_bytree(struct ldb_module * module, - const char * pBaseDN, - enum ldb_scope scope, - struct ldb_parse_tree * pTree, - const char * const * attrs, - struct ldb_message *** pppRes); + if (pBase160 == NULL) { -static int -lsqlite3_search(struct ldb_module * module, - const char * pBaseDN, - enum ldb_scope scope, - const char * pExpression, - const char * const attrs[], - struct ldb_message *** pppRes); + sqlite3_result_null(hContext); + return; + } -static int -lsqlite3_add(struct ldb_module *module, - const struct ldb_message *msg); + pBase160 += strlen(pBase160) - 1; -static int -lsqlite3_modify(struct ldb_module *module, - const struct ldb_message *msg); + /* We only carry through four digits: one level in the tree */ + for (i = 0; i < 4; i++) { -static int -lsqlite3_lock(struct ldb_module *module, - const char *lockname); + /* What base160 value does this digit have? */ + pTab = strchr(base160tab, *pBase160); -static int -lsqlite3_unlock(struct ldb_module *module, - const char *lockname); + /* Is there a carry? */ + if (pTab < base160tab + sizeof(base160tab) - 1) { -static const char * -lsqlite3_errstring(struct ldb_module *module); + /* + * Nope. Just increment this value and we're + * done. + */ + *pBase160 = *++pTab; + break; + } else { -static int -initialize(struct lsqlite3_private *lsqlite3, - const char *url); + /* + * There's a carry. This value gets + * base160tab[0], we decrement the buffer + * pointer to get the next higher-order digit, + * and continue in the loop. + */ + *pBase160-- = base160tab[0]; + } + } -static int -destructor(void *p); + sqlite3_result_text(hContext, + pStart, + strlen(pStart), + free); + } else { + sqlite3_result_value(hContext, argv[0]); + if (pBase160 != NULL) { + free(pBase160); + } + } +} -static int -query_norows(const struct lsqlite3_private *lsqlite3, - const char *pSql, - ...); +static char *parsetree_to_sql(struct ldb_module *module, + void *mem_ctx, + const struct ldb_parse_tree *t) +{ + const struct ldb_attrib_handler *h; + struct ldb_val value, subval; + char *wild_card_string; + char *child, *tmp; + char *ret = NULL; + int i; -static int -query_int(const struct lsqlite3_private * lsqlite3, - long long * pRet, - const char * pSql, - ...); -static int -getEID(const struct lsqlite3_private * lsqlite3, - long long * pRet, - const char * pNormalizedDN); + switch(t->operation) { + case LDB_OP_AND: -static int case_fold_attr_required(void * hUserData, - char *attr); + tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]); + if (tmp == NULL) return NULL; -static int case_fold_attr_not_required(void * hUserData, - char *attr); + for (i = 1; i < t->u.list.num_elements; i++) { -static int -add_msg_attr(void * hTalloc, - long long eid, - const char * pDN, - const char * pAttrName, - const char * pAttrValue, - long long prevEID, - int * pAllocated, - struct ldb_message *** pppRes); - -static char * -parsetree_to_sql(struct ldb_module *module, - char * hTalloc, - const struct ldb_parse_tree *t); + child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); + if (child == NULL) return NULL; -static int -parsetree_to_attrlist(struct ldb_module *module, - const struct ldb_parse_tree * t); + tmp = talloc_asprintf_append(tmp, "INTERSECT %s ", child); + if (tmp == NULL) return NULL; + } -static int -msg_to_sql(struct ldb_module * module, - const struct ldb_message * msg, - long long eid, - int use_flags); + ret = talloc_asprintf(mem_ctx, "SELECT * FROM ( %s )\n", tmp); -static int -new_dn(struct ldb_module * module, - char * pDN, - long long * pEID); + return ret; + + case LDB_OP_OR: -static void -base160_sql(sqlite3_context * hContext, - int argc, - sqlite3_value ** argv); + tmp = parsetree_to_sql(module, mem_ctx, t->u.list.elements[0]); + if (tmp == NULL) return NULL; -static void -base160next_sql(sqlite3_context * hContext, - int argc, - sqlite3_value ** argv); - -#ifdef DEBUG_LOCKS -static int lock_debug(struct ldb_module * module, - const char * lockname, - const char * pFileName, - int linenum); - -static int unlock_debug(struct ldb_module * module, - const char * lockname, - const char * pFileName, - int linenum); -#endif + for (i = 1; i < t->u.list.num_elements; i++) { + child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); + if (child == NULL) return NULL; -/* - * Table of operations for the sqlite3 backend - */ -static const struct ldb_module_ops lsqlite3_ops = { - .name = "sqlite", - .search = lsqlite3_search, - .search_bytree = lsqlite3_search_bytree, - .add_record = lsqlite3_add, - .modify_record = lsqlite3_modify, - .delete_record = lsqlite3_delete, - .rename_record = lsqlite3_rename, - .named_lock = lsqlite3_lock, - .named_unlock = lsqlite3_unlock, - .errstring = lsqlite3_errstring -}; + tmp = talloc_asprintf_append(tmp, "UNION %s ", child); + if (tmp == NULL) return NULL; + } + return talloc_asprintf(mem_ctx, "SELECT * FROM ( %s )", tmp); + case LDB_OP_NOT: + child = parsetree_to_sql(module, mem_ctx, t->u.isnot.child); + if (child == NULL) return NULL; -/* - * Public functions - */ + return talloc_asprintf(mem_ctx, + "SELECT eid FROM ldb_entry " + "WHERE eid NOT IN ( %s )", child); + + case LDB_OP_EQUALITY: + /* + * For simple searches, we want to retrieve the list of EIDs that + * match the criteria. + */ + h = ldb_attrib_handler(module->ldb, t->u.equality.attr); + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + if (strcasecmp(t->u.equality.attr, "objectclass") == 0) { + /* + * For object classes, we want to search for all objectclasses + * that are subclasses as well. + */ + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values\n" + "WHERE norm_attr_name = 'OBJECTCLASS' " + "AND norm_attr_value IN\n" + " (SELECT class_name FROM ldb_object_classes\n" + " WHERE tree_key GLOB\n" + " (SELECT tree_key FROM ldb_object_classes\n" + " WHERE class_name = '%q'\n" + " ) || '*'\n" + " )\n", value.data); + + } else if (strcasecmp(t->u.equality.attr, "dn") == 0) { + /* DN query is a special ldb case */ + char *cdn = ldb_dn_linearize_casefold(module->ldb, + ldb_dn_explode(module->ldb, + value.data)); + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_entry " + "WHERE norm_dn = '%q'", cdn); + + } else { + /* A normal query. */ + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = upper('%q') " + "AND norm_attr_value = '%q'", + t->u.equality.attr, + value.data); + + } + + case LDB_OP_SUBSTRING: + + wild_card_string = talloc_strdup(mem_ctx, + (t->u.substring.start_with_wildcard)?"*":""); + if (wild_card_string == NULL) return NULL; + + for (i = 0; t->u.substring.chunks[i]; i++) { + wild_card_string = talloc_asprintf_append(wild_card_string, "%s*", + t->u.substring.chunks[i]); + if (wild_card_string == NULL) return NULL; + } + + if ( ! t->u.substring.end_with_wildcard ) { + /* remove last wildcard */ + wild_card_string[strlen(wild_card_string) - 1] = '\0'; + } + + h = ldb_attrib_handler(module->ldb, t->u.substring.attr); + + subval.data = wild_card_string; + subval.length = strlen(wild_card_string) + 1; + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(subval), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = upper('%q') " + "AND norm_attr_value GLOB '%q'", + t->u.substring.attr, + value.data); + + case LDB_OP_GREATER: + h = ldb_attrib_handler(module->ldb, t->u.equality.attr); + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = upper('%q') " + "AND norm_attr_value >= '%q'", + t->u.equality.attr, + value.data); + + case LDB_OP_LESS: + h = ldb_attrib_handler(module->ldb, t->u.equality.attr); + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = upper('%q') " + "AND norm_attr_value <= '%q'", + t->u.equality.attr, + value.data); + + case LDB_OP_PRESENT: + if (strcasecmp(t->u.present.attr, "dn")) { + return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry"); + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = upper('%q')", + t->u.present.attr); + + case LDB_OP_APPROX: + h = ldb_attrib_handler(module->ldb, t->u.equality.attr); + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + if (value.data == NULL) { + return NULL; + } + + return lsqlite3_tprintf(mem_ctx, + "SELECT eid FROM ldb_attribute_values " + "WHERE norm_attr_name = upper('%q') " + "AND norm_attr_value LIKE '%q'", + t->u.equality.attr, + value.data); + + case LDB_OP_EXTENDED: +#warning "work out how to handle bitops" + return NULL; + + default: + break; + }; + + /* should never occur */ + abort(); + return NULL; +} /* - * connect to the database + * query_norows() + * + * This function is used for queries that are not expected to return any rows, + * e.g. BEGIN, COMMIT, ROLLBACK, CREATE TABLE, INSERT, UPDATE, DELETE, etc. + * There are no provisions here for returning data from rows in a table, so do + * not pass SELECT queries to this function. */ -int lsqlite3_connect(struct ldb_context *ldb, - const char *url, - unsigned int flags, - const char *options[]) +static int +query_norows(const struct lsqlite3_private *lsqlite3, + const char *pSql, + ...) { - int i; - int ret; - struct lsqlite3_private * lsqlite3 = NULL; - - lsqlite3 = talloc(ldb, struct lsqlite3_private); - if (!lsqlite3) { - goto failed; - } - - lsqlite3->sqlite = NULL; - lsqlite3->options = NULL; - lsqlite3->lock_count = 0; - - ret = initialize(lsqlite3, url); - if (ret != SQLITE_OK) { - goto failed; - } - - talloc_set_destructor(lsqlite3, destructor); - - ldb->modules = talloc(ldb, struct ldb_module); - if (!ldb->modules) { - goto failed; - } - ldb->modules->ldb = ldb; - ldb->modules->prev = ldb->modules->next = NULL; - ldb->modules->private_data = lsqlite3; - ldb->modules->ops = &lsqlite3_ops; - - if (options) { - /* - * take a copy of the options array, so we don't have to rely - * on the caller keeping it around (it might be dynamic) - */ - for (i=0;options[i];i++) ; - - lsqlite3->options = talloc_array(lsqlite3, char *, i+1); - if (!lsqlite3->options) { - goto failed; - } - - for (i=0;options[i];i++) { - - lsqlite3->options[i+1] = NULL; - lsqlite3->options[i] = - talloc_strdup(lsqlite3->options, options[i]); - if (!lsqlite3->options[i]) { - goto failed; - } - } - } - - return 0; - -failed: - if (lsqlite3->sqlite != NULL) { - (void) sqlite3_close(lsqlite3->sqlite); - } - talloc_free(lsqlite3); - return -1; -} - - -/* - * Interface functions referenced by lsqlite3_ops - */ - -/* rename a record */ -static int -lsqlite3_rename(struct ldb_module * module, - const char * pOldDN, - const char * pNewDN) -{ - const char *pOldNormalizedDN; - const char *pNewNormalizedDN; - long long eid; - struct lsqlite3_private * lsqlite3 = module->private_data; - - /* ignore ltdb specials */ - if (*pOldDN == '@' || *pNewDN == '@') { - return 0; - } - - /* Case-fold each of the DNs */ - pOldNormalizedDN = - ldb_dn_fold(module->ldb, pOldDN, module, case_fold_attr_required); - pNewNormalizedDN = - ldb_dn_fold(module->ldb, pNewDN, module, case_fold_attr_required); - - /* Begin a transaction */ - if (LOCK_DB(module, "transaction") < 0) { - return -1; - } - - /* Determine the eid of the DN being renamed */ - GET_EID(lsqlite3, eid, TRUE, pOldNormalizedDN); - - QUERY_NOROWS(lsqlite3, - TRUE, - "UPDATE ldb_entry " - " SET dn = %Q, " - " normalized_dn = %Q " - " WHERE eid = %lld;", - pNewDN, pNewNormalizedDN, eid); - - QUERY_NOROWS(lsqlite3, - TRUE, - "UPDATE ldb_attribute_values " - " SET attr_value = %Q, " - " attr_value_normalized = %Q " - " WHERE eid = %lld " - " AND attr_name = 'DN';", - pNewDN, - pNewNormalizedDN, - eid); - - /* Commit the transaction */ - if (UNLOCK_DB(module, "transaction") < 0) { - UNLOCK_DB(module, "rollback"); - return -1; - } - - return 0; -} - -/* delete a record */ -static int -lsqlite3_delete(struct ldb_module * module, - const char * pDN) -{ - char *pNormalizedDN; - long long eid; - struct lsqlite3_private * lsqlite3 = module->private_data; - - /* ignore ltdb specials */ - if (*pDN == '@') { - return 0; - } - - /* Begin a transaction */ - if (LOCK_DB(module, "transaction") < 0) { - return -1; - } - - /* Case-fold the DNs */ - pNormalizedDN = - ldb_dn_fold(module->ldb, pDN, module, case_fold_attr_required); - - /* Determine the eid of the DN being deleted */ - GET_EID(lsqlite3, eid, TRUE, pNormalizedDN); - - /* Delete attribute/value table entries pertaining to this DN */ - QUERY_NOROWS(lsqlite3, - TRUE, - "DELETE FROM ldb_attribute_values " - " WHERE eid = %lld;", - eid); - - /* Delete this entry */ - QUERY_NOROWS(lsqlite3, - TRUE, - "DELETE FROM ldb_entry " - " WHERE eid = %lld;", - eid); - - /* Commit the transaction */ - if (UNLOCK_DB(module, "transaction") < 0) { - UNLOCK_DB(module, "rollback"); - return -1; - } - - return 0; -} - -/* search for matching records, by tree */ -static int -lsqlite3_search_bytree(struct ldb_module * module, - const char * pBaseDN, - enum ldb_scope scope, - struct ldb_parse_tree * pTree, - const char * const * attrs, - struct ldb_message *** pppRes) -{ - int ret; - int allocated; - int bLoop; - long long eid = 0; - long long prevEID; - char * pSql = NULL; - char * pSqlConstraints; - char * hTalloc = NULL; - const char * pDN; - const char * pNormalizedBaseDN; - const char * pAttrName; - const char * pAttrValue; - const char * pResultAttrList; - const char * const * pRequestedAttrs; - sqlite3_stmt * pStmt; - struct lsqlite3_private * lsqlite3 = module->private_data; - - /* Allocate a temporary talloc context */ - if ((hTalloc = talloc_new(module->ldb)) == NULL) { - return -1; - } - - /* Case-fold the base DN */ - if ((pNormalizedBaseDN = - ldb_dn_fold(hTalloc, - pBaseDN == NULL ? "" : pBaseDN, - module, - case_fold_attr_required)) == NULL) { - - talloc_free(hTalloc); - return -1; - } - - /* Begin a transaction */ - if (LOCK_DB(module, "transaction") < 0) { - talloc_free(hTalloc); - return -1; - } + int ret; + int bLoop; + char * p; + sqlite3_stmt * pStmt; + va_list args; + + /* Begin access to variable argument list */ + va_start(args, pSql); - /* - * Obtain the eid of the base DN - */ - if ((ret = getEID(lsqlite3, &eid, pNormalizedBaseDN)) == SQLITE_DONE) { - UNLOCK_DB(module, "rollback"); - talloc_free(hTalloc); - return 0; - } else if (ret != SQLITE_OK) { - UNLOCK_DB(module, "rollback"); - talloc_free(hTalloc); + /* Format the query */ + if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { return -1; } - /* Convert filter into a series of SQL conditions (constraints) */ - pSqlConstraints = parsetree_to_sql(module, hTalloc, pTree); - - /* Ensure we're starting with an empty result attribute table */ - QUERY_NOROWS(lsqlite3, - FALSE, - "DELETE FROM " RESULT_ATTR_TABLE "\n" - " WHERE 1;");/* avoid a schema change with WHERE 1 */ - - /* Initially, we don't know what the requested attributes are */ - pResultAttrList = NULL; - - /* Insert the list of requested attributes into this table */ - for (pRequestedAttrs = (const char * const *) attrs; - pRequestedAttrs != NULL && *pRequestedAttrs != NULL; - pRequestedAttrs++) { - - /* If any attribute in the list is "*" then... */ - if (strcmp(*pRequestedAttrs, "*") == 0) { - /* we want all attribute types */ - pResultAttrList = ""; - break; - - } else { - /* otherwise, add this name to the resuult list */ - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT OR IGNORE\n" - " INTO " RESULT_ATTR_TABLE "\n" - " (attr_name)\n" - " VALUES\n" - " (%Q);", - *pRequestedAttrs); - } - } - - /* If we didn't get a "*" for all attributes in the result list... */ - if (pResultAttrList == NULL) { - /* ... then we'll use the result attribute table */ - pResultAttrList = - " AND upper(av.attr_name) IN\n" - " (SELECT attr_name\n" - " FROM " RESULT_ATTR_TABLE ") "; - } - - /* Ensure we're starting with an empty filter attribute table */ - QUERY_NOROWS(lsqlite3, - FALSE, - "DELETE FROM " FILTER_ATTR_TABLE "\n" - " WHERE 1;");/* avoid a schema change with WHERE 1 */ - - /* - * Create a table of unique attribute names for our extra table list - */ - if ((ret = parsetree_to_attrlist(module, pTree)) != 0) { - ret = -1; - goto cleanup; - } - - switch(scope) { - case LDB_SCOPE_DEFAULT: - case LDB_SCOPE_SUBTREE: - pSql = sqlite3_mprintf( - "SELECT entry.eid,\n" - " entry.dn,\n" - " av.attr_name,\n" - " av.attr_value\n" - " FROM ldb_entry AS entry\n" - - " LEFT OUTER JOIN ldb_attribute_values AS av\n" - " ON av.eid = entry.eid\n" - " %s\n" - - " WHERE entry.eid IN\n" - " (SELECT DISTINCT ldb_entry.eid\n" - " FROM ldb_entry\n" - " WHERE ldb_entry.tree_key >=\n" - " (SELECT tree_key\n" - " FROM ldb_entry\n" - " WHERE eid = %lld)\n" - " AND ldb_entry.tree_key <\n" - " (SELECT base160_next(tree_key)\n" - " FROM ldb_entry\n" - " WHERE eid = %lld)\n" - " AND ldb_entry.eid IN\n(%s)\n" - " )\n" - " ORDER BY entry.tree_key DESC,\n" - " COALESCE(av.attr_name, '');", - pResultAttrList, - eid, - eid, - pSqlConstraints); - break; - - case LDB_SCOPE_BASE: - pSql = sqlite3_mprintf( - "SELECT entry.eid,\n" - " entry.dn,\n" - " av.attr_name,\n" - " av.attr_value\n" - " FROM ldb_entry AS entry\n" - - " LEFT OUTER JOIN ldb_attribute_values AS av\n" - " ON av.eid = entry.eid\n" - " %s\n" - - " WHERE entry.eid IN\n" - " (SELECT DISTINCT ldb_entry.eid\n" - " FROM ldb_entry\n" - " WHERE ldb_entry.eid = %lld\n" - " AND ldb_entry.eid IN\n(%s)\n" - " )\n" - " ORDER BY entry.tree_key DESC,\n" - " COALESCE(av.attr_name, '');", - pResultAttrList, - eid, - pSqlConstraints); - break; - - case LDB_SCOPE_ONELEVEL: - pSql = sqlite3_mprintf( - "SELECT entry.eid,\n" - " entry.dn,\n" - " av.attr_name,\n" - " av.attr_value\n" - " FROM ldb_entry AS entry\n" - - " LEFT OUTER JOIN ldb_attribute_values AS av\n" - " ON av.eid = entry.eid\n" - " %s\n" - - " WHERE entry.eid IN\n" - " (SELECT DISTINCT ldb_entry.eid\n" - " FROM ldb_entry\n" - " WHERE ldb_entry.tree_key >=\n" - " (SELECT tree_key\n" - " FROM ldb_entry\n" - " WHERE eid = %lld)\n" - " AND ldb_entry.tree_key <\n" - " (SELECT base160_next(tree_key)\n" - " FROM ldb_entry\n" - " WHERE eid = %lld)\n" - " AND length(ldb_entry.tree_key) =\n" - " (SELECT length(tree_key) + 4\n" - " FROM ldb_entry\n" - " WHERE eid = %lld)\n" - " AND ldb_entry.eid IN\n(%s)\n" - " )\n" - - " ORDER BY entry.tree_key DESC,\n" - " COALESCE(av.attr_name, '');\n", - pResultAttrList, - eid, - eid, - eid, - pSqlConstraints); - break; - } - - if (pSql == NULL) { - ret = -1; - goto cleanup; - } - - if (lsqlite3_debug & SQLITE3_DEBUG_SEARCH) { - printf("%s\n", pSql); - } - /* * Prepare and execute the SQL statement. Loop allows retrying on * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, * requiring retrying the operation. */ for (bLoop = TRUE; bLoop; ) { - /* There are no allocate message structures yet */ - allocated = 0; - if (pppRes != NULL) { - *pppRes = NULL; - } /* Compile the SQL statement into sqlite virtual machine */ if ((ret = sqlite3_prepare(lsqlite3->sqlite, - pSql, + p, -1, &pStmt, NULL)) == SQLITE_SCHEMA) { @@ -693,62 +484,19 @@ lsqlite3_search_bytree(struct ldb_module * module, sqlite3_finalize(stmtGetEID); stmtGetEID = NULL; } - - if (pppRes != NULL && *pppRes != NULL) { - talloc_free(*pppRes); - } - continue; } else if (ret != SQLITE_OK) { ret = -1; break; } - /* Initially, we have no previous eid */ - prevEID = -1; - - /* Loop through the returned rows */ - for (ret = SQLITE_ROW; ret == SQLITE_ROW; ) { - - /* Get the next row */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_ROW) { - - /* Get the values from this row */ - eid = sqlite3_column_int64(pStmt, 0); - pDN = sqlite3_column_text(pStmt, 1); - pAttrName = sqlite3_column_text(pStmt, 2); - pAttrValue = sqlite3_column_text(pStmt, 3); - - /* Add this result to the result set */ - if (add_msg_attr(hTalloc, - eid, - pDN, - pAttrName, - pAttrValue, - prevEID, - &allocated, - pppRes) != 0) { - - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* Save the most recent EID */ - prevEID = eid; - } - } - - if (ret == SQLITE_SCHEMA) { + /* No rows expected, so just step through machine code once */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { if (stmtGetEID != NULL) { sqlite3_finalize(stmtGetEID); stmtGetEID = NULL; } - (void) sqlite3_finalize(pStmt); - if (pppRes != NULL && *pppRes != NULL) { - talloc_free(*pppRes); - } continue; } else if (ret != SQLITE_DONE) { (void) sqlite3_finalize(pStmt); @@ -762,10 +510,6 @@ lsqlite3_search_bytree(struct ldb_module * module, sqlite3_finalize(stmtGetEID); stmtGetEID = NULL; } - - if (pppRes != NULL && *pppRes != NULL) { - talloc_free(*pppRes); - } continue; } else if (ret != SQLITE_OK) { (void) sqlite3_finalize(pStmt); @@ -781,184 +525,24 @@ lsqlite3_search_bytree(struct ldb_module * module, bLoop = FALSE; } - /* We're alll done with this query */ - sqlite3_free(pSql); - - /* End the transaction */ - UNLOCK_DB(module, "rollback"); - - /* Were there any results? */ - if (ret != 0 || allocated == 0) { - /* Nope. We can free the results. */ - if (pppRes != NULL && *pppRes != NULL) { - talloc_free(*pppRes); - } - } - -cleanup: - /* Clean up our temporary tables */ - QUERY_NOROWS(lsqlite3, - FALSE, - "DELETE FROM " RESULT_ATTR_TABLE "\n" - " WHERE 1;");/* avoid a schema change with WHERE 1 */ - - QUERY_NOROWS(lsqlite3, - FALSE, - "DELETE FROM " FILTER_ATTR_TABLE "\n" - " WHERE 1;");/* avoid a schema change with WHERE 1 */ - + /* All done with variable argument list */ + va_end(args); - if (hTalloc != NULL) { - talloc_free(hTalloc); - } + /* Free the memory we allocated for our query string */ + sqlite3_free(p); - /* If error, return error code; otherwise return number of results */ - return ret == 0 ? allocated : ret; + return ret; } -/* search for matching records, by expression */ + +/* obtain a named lock */ static int -lsqlite3_search(struct ldb_module * module, - const char * pBaseDN, - enum ldb_scope scope, - const char * pExpression, - const char * const * attrs, - struct ldb_message *** pppRes) +lsqlite3_lock(struct ldb_module * module, + const char * lockname) { - int ret; - struct ldb_parse_tree * pTree; - - /* Handle tdb specials */ - if (pBaseDN != NULL && *pBaseDN == '@') { -#warning "handle tdb specials" - return 0; - } - -#if 0 -/* (|(objectclass=*)(dn=*)) is passed by the command line tool now instead */ - /* Handle the special case of requesting all */ - if (pExpression != NULL && *pExpression == '\0') { - pExpression = "dn=*"; - } -#endif - - /* Parse the filter expression into a tree we can work with */ - if ((pTree = ldb_parse_tree(module->ldb, pExpression)) == NULL) { - return -1; - } - - /* Now use the bytree function for the remainder of processing */ - ret = lsqlite3_search_bytree(module, pBaseDN, scope, - pTree, attrs, pppRes); - - /* Free the parse tree */ - talloc_free(pTree); - - /* All done. */ - return ret; -} - - -/* add a record */ -static int -lsqlite3_add(struct ldb_module *module, - const struct ldb_message *msg) -{ - long long eid; - - /* See if this is an ltdb special */ - if (*msg->dn == '@') { - /* Yup. We handle a few of these and ignore others */ - if (strcmp(msg->dn, "@SUBCLASSES") == 0) { -#warning "insert subclasses into object class tree" - } - - if (strcmp(msg->dn, "@INDEXLIST") == 0) { - /* explicitly ignored */ - return 0; - } - - /* Others are implicitly ignored */ - return 0; - } - - /* Begin a transaction */ - if (LOCK_DB(module, "transaction") < 0) { - return -1; - } - - /* - * Build any portions of the directory tree that don't exist. If the - * final component already exists, it's an error. - */ - if (new_dn(module, msg->dn, &eid) != 0) { - UNLOCK_DB(module, "rollback"); - return -1; - } - - /* Add attributes to this new entry */ - if (msg_to_sql(module, msg, eid, FALSE) != 0) { - UNLOCK_DB(module, "rollback"); - return -1; - } - - /* Everything worked. Commit it! */ - if (UNLOCK_DB(module, "transaction") < 0) { - UNLOCK_DB(module, "rollback"); - return -1; - } - return 0; -} - - -/* modify a record */ -static int -lsqlite3_modify(struct ldb_module * module, - const struct ldb_message * msg) -{ - char * pNormalizedDN; - long long eid; - struct lsqlite3_private * lsqlite3 = module->private_data; - - /* ignore ltdb specials */ - if (*msg->dn == '@') { - return 0; - } - - /* Begin a transaction */ - if (LOCK_DB(module, "transaction") < 0) { - return -1; - } - - /* Case-fold the DN so we can compare it to what's in the database */ - pNormalizedDN = ldb_dn_fold(module->ldb, msg->dn, - module, case_fold_attr_required); - - /* Determine the eid of the DN being deleted */ - GET_EID(lsqlite3, eid, TRUE, pNormalizedDN); - - /* Apply the message attributes */ - if (msg_to_sql(module, msg, eid, TRUE) != 0) { - UNLOCK_DB(module, "rollback"); - return -1; - } - - - /* Everything worked. Commit it! */ - if (UNLOCK_DB(module, "transaction") < 0) { - UNLOCK_DB(module, "rollback"); - return -1; - } - return 0 ; -} - -/* obtain a named lock */ -static int -lsqlite3_lock(struct ldb_module * module, - const char * lockname) -{ - struct lsqlite3_private * lsqlite3 = module->private_data; + struct lsqlite3_private * lsqlite3 = module->private_data; +/* FIXME if (lockname == NULL) { return -1; } @@ -971,7 +555,7 @@ lsqlite3_lock(struct ldb_module * module, } ++lsqlite3->lock_count; } - +*/ return 0; } @@ -982,6 +566,7 @@ lsqlite3_unlock(struct ldb_module *module, { struct lsqlite3_private * lsqlite3 = module->private_data; +/* FIXME if (lockname == NULL) { return -1; } @@ -997,1559 +582,1313 @@ lsqlite3_unlock(struct ldb_module *module, } else if (strcmp(lockname, "rollback") == 0) { query_norows(lsqlite3, "ROLLBACK;"); } - +*/ return 0; } -/* return extended error information */ -static const char * -lsqlite3_errstring(struct ldb_module *module) -{ - struct lsqlite3_private * lsqlite3 = module->private_data; - - return sqlite3_errmsg(lsqlite3->sqlite); -} - - - - /* - * Static functions + * query_int() + * + * This function is used for the common case of queries that return a single + * integer value. + * + * NOTE: If more than one value is returned by the query, all but the first + * one will be ignored. */ - static int -initialize(struct lsqlite3_private *lsqlite3, - const char *url) +query_int(const struct lsqlite3_private * lsqlite3, + long long * pRet, + const char * pSql, + ...) { int ret; - long long queryInt; - const char * pTail; - sqlite3_stmt * stmt; - const char * schema = - + int bLoop; + char * p; + sqlite3_stmt * pStmt; + va_list args; + + /* Begin access to variable argument list */ + va_start(args, pSql); + + /* Format the query */ + if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { + return SQLITE_NOMEM; + } + + /* + * Prepare and execute the SQL statement. Loop allows retrying on + * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, + * requiring retrying the operation. + */ + for (bLoop = TRUE; bLoop; ) { - "CREATE TABLE ldb_info AS " - " SELECT 'LDB' AS database_type," - " '1.0' AS version;" + /* Compile the SQL statement into sqlite virtual machine */ + if ((ret = sqlite3_prepare(lsqlite3->sqlite, + p, + -1, + &pStmt, + NULL)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + continue; + } else if (ret != SQLITE_OK) { + break; + } - /* - * The entry table holds the information about an entry. - * This table is used to obtain the EID of the entry and to - * support scope=one and scope=base. The parent and child - * table is included in the entry table since all the other - * attributes are dependent on EID. - */ - "CREATE TABLE ldb_entry " - "(" - " eid INTEGER PRIMARY KEY," - " peid INTEGER REFERENCES ldb_entry," - " dn TEXT UNIQUE NOT NULL," - " normalized_dn TEXT UNIQUE NOT NULL," - " tree_key TEXT UNIQUE," - " max_child_num INTEGER DEFAULT 0," - " create_timestamp INTEGER," - " modify_timestamp INTEGER" - ");" + /* One row expected */ + if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + (void) sqlite3_finalize(pStmt); + continue; + } else if (ret != SQLITE_ROW) { + (void) sqlite3_finalize(pStmt); + break; + } - - "CREATE TABLE ldb_object_classes" - "(" - " class_name TEXT PRIMARY KEY," - " parent_class_name TEXT," - " tree_key TEXT UNIQUE," - " max_child_num INTEGER DEFAULT 0" - ");" + /* Get the value to be returned */ + *pRet = sqlite3_column_int64(pStmt, 0); - /* - * We keep a full listing of attribute/value pairs here - */ - "CREATE TABLE ldb_attribute_values" - "(" - " eid INTEGER REFERENCES ldb_entry," - " attr_name TEXT," - " attr_value TEXT," - " attr_value_normalized TEXT " - ");" + /* Free the virtual machine */ + if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { + if (stmtGetEID != NULL) { + sqlite3_finalize(stmtGetEID); + stmtGetEID = NULL; + } + continue; + } else if (ret != SQLITE_OK) { + (void) sqlite3_finalize(pStmt); + break; + } - /* - * Indexes + * Normal condition is only one time through loop. Loop is + * rerun in error conditions, via "continue", above. */ - "CREATE INDEX ldb_entry_tree_key_idx " - " ON ldb_entry (tree_key);" + bLoop = FALSE; + } + + /* All done with variable argument list */ + va_end(args); + - "CREATE INDEX ldb_attribute_values_eid_idx " - " ON ldb_attribute_values (eid);" - - "CREATE INDEX ldb_attribute_values_name_value_idx " - " ON ldb_attribute_values (attr_name, attr_value_normalized);" - - + /* Free the memory we allocated for our query string */ + sqlite3_free(p); + + return ret; +} - /* - * Triggers - */ - - "CREATE TRIGGER ldb_entry_insert_tr" - " AFTER INSERT" - " ON ldb_entry" - " FOR EACH ROW" - " BEGIN" - " UPDATE ldb_entry" - " SET create_timestamp = strftime('%s', 'now')," - " modify_timestamp = strftime('%s', 'now')" - " ," - " tree_key = COALESCE(tree_key, " - " (" - " SELECT tree_key || " - " (SELECT base160(max_child_num + 1)" - " FROM ldb_entry" - " WHERE eid = new.peid)" - " FROM ldb_entry " - " WHERE eid = new.peid " - " ));" - " UPDATE ldb_entry " - " SET max_child_num = max_child_num + 1" - " WHERE eid = new.peid;" - " END;" - - "CREATE TRIGGER ldb_entry_update_tr" - " AFTER UPDATE" - " ON ldb_entry" - " FOR EACH ROW" - " BEGIN" - " UPDATE ldb_entry" - " SET modify_timestamp = strftime('%s', 'now')" - " WHERE eid = old.eid;" - " END;" - - "CREATE TRIGGER ldb_object_classes_insert_tr" - " AFTER INSERT" - " ON ldb_object_classes" - " FOR EACH ROW" - " BEGIN" - " UPDATE ldb_object_classes" - " SET tree_key = COALESCE(tree_key, " - " (" - " SELECT tree_key || " - " (SELECT base160(max_child_num + 1)" - " FROM ldb_object_classes" - " WHERE class_name = " - " new.parent_class_name)" - " FROM ldb_object_classes " - " WHERE class_name = new.parent_class_name " - " ));" - " UPDATE ldb_object_classes " - " SET max_child_num = max_child_num + 1" - " WHERE class_name = new.parent_class_name;" - " END;" - - /* - * Table initialization - */ +/* rename a record */ +static int lsqlite3_safe_rollback(sqlite3 *sqlite) +{ + char *errmsg; + int ret; - /* The root node */ - "INSERT INTO ldb_entry " - " (eid, peid, dn, normalized_dn, tree_key) " - " VALUES " - " (0, NULL, '', '', '0001');" + /* execute */ + ret = sqlite3_exec(sqlite, "ROLLBACK;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_safe_rollback: Serious Error: %s\n", errmsg); + free(errmsg); + } + return -1; + } - /* And the root node "dn" attribute */ - "INSERT INTO ldb_attribute_values " - " (eid, attr_name, attr_value, attr_value_normalized) " - " VALUES " - " (0, 'DN', '', '');" + return 0; +} - "INSERT INTO ldb_object_classes " - " (class_name, tree_key) " - " VALUES " - " ('TOP', '0001');" +/* return an eid as result */ +static int lsqlite3_eid_callback(void *result, int col_num, char **cols, char **names) +{ + long long *eid = (long long *)result; - ; - - /* Skip protocol indicator of url */ - if (strncmp(url, "sqlite://", 9) != 0) { - return SQLITE_MISUSE; - } - - /* Update pointer to just after the protocol indicator */ - url += 9; - - /* Try to open the (possibly empty/non-existent) database */ - if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) { - return ret; - } - - /* In case this is a new database, enable auto_vacuum */ - if (query_norows(lsqlite3, "PRAGMA auto_vacuum=1;") != 0) { - return -1; - } - - /* Establish a busy timeout of 30 seconds */ - if ((ret = sqlite3_busy_timeout(lsqlite3->sqlite, - 30000)) != SQLITE_OK) { - return ret; - } + if (col_num != 1) return SQLITE_ABORT; + if (strcasecmp(names[0], "eid") != 0) return SQLITE_ABORT; - /* Create a function, callable from sql, to increment a tree_key */ - if ((ret = - sqlite3_create_function(lsqlite3->sqlite,/* handle */ - "base160_next", /* function name */ - 1, /* number of args */ - SQLITE_ANY, /* preferred text type */ - NULL, /* user data */ - base160next_sql, /* called func */ - NULL, /* step func */ - NULL /* final func */ - )) != SQLITE_OK) { - return ret; - } + *eid = atoll(cols[0]); + return SQLITE_OK; +} - /* Create a function, callable from sql, to convert int to base160 */ - if ((ret = - sqlite3_create_function(lsqlite3->sqlite,/* handle */ - "base160", /* function name */ - 1, /* number of args */ - SQLITE_ANY, /* preferred text type */ - NULL, /* user data */ - base160_sql, /* called func */ - NULL, /* step func */ - NULL /* final func */ - )) != SQLITE_OK) { - return ret; - } +struct lsqlite3_msgs { + int count; + struct ldb_message **msgs; + long long current_eid; + TALLOC_CTX *mem_ctx; +}; - /* Begin a transaction */ - if ((ret = query_norows(lsqlite3, "BEGIN EXCLUSIVE;")) != 0) { - return ret; - } - - /* Determine if this is a new database. No tables means it is. */ - if (query_int(lsqlite3, - &queryInt, - "SELECT COUNT(*)\n" - " FROM sqlite_master\n" - " WHERE type = 'table';") != 0) { - query_norows(lsqlite3, "ROLLBACK;"); - return -1; - } - - if (queryInt == 0) { - /* - * Create the database schema - */ - for (pTail = discard_const_p(char, schema); - pTail != NULL && *pTail != '\0'; - ) { - - if (lsqlite3_debug & SQLITE3_DEBUG_INIT) { - printf("Execute first query in:\n%s\n", pTail); - } - - if ((ret = sqlite3_prepare( - lsqlite3->sqlite, - pTail, - -1, - &stmt, - &pTail)) != SQLITE_OK || - (ret = sqlite3_step(stmt)) != SQLITE_DONE || - (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { - - if (lsqlite3_debug & SQLITE3_DEBUG_INIT) { - printf("%s\n", - sqlite3_errmsg(lsqlite3->sqlite)); - printf("pTail = [%s]\n", pTail); - } - - query_norows(lsqlite3, "ROLLBACK;"); - (void) sqlite3_close(lsqlite3->sqlite); - return ret; - } - } - } else { - /* - * Ensure that the database we opened is one of ours - */ - if (query_int(lsqlite3, - &queryInt, - "SELECT " - " (SELECT COUNT(*) = 2" - " FROM sqlite_master " - " WHERE type = 'table' " - " AND name IN " - " (" - " 'ldb_entry', " - " 'ldb_object_classes' " - " ) " - " ) " - " AND " - " (SELECT 1 " - " FROM ldb_info " - " WHERE database_type = 'LDB' " - " AND version = '1.0'" - " );") != 0 || - queryInt != 1) { - - /* It's not one that we created. See ya! */ - query_norows(lsqlite3, "ROLLBACK;"); - (void) sqlite3_close(lsqlite3->sqlite); - return SQLITE_MISUSE; - } - } - - /* - * Create a temporary table to hold attributes requested in the result - * set of a search. - */ - query_norows(lsqlite3, "DROP TABLE " RESULT_ATTR_TABLE ";\n"); - if ((ret = - query_norows(lsqlite3, - "CREATE " TEMPTAB " TABLE " RESULT_ATTR_TABLE "\n" - " (\n" - " attr_name TEXT PRIMARY KEY\n" - " );")) != 0) { - query_norows(lsqlite3, "ROLLBACK;"); - return ret; - } +/* + * add a single set of ldap message values to a ldb_message + */ - /* - * Create a temporary table to hold the attributes used by filters - * during a search. - */ - query_norows(lsqlite3, "DROP TABLE " FILTER_ATTR_TABLE ";\n"); - if ((ret = - query_norows(lsqlite3, - "CREATE " TEMPTAB " TABLE " FILTER_ATTR_TABLE "\n" - " (\n" - " attr_name TEXT PRIMARY KEY\n" - " );")) != 0) { - query_norows(lsqlite3, "ROLLBACK;"); - return ret; - } +static int lsqlite3_search_callback(void *result, int col_num, char **cols, char **names) +{ + struct lsqlite3_msgs *msgs = (struct lsqlite3_msgs *)result; + struct ldb_message *msg; + long long eid; - /* Commit the transaction */ - if ((ret = query_norows(lsqlite3, "COMMIT;")) != 0) { - query_norows(lsqlite3, "ROLLBACK;"); - return ret; - } - - return SQLITE_OK; + /* eid, dn, attr_name, attr_value */ + if (col_num != 4) return SQLITE_ABORT; + + eid = atoll(cols[0]); + + if (eid != msgs->current_eid) { + msgs->msgs = talloc_realloc(msgs->mem_ctx, + msgs->msgs, + struct ldb_message *, + msgs->count + 2); + if (msgs->msgs == NULL) return SQLITE_ABORT; + + msgs->msgs[msgs->count] = talloc(msgs->msgs, struct ldb_message); + if (msgs->msgs[msgs->count] == NULL) return SQLITE_ABORT; + + msgs->msgs[msgs->count]->dn = NULL; + msgs->msgs[msgs->count]->num_elements = 0; + msgs->msgs[msgs->count]->elements = NULL; + msgs->msgs[msgs->count]->private_data = NULL; + + msgs->count++; + msgs->current_eid = eid; + } + + msg = msgs->msgs[msgs->count -1]; + + if (msg->dn == NULL) { + msg->dn = ldb_dn_explode(msg, cols[1]); + if (msg->dn == NULL) return SQLITE_ABORT; + } + + msg->elements = talloc_realloc(msg, + msg->elements, + struct ldb_message_element, + msg->num_elements + 1); + if (msg->elements == NULL) return SQLITE_ABORT; + + msg->elements[msg->num_elements].flags = 0; + msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, cols[2]); + if (msg->elements[msg->num_elements].name == NULL) return SQLITE_ABORT; + + msg->elements[msg->num_elements].num_values = 1; + msg->elements[msg->num_elements].values = talloc_array(msg->elements, + struct ldb_val, 1); + if (msg->elements[msg->num_elements].values == NULL) return SQLITE_ABORT; + + msg->elements[msg->num_elements].values[0].length = strlen(cols[3]); + msg->elements[msg->num_elements].values[0].data = talloc_strdup(msg->elements, cols[3]); + if (msg->elements[msg->num_elements].values[0].data == NULL) return SQLITE_ABORT; + + msg->num_elements++; + + return SQLITE_OK; } -static int -destructor(void *p) + +/* + * lsqlite3_get_eid() + * lsqlite3_get_eid_ndn() + * + * These functions are used for the very common case of retrieving an EID value + * given a (normalized) DN. + */ + +static long long lsqlite3_get_eid_ndn(sqlite3 *sqlite, void *mem_ctx, const char *norm_dn) { - struct lsqlite3_private * lsqlite3 = p; - - if (lsqlite3->sqlite) { - sqlite3_close(lsqlite3->sqlite); + char *errmsg; + char *query; + long long eid = -1; + long long ret; + + /* get object eid */ + query = lsqlite3_tprintf(mem_ctx, "SELECT eid " + "FROM ldb_entry " + "WHERE norm_dn = '%q';", norm_dn); + if (query == NULL) return -1; + + ret = sqlite3_exec(sqlite, query, lsqlite3_eid_callback, &eid, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_get_eid: Fatal Error: %s\n", errmsg); + free(errmsg); + } + return -1; } - return 0; + + return eid; } +static long long lsqlite3_get_eid(struct ldb_module *module, const struct ldb_dn *dn) +{ + TALLOC_CTX *local_ctx; + struct lsqlite3_private *lsqlite3 = module->private_data; + long long eid = -1; + char *cdn; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(dn)) { + return -1; + } + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_get_eid local context"); + if (local_ctx == NULL) { + return -1; + } + + cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, dn)); + if (!cdn) goto done; + + eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, cdn); + +done: + talloc_free(local_ctx); + return eid; +} /* - * query_norows() - * - * This function is used for queries that are not expected to return any rows, - * e.g. BEGIN, COMMIT, ROLLBACK, CREATE TABLE, INSERT, UPDATE, DELETE, etc. - * There are no provisions here for returning data from rows in a table, so do - * not pass SELECT queries to this function. + * Interface functions referenced by lsqlite3_ops */ -static int -query_norows(const struct lsqlite3_private *lsqlite3, - const char *pSql, - ...) + +/* search for matching records, by tree */ +static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_dn* basedn, + enum ldb_scope scope, struct ldb_parse_tree * tree, + const char * const * attrs, struct ldb_message *** res) { - int ret; - int bLoop; - char * p; - sqlite3_stmt * pStmt; - va_list args; - double t0 = 0; - double t1; - struct timeval tv; - struct timezone tz; - - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { - gettimeofday(&tv, &tz); - t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + TALLOC_CTX *local_ctx; + struct lsqlite3_private *lsqlite3 = module->private_data; + struct lsqlite3_msgs msgs; + char *norm_basedn; + char *attr_list; + char *sqlfilter; + char *errmsg; + char *query; + int ret, i; + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_search_by_tree local context"); + if (local_ctx == NULL) { + return -1; } - /* Begin access to variable argument list */ - va_start(args, pSql); - - /* Format the query */ - if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { - return -1; - } + if (basedn) { + norm_basedn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, basedn)); + if (norm_basedn == NULL) goto failed; + } else norm_basedn = talloc_strdup(local_ctx, ""); + + if (*norm_basedn == '\0' && + (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) + goto failed; + + /* Convert filter into a series of SQL conditions (constraints) */ + sqlfilter = parsetree_to_sql(module, local_ctx, tree); - /* - * Prepare and execute the SQL statement. Loop allows retrying on - * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, - * requiring retrying the operation. - */ - for (bLoop = TRUE; bLoop; ) { - - /* Compile the SQL statement into sqlite virtual machine */ - if ((ret = sqlite3_prepare(lsqlite3->sqlite, - p, - -1, - &pStmt, - NULL)) == SQLITE_SCHEMA) { - if (stmtGetEID != NULL) { - sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - } - continue; - } else if (ret != SQLITE_OK) { - ret = -1; - break; - } - - /* No rows expected, so just step through machine code once */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { - if (stmtGetEID != NULL) { - sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - } - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_DONE) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } + /* Initially, we don't know what the requested attributes are */ + if (attrs != NULL) { + attr_list = talloc_strdup(local_ctx, "AND norm_attr_name IN ("); + if (attr_list == NULL) goto failed; + + for (i = 0; attrs[i]; i++) { + char *norm_attr_name; + + /* If any attribute in the list is "*" then... */ + if (strcmp(attrs[i], "*") == 0) { + /* we want all attribute types */ + attr_list = talloc_strdup(local_ctx, ""); + if (attr_list == NULL) goto failed; + break; + } + + norm_attr_name = ldb_casefold(local_ctx, attrs[i]); + if (norm_attr_name == NULL) goto failed; + + attr_list = talloc_asprintf_append(attr_list, "'%q', ", + norm_attr_name); + if (attr_list == NULL) goto failed; + + } + + /* substitute the last ',' with ')' */ + attr_list[strlen(attr_list)-2] = ')'; + + } else { + attr_list = talloc_strdup(local_ctx, ""); + if (attr_list == NULL) goto failed; + } + + switch(scope) { + case LDB_SCOPE_DEFAULT: + case LDB_SCOPE_SUBTREE: + if (*norm_basedn != '\0') { + query = lsqlite3_tprintf(local_ctx, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE (ldb_entry.norm_dn GLOB('*,%q')\n" + " OR ldb_entry.norm_dn = '%q')\n" + " AND ldb_entry.eid IN\n" + " (%s)\n" + " )\n" + + " %s\n" + + " ORDER BY entry.eid ASC;", + norm_basedn, + norm_basedn, + sqlfilter, + attr_list); + } else { + query = lsqlite3_tprintf(local_ctx, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE ldb_entry.eid IN\n" + " (%s)\n" + " )\n" + + " %s\n" + + " ORDER BY entry.eid ASC;", + sqlfilter, + attr_list); + } + + break; - /* Free the virtual machine */ - if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - if (stmtGetEID != NULL) { - sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - } - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } + case LDB_SCOPE_BASE: + query = lsqlite3_tprintf(local_ctx, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE ldb_entry.norm_dn = '%q'\n" + " AND ldb_entry.eid IN\n" + " (%s)\n" + " )\n" + + " %s\n" + + " ORDER BY entry.eid ASC;", + norm_basedn, + sqlfilter, + attr_list); + break; - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - ret = 0; - bLoop = FALSE; + case LDB_SCOPE_ONELEVEL: + query = lsqlite3_tprintf(local_ctx, + "SELECT entry.eid,\n" + " entry.dn,\n" + " av.attr_name,\n" + " av.attr_value\n" + " FROM ldb_entry AS entry\n" + + " LEFT OUTER JOIN ldb_attribute_values AS av\n" + " ON av.eid = entry.eid\n" + + " WHERE entry.eid IN\n" + " (SELECT DISTINCT ldb_entry.eid\n" + " FROM ldb_entry\n" + " WHERE norm_dn GLOB('*,%q')\n" + " AND NOT norm_dn GLOB('*,*,%q')\n" + " AND ldb_entry.eid IN\n(%s)\n" + " )\n" + + " %s\n" + + " ORDER BY entry.eid ASC;", + norm_basedn, + norm_basedn, + sqlfilter, + attr_list); + break; } - - /* All done with variable argument list */ - va_end(args); - - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { - gettimeofday(&tv, NULL); - t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); - printf("%1.6lf %s\n%s\n\n", t1 - t0, - ret == 0 ? "SUCCESS" : "FAIL", - p); + + if (query == NULL) { + ret = -1; + goto failed; } - /* Free the memory we allocated for our query string */ - sqlite3_free(p); - - return ret; -} + /* printf ("%s\n", query); */ + msgs.msgs = NULL; + msgs.count = 0; + msgs.current_eid = 0; + msgs.mem_ctx = local_ctx; -/* - * query_int() - * - * This function is used for the common case of queries that return a single - * integer value. - * - * NOTE: If more than one value is returned by the query, all but the first - * one will be ignored. - */ -static int -query_int(const struct lsqlite3_private * lsqlite3, - long long * pRet, - const char * pSql, - ...) -{ - int ret; - int bLoop; - char * p; - sqlite3_stmt * pStmt; - va_list args; - double t0 = 0; - double t1; - struct timeval tv; - struct timezone tz; - - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { - gettimeofday(&tv, &tz); - t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); + ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, &msgs, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_search_bytree: Fatal Error: %s\n", errmsg); + free(errmsg); + } + goto failed; } - /* Begin access to variable argument list */ - va_start(args, pSql); - - /* Format the query */ - if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { - return SQLITE_NOMEM; - } + for (i = 0; i < msgs.count; i++) { + msgs.msgs[i] = ldb_msg_canonicalize(module->ldb, msgs.msgs[i]); + if (msgs.msgs[i] == NULL) goto failed; + } + + *res = talloc_steal(module, msgs.msgs); + ret = msgs.count; + + talloc_free(local_ctx); + return ret; + +/* If error, return error code; otherwise return number of results */ +failed: + talloc_free(local_ctx); + return -1; +} + +/* search for matching records, by expression */ +static int lsqlite3_search(struct ldb_module * module, const struct ldb_dn *basedn, + enum ldb_scope scope, const char * expression, + const char * const *attrs, struct ldb_message *** res) +{ + struct ldb_parse_tree * tree; + int ret; - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { - printf("%s\n", p); + /* Handle tdb specials */ + if (ldb_dn_is_special(basedn)) { +#warning "handle tdb specials" + return 0; } - /* - * Prepare and execute the SQL statement. Loop allows retrying on - * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, - * requiring retrying the operation. - */ - for (bLoop = TRUE; bLoop; ) { - - /* Compile the SQL statement into sqlite virtual machine */ - if ((ret = sqlite3_prepare(lsqlite3->sqlite, - p, - -1, - &pStmt, - NULL)) == SQLITE_SCHEMA) { - if (stmtGetEID != NULL) { - sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - } - continue; - } else if (ret != SQLITE_OK) { - break; - } - - /* One row expected */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { - if (stmtGetEID != NULL) { - sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - } - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_ROW) { - (void) sqlite3_finalize(pStmt); - break; - } - - /* Get the value to be returned */ - *pRet = sqlite3_column_int64(pStmt, 0); - - /* Free the virtual machine */ - if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - if (stmtGetEID != NULL) { - sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - } - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(pStmt); - break; - } - - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - bLoop = FALSE; +#if 0 +/* (|(objectclass=*)(dn=*)) is passed by the command line tool now instead */ + /* Handle the special case of requesting all */ + if (pExpression != NULL && *pExpression == '\0') { + pExpression = "dn=*"; } +#endif + + /* Parse the filter expression into a tree we can work with */ + if ((tree = ldb_parse_tree(module->ldb, expression)) == NULL) { + return -1; + } - /* All done with variable argument list */ - va_end(args); + /* Now use the bytree function for the remainder of processing */ + ret = lsqlite3_search_bytree(module, basedn, scope, tree, attrs, res); - - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { - gettimeofday(&tv, NULL); - t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); - printf("%1.6lf %s\n%s\n\n", t1 - t0, - ret == 0 ? "SUCCESS" : "FAIL", - p); - } - - /* Free the memory we allocated for our query string */ - sqlite3_free(p); + /* Free the parse tree */ + talloc_free(tree); + /* All done. */ return ret; } -/* - * getEID() - * - * This function is used for the very common case of retrieving an EID value - * given a normalized DN. - * - * NOTE: If more than one value is returned by the query, all but the first - * one will be ignored. - */ -static int -getEID(const struct lsqlite3_private * lsqlite3, - long long * pRet, - const char * pNormalizedDN) +/* add a record */ +static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg) { - int ret; - int bLoop; - const char * query = - "SELECT eid\n" - " FROM ldb_attribute_values\n" - " WHERE attr_name = 'DN'\n" - " AND attr_value_normalized = :dn;"; - - /* - * Prepare and execute the SQL statement. Loop allows retrying on - * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, - * requiring retrying the operation. - */ - for (bLoop = TRUE; bLoop; ) { - - /* Compile the SQL statement into sqlite virtual machine */ - ret = SQLITE_OK; - if (stmtGetEID == NULL && - (ret = sqlite3_prepare(lsqlite3->sqlite, - query, - -1, - &stmtGetEID, - NULL)) == SQLITE_SCHEMA) { - continue; - } else if (ret != SQLITE_OK) { - break; - } - - /* Bind our parameter */ - if ((ret = sqlite3_bind_text(stmtGetEID, - 1, - pNormalizedDN, - -1, - SQLITE_STATIC)) != SQLITE_OK) { - break; - } + TALLOC_CTX *local_ctx; + struct lsqlite3_private *lsqlite3 = module->private_data; + long long eid; + char *dn, *ndn; + char *errmsg; + char *query; + int rollback = 0; + int ret; + int i; + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_add local context"); + if (local_ctx == NULL) { + return -1; + } - /* One row expected */ - if ((ret = sqlite3_step(stmtGetEID)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - continue; - } else if (ret != SQLITE_ROW) { - (void) sqlite3_reset(stmtGetEID); - break; - } - - /* Get the value to be returned */ - *pRet = sqlite3_column_int64(stmtGetEID, 0); - - /* Free the virtual machine */ - if ((ret = sqlite3_reset(stmtGetEID)) == SQLITE_SCHEMA) { - (void) sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - break; - } - - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - bLoop = FALSE; - } - - return ret; -} + /* See if this is an ltdb special */ + if (ldb_dn_is_special(msg->dn)) { + struct ldb_dn *c; + c = ldb_dn_explode(local_ctx, "@SUBCLASSES"); + if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { +#warning "insert subclasses into object class tree" + goto failed; + } -/* - callback function used in call to ldb_dn_fold() for determining whether an - attribute type requires case folding. -*/ -static int -case_fold_attr_required(void * hUserData, - char *attr) -{ -// struct ldb_module * module = hUserData; - - return TRUE; -} + c = ldb_dn_explode(local_ctx, "@INDEXLIST"); + if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { +#warning "should we handle indexes somehow ?" + goto failed; + } -static int -case_fold_attr_not_required(void * hUserData, - char *attr) -{ -// struct ldb_module * module = hUserData; - - return FALSE; -} + /* Others are implicitly ignored */ + return 0; + } + + /* create linearized and normalized dns */ + dn = ldb_dn_linearize(local_ctx, msg->dn); + ndn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, msg->dn)); + if (dn == NULL || ndn == NULL) goto failed; + + query = lsqlite3_tprintf(local_ctx, + /* Begin the transaction */ + "BEGIN EXCLUSIVE; " + /* Add new entry */ + "INSERT OR ABORT INTO ldb_entry " + "('dn', 'norm_dn') " + "VALUES ('%q', '%q');", + dn, ndn); + if (query == NULL) goto failed; + + ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_add: exec error: %s\n", errmsg); + free(errmsg); + } + lsqlite3_safe_rollback(lsqlite3->sqlite); + goto failed; + } + rollback = 1; + eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, ndn); + if (eid == -1) goto failed; -/* - * add a single set of ldap message values to a ldb_message - */ + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_message_element *el = &msg->elements[i]; + const struct ldb_attrib_handler *h; + char *attr; + int j; -static int -add_msg_attr(void * hTalloc, - long long eid, - const char * pDN, - const char * pAttrName, - const char * pAttrValue, - long long prevEID, - int * pAllocated, - struct ldb_message *** pppRes) -{ - void * x; - struct ldb_message * msg; - struct ldb_message_element * el; - - /* Is this a different EID than the previous one? */ - if (eid != prevEID) { - /* Yup. Add another result to the result array */ - if ((x = talloc_realloc(hTalloc, - *pAllocated == 0 ? NULL : *pppRes, - struct ldb_message *, - *pAllocated + 1)) == NULL) { - - return -1; - } - - /* Save the new result list */ - *pppRes = x; + /* Get a case-folded copy of the attribute name */ + attr = ldb_casefold(local_ctx, el->name); + if (attr == NULL) goto failed; - /* Allocate a new result structure */ - if ((x = talloc(*pppRes, struct ldb_message)) == NULL) { - return -1; - } + h = ldb_attrib_handler(module->ldb, el->name); - /* Save the new result */ - (*pppRes)[*pAllocated] = x; + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + struct ldb_val value; + char *insert; + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value); + if (value.data == NULL) goto failed; + + insert = lsqlite3_tprintf(local_ctx, + "INSERT OR ROLLBACK INTO ldb_attribute_values " + "('eid', 'attr_name', 'norm_attr_name'," + " 'attr_value', 'norm_attr_value') " + "VALUES ('%lld', '%q', '%q', '%q', '%q');", + eid, el->name, attr, + el->values[j].data, value.data); + if (insert == NULL) goto failed; + + ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_add: insert error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + } + } - /* Steal the initial result and put it in its own context */ - talloc_steal(NULL, *pppRes); + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_add: commit error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } - /* We've allocated one more result */ - ++*pAllocated; - - /* Ensure that the message is initialized */ - msg = x; - if ((msg->dn = talloc_strdup(msg, pDN)) == NULL) { - return -1; - } - msg->num_elements = 0; - msg->elements = NULL; - msg->private_data = NULL; - } else { - /* Same EID. Point to the previous most-recent message */ - msg = (*pppRes)[*pAllocated - 1]; - } - - if (pAttrName != NULL && pAttrValue != NULL) { - /* - * Point to the most recent previous element. (If there are none, - * this will point to non-allocated memory, but the pointer will - * never be dereferenced.) - */ - el = &msg->elements[msg->num_elements - 1]; - - /* - * See if the most recent previous element has the same attr_name - */ - if (msg->num_elements == 0 || strcmp(el->name, pAttrName) != 0) { - - /* It's a new attr_name. Allocate another message element */ - if ((el = talloc_realloc(msg, - msg->elements, - struct ldb_message_element, - msg->num_elements + 1)) == NULL) { - return -1; - } - - /* Save the new element */ - msg->elements = el; - - /* Save the attribute name */ - if ((el->name = - talloc_strdup(msg->elements, pAttrName)) == NULL) { - - return -1; - } - - /* There's now one additional element */ - msg->num_elements++; - - /* No flags */ - el->flags = 0; - - /* Initialize number of attribute values for this type */ - el->num_values = 0; - el->values = NULL; - } - - /* Increase the value array size by 1 */ - if ((el->values = - talloc_realloc(el, - el->num_values == 0 ? NULL : el->values, - struct ldb_val, - el->num_values + 1)) == NULL) { - return -1; - } - - /* Save the new attribute value length */ - el->values[el->num_values].length = strlen(pAttrValue); - - /* Copy the new attribute value */ - if ((el->values[el->num_values].data = - talloc_memdup(el->values, - pAttrValue, - el->values[el->num_values].length)) == NULL) { - return -1; - } - - /* We now have one additional value of this type */ - el->num_values++; - } - - return 0; + talloc_free(local_ctx); + return 0; + +failed: + if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite); + talloc_free(local_ctx); + return -1; } -static char * -parsetree_to_sql(struct ldb_module *module, - char * hTalloc, - const struct ldb_parse_tree *t) + +/* modify a record */ +static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) { - int i; - char * pNormalizedDN; - char * child; - char * p; - char * ret = NULL; - char * pAttrName; - - - switch(t->operation) { - case LDB_OP_SIMPLE: - break; - - case LDB_OP_EXTENDED: -#warning "work out how to handle bitops" - return NULL; + TALLOC_CTX *local_ctx; + struct lsqlite3_private *lsqlite3 = module->private_data; + long long eid; + char *errmsg; + int rollback = 0; + int ret; + int i; + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_modify local context"); + if (local_ctx == NULL) { + return -1; + } - case LDB_OP_AND: - ret = parsetree_to_sql(module, - hTalloc, - t->u.list.elements[0]); - - for (i = 1; i < t->u.list.num_elements; i++) { - child = - parsetree_to_sql( - module, - hTalloc, - t->u.list.elements[i]); - ret = talloc_asprintf_append(ret, - "INTERSECT\n" - "%s\n", - child); - talloc_free(child); - } - - child = ret; - ret = talloc_asprintf(hTalloc, - "SELECT * FROM (\n" - "%s\n" - ")\n", - child); - talloc_free(child); - return ret; - - case LDB_OP_OR: - ret = parsetree_to_sql(module, - hTalloc, - t->u.list.elements[0]); - - for (i = 1; i < t->u.list.num_elements; i++) { - child = - parsetree_to_sql( - module, - hTalloc, - t->u.list.elements[i]); - ret = talloc_asprintf_append(ret, - "UNION\n" - "%s\n", - child); - talloc_free(child); - } - child = ret; - ret = talloc_asprintf(hTalloc, - "SELECT * FROM (\n" - "%s\n" - ")\n", - child); - talloc_free(child); - return ret; - - case LDB_OP_NOT: - child = - parsetree_to_sql( - module, - hTalloc, - t->u.not.child); - ret = talloc_asprintf(hTalloc, - " SELECT eid\n" - " FROM ldb_entry\n" - " WHERE eid NOT IN (%s)\n", - child); - talloc_free(child); - return ret; - - default: - /* should never occur */ - abort(); - }; - - /* Get a case-folded copy of the attribute name */ - pAttrName = ldb_casefold((struct ldb_context *) module, - t->u.simple.attr); - - /* - * For simple searches, we want to retrieve the list of EIDs that - * match the criteria. - */ - if (t->u.simple.value.length == 1 && - (*(const char *) t->u.simple.value.data) == '*') { - /* - * Special case for "attr_name=*". In this case, we want the - * eid corresponding to all values in the specified attribute - * table. - */ - if ((p = sqlite3_mprintf(" SELECT eid\n" - " FROM ldb_attribute_values\n" - " WHERE attr_name = %Q", - pAttrName)) == NULL) { - return NULL; - } - - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { - printf("%s\n", p); - } + /* See if this is an ltdb special */ + if (ldb_dn_is_special(msg->dn)) { + struct ldb_dn *c; - ret = talloc_strdup(hTalloc, p); - sqlite3_free(p); + c = ldb_dn_explode(local_ctx, "@SUBCLASSES"); + if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { +#warning "modify subclasses into object class tree" + goto failed; + } - } else if (strcasecmp(t->u.simple.attr, "objectclass") == 0) { - /* - * For object classes, we want to search for all objectclasses - * that are subclasses as well. - */ - if ((p = sqlite3_mprintf( - " SELECT eid\n" - " FROM ldb_attribute_values\n" - " WHERE attr_name = 'OBJECTCLASS' " - " AND attr_value_normalized IN\n" - " (SELECT class_name\n" - " FROM ldb_object_classes\n" - " WHERE tree_key GLOB\n" - " (SELECT tree_key\n" - " FROM ldb_object_classes\n" - " WHERE class_name = upper(%Q)) " - " || '*')\n", - t->u.simple.value.data)) == NULL) { - return NULL; - } - - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { - printf("%s\n", p); - } + c = ldb_dn_explode(local_ctx, "@INDEXLIST"); + if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { +#warning "should we handle indexes somehow ?" + goto failed; + } - ret = talloc_strdup(hTalloc, p); - sqlite3_free(p); - - } else if (strcasecmp(t->u.simple.attr, "dn") == 0) { - pNormalizedDN = ldb_dn_fold(module->ldb, t->u.simple.value.data, - module, case_fold_attr_required); - if ((p = sqlite3_mprintf( - " SELECT eid\n" - " FROM ldb_attribute_values\n" - " WHERE attr_name = %Q\n" - " AND attr_value_normalized = %Q\n", - pAttrName, - pNormalizedDN)) == NULL) { - return NULL; - } - - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { - printf("%s\n", p); - } + /* Others are implicitly ignored */ + return 0; + } - ret = talloc_strdup(hTalloc, p); - sqlite3_free(p); - } else { - /* A normal query. */ - if ((p = sqlite3_mprintf( - " SELECT eid\n" - " FROM ldb_attribute_values\n" - " WHERE attr_name = %Q\n" - " AND attr_value_normalized = upper(%Q)\n", - pAttrName, - t->u.simple.value.data)) == NULL) { - return NULL; - } - - if (lsqlite3_debug & SQLITE3_DEBUG_QUERY) { - printf("%s\n", p); - } + ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN EXCLUSIVE;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_modify: error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + rollback = 1; - ret = talloc_strdup(hTalloc, p); - sqlite3_free(p); + eid = lsqlite3_get_eid(module, msg->dn); + if (eid == -1) { + goto failed; } - return ret; -} + for (i = 0; i < msg->num_elements; i++) { + const struct ldb_message_element *el = &msg->elements[i]; + const struct ldb_attrib_handler *h; + int flags = el->flags & LDB_FLAG_MOD_MASK; + char *attr; + char *mod; + int j; + + /* Get a case-folded copy of the attribute name */ + attr = ldb_casefold(local_ctx, el->name); + if (attr == NULL) { + goto failed; + } + h = ldb_attrib_handler(module->ldb, el->name); + + switch (flags) { + + case LDB_FLAG_MOD_REPLACE: + + /* remove all attributes before adding the replacements */ + mod = lsqlite3_tprintf(local_ctx, + "DELETE FROM ldb_attribute_values " + "WHERE eid = '%lld' " + "AND norm_attr_name = '%q';", + eid, attr); + if (mod == NULL) goto failed; + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_modify: error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } -static int -parsetree_to_attrlist(struct ldb_module *module, - const struct ldb_parse_tree * t) -{ - int i; - struct lsqlite3_private * lsqlite3 = module->private_data; - - switch(t->operation) { - case LDB_OP_SIMPLE: - break; - - case LDB_OP_EXTENDED: -#warning "work out how to handle bitops" - return -1; + /* MISSING break is INTENTIONAL */ + + case LDB_FLAG_MOD_ADD: +#warning "We should throw an error if no value is provided!" + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + struct ldb_val value; + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value); + if (value.data == NULL) { + goto failed; + } + + mod = lsqlite3_tprintf(local_ctx, + "INSERT OR ROLLBACK INTO ldb_attribute_values " + "('eid', 'attr_name', 'norm_attr_name'," + " 'attr_value', 'norm_attr_value') " + "VALUES ('%lld', '%q', '%q', '%q', '%q');", + eid, el->name, attr, + el->values[j].data, value.data); + + if (mod == NULL) goto failed; + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_modify: error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + } - case LDB_OP_AND: - if (parsetree_to_attrlist( - module, - t->u.list.elements[0]) != 0) { - return -1; - } - - for (i = 1; i < t->u.list.num_elements; i++) { - if (parsetree_to_attrlist( - module, - t->u.list.elements[i]) != 0) { - return -1; - } - } - - return 0; - - case LDB_OP_OR: - if (parsetree_to_attrlist( - module, - t->u.list.elements[0]) != 0) { - return -1; - } - - for (i = 1; i < t->u.list.num_elements; i++) { - if (parsetree_to_attrlist( - module, - t->u.list.elements[i]) != 0) { - return -1; - } - } - - return 0; - - case LDB_OP_NOT: - if (parsetree_to_attrlist(module, - t->u.not.child) != 0) { - return -1; - } - - return 0; - - default: - /* should never occur */ - abort(); - }; - - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT OR IGNORE INTO " FILTER_ATTR_TABLE "\n" - " (attr_name)\n" - " VALUES\n" - " (%Q);", - t->u.simple.attr); - return 0; -} + break; + + case LDB_FLAG_MOD_DELETE: +#warning "We should throw an error if the attribute we are trying to delete does not exist!" + if (el->num_values == 0) { + mod = lsqlite3_tprintf(local_ctx, + "DELETE FROM ldb_attribute_values " + "WHERE eid = '%lld' " + "AND norm_attr_name = '%q';", + eid, attr); + if (mod == NULL) goto failed; + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_modify: error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + } + /* For each value of the specified attribute name... */ + for (j = 0; j < el->num_values; j++) { + struct ldb_val value; + + /* Get a canonicalised copy of the data */ + h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value); + if (value.data == NULL) { + goto failed; + } + + mod = lsqlite3_tprintf(local_ctx, + "DELETE FROM ldb_attribute_values " + "WHERE eid = '%lld' " + "AND norm_attr_name = '%q' " + "AND norm_attr_value = '%q';", + eid, attr, value.data); + + if (mod == NULL) goto failed; + + ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_modify: error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + } -/* - * Issue a series of SQL statements to implement the ADD/MODIFY/DELETE - * requests in the ldb_message - */ -static int -msg_to_sql(struct ldb_module * module, - const struct ldb_message * msg, - long long eid, - int use_flags) -{ - int flags; - char * pAttrName; - unsigned int i; - unsigned int j; - struct lsqlite3_private * lsqlite3 = module->private_data; - - for (i = 0; i < msg->num_elements; i++) { - const struct ldb_message_element *el = &msg->elements[i]; - - if (! use_flags) { - flags = LDB_FLAG_MOD_ADD; - } else { - flags = el->flags & LDB_FLAG_MOD_MASK; - } - - /* Get a case-folded copy of the attribute name */ - pAttrName = ldb_casefold((struct ldb_context *) module, - el->name); - - /* For each value of the specified attribute name... */ - for (j = 0; j < el->num_values; j++) { - - /* ... bind the attribute value, if necessary */ - switch (flags) { - case LDB_FLAG_MOD_ADD: - QUERY_NOROWS( - lsqlite3, - FALSE, - "INSERT INTO ldb_attribute_values\n" - " (eid,\n" - " attr_name,\n" - " attr_value,\n" - " attr_value_normalized)\n" - " VALUES\n" - " (%lld, %Q, %Q, upper(%Q));", - eid, - pAttrName, - el->values[j].data, /* FIX ME */ - el->values[j].data); - - /* Is this a special "objectclass"? */ - if (strcasecmp(pAttrName, - "objectclass") != 0) { - /* Nope. */ - break; - } - - /* Handle special "objectclass" type */ - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT OR IGNORE " - " INTO ldb_object_classes " - " (class_name, " - " parent_class_name) " - " VALUES " - " (upper(%Q), 'TOP');", - ldb_casefold(module, - el->values[j].data)); - break; - - case LDB_FLAG_MOD_REPLACE: - QUERY_NOROWS( - lsqlite3, - FALSE, - "UPDATE ldb_attribute_values\n" - " SET attr_value = %Q,\n" - " attr_value_normalized =\n" - " upper(%Q)\n" - " WHERE eid = %lld\n" - " AND attr_name = %Q;", - el->values[j].data, /* FIX ME */ - el->values[j].data, - eid, - pAttrName); - break; - - case LDB_FLAG_MOD_DELETE: - /* No additional parameters to this query */ - QUERY_NOROWS( - lsqlite3, - FALSE, - "DELETE FROM ldb_attribute_values" - " WHERE eid = %lld " - " AND attr_name = %Q " - " AND attr_value_normalized =\n" - " upper(%Q);", - eid, - el->name, - el->values[j].data); - break; - } + break; } } - - return 0; -} + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_modify: error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + + talloc_free(local_ctx); + return 0; +failed: + if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite); + talloc_free(local_ctx); + return -1; +} -static int -new_dn(struct ldb_module * module, - char * pDN, - long long * pEID) +/* delete a record */ +static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) { - int ret; - int bFirst; - int nComponent; - char * p; - char * pPartialDN; - char * pPartialNormalizedDN; - long long eid; - long long peid; - double t0 = 0; - double t1 = 0; - struct timeval tv; - struct timezone tz; - struct ldb_dn * pExplodedDN; - struct ldb_dn_component * pComponent; - struct ldb_context * ldb = module->ldb; - struct lsqlite3_private * lsqlite3 = module->private_data; - - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, &tz); - t0 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); - } + TALLOC_CTX *local_ctx; + struct lsqlite3_private *lsqlite3 = module->private_data; + long long eid; + char *errmsg; + char *query; + int ret; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(dn)) { + return 0; + } - /* Explode the DN */ - if ((pExplodedDN = - ldb_explode_dn(ldb, - pDN, - ldb, - case_fold_attr_not_required)) == NULL) { - return -1; - } - - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, NULL); - t1 = (double) tv.tv_sec + ((double) tv.tv_usec / 1000000.0); - printf("%1.6lf loc 1\n", t1 - t0); - t0 = t1; - } + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_delete local context"); + if (local_ctx == NULL) { + return -1; + } - /* Allocate a string to hold the partial DN of each component */ - if ((pPartialDN = talloc_strdup(ldb, "")) == NULL) { - return -1; - } - - if ((pPartialNormalizedDN = talloc_strdup(pPartialDN, "")) == NULL) { - return -1; - } + eid = lsqlite3_get_eid(module, dn); + if (eid == -1) goto failed; + + query = lsqlite3_tprintf(local_ctx, + /* Begin the transaction */ + "BEGIN EXCLUSIVE; " + /* Delete entry */ + "DELETE FROM ldb_entry WHERE eid = %lld; " + /* Delete attributes */ + "DELETE FROM ldb_attribute_values WHERE eid = %lld; " + /* Commit */ + "COMMIT;", + eid, eid); + if (query == NULL) goto failed; + + ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_delete: error getting eid: %s\n", errmsg); + free(errmsg); + } + lsqlite3_safe_rollback(lsqlite3->sqlite); + goto failed; + } + + talloc_free(local_ctx); + return 0; + +failed: + talloc_free(local_ctx); + return -1; +} + +/* rename a record */ +static int lsqlite3_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) +{ + TALLOC_CTX *local_ctx; + struct lsqlite3_private *lsqlite3 = module->private_data; + char *new_dn, *new_cdn, *old_cdn; + char *errmsg; + char *query; + int ret; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) { + return 0; + } + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_rename local context"); + if (local_ctx == NULL) { + return -1; + } + + /* create linearized and normalized dns */ + old_cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, olddn)); + new_cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, newdn)); + new_dn = ldb_dn_linearize(local_ctx, newdn); + if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) goto failed; + + /* build the SQL query */ + query = lsqlite3_tprintf(local_ctx, + "UPDATE ldb_entry SET dn = '%q', norm_dn = '%q' " + "WHERE norm_dn = '%q';", + new_dn, new_cdn, old_cdn); + if (query == NULL) goto failed; + + /* execute */ + ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_rename: sqlite3_exec error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + + /* clean up and exit */ + talloc_free(local_ctx); + return 0; + +failed: + talloc_free(local_ctx); + return -1; +} +/* return extended error information */ +static const char * +lsqlite3_errstring(struct ldb_module *module) +{ + struct lsqlite3_private * lsqlite3 = module->private_data; - /* For each component of the DN (starting with the last one)... */ -#warning "convert this loop to recursive, and search backwards instead" - eid = 0; + return sqlite3_errmsg(lsqlite3->sqlite); +} + + + + +/* + * Static functions + */ - for (nComponent = pExplodedDN->comp_num - 1, bFirst = TRUE; - nComponent >= 0; - nComponent--, bFirst = FALSE) { +static int initialize(struct lsqlite3_private *lsqlite3, const char *url) +{ + int ret; + long long queryInt; + const char *pTail; + sqlite3_stmt *stmt; + const char *schema = - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, NULL); - t1 = ((double) tv.tv_sec + - ((double) tv.tv_usec / 1000000.0)); - printf("%1.6lf loc 2\n", t1 - t0); - t0 = t1; - } - /* Point to the component */ - pComponent = pExplodedDN->components[nComponent]; + "CREATE TABLE ldb_info AS " + " SELECT 'LDB' AS database_type," + " '1.0' AS version;" - /* Add this component on to the partial DN to date */ - if ((p = talloc_asprintf(ldb, - "%s%s%s", - pComponent->component, - bFirst ? "" : ",", - pPartialDN)) == NULL) { - return -1; - } + /* + * The entry table holds the information about an entry. + * This table is used to obtain the EID of the entry and to + * support scope=one and scope=base. The parent and child + * table is included in the entry table since all the other + * attributes are dependent on EID. + */ + "CREATE TABLE ldb_entry " + "(" + " eid INTEGER PRIMARY KEY AUTOINCREMENT," + " dn TEXT UNIQUE NOT NULL," + " norm_dn TEXT UNIQUE NOT NULL" + ");" - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, NULL); - t1 = ((double) tv.tv_sec + - ((double) tv.tv_usec / 1000000.0)); - printf("%1.6lf loc 3\n", t1 - t0); - t0 = t1; - } + + "CREATE TABLE ldb_object_classes" + "(" + " class_name TEXT PRIMARY KEY," + " parent_class_name TEXT," + " tree_key TEXT UNIQUE," + " max_child_num INTEGER DEFAULT 0" + ");" - /* No need for the old partial DN any more */ - talloc_free(pPartialDN); + /* + * We keep a full listing of attribute/value pairs here + */ + "CREATE TABLE ldb_attribute_values" + "(" + " eid INTEGER REFERENCES ldb_entry," + " attr_name TEXT," + " norm_attr_name TEXT," + " attr_value TEXT," + " norm_attr_value TEXT " + ");" - /* Save the new partial DN */ - pPartialDN = p; - pPartialNormalizedDN = ldb_dn_fold(pPartialDN, - p, - module, - case_fold_attr_required); + + /* + * Indexes + */ + "CREATE INDEX ldb_attribute_values_eid_idx " + " ON ldb_attribute_values (eid);" - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, NULL); - t1 = ((double) tv.tv_sec + - ((double) tv.tv_usec / 1000000.0)); - printf("%1.6lf loc 4\n", t1 - t0); - t0 = t1; - } + "CREATE INDEX ldb_attribute_values_name_value_idx " + " ON ldb_attribute_values (attr_name, norm_attr_value);" + + /* - * Ensure that an entry is in the ldb_entry table for this - * component. + * Triggers */ - if ((ret = getEID(lsqlite3, - &eid, - pPartialNormalizedDN)) == SQLITE_DONE) { - - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT INTO ldb_entry\n" - " (peid, dn, normalized_dn)\n" - " VALUES\n" - " (%lld, %Q, %Q);", - eid, pPartialDN, pPartialNormalizedDN); - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, NULL); - t1 = ((double) tv.tv_sec + - ((double) tv.tv_usec / 1000000.0)); - printf("%1.6lf loc 5\n", t1 - t0); - t0 = t1; - } - - /* Get the EID of the just inserted row */ - eid = sqlite3_last_insert_rowid(lsqlite3->sqlite); - - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, NULL); - t1 = ((double) tv.tv_sec + - ((double) tv.tv_usec / 1000000.0)); - printf("%1.6lf loc 8\n", t1 - t0); - t0 = t1; - } + "CREATE TRIGGER ldb_object_classes_insert_tr" + " AFTER INSERT" + " ON ldb_object_classes" + " FOR EACH ROW" + " BEGIN" + " UPDATE ldb_object_classes" + " SET tree_key = COALESCE(tree_key, " + " (" + " SELECT tree_key || " + " (SELECT base160(max_child_num + 1)" + " FROM ldb_object_classes" + " WHERE class_name = " + " new.parent_class_name)" + " FROM ldb_object_classes " + " WHERE class_name = new.parent_class_name " + " ));" + " UPDATE ldb_object_classes " + " SET max_child_num = max_child_num + 1" + " WHERE class_name = new.parent_class_name;" + " END;" - /* Also add DN attribute */ - QUERY_NOROWS(lsqlite3, - FALSE, - "INSERT INTO ldb_attribute_values\n" - " (eid,\n" - " attr_name,\n" - " attr_value,\n" - " attr_value_normalized) " - " VALUES " - " (%lld, 'DN', %Q, %Q);", - eid, - pPartialDN, /* FIX ME */ - pPartialNormalizedDN); + /* + * Table initialization + */ - } else if (ret != SQLITE_OK) { - UNLOCK_DB(module, "rollback"); - return -1; - } + "INSERT INTO ldb_object_classes " + " (class_name, tree_key) " + " VALUES " + " ('TOP', '0001');" - /* Save the parent EID */ - peid = eid; + ; + + /* Skip protocol indicator of url */ + if (strncmp(url, "sqlite://", 9) != 0) { + return SQLITE_MISUSE; } - if (lsqlite3_debug & SQLITE3_DEBUG_NEWDN) { - gettimeofday(&tv, NULL); - t1 = ((double) tv.tv_sec + - ((double) tv.tv_usec / 1000000.0)); - printf("%1.6lf loc 9\n", t1 - t0); - t0 = t1; + /* Update pointer to just after the protocol indicator */ + url += 9; + + /* Try to open the (possibly empty/non-existent) database */ + if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) { + return ret; } - - /* Give 'em what they came for! */ - *pEID = eid; - return 0; -} - - -static unsigned char base160tab[161] = { - 48 ,49 ,50 ,51 ,52 ,53 ,54 ,55 ,56 ,57 , /* 0-9 */ - 58 ,59 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 , /* : ; A-H */ - 73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 , /* I-R */ - 83 ,84 ,85 ,86 ,87 ,88 ,89 ,90 ,97 ,98 , /* S-Z , a-b */ - 99 ,100,101,102,103,104,105,106,107,108, /* c-l */ - 109,110,111,112,113,114,115,116,117,118, /* m-v */ - 119,120,121,122,160,161,162,163,164,165, /* w-z, latin1 */ - 166,167,168,169,170,171,172,173,174,175, /* latin1 */ - 176,177,178,179,180,181,182,183,184,185, /* latin1 */ - 186,187,188,189,190,191,192,193,194,195, /* latin1 */ - 196,197,198,199,200,201,202,203,204,205, /* latin1 */ - 206,207,208,209,210,211,212,213,214,215, /* latin1 */ - 216,217,218,219,220,221,222,223,224,225, /* latin1 */ - 226,227,228,229,230,231,232,233,234,235, /* latin1 */ - 236,237,238,239,240,241,242,243,244,245, /* latin1 */ - 246,247,248,249,250,251,252,253,254,255, /* latin1 */ - '\0' -}; - - -/* - * base160() - * - * Convert an unsigned long integer into a base160 representation of the - * number. - * - * Parameters: - * val -- - * value to be converted - * - * result -- - * character array, 5 bytes long, into which the base160 representation - * will be placed. The result will be a four-digit representation of the - * number (with leading zeros prepended as necessary), and null - * terminated. - * - * Returns: - * Nothing - */ -static void -base160_sql(sqlite3_context * hContext, - int argc, - sqlite3_value ** argv) -{ - int i; - long long val; - char result[5]; - - val = sqlite3_value_int64(argv[0]); - - for (i = 3; i >= 0; i--) { + /* In case this is a new database, enable auto_vacuum */ + if (query_norows(lsqlite3, "PRAGMA auto_vacuum=1;") != 0) { + return -1; + } - result[i] = base160tab[val % 160]; - val /= 160; - } - - result[4] = '\0'; - - sqlite3_result_text(hContext, result, -1, SQLITE_TRANSIENT); -} - - -/* - * base160next_sql() - * - * This function enhances sqlite by adding a "base160_next()" function which is - * accessible via queries. - * - * Retrieve the next-greater number in the base160 sequence for the terminal - * tree node (the last four digits). Only one tree level (four digits) is - * operated on. - * - * Input: - * A character string: either an empty string (in which case no operation is - * performed), or a string of base160 digits with a length of a multiple of - * four digits. - * - * Output: - * Upon return, the trailing four digits (one tree level) will have been - * incremented by 1. - */ -static void -base160next_sql(sqlite3_context * hContext, - int argc, - sqlite3_value ** argv) -{ - int i; - int len; - unsigned char * pTab; - unsigned char * pBase160 = - strdup(sqlite3_value_text(argv[0])); - unsigned char * pStart = pBase160; - - /* - * We need a minimum of four digits, and we will always get a multiple - * of four digits. - */ - if (pBase160 != NULL && - (len = strlen(pBase160)) >= 4 && - len % 4 == 0) { - - if (pBase160 == NULL) { - - sqlite3_result_null(hContext); - return; - } - - pBase160 += strlen(pBase160) - 1; - - /* We only carry through four digits: one level in the tree */ - for (i = 0; i < 4; i++) { - - /* What base160 value does this digit have? */ - pTab = strchr(base160tab, *pBase160); + /* Establish a busy timeout of 30 seconds */ + if ((ret = sqlite3_busy_timeout(lsqlite3->sqlite, + 30000)) != SQLITE_OK) { + return ret; + } - /* Is there a carry? */ - if (pTab < base160tab + sizeof(base160tab) - 1) { + /* Create a function, callable from sql, to increment a tree_key */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite,/* handle */ + "base160_next", /* function name */ + 1, /* number of args */ + SQLITE_ANY, /* preferred text type */ + NULL, /* user data */ + base160next_sql, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } - /* - * Nope. Just increment this value and we're - * done. - */ - *pBase160 = *++pTab; - break; - } else { + /* Create a function, callable from sql, to convert int to base160 */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite,/* handle */ + "base160", /* function name */ + 1, /* number of args */ + SQLITE_ANY, /* preferred text type */ + NULL, /* user data */ + base160_sql, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; + } - /* - * There's a carry. This value gets - * base160tab[0], we decrement the buffer - * pointer to get the next higher-order digit, - * and continue in the loop. - */ - *pBase160-- = base160tab[0]; + /* Begin a transaction */ + if ((ret = query_norows(lsqlite3, "BEGIN EXCLUSIVE;")) != 0) { + return ret; + } + + /* Determine if this is a new database. No tables means it is. */ + if (query_int(lsqlite3, + &queryInt, + "SELECT COUNT(*)\n" + " FROM sqlite_master\n" + " WHERE type = 'table';") != 0) { + query_norows(lsqlite3, "ROLLBACK;"); + return -1; + } + + if (queryInt == 0) { + /* + * Create the database schema + */ + for (pTail = discard_const_p(char, schema); + pTail != NULL && *pTail != '\0'; + ) { + + if ((ret = sqlite3_prepare( + lsqlite3->sqlite, + pTail, + -1, + &stmt, + &pTail)) != SQLITE_OK || + (ret = sqlite3_step(stmt)) != SQLITE_DONE || + (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { + + query_norows(lsqlite3, "ROLLBACK;"); + (void) sqlite3_close(lsqlite3->sqlite); + return ret; } } - - sqlite3_result_text(hContext, - pStart, - strlen(pStart), - free); } else { - sqlite3_result_value(hContext, argv[0]); - if (pBase160 != NULL) { - free(pBase160); + /* + * Ensure that the database we opened is one of ours + */ + if (query_int(lsqlite3, + &queryInt, + "SELECT " + " (SELECT COUNT(*) = 2" + " FROM sqlite_master " + " WHERE type = 'table' " + " AND name IN " + " (" + " 'ldb_entry', " + " 'ldb_object_classes' " + " ) " + " ) " + " AND " + " (SELECT 1 " + " FROM ldb_info " + " WHERE database_type = 'LDB' " + " AND version = '1.0'" + " );") != 0 || + queryInt != 1) { + + /* It's not one that we created. See ya! */ + query_norows(lsqlite3, "ROLLBACK;"); + (void) sqlite3_close(lsqlite3->sqlite); + return SQLITE_MISUSE; } } -} + + /* + * Create a temporary table to hold attributes requested in the result + * set of a search. + */ + query_norows(lsqlite3, "DROP TABLE " RESULT_ATTR_TABLE ";\n"); + if ((ret = + query_norows(lsqlite3, + "CREATE " TEMPTAB " TABLE " RESULT_ATTR_TABLE "\n" + " (\n" + " attr_name TEXT PRIMARY KEY\n" + " );")) != 0) { + query_norows(lsqlite3, "ROLLBACK;"); + return ret; + } + /* Commit the transaction */ + if ((ret = query_norows(lsqlite3, "COMMIT;")) != 0) { + query_norows(lsqlite3, "ROLLBACK;"); + return ret; + } + + return SQLITE_OK; +} -#ifdef DEBUG_LOCKS -static int lock_debug(struct ldb_module * module, - const char * lockname, - const char * pFileName, - int linenum) +static int +destructor(void *p) { - int ret; - struct lsqlite3_private * lsqlite3 = module->private_data; + struct lsqlite3_private *lsqlite3 = p; + + if (lsqlite3->sqlite) { + sqlite3_close(lsqlite3->sqlite); + } + return 0; +} - printf("%s(%d): LOCK (%d) ", - pFileName, linenum, lsqlite3->lock_count); - ret = lsqlite3_lock(module, lockname); - printf("got %d\n", ret); - return ret; -} - -static int unlock_debug(struct ldb_module * module, - const char * lockname, - const char * pFileName, - int linenum) +/* + * Table of operations for the sqlite3 backend + */ +static const struct ldb_module_ops lsqlite3_ops = { + .name = "sqlite", + .search = lsqlite3_search, + .search_bytree = lsqlite3_search_bytree, + .add_record = lsqlite3_add, + .modify_record = lsqlite3_modify, + .delete_record = lsqlite3_delete, + .rename_record = lsqlite3_rename, + .named_lock = lsqlite3_lock, + .named_unlock = lsqlite3_unlock, + .errstring = lsqlite3_errstring +}; + +/* + * connect to the database + */ +int lsqlite3_connect(struct ldb_context *ldb, + const char *url, + unsigned int flags, + const char *options[]) { + int i; int ret; - struct lsqlite3_private * lsqlite3 = module->private_data; - - ret = lsqlite3_unlock(module, lockname); - printf("%s(%d): UNLOCK (%d) got %d\n", - pFileName, linenum, lsqlite3->lock_count, ret); - - return ret; + struct lsqlite3_private * lsqlite3 = NULL; + + lsqlite3 = talloc(ldb, struct lsqlite3_private); + if (!lsqlite3) { + goto failed; + } + + lsqlite3->sqlite = NULL; + lsqlite3->options = NULL; + lsqlite3->lock_count = 0; + + ret = initialize(lsqlite3, url); + if (ret != SQLITE_OK) { + goto failed; + } + + talloc_set_destructor(lsqlite3, destructor); + + ldb->modules = talloc(ldb, struct ldb_module); + if (!ldb->modules) { + goto failed; + } + ldb->modules->ldb = ldb; + ldb->modules->prev = ldb->modules->next = NULL; + ldb->modules->private_data = lsqlite3; + ldb->modules->ops = &lsqlite3_ops; + + if (options) { + /* + * take a copy of the options array, so we don't have to rely + * on the caller keeping it around (it might be dynamic) + */ + for (i=0;options[i];i++) ; + + lsqlite3->options = talloc_array(lsqlite3, char *, i+1); + if (!lsqlite3->options) { + goto failed; + } + + for (i=0;options[i];i++) { + + lsqlite3->options[i+1] = NULL; + lsqlite3->options[i] = + talloc_strdup(lsqlite3->options, options[i]); + if (!lsqlite3->options[i]) { + goto failed; + } + } + } + + return 0; + +failed: + if (lsqlite3->sqlite != NULL) { + (void) sqlite3_close(lsqlite3->sqlite); + } + talloc_free(lsqlite3); + return -1; } -#endif + -- cgit From 36d6ebf37602b1878801fdb34cea5e7c5c1197d5 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 14 Sep 2005 23:14:42 +0000 Subject: r10233: add commented PRAGMA to avoid fsyncs (This used to be commit e5d8d834600040793c1e45c7aaceb374df2b3839) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index e283e6b0c1..5cee239b5c 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1616,7 +1616,7 @@ static int initialize(struct lsqlite3_private *lsqlite3, const char *url) /* * Triggers */ - + "CREATE TRIGGER ldb_object_classes_insert_tr" " AFTER INSERT" " ON ldb_object_classes" @@ -1637,7 +1637,7 @@ static int initialize(struct lsqlite3_private *lsqlite3, const char *url) " SET max_child_num = max_child_num + 1" " WHERE class_name = new.parent_class_name;" " END;" - + /* * Table initialization */ @@ -1667,6 +1667,12 @@ static int initialize(struct lsqlite3_private *lsqlite3, const char *url) return -1; } + /* DANGEROUS + if (query_norows(lsqlite3, "PRAGMA synchronous = OFF;") != 0) { + return -1; + } + */ + /* Establish a busy timeout of 30 seconds */ if ((ret = sqlite3_busy_timeout(lsqlite3->sqlite, 30000)) != SQLITE_OK) { -- cgit From f77e859e484bee3ebb99dcaa2935a1a323ccfa6f Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 15 Sep 2005 07:23:15 +0000 Subject: r10236: fix (C) note (This used to be commit 466e6812c35af9096fea05520c6b59a19793c4d1) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 5cee239b5c..4a4a83090a 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2,6 +2,7 @@ ldb database library Copyright (C) Derrell Lipman 2005 + Copyright (C) Simo Sorce 2005 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released -- cgit From d8da5e4fb7534d2931a01bfc4b6f59bdca206c65 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 15 Sep 2005 23:10:07 +0000 Subject: r10251: some more work on ldb_sqlite3 I must say that writing a new module is a very good way to find lot of subtle bugs laying in the code We need more tests! commit oLschema2ldif.c to keep it safe from data losses (rm -fr :-) update test generic to reflect the fix made on comparsion functions (This used to be commit 4357a2db5eadb15519ed93b957b2bad25ebf2a7d) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 467 ++++++++++++++---------------- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 5 +- 2 files changed, 227 insertions(+), 245 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 4a4a83090a..1a855e0850 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -237,6 +237,7 @@ static char *parsetree_to_sql(struct ldb_module *module, char *wild_card_string; char *child, *tmp; char *ret = NULL; + char *attr; int i; @@ -251,7 +252,7 @@ static char *parsetree_to_sql(struct ldb_module *module, child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); if (child == NULL) return NULL; - tmp = talloc_asprintf_append(tmp, "INTERSECT %s ", child); + tmp = talloc_asprintf_append(tmp, " INTERSECT %s ", child); if (tmp == NULL) return NULL; } @@ -269,11 +270,11 @@ static char *parsetree_to_sql(struct ldb_module *module, child = parsetree_to_sql(module, mem_ctx, t->u.list.elements[i]); if (child == NULL) return NULL; - tmp = talloc_asprintf_append(tmp, "UNION %s ", child); + tmp = talloc_asprintf_append(tmp, " UNION %s ", child); if (tmp == NULL) return NULL; } - return talloc_asprintf(mem_ctx, "SELECT * FROM ( %s )", tmp); + return talloc_asprintf(mem_ctx, "SELECT * FROM ( %s ) ", tmp); case LDB_OP_NOT: @@ -282,14 +283,16 @@ static char *parsetree_to_sql(struct ldb_module *module, return talloc_asprintf(mem_ctx, "SELECT eid FROM ldb_entry " - "WHERE eid NOT IN ( %s )", child); + "WHERE eid NOT IN ( %s ) ", child); case LDB_OP_EQUALITY: /* * For simple searches, we want to retrieve the list of EIDs that * match the criteria. */ - h = ldb_attrib_handler(module->ldb, t->u.equality.attr); + attr = ldb_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); /* Get a canonicalised copy of the data */ h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); @@ -327,9 +330,9 @@ static char *parsetree_to_sql(struct ldb_module *module, /* A normal query. */ return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " - "WHERE norm_attr_name = upper('%q') " + "WHERE norm_attr_name = '%q' " "AND norm_attr_value = '%q'", - t->u.equality.attr, + attr, value.data); } @@ -342,7 +345,7 @@ static char *parsetree_to_sql(struct ldb_module *module, for (i = 0; t->u.substring.chunks[i]; i++) { wild_card_string = talloc_asprintf_append(wild_card_string, "%s*", - t->u.substring.chunks[i]); + t->u.substring.chunks[i]->data); if (wild_card_string == NULL) return NULL; } @@ -351,7 +354,9 @@ static char *parsetree_to_sql(struct ldb_module *module, wild_card_string[strlen(wild_card_string) - 1] = '\0'; } - h = ldb_attrib_handler(module->ldb, t->u.substring.attr); + attr = ldb_casefold(mem_ctx, t->u.substring.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); subval.data = wild_card_string; subval.length = strlen(wild_card_string) + 1; @@ -364,13 +369,15 @@ static char *parsetree_to_sql(struct ldb_module *module, return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " - "WHERE norm_attr_name = upper('%q') " + "WHERE norm_attr_name = '%q' " "AND norm_attr_value GLOB '%q'", - t->u.substring.attr, + attr, value.data); case LDB_OP_GREATER: - h = ldb_attrib_handler(module->ldb, t->u.equality.attr); + attr = ldb_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); /* Get a canonicalised copy of the data */ h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); @@ -380,13 +387,16 @@ static char *parsetree_to_sql(struct ldb_module *module, return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " - "WHERE norm_attr_name = upper('%q') " - "AND norm_attr_value >= '%q'", - t->u.equality.attr, - value.data); + "WHERE norm_attr_name = '%q' " + "AND norm_attr_value LIKE '>=%q' ESCAPE '%q' ", + attr, + value.data, + attr); case LDB_OP_LESS: - h = ldb_attrib_handler(module->ldb, t->u.equality.attr); + attr = ldb_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); /* Get a canonicalised copy of the data */ h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); @@ -396,23 +406,29 @@ static char *parsetree_to_sql(struct ldb_module *module, return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " - "WHERE norm_attr_name = upper('%q') " - "AND norm_attr_value <= '%q'", - t->u.equality.attr, - value.data); + "WHERE norm_attr_name = '%q' " + "AND norm_attr_value LIKE '<=%q' ESCAPE '%q' ", + attr, + value.data, + attr); case LDB_OP_PRESENT: - if (strcasecmp(t->u.present.attr, "dn")) { + if (strcasecmp(t->u.present.attr, "dn") == 0) { return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry"); } + attr = ldb_casefold(mem_ctx, t->u.present.attr); + if (attr == NULL) return NULL; + return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " - "WHERE norm_attr_name = upper('%q')", - t->u.present.attr); + "WHERE norm_attr_name = '%q' ", + attr); case LDB_OP_APPROX: - h = ldb_attrib_handler(module->ldb, t->u.equality.attr); + attr = ldb_casefold(mem_ctx, t->u.equality.attr); + if (attr == NULL) return NULL; + h = ldb_attrib_handler(module->ldb, attr); /* Get a canonicalised copy of the data */ h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); @@ -422,10 +438,11 @@ static char *parsetree_to_sql(struct ldb_module *module, return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " - "WHERE norm_attr_name = upper('%q') " - "AND norm_attr_value LIKE '%q'", - t->u.equality.attr, - value.data); + "WHERE norm_attr_name = '%q' " + "AND norm_attr_value LIKE '~%q' ESCAPE '%q' ", + attr, + value.data, + attr); case LDB_OP_EXTENDED: #warning "work out how to handle bitops" @@ -440,102 +457,6 @@ static char *parsetree_to_sql(struct ldb_module *module, return NULL; } - -/* - * query_norows() - * - * This function is used for queries that are not expected to return any rows, - * e.g. BEGIN, COMMIT, ROLLBACK, CREATE TABLE, INSERT, UPDATE, DELETE, etc. - * There are no provisions here for returning data from rows in a table, so do - * not pass SELECT queries to this function. - */ -static int -query_norows(const struct lsqlite3_private *lsqlite3, - const char *pSql, - ...) -{ - int ret; - int bLoop; - char * p; - sqlite3_stmt * pStmt; - va_list args; - - /* Begin access to variable argument list */ - va_start(args, pSql); - - /* Format the query */ - if ((p = sqlite3_vmprintf(pSql, args)) == NULL) { - return -1; - } - - /* - * Prepare and execute the SQL statement. Loop allows retrying on - * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes, - * requiring retrying the operation. - */ - for (bLoop = TRUE; bLoop; ) { - - /* Compile the SQL statement into sqlite virtual machine */ - if ((ret = sqlite3_prepare(lsqlite3->sqlite, - p, - -1, - &pStmt, - NULL)) == SQLITE_SCHEMA) { - if (stmtGetEID != NULL) { - sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - } - continue; - } else if (ret != SQLITE_OK) { - ret = -1; - break; - } - - /* No rows expected, so just step through machine code once */ - if ((ret = sqlite3_step(pStmt)) == SQLITE_SCHEMA) { - if (stmtGetEID != NULL) { - sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - } - (void) sqlite3_finalize(pStmt); - continue; - } else if (ret != SQLITE_DONE) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* Free the virtual machine */ - if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) { - if (stmtGetEID != NULL) { - sqlite3_finalize(stmtGetEID); - stmtGetEID = NULL; - } - continue; - } else if (ret != SQLITE_OK) { - (void) sqlite3_finalize(pStmt); - ret = -1; - break; - } - - /* - * Normal condition is only one time through loop. Loop is - * rerun in error conditions, via "continue", above. - */ - ret = 0; - bLoop = FALSE; - } - - /* All done with variable argument list */ - va_end(args); - - /* Free the memory we allocated for our query string */ - sqlite3_free(p); - - return ret; -} - - /* obtain a named lock */ static int lsqlite3_lock(struct ldb_module * module, @@ -683,6 +604,78 @@ query_int(const struct lsqlite3_private * lsqlite3, return ret; } +/* + * This is a bad hack to support ldap style comparisons whithin sqlite. + * This function substitues the X LIKE Y ESCAPE Z expression + * X is an expression + value to compare against (eg: ">=test") + * Y is the attribute in the row currently under test + * Z is the attribute name the value of which we want to test + */ + +static void lsqlite3_compare(sqlite3_context *ctx, int argc, + sqlite3_value **argv) +{ + struct ldb_context *ldb = (struct ldb_context *)sqlite3_user_data(ctx); + const unsigned char *X = sqlite3_value_text(argv[0]); + const unsigned char *Y = sqlite3_value_text(argv[1]); + const unsigned char *Z = sqlite3_value_text(argv[2]); + const unsigned char *p; + const struct ldb_attrib_handler *h; + struct ldb_val valX; + struct ldb_val valY; + int ret; + + switch (X[0]) { + /* greater */ + case '>': /* >= */ + p = &(X[2]); + h = ldb_attrib_handler(ldb, Z); + valX.data = p; + valX.length = strlen(p); + valY.data = Y; + valY.length = strlen(Y); + ret = h->comparison_fn(ldb, ldb, &valY, &valX); + if (ret >= 0) + sqlite3_result_int(ctx, 1); + else + sqlite3_result_int(ctx, 0); + return; + + /* lesser */ + case '<': /* <= */ + p = &(X[2]); + h = ldb_attrib_handler(ldb, Z); + valX.data = p; + valX.length = strlen(p); + valY.data = Y; + valY.length = strlen(Y); + ret = h->comparison_fn(ldb, ldb, &valY, &valX); + if (ret <= 0) + sqlite3_result_int(ctx, 1); + else + sqlite3_result_int(ctx, 0); + return; + + /* approx */ + case '~': + /* TODO */ + sqlite3_result_int(ctx, 0); + return; + + /* bitops */ + case ':': + /* TODO */ + sqlite3_result_int(ctx, 0); + return; + + default: + break; + } + + sqlite3_result_error(ctx, "Value must start with a special operation char (<>~:)!", -1); + return; +} + /* rename a record */ static int lsqlite3_safe_rollback(sqlite3 *sqlite) @@ -719,6 +712,7 @@ struct lsqlite3_msgs { int count; struct ldb_message **msgs; long long current_eid; + const char * const * attrs; TALLOC_CTX *mem_ctx; }; @@ -731,6 +725,7 @@ static int lsqlite3_search_callback(void *result, int col_num, char **cols, char struct lsqlite3_msgs *msgs = (struct lsqlite3_msgs *)result; struct ldb_message *msg; long long eid; + int i; /* eid, dn, attr_name, attr_value */ if (col_num != 4) return SQLITE_ABORT; @@ -763,6 +758,17 @@ static int lsqlite3_search_callback(void *result, int col_num, char **cols, char if (msg->dn == NULL) return SQLITE_ABORT; } + if (msgs->attrs) { + int found = 0; + for (i = 0; msgs->attrs[i]; i++) { + if (strcasecmp(cols[2], msgs->attrs[i]) == 0) { + found = 1; + break; + } + } + if (!found) return 0; + } + msg->elements = talloc_realloc(msg, msg->elements, struct ldb_message_element, @@ -862,7 +868,6 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d struct lsqlite3_private *lsqlite3 = module->private_data; struct lsqlite3_msgs msgs; char *norm_basedn; - char *attr_list; char *sqlfilter; char *errmsg; char *query; @@ -886,39 +891,6 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d /* Convert filter into a series of SQL conditions (constraints) */ sqlfilter = parsetree_to_sql(module, local_ctx, tree); - /* Initially, we don't know what the requested attributes are */ - if (attrs != NULL) { - attr_list = talloc_strdup(local_ctx, "AND norm_attr_name IN ("); - if (attr_list == NULL) goto failed; - - for (i = 0; attrs[i]; i++) { - char *norm_attr_name; - - /* If any attribute in the list is "*" then... */ - if (strcmp(attrs[i], "*") == 0) { - /* we want all attribute types */ - attr_list = talloc_strdup(local_ctx, ""); - if (attr_list == NULL) goto failed; - break; - } - - norm_attr_name = ldb_casefold(local_ctx, attrs[i]); - if (norm_attr_name == NULL) goto failed; - - attr_list = talloc_asprintf_append(attr_list, "'%q', ", - norm_attr_name); - if (attr_list == NULL) goto failed; - - } - - /* substitute the last ',' with ')' */ - attr_list[strlen(attr_list)-2] = ')'; - - } else { - attr_list = talloc_strdup(local_ctx, ""); - if (attr_list == NULL) goto failed; - } - switch(scope) { case LDB_SCOPE_DEFAULT: case LDB_SCOPE_SUBTREE: @@ -942,13 +914,10 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d " (%s)\n" " )\n" - " %s\n" - " ORDER BY entry.eid ASC;", norm_basedn, norm_basedn, - sqlfilter, - attr_list); + sqlfilter); } else { query = lsqlite3_tprintf(local_ctx, "SELECT entry.eid,\n" @@ -967,11 +936,8 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d " (%s)\n" " )\n" - " %s\n" - " ORDER BY entry.eid ASC;", - sqlfilter, - attr_list); + sqlfilter); } break; @@ -995,12 +961,9 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d " (%s)\n" " )\n" - " %s\n" - " ORDER BY entry.eid ASC;", norm_basedn, - sqlfilter, - attr_list); + sqlfilter); break; case LDB_SCOPE_ONELEVEL: @@ -1022,13 +985,10 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d " AND ldb_entry.eid IN\n(%s)\n" " )\n" - " %s\n" - " ORDER BY entry.eid ASC;", norm_basedn, norm_basedn, - sqlfilter, - attr_list); + sqlfilter); break; } @@ -1037,12 +997,15 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d goto failed; } - /* printf ("%s\n", query); */ + /* * / + printf ("%s\n", query); + / * */ msgs.msgs = NULL; msgs.count = 0; msgs.current_eid = 0; msgs.mem_ctx = local_ctx; + msgs.attrs = attrs; ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, &msgs, &errmsg); if (ret != SQLITE_OK) { @@ -1137,12 +1100,13 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg goto failed; } +/* c = ldb_dn_explode(local_ctx, "@INDEXLIST"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "should we handle indexes somehow ?" goto failed; } - +*/ /* Others are implicitly ignored */ return 0; } @@ -1554,13 +1518,23 @@ lsqlite3_errstring(struct ldb_module *module) * Static functions */ -static int initialize(struct lsqlite3_private *lsqlite3, const char *url) +static int initialize(struct lsqlite3_private *lsqlite3, + struct ldb_context *ldb, const char *url) { - int ret; + TALLOC_CTX *local_ctx; long long queryInt; - const char *pTail; - sqlite3_stmt *stmt; - const char *schema = + int rollback = 0; + char *errmsg; + char *schema; + int ret; + + /* create a local ctx */ + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_rename local context"); + if (local_ctx == NULL) { + return -1; + } + + schema = lsqlite3_tprintf(local_ctx, "CREATE TABLE ldb_info AS " @@ -1646,9 +1620,7 @@ static int initialize(struct lsqlite3_private *lsqlite3, const char *url) "INSERT INTO ldb_object_classes " " (class_name, tree_key) " " VALUES " - " ('TOP', '0001');" - - ; + " ('TOP', '0001');"); /* Skip protocol indicator of url */ if (strncmp(url, "sqlite://", 9) != 0) { @@ -1664,15 +1636,26 @@ static int initialize(struct lsqlite3_private *lsqlite3, const char *url) } /* In case this is a new database, enable auto_vacuum */ - if (query_norows(lsqlite3, "PRAGMA auto_vacuum=1;") != 0) { - return -1; - } + ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA auto_vacuum = 1;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } - /* DANGEROUS - if (query_norows(lsqlite3, "PRAGMA synchronous = OFF;") != 0) { - return -1; - } - */ + /* DANGEROUS */ + ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + + /* */ /* Establish a busy timeout of 30 seconds */ if ((ret = sqlite3_busy_timeout(lsqlite3->sqlite, @@ -1708,43 +1691,52 @@ static int initialize(struct lsqlite3_private *lsqlite3, const char *url) return ret; } - /* Begin a transaction */ - if ((ret = query_norows(lsqlite3, "BEGIN EXCLUSIVE;")) != 0) { - return ret; + /* Create a function, callable from sql, to perform various comparisons */ + if ((ret = + sqlite3_create_function(lsqlite3->sqlite, /* handle */ + "like", /* function name */ + 3, /* number of args */ + SQLITE_ANY, /* preferred text type */ + ldb , /* user data */ + lsqlite3_compare, /* called func */ + NULL, /* step func */ + NULL /* final func */ + )) != SQLITE_OK) { + return ret; } - + + /* Begin a transaction */ + ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN EXCLUSIVE;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3: initialization error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + rollback = 1; + /* Determine if this is a new database. No tables means it is. */ if (query_int(lsqlite3, &queryInt, "SELECT COUNT(*)\n" " FROM sqlite_master\n" " WHERE type = 'table';") != 0) { - query_norows(lsqlite3, "ROLLBACK;"); - return -1; + goto failed; } if (queryInt == 0) { /* * Create the database schema */ - for (pTail = discard_const_p(char, schema); - pTail != NULL && *pTail != '\0'; - ) { - - if ((ret = sqlite3_prepare( - lsqlite3->sqlite, - pTail, - -1, - &stmt, - &pTail)) != SQLITE_OK || - (ret = sqlite3_step(stmt)) != SQLITE_DONE || - (ret = sqlite3_finalize(stmt)) != SQLITE_OK) { - - query_norows(lsqlite3, "ROLLBACK;"); - (void) sqlite3_close(lsqlite3->sqlite); - return ret; - } - } + ret = sqlite3_exec(lsqlite3->sqlite, schema, NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } } else { /* * Ensure that the database we opened is one of ours @@ -1770,34 +1762,26 @@ static int initialize(struct lsqlite3_private *lsqlite3, const char *url) queryInt != 1) { /* It's not one that we created. See ya! */ - query_norows(lsqlite3, "ROLLBACK;"); - (void) sqlite3_close(lsqlite3->sqlite); - return SQLITE_MISUSE; + goto failed; } } - /* - * Create a temporary table to hold attributes requested in the result - * set of a search. - */ - query_norows(lsqlite3, "DROP TABLE " RESULT_ATTR_TABLE ";\n"); - if ((ret = - query_norows(lsqlite3, - "CREATE " TEMPTAB " TABLE " RESULT_ATTR_TABLE "\n" - " (\n" - " attr_name TEXT PRIMARY KEY\n" - " );")) != 0) { - query_norows(lsqlite3, "ROLLBACK;"); - return ret; - } - /* Commit the transaction */ - if ((ret = query_norows(lsqlite3, "COMMIT;")) != 0) { - query_norows(lsqlite3, "ROLLBACK;"); - return ret; - } - + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3: iniialization error: %s\n", errmsg); + free(errmsg); + } + goto failed; + } + return SQLITE_OK; + +failed: + if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite); + sqlite3_close(lsqlite3->sqlite); + return -1; } static int @@ -1848,9 +1832,8 @@ int lsqlite3_connect(struct ldb_context *ldb, lsqlite3->sqlite = NULL; lsqlite3->options = NULL; - lsqlite3->lock_count = 0; - ret = initialize(lsqlite3, url); + ret = initialize(lsqlite3, ldb, url); if (ret != SQLITE_OK) { goto failed; } diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h index 46ee1e93ba..46c949a564 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h @@ -1,7 +1,6 @@ #include struct lsqlite3_private { - char ** options; - sqlite3 * sqlite; - int lock_count; + char **options; + sqlite3 *sqlite; }; -- cgit From 5c708830bc07e1b59c063ae1c04b8fdf2b972318 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 16 Sep 2005 20:54:57 +0000 Subject: r10277: do not ovverride LIKE, thanks to derrel I found out how to do the same thing with a harmless user function (This used to be commit 158693b4064bd731aa4f6cdb2fde51d7aa596cf5) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 50 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 26 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 1a855e0850..f136fb7072 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -388,7 +388,7 @@ static char *parsetree_to_sql(struct ldb_module *module, return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " "WHERE norm_attr_name = '%q' " - "AND norm_attr_value LIKE '>=%q' ESCAPE '%q' ", + "AND ldap_compare(norm_attr_value, '>=', '%q', '%q') ", attr, value.data, attr); @@ -407,7 +407,7 @@ static char *parsetree_to_sql(struct ldb_module *module, return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " "WHERE norm_attr_name = '%q' " - "AND norm_attr_value LIKE '<=%q' ESCAPE '%q' ", + "AND ldap_compare(norm_attr_value, '<=', '%q', '%q') ", attr, value.data, attr); @@ -439,7 +439,7 @@ static char *parsetree_to_sql(struct ldb_module *module, return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_attribute_values " "WHERE norm_attr_name = '%q' " - "AND norm_attr_value LIKE '~%q' ESCAPE '%q' ", + "AND ldap_compare(norm_attr_value, '~%', 'q', '%q') ", attr, value.data, attr); @@ -606,34 +606,33 @@ query_int(const struct lsqlite3_private * lsqlite3, /* * This is a bad hack to support ldap style comparisons whithin sqlite. - * This function substitues the X LIKE Y ESCAPE Z expression - * X is an expression + value to compare against (eg: ">=test") - * Y is the attribute in the row currently under test - * Z is the attribute name the value of which we want to test + * val is the attribute in the row currently under test + * func is the desired test "<=" ">=" "~" ":" + * cmp is the value to compare against (eg: "test") + * attr is the attribute name the value of which we want to test */ static void lsqlite3_compare(sqlite3_context *ctx, int argc, sqlite3_value **argv) { struct ldb_context *ldb = (struct ldb_context *)sqlite3_user_data(ctx); - const unsigned char *X = sqlite3_value_text(argv[0]); - const unsigned char *Y = sqlite3_value_text(argv[1]); - const unsigned char *Z = sqlite3_value_text(argv[2]); - const unsigned char *p; + const unsigned char *val = sqlite3_value_text(argv[0]); + const unsigned char *func = sqlite3_value_text(argv[1]); + const unsigned char *cmp = sqlite3_value_text(argv[2]); + const unsigned char *attr = sqlite3_value_text(argv[3]); const struct ldb_attrib_handler *h; struct ldb_val valX; struct ldb_val valY; int ret; - switch (X[0]) { + switch (func[0]) { /* greater */ case '>': /* >= */ - p = &(X[2]); - h = ldb_attrib_handler(ldb, Z); - valX.data = p; - valX.length = strlen(p); - valY.data = Y; - valY.length = strlen(Y); + h = ldb_attrib_handler(ldb, attr); + valX.data = cmp; + valX.length = strlen(cmp); + valY.data = val; + valY.length = strlen(val); ret = h->comparison_fn(ldb, ldb, &valY, &valX); if (ret >= 0) sqlite3_result_int(ctx, 1); @@ -643,12 +642,11 @@ static void lsqlite3_compare(sqlite3_context *ctx, int argc, /* lesser */ case '<': /* <= */ - p = &(X[2]); - h = ldb_attrib_handler(ldb, Z); - valX.data = p; - valX.length = strlen(p); - valY.data = Y; - valY.length = strlen(Y); + h = ldb_attrib_handler(ldb, attr); + valX.data = cmp; + valX.length = strlen(cmp); + valY.data = val; + valY.length = strlen(val); ret = h->comparison_fn(ldb, ldb, &valY, &valX); if (ret <= 0) sqlite3_result_int(ctx, 1); @@ -1694,8 +1692,8 @@ static int initialize(struct lsqlite3_private *lsqlite3, /* Create a function, callable from sql, to perform various comparisons */ if ((ret = sqlite3_create_function(lsqlite3->sqlite, /* handle */ - "like", /* function name */ - 3, /* number of args */ + "ldap_compare", /* function name */ + 4, /* number of args */ SQLITE_ANY, /* preferred text type */ ldb , /* user data */ lsqlite3_compare, /* called func */ -- cgit From 8919d6bf9a88ce9ac43dae61989c33082c984b66 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 17 Sep 2005 19:25:50 +0000 Subject: r10299: remove the public (un)lock functions and introduce a transaction based private ldb API ldb_sqlite3 is already working with this model and ldb_tdb will do as soon as tridge finishes the tdb transaction code. currently the transactions are always implicit and wrap any single ldb API call except searching, the transaction functions are currently not made public on purpose. Simo. (This used to be commit 1da4ac2cdcb7e54076f85242a93784260dced918) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 159 +++++++++++------------------- 1 file changed, 55 insertions(+), 104 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index f136fb7072..c0adab7bc3 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -457,57 +457,6 @@ static char *parsetree_to_sql(struct ldb_module *module, return NULL; } -/* obtain a named lock */ -static int -lsqlite3_lock(struct ldb_module * module, - const char * lockname) -{ - struct lsqlite3_private * lsqlite3 = module->private_data; - -/* FIXME - if (lockname == NULL) { - return -1; - } - - if (strcmp(lockname, "transaction") == 0) { - if (lsqlite3->lock_count == 0) { - if (query_norows(lsqlite3, "BEGIN EXCLUSIVE;") != 0) { - return -1; - } - } - ++lsqlite3->lock_count; - } -*/ - return 0; -} - -/* release a named lock */ -static int -lsqlite3_unlock(struct ldb_module *module, - const char *lockname) -{ - struct lsqlite3_private * lsqlite3 = module->private_data; - -/* FIXME - if (lockname == NULL) { - return -1; - } - - if (strcmp(lockname, "transaction") == 0) { - if (lsqlite3->lock_count == 1) { - if (query_norows(lsqlite3, "COMMIT;") != 0) { - query_norows(lsqlite3, "ROLLBACK;"); - } - } else if (lsqlite3->lock_count > 0) { - --lsqlite3->lock_count; - } - } else if (strcmp(lockname, "rollback") == 0) { - query_norows(lsqlite3, "ROLLBACK;"); - } -*/ - return 0; -} - /* * query_int() * @@ -685,7 +634,7 @@ static int lsqlite3_safe_rollback(sqlite3 *sqlite) ret = sqlite3_exec(sqlite, "ROLLBACK;", NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_safe_rollback: Serious Error: %s\n", errmsg); + printf("lsqlite3_safe_rollback: Error: %s\n", errmsg); free(errmsg); } return -1; @@ -1078,7 +1027,6 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg char *dn, *ndn; char *errmsg; char *query; - int rollback = 0; int ret; int i; @@ -1115,8 +1063,6 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg if (dn == NULL || ndn == NULL) goto failed; query = lsqlite3_tprintf(local_ctx, - /* Begin the transaction */ - "BEGIN EXCLUSIVE; " /* Add new entry */ "INSERT OR ABORT INTO ldb_entry " "('dn', 'norm_dn') " @@ -1130,10 +1076,8 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg printf("lsqlite3_add: exec error: %s\n", errmsg); free(errmsg); } - lsqlite3_safe_rollback(lsqlite3->sqlite); goto failed; } - rollback = 1; eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, ndn); if (eid == -1) goto failed; @@ -1179,20 +1123,10 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg } } - ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - if (errmsg) { - printf("lsqlite3_add: commit error: %s\n", errmsg); - free(errmsg); - } - goto failed; - } - talloc_free(local_ctx); return 0; failed: - if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite); talloc_free(local_ctx); return -1; } @@ -1205,7 +1139,6 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * struct lsqlite3_private *lsqlite3 = module->private_data; long long eid; char *errmsg; - int rollback = 0; int ret; int i; @@ -1235,16 +1168,6 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * return 0; } - ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN EXCLUSIVE;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - if (errmsg) { - printf("lsqlite3_modify: error: %s\n", errmsg); - free(errmsg); - } - goto failed; - } - rollback = 1; - eid = lsqlite3_get_eid(module, msg->dn); if (eid == -1) { goto failed; @@ -1376,20 +1299,10 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * } } - ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - if (errmsg) { - printf("lsqlite3_modify: error: %s\n", errmsg); - free(errmsg); - } - goto failed; - } - talloc_free(local_ctx); return 0; failed: - if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite); talloc_free(local_ctx); return -1; } @@ -1419,14 +1332,10 @@ static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) if (eid == -1) goto failed; query = lsqlite3_tprintf(local_ctx, - /* Begin the transaction */ - "BEGIN EXCLUSIVE; " /* Delete entry */ "DELETE FROM ldb_entry WHERE eid = %lld; " /* Delete attributes */ - "DELETE FROM ldb_attribute_values WHERE eid = %lld; " - /* Commit */ - "COMMIT;", + "DELETE FROM ldb_attribute_values WHERE eid = %lld; ", eid, eid); if (query == NULL) goto failed; @@ -1436,7 +1345,6 @@ static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) printf("lsqlite3_delete: error getting eid: %s\n", errmsg); free(errmsg); } - lsqlite3_safe_rollback(lsqlite3->sqlite); goto failed; } @@ -1500,6 +1408,49 @@ failed: talloc_free(local_ctx); return -1; } + +static int lsqlite3_start_trans(struct ldb_module * module) +{ + int ret; + char *errmsg; + struct lsqlite3_private * lsqlite3 = module->private_data; + + ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN IMMEDIATE;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_start_trans: error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + + return 0; +} + +static int lsqlite3_end_trans(struct ldb_module *module, int status) +{ + int ret; + char *errmsg; + struct lsqlite3_private *lsqlite3 = module->private_data; + + if (status == 0) { + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_end_trans: error: %s\n", errmsg); + free(errmsg); + } + return -1; + } + } else { + return lsqlite3_safe_rollback(lsqlite3->sqlite); + } + + return 0; +} + + + /* return extended error information */ static const char * lsqlite3_errstring(struct ldb_module *module) @@ -1799,16 +1750,16 @@ destructor(void *p) * Table of operations for the sqlite3 backend */ static const struct ldb_module_ops lsqlite3_ops = { - .name = "sqlite", - .search = lsqlite3_search, - .search_bytree = lsqlite3_search_bytree, - .add_record = lsqlite3_add, - .modify_record = lsqlite3_modify, - .delete_record = lsqlite3_delete, - .rename_record = lsqlite3_rename, - .named_lock = lsqlite3_lock, - .named_unlock = lsqlite3_unlock, - .errstring = lsqlite3_errstring + .name = "sqlite", + .search = lsqlite3_search, + .search_bytree = lsqlite3_search_bytree, + .add_record = lsqlite3_add, + .modify_record = lsqlite3_modify, + .delete_record = lsqlite3_delete, + .rename_record = lsqlite3_rename, + .start_transaction = lsqlite3_start_trans, + .end_transaction = lsqlite3_end_trans, + .errstring = lsqlite3_errstring }; /* -- cgit From 16aff2a184f7fab64d718b356056070e305e99e9 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sun, 18 Sep 2005 18:49:06 +0000 Subject: r10305: start implementing better error handling changed the prioivate modules API error string are now not spread over all modules but are kept in a single place. This allows a better control of memory and error reporting. (This used to be commit 3fc676ac1d6f59d08bedbbd9377986154cf84ce4) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 216 +++++++++++++++++++----------- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 1 + 2 files changed, 136 insertions(+), 81 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index c0adab7bc3..8742b53962 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -36,6 +36,7 @@ #include #include "includes.h" #include "ldb/include/ldb.h" +#include "ldb/include/ldb_errors.h" #include "ldb/include/ldb_private.h" #include "ldb/ldb_sqlite3/ldb_sqlite3.h" @@ -828,12 +829,17 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d if (basedn) { norm_basedn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, basedn)); - if (norm_basedn == NULL) goto failed; + if (norm_basedn == NULL) { + ret = LDB_ERR_INVALID_DN_SYNTAX; + goto failed; + } } else norm_basedn = talloc_strdup(local_ctx, ""); if (*norm_basedn == '\0' && - (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) + (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) { + ret = LDB_ERR_UNWILLING_TO_PERFORM; goto failed; + } /* Convert filter into a series of SQL conditions (constraints) */ sqlfilter = parsetree_to_sql(module, local_ctx, tree); @@ -940,7 +946,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d } if (query == NULL) { - ret = -1; + ret = LDB_ERR_OTHER; goto failed; } @@ -957,15 +963,19 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, &msgs, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_search_bytree: Fatal Error: %s\n", errmsg); + ldb_set_errstring(module, talloc_strdup(module, errmsg)); free(errmsg); } + ret = LDB_ERR_OTHER; goto failed; } for (i = 0; i < msgs.count; i++) { msgs.msgs[i] = ldb_msg_canonicalize(module->ldb, msgs.msgs[i]); - if (msgs.msgs[i] == NULL) goto failed; + if (msgs.msgs[i] == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } } *res = talloc_steal(module, msgs.msgs); @@ -1033,7 +1043,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg /* create a local ctx */ local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_add local context"); if (local_ctx == NULL) { - return -1; + return LDB_ERR_OTHER; } /* See if this is an ltdb special */ @@ -1043,6 +1053,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg c = ldb_dn_explode(local_ctx, "@SUBCLASSES"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "insert subclasses into object class tree" + ret = LDB_ERR_UNWILLING_TO_PERFORM; goto failed; } @@ -1054,13 +1065,16 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg } */ /* Others are implicitly ignored */ - return 0; + return LDB_ERR_SUCCESS; } /* create linearized and normalized dns */ dn = ldb_dn_linearize(local_ctx, msg->dn); ndn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, msg->dn)); - if (dn == NULL || ndn == NULL) goto failed; + if (dn == NULL || ndn == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } query = lsqlite3_tprintf(local_ctx, /* Add new entry */ @@ -1068,19 +1082,26 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg "('dn', 'norm_dn') " "VALUES ('%q', '%q');", dn, ndn); - if (query == NULL) goto failed; + if (query == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_add: exec error: %s\n", errmsg); + ldb_set_errstring(module, talloc_strdup(module, errmsg)); free(errmsg); } + ret = LDB_ERR_OTHER; goto failed; } eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, ndn); - if (eid == -1) goto failed; + if (eid == -1) { + ret = LDB_ERR_OTHER; + goto failed; + } for (i = 0; i < msg->num_elements; i++) { const struct ldb_message_element *el = &msg->elements[i]; @@ -1090,7 +1111,10 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg /* Get a case-folded copy of the attribute name */ attr = ldb_casefold(local_ctx, el->name); - if (attr == NULL) goto failed; + if (attr == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } h = ldb_attrib_handler(module->ldb, el->name); @@ -1101,7 +1125,10 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg /* Get a canonicalised copy of the data */ h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value); - if (value.data == NULL) goto failed; + if (value.data == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } insert = lsqlite3_tprintf(local_ctx, "INSERT OR ROLLBACK INTO ldb_attribute_values " @@ -1110,25 +1137,29 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg "VALUES ('%lld', '%q', '%q', '%q', '%q');", eid, el->name, attr, el->values[j].data, value.data); - if (insert == NULL) goto failed; + if (insert == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_add: insert error: %s\n", errmsg); + ldb_set_errstring(module, talloc_strdup(module, errmsg)); free(errmsg); } + ret = LDB_ERR_OTHER; goto failed; } } } talloc_free(local_ctx); - return 0; + return LDB_ERR_SUCCESS; failed: talloc_free(local_ctx); - return -1; + return ret; } @@ -1145,7 +1176,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * /* create a local ctx */ local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_modify local context"); if (local_ctx == NULL) { - return -1; + return LDB_ERR_OTHER; } /* See if this is an ltdb special */ @@ -1155,21 +1186,17 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * c = ldb_dn_explode(local_ctx, "@SUBCLASSES"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "modify subclasses into object class tree" - goto failed; - } - - c = ldb_dn_explode(local_ctx, "@INDEXLIST"); - if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { -#warning "should we handle indexes somehow ?" + ret = LDB_ERR_UNWILLING_TO_PERFORM; goto failed; } /* Others are implicitly ignored */ - return 0; + return LDB_ERR_SUCCESS; } eid = lsqlite3_get_eid(module, msg->dn); if (eid == -1) { + ret = LDB_ERR_OTHER; goto failed; } @@ -1184,6 +1211,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * /* Get a case-folded copy of the attribute name */ attr = ldb_casefold(local_ctx, el->name); if (attr == NULL) { + ret = LDB_ERR_OTHER; goto failed; } @@ -1199,14 +1227,18 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * "WHERE eid = '%lld' " "AND norm_attr_name = '%q';", eid, attr); - if (mod == NULL) goto failed; + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_modify: error: %s\n", errmsg); + ldb_set_errstring(module, talloc_strdup(module, errmsg)); free(errmsg); } + ret = LDB_ERR_OTHER; goto failed; } @@ -1221,6 +1253,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * /* Get a canonicalised copy of the data */ h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value); if (value.data == NULL) { + ret = LDB_ERR_OTHER; goto failed; } @@ -1232,14 +1265,18 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * eid, el->name, attr, el->values[j].data, value.data); - if (mod == NULL) goto failed; + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_modify: error: %s\n", errmsg); + ldb_set_errstring(module, talloc_strdup(module, errmsg)); free(errmsg); } + ret = LDB_ERR_OTHER; goto failed; } } @@ -1254,14 +1291,18 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * "WHERE eid = '%lld' " "AND norm_attr_name = '%q';", eid, attr); - if (mod == NULL) goto failed; + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_modify: error: %s\n", errmsg); + ldb_set_errstring(module, talloc_strdup(module, errmsg)); free(errmsg); } + ret = LDB_ERR_OTHER; goto failed; } } @@ -1273,6 +1314,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * /* Get a canonicalised copy of the data */ h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value); if (value.data == NULL) { + ret = LDB_ERR_OTHER; goto failed; } @@ -1283,14 +1325,18 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * "AND norm_attr_value = '%q';", eid, attr, value.data); - if (mod == NULL) goto failed; + if (mod == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_modify: error: %s\n", errmsg); + ldb_set_errstring(module, talloc_strdup(module, errmsg)); free(errmsg); } + ret = LDB_ERR_OTHER; goto failed; } } @@ -1300,11 +1346,11 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * } talloc_free(local_ctx); - return 0; + return LDB_ERR_SUCCESS; failed: talloc_free(local_ctx); - return -1; + return ret; } /* delete a record */ @@ -1319,17 +1365,20 @@ static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) /* ignore ltdb specials */ if (ldb_dn_is_special(dn)) { - return 0; + return LDB_ERR_SUCCESS; } /* create a local ctx */ local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_delete local context"); if (local_ctx == NULL) { - return -1; + return LDB_ERR_OTHER; } eid = lsqlite3_get_eid(module, dn); - if (eid == -1) goto failed; + if (eid == -1) { + ret = LDB_ERR_OTHER; + goto failed; + } query = lsqlite3_tprintf(local_ctx, /* Delete entry */ @@ -1337,23 +1386,27 @@ static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) /* Delete attributes */ "DELETE FROM ldb_attribute_values WHERE eid = %lld; ", eid, eid); - if (query == NULL) goto failed; + if (query == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_delete: error getting eid: %s\n", errmsg); + ldb_set_errstring(module, talloc_strdup(module, errmsg)); free(errmsg); } + ret = LDB_ERR_OTHER; goto failed; } talloc_free(local_ctx); - return 0; + return LDB_ERR_SUCCESS; failed: talloc_free(local_ctx); - return -1; + return ret; } /* rename a record */ @@ -1368,45 +1421,52 @@ static int lsqlite3_rename(struct ldb_module *module, const struct ldb_dn *olddn /* ignore ltdb specials */ if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) { - return 0; + return LDB_ERR_SUCCESS; } /* create a local ctx */ local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_rename local context"); if (local_ctx == NULL) { - return -1; + return LDB_ERR_OTHER; } /* create linearized and normalized dns */ old_cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, olddn)); new_cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, newdn)); new_dn = ldb_dn_linearize(local_ctx, newdn); - if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) goto failed; + if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } /* build the SQL query */ query = lsqlite3_tprintf(local_ctx, "UPDATE ldb_entry SET dn = '%q', norm_dn = '%q' " "WHERE norm_dn = '%q';", new_dn, new_cdn, old_cdn); - if (query == NULL) goto failed; + if (query == NULL) { + ret = LDB_ERR_OTHER; + goto failed; + } /* execute */ ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - printf("lsqlite3_rename: sqlite3_exec error: %s\n", errmsg); + ldb_set_errstring(module, talloc_strdup(module, errmsg)); free(errmsg); } + ret = LDB_ERR_OTHER; goto failed; } /* clean up and exit */ talloc_free(local_ctx); - return 0; + return LDB_ERR_SUCCESS; failed: talloc_free(local_ctx); - return -1; + return ret; } static int lsqlite3_start_trans(struct ldb_module * module) @@ -1415,14 +1475,18 @@ static int lsqlite3_start_trans(struct ldb_module * module) char *errmsg; struct lsqlite3_private * lsqlite3 = module->private_data; - ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN IMMEDIATE;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - if (errmsg) { - printf("lsqlite3_start_trans: error: %s\n", errmsg); - free(errmsg); + if (lsqlite3->trans_count == 0) { + ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN IMMEDIATE;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_start_trans: error: %s\n", errmsg); + free(errmsg); + } + return -1; } - return -1; - } + }; + + lsqlite3->trans_count++; return 0; } @@ -1433,36 +1497,26 @@ static int lsqlite3_end_trans(struct ldb_module *module, int status) char *errmsg; struct lsqlite3_private *lsqlite3 = module->private_data; - if (status == 0) { - ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - if (errmsg) { - printf("lsqlite3_end_trans: error: %s\n", errmsg); - free(errmsg); + lsqlite3->trans_count--; + + if (lsqlite3->trans_count == 0) { + if (status == 0) { + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_end_trans: error: %s\n", errmsg); + free(errmsg); + } + return -1; } - return -1; + } else { + return lsqlite3_safe_rollback(lsqlite3->sqlite); } - } else { - return lsqlite3_safe_rollback(lsqlite3->sqlite); } return 0; } - - -/* return extended error information */ -static const char * -lsqlite3_errstring(struct ldb_module *module) -{ - struct lsqlite3_private * lsqlite3 = module->private_data; - - return sqlite3_errmsg(lsqlite3->sqlite); -} - - - - /* * Static functions */ @@ -1758,8 +1812,7 @@ static const struct ldb_module_ops lsqlite3_ops = { .delete_record = lsqlite3_delete, .rename_record = lsqlite3_rename, .start_transaction = lsqlite3_start_trans, - .end_transaction = lsqlite3_end_trans, - .errstring = lsqlite3_errstring + .end_transaction = lsqlite3_end_trans }; /* @@ -1781,6 +1834,7 @@ int lsqlite3_connect(struct ldb_context *ldb, lsqlite3->sqlite = NULL; lsqlite3->options = NULL; + lsqlite3->trans_count = 0; ret = initialize(lsqlite3, ldb, url); if (ret != SQLITE_OK) { diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h index 46c949a564..d14a1aa0e0 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h @@ -1,6 +1,7 @@ #include struct lsqlite3_private { + int trans_count; char **options; sqlite3 *sqlite; }; -- cgit From d78ea3e34abd30fb388c4cc39e12611e211416a6 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 22 Sep 2005 04:16:46 +0000 Subject: r10406: added --nosync option to all ldb tools, so that you can control if transactions are synchronous or not on the command line. add LDB_FLG_NOSYNC flag to ldb_connect() so we can make our temporary ldb databases non-synchronous (This used to be commit dba41164e0c52f1e4351bd9057b16661cee3a822) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 8742b53962..ac706291ef 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1522,7 +1522,7 @@ static int lsqlite3_end_trans(struct ldb_module *module, int status) */ static int initialize(struct lsqlite3_private *lsqlite3, - struct ldb_context *ldb, const char *url) + struct ldb_context *ldb, const char *url, int flags) { TALLOC_CTX *local_ctx; long long queryInt; @@ -1648,14 +1648,16 @@ static int initialize(struct lsqlite3_private *lsqlite3, goto failed; } - /* DANGEROUS */ - ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - if (errmsg) { - printf("lsqlite3 initializaion error: %s\n", errmsg); - free(errmsg); + if (flags & LDB_FLG_NOSYNC) { + /* DANGEROUS */ + ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3 initializaion error: %s\n", errmsg); + free(errmsg); + } + goto failed; } - goto failed; } /* */ @@ -1836,7 +1838,7 @@ int lsqlite3_connect(struct ldb_context *ldb, lsqlite3->options = NULL; lsqlite3->trans_count = 0; - ret = initialize(lsqlite3, ldb, url); + ret = initialize(lsqlite3, ldb, url, flags); if (ret != SQLITE_OK) { goto failed; } -- cgit From 63b43dd12fb579aaaccedd07aaa630cb1cd7aa88 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 24 Sep 2005 15:42:15 +0000 Subject: r10477: expose transactions outside ldb and change the API once more do not autostart transactions on ldb operations if a transaction is already in place test transactions on winsdb all my tests passes so far tridge please confirm this is ok for you (This used to be commit c2bb2a36bdbe0ec7519697a9a9ba7526a0defac2) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 56 +++++++++++++++++++------------ 1 file changed, 35 insertions(+), 21 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index ac706291ef..052b10f245 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1065,7 +1065,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg } */ /* Others are implicitly ignored */ - return LDB_ERR_SUCCESS; + return LDB_SUCCESS; } /* create linearized and normalized dns */ @@ -1155,7 +1155,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg } talloc_free(local_ctx); - return LDB_ERR_SUCCESS; + return LDB_SUCCESS; failed: talloc_free(local_ctx); @@ -1191,7 +1191,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * } /* Others are implicitly ignored */ - return LDB_ERR_SUCCESS; + return LDB_SUCCESS; } eid = lsqlite3_get_eid(module, msg->dn); @@ -1346,7 +1346,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * } talloc_free(local_ctx); - return LDB_ERR_SUCCESS; + return LDB_SUCCESS; failed: talloc_free(local_ctx); @@ -1365,7 +1365,7 @@ static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) /* ignore ltdb specials */ if (ldb_dn_is_special(dn)) { - return LDB_ERR_SUCCESS; + return LDB_SUCCESS; } /* create a local ctx */ @@ -1402,7 +1402,7 @@ static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) } talloc_free(local_ctx); - return LDB_ERR_SUCCESS; + return LDB_SUCCESS; failed: talloc_free(local_ctx); @@ -1421,7 +1421,7 @@ static int lsqlite3_rename(struct ldb_module *module, const struct ldb_dn *olddn /* ignore ltdb specials */ if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) { - return LDB_ERR_SUCCESS; + return LDB_SUCCESS; } /* create a local ctx */ @@ -1462,7 +1462,7 @@ static int lsqlite3_rename(struct ldb_module *module, const struct ldb_dn *olddn /* clean up and exit */ talloc_free(local_ctx); - return LDB_ERR_SUCCESS; + return LDB_SUCCESS; failed: talloc_free(local_ctx); @@ -1491,32 +1491,45 @@ static int lsqlite3_start_trans(struct ldb_module * module) return 0; } -static int lsqlite3_end_trans(struct ldb_module *module, int status) +static int lsqlite3_end_trans(struct ldb_module *module) { int ret; char *errmsg; struct lsqlite3_private *lsqlite3 = module->private_data; - lsqlite3->trans_count--; + if (lsqlite3->trans_count > 0) { + lsqlite3->trans_count--; + } else return -1; if (lsqlite3->trans_count == 0) { - if (status == 0) { - ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); - if (ret != SQLITE_OK) { - if (errmsg) { - printf("lsqlite3_end_trans: error: %s\n", errmsg); - free(errmsg); - } - return -1; + ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg); + if (ret != SQLITE_OK) { + if (errmsg) { + printf("lsqlite3_end_trans: error: %s\n", errmsg); + free(errmsg); } - } else { - return lsqlite3_safe_rollback(lsqlite3->sqlite); + return -1; } } return 0; } +static int lsqlite3_del_trans(struct ldb_module *module) +{ + struct lsqlite3_private *lsqlite3 = module->private_data; + + if (lsqlite3->trans_count > 0) { + lsqlite3->trans_count--; + } else return -1; + + if (lsqlite3->trans_count == 0) { + return lsqlite3_safe_rollback(lsqlite3->sqlite); + } + + return -1; +} + /* * Static functions */ @@ -1814,7 +1827,8 @@ static const struct ldb_module_ops lsqlite3_ops = { .delete_record = lsqlite3_delete, .rename_record = lsqlite3_rename, .start_transaction = lsqlite3_start_trans, - .end_transaction = lsqlite3_end_trans + .end_transaction = lsqlite3_end_trans, + .del_transaction = lsqlite3_del_trans }; /* -- cgit From 5fd031c97daaa1bf09a7ad80550753acd434075f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 6 Oct 2005 05:24:46 +0000 Subject: r10753: don't require every ldb module to implement both a search_bytree() and a search() function, instead each module now only implements the bytree method, and the expression based search is handled generically by the modules code. This makes for more consistency and less code duplication. fixed the tdb backend to handle BASE searches much more efficiently. They now always only lookup one record, regardless of the search expression (This used to be commit 7e44f9153c5578624e2fca04cdc0a00af0fd9eb4) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 40 +------------------------------ 1 file changed, 1 insertion(+), 39 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 052b10f245..1054722178 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -822,7 +822,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d int ret, i; /* create a local ctx */ - local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_search_by_tree local context"); + local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_search_bytree local context"); if (local_ctx == NULL) { return -1; } @@ -990,43 +990,6 @@ failed: return -1; } -/* search for matching records, by expression */ -static int lsqlite3_search(struct ldb_module * module, const struct ldb_dn *basedn, - enum ldb_scope scope, const char * expression, - const char * const *attrs, struct ldb_message *** res) -{ - struct ldb_parse_tree * tree; - int ret; - - /* Handle tdb specials */ - if (ldb_dn_is_special(basedn)) { -#warning "handle tdb specials" - return 0; - } - -#if 0 -/* (|(objectclass=*)(dn=*)) is passed by the command line tool now instead */ - /* Handle the special case of requesting all */ - if (pExpression != NULL && *pExpression == '\0') { - pExpression = "dn=*"; - } -#endif - - /* Parse the filter expression into a tree we can work with */ - if ((tree = ldb_parse_tree(module->ldb, expression)) == NULL) { - return -1; - } - - /* Now use the bytree function for the remainder of processing */ - ret = lsqlite3_search_bytree(module, basedn, scope, tree, attrs, res); - - /* Free the parse tree */ - talloc_free(tree); - - /* All done. */ - return ret; -} - /* add a record */ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg) @@ -1820,7 +1783,6 @@ destructor(void *p) */ static const struct ldb_module_ops lsqlite3_ops = { .name = "sqlite", - .search = lsqlite3_search, .search_bytree = lsqlite3_search_bytree, .add_record = lsqlite3_add, .modify_record = lsqlite3_modify, -- cgit From 5c9590587197dcb95007fdc54318187d5716c7c6 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 8 Nov 2005 00:11:45 +0000 Subject: r11567: Ldb API change patch. This patch changes the way lsb_search is called and the meaning of the returned integer. The last argument of ldb_search is changed from struct ldb_message to struct ldb_result which contains a pointer to a struct ldb_message list and a count of the number of messages. The return is not the count of messages anymore but instead it is an ldb error value. I tryed to keep the patch as tiny as possible bu as you can guess I had to change a good amount of places. I also tried to double check all my changes being sure that the calling functions would still behave as before. But this patch is big enough that I fear some bug may have been introduced anyway even if it passes the test suite. So if you are currently working on any file being touched please give it a deep look and blame me for any error. Simo. (This used to be commit 22c8c97e6fb466b41859e090e959d7f1134be780) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 54 ++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 11 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 1054722178..1d23478941 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -810,7 +810,7 @@ done: /* search for matching records, by tree */ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_dn* basedn, enum ldb_scope scope, struct ldb_parse_tree * tree, - const char * const * attrs, struct ldb_message *** res) + const char * const * attrs, struct ldb_result ** res) { TALLOC_CTX *local_ctx; struct lsqlite3_private *lsqlite3 = module->private_data; @@ -973,21 +973,25 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d for (i = 0; i < msgs.count; i++) { msgs.msgs[i] = ldb_msg_canonicalize(module->ldb, msgs.msgs[i]); if (msgs.msgs[i] == NULL) { - ret = LDB_ERR_OTHER; goto failed; } } - *res = talloc_steal(module, msgs.msgs); - ret = msgs.count; + *res = talloc(module, struct ldb_result); + if (! *res) { + goto failed; + } + + (*res)->msgs = talloc_steal(*res, msgs.msgs); + (*res)->count = msgs.count; talloc_free(local_ctx); - return ret; + return LDB_SUCCESS; /* If error, return error code; otherwise return number of results */ failed: talloc_free(local_ctx); - return -1; + return LDB_ERR_OTHER; } @@ -1777,17 +1781,45 @@ destructor(void *p) } +static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req) +{ + switch (req->operation) { + + case LDB_REQ_SEARCH: + return lsqlite3_search_bytree(module, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + req->op.search.res); + + case LDB_REQ_ADD: + return lsqlite3_add(module, req->op.add.message); + + case LDB_REQ_MODIFY: + return lsqlite3_modify(module, req->op.mod.message); + + case LDB_REQ_DELETE: + return lsqlite3_delete(module, req->op.del.dn); + + case LDB_REQ_RENAME: + return lsqlite3_rename(module, + req->op.rename.olddn, + req->op.rename.newdn); + + default: + return LDB_ERR_OPERATIONS_ERROR; + + } +} + /* * Table of operations for the sqlite3 backend */ static const struct ldb_module_ops lsqlite3_ops = { .name = "sqlite", - .search_bytree = lsqlite3_search_bytree, - .add_record = lsqlite3_add, - .modify_record = lsqlite3_modify, - .delete_record = lsqlite3_delete, - .rename_record = lsqlite3_rename, + .request = lsqlite3_request, .start_transaction = lsqlite3_start_trans, .end_transaction = lsqlite3_end_trans, .del_transaction = lsqlite3_del_trans -- cgit From c908d0b2aa111659e57a73efb8c33c413965c846 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 6 Jan 2006 04:01:23 +0000 Subject: r12733: Merge ldap/ldb controls into main tree There's still lot of work to do but the patch is stable enough to be pushed into the main samba4 tree. Simo. (This used to be commit 77125feaff252cab44d26593093a9c211c846ce8) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 1d23478941..464c8ce69f 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -984,6 +984,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d (*res)->msgs = talloc_steal(*res, msgs.msgs); (*res)->count = msgs.count; + (*res)->controls = NULL; talloc_free(local_ctx); return LDB_SUCCESS; @@ -1783,6 +1784,11 @@ destructor(void *p) static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req) { + /* check for oustanding critical controls and return an error if found */ + if (check_critical_controls(req->controls)) { + return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; + } + switch (req->operation) { case LDB_REQ_SEARCH: @@ -1791,7 +1797,7 @@ static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req) req->op.search.scope, req->op.search.tree, req->op.search.attrs, - req->op.search.res); + &req->op.search.res); case LDB_REQ_ADD: return lsqlite3_add(module, req->op.add.message); -- cgit From dbef4d76de92c3388f4e1819a76d6febf90be290 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 6 Jan 2006 16:12:45 +0000 Subject: r12743: Remove the ugly way we had to make a second stage init and introduce a second_stage_init private function for modules that need a second stage init. Simo. (This used to be commit 5e8b365fa2d93801a5de1d9ea76ce9d5546bd248) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 464c8ce69f..2e8b88a090 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1819,6 +1819,10 @@ static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req) } } +static int lsqlite3_init_2(struct ldb_module *module) +{ + return LDB_SUCCESS; +} /* * Table of operations for the sqlite3 backend @@ -1828,7 +1832,8 @@ static const struct ldb_module_ops lsqlite3_ops = { .request = lsqlite3_request, .start_transaction = lsqlite3_start_trans, .end_transaction = lsqlite3_end_trans, - .del_transaction = lsqlite3_del_trans + .del_transaction = lsqlite3_del_trans, + .second_stage_init = lsqlite3_init_2 }; /* -- cgit From 4d1c5a023cf6680474bd8d8be73f576d155cfe81 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 10 Jan 2006 16:48:32 +0000 Subject: r12829: fix ldb headers, to not include '<...>' files in .c files this helps in getting symbol -fvisibility=hidden (GCC 4 feature) working later. metze (This used to be commit 380938e97f31c7860aed1e73cc0110c6e17b472e) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 2e8b88a090..4c00998fa9 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -33,11 +33,9 @@ * Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend) */ -#include #include "includes.h" -#include "ldb/include/ldb.h" -#include "ldb/include/ldb_errors.h" -#include "ldb/include/ldb_private.h" +#include "ldb/include/includes.h" + #include "ldb/ldb_sqlite3/ldb_sqlite3.h" /* @@ -818,7 +816,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d char *norm_basedn; char *sqlfilter; char *errmsg; - char *query; + char *query = NULL; int ret, i; /* create a local ctx */ -- cgit From f5ebc8e404f4397c0ef2c8b838984df1767c955c Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 4 Feb 2006 00:38:48 +0000 Subject: r13324: From now on check attribute names obey rfc2251 Also add a way to provide utf8 compliant functions by registering them with ldb_set_utf8_fns() Next comes code to register samba internal utf8 functions. Simo. (This used to be commit ac9b8a41ffca8e06c5e849d544d3203a665b8e0d) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 38 ++++++++----------------------- 1 file changed, 10 insertions(+), 28 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 4c00998fa9..fbbbf037b3 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -289,7 +289,7 @@ static char *parsetree_to_sql(struct ldb_module *module, * For simple searches, we want to retrieve the list of EIDs that * match the criteria. */ - attr = ldb_casefold(mem_ctx, t->u.equality.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -353,7 +353,7 @@ static char *parsetree_to_sql(struct ldb_module *module, wild_card_string[strlen(wild_card_string) - 1] = '\0'; } - attr = ldb_casefold(mem_ctx, t->u.substring.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.substring.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -374,7 +374,7 @@ static char *parsetree_to_sql(struct ldb_module *module, value.data); case LDB_OP_GREATER: - attr = ldb_casefold(mem_ctx, t->u.equality.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -393,7 +393,7 @@ static char *parsetree_to_sql(struct ldb_module *module, attr); case LDB_OP_LESS: - attr = ldb_casefold(mem_ctx, t->u.equality.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -416,7 +416,7 @@ static char *parsetree_to_sql(struct ldb_module *module, return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry"); } - attr = ldb_casefold(mem_ctx, t->u.present.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.present.attr); if (attr == NULL) return NULL; return lsqlite3_tprintf(mem_ctx, @@ -425,7 +425,7 @@ static char *parsetree_to_sql(struct ldb_module *module, attr); case LDB_OP_APPROX: - attr = ldb_casefold(mem_ctx, t->u.equality.attr); + attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -715,26 +715,8 @@ static int lsqlite3_search_callback(void *result, int col_num, char **cols, char if (!found) return 0; } - msg->elements = talloc_realloc(msg, - msg->elements, - struct ldb_message_element, - msg->num_elements + 1); - if (msg->elements == NULL) return SQLITE_ABORT; - - msg->elements[msg->num_elements].flags = 0; - msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, cols[2]); - if (msg->elements[msg->num_elements].name == NULL) return SQLITE_ABORT; - - msg->elements[msg->num_elements].num_values = 1; - msg->elements[msg->num_elements].values = talloc_array(msg->elements, - struct ldb_val, 1); - if (msg->elements[msg->num_elements].values == NULL) return SQLITE_ABORT; - - msg->elements[msg->num_elements].values[0].length = strlen(cols[3]); - msg->elements[msg->num_elements].values[0].data = talloc_strdup(msg->elements, cols[3]); - if (msg->elements[msg->num_elements].values[0].data == NULL) return SQLITE_ABORT; - - msg->num_elements++; + if (ldb_msg_add_string(msg, cols[2], cols[3]) != 0) + return SQLITE_ABORT; return SQLITE_OK; } @@ -1076,7 +1058,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg int j; /* Get a case-folded copy of the attribute name */ - attr = ldb_casefold(local_ctx, el->name); + attr = ldb_casefold(module->ldb, local_ctx, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; goto failed; @@ -1175,7 +1157,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * int j; /* Get a case-folded copy of the attribute name */ - attr = ldb_casefold(local_ctx, el->name); + attr = ldb_casefold(module->ldb, local_ctx, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; goto failed; -- cgit From 04396c36d3ee8300b2b73ea8b43a45ea1b250828 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 4 Feb 2006 06:57:28 +0000 Subject: r13333: revert previous commit I will use ldb_caseless_cmp in attrib_handlers to correctly support utf8 comparisons add an ldb_attr_Casefold function for attribute names and use it instead of casefold in the right places (This used to be commit 3b4eb2413bbce059dde69f35c03cdc3cc2ba85c5) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index fbbbf037b3..3e24093118 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -289,7 +289,7 @@ static char *parsetree_to_sql(struct ldb_module *module, * For simple searches, we want to retrieve the list of EIDs that * match the criteria. */ - attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); + attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -353,7 +353,7 @@ static char *parsetree_to_sql(struct ldb_module *module, wild_card_string[strlen(wild_card_string) - 1] = '\0'; } - attr = ldb_casefold(module->ldb, mem_ctx, t->u.substring.attr); + attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.substring.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -374,7 +374,7 @@ static char *parsetree_to_sql(struct ldb_module *module, value.data); case LDB_OP_GREATER: - attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); + attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -393,7 +393,7 @@ static char *parsetree_to_sql(struct ldb_module *module, attr); case LDB_OP_LESS: - attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); + attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -416,7 +416,7 @@ static char *parsetree_to_sql(struct ldb_module *module, return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry"); } - attr = ldb_casefold(module->ldb, mem_ctx, t->u.present.attr); + attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.present.attr); if (attr == NULL) return NULL; return lsqlite3_tprintf(mem_ctx, @@ -425,7 +425,7 @@ static char *parsetree_to_sql(struct ldb_module *module, attr); case LDB_OP_APPROX: - attr = ldb_casefold(module->ldb, mem_ctx, t->u.equality.attr); + attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -1058,7 +1058,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg int j; /* Get a case-folded copy of the attribute name */ - attr = ldb_casefold(module->ldb, local_ctx, el->name); + attr = ldb_attr_casefold(module->ldb, local_ctx, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; goto failed; @@ -1157,7 +1157,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * int j; /* Get a case-folded copy of the attribute name */ - attr = ldb_casefold(module->ldb, local_ctx, el->name); + attr = ldb_attr_casefold(module->ldb, local_ctx, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; goto failed; -- cgit From 00fe70e5b917769418f68eaa255d3a06a9a08ce7 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 22 Feb 2006 01:31:35 +0000 Subject: r13609: Get in the initial work on making ldb async Currently only ldb_ildap is async, the plan is to first make all backend support the async calls, and then remove the sync functions from backends and keep the only in the API. Modules will need to be transformed along the way. Simo (This used to be commit 1e2c13b2d52de7c534493dd79a2c0596a3e8c1f5) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 3e24093118..48d849746f 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -964,6 +964,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d (*res)->msgs = talloc_steal(*res, msgs.msgs); (*res)->count = msgs.count; + (*res)->refs = NULL; (*res)->controls = NULL; talloc_free(local_ctx); -- cgit From d590dea10b3abf93fcc8138189291e8b66bae7d7 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 22 Feb 2006 05:21:43 +0000 Subject: r13615: Make ldb_set_errstring get ldb instead of module as parameter. The module was just used to get to the ldb so it was meningless. Also add LDB_WAIT_ONCE e relative code in ldb_ildap.c (This used to be commit d5b467b7c132b0bd4d23918ba7bf3370b1afcce8) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 48d849746f..aedba4e895 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -943,7 +943,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, &msgs, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1039,7 +1039,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1094,7 +1094,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1184,7 +1184,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1222,7 +1222,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1248,7 +1248,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1282,7 +1282,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1343,7 +1343,7 @@ static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1402,7 +1402,7 @@ static int lsqlite3_rename(struct ldb_module *module, const struct ldb_dn *olddn ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } ret = LDB_ERR_OTHER; -- cgit From e07f36a48cbc1b24192bddd3d27b164d52bfe31c Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 3 Mar 2006 22:52:38 +0000 Subject: r13826: Try to keep this backend updated This need more testing and to be built by default when possible (This used to be commit 76cbab0e252620ef6591e2a7354484660bbb6df5) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 638 +++++++++++++++++++++--------- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 7 - 2 files changed, 444 insertions(+), 201 deletions(-) delete mode 100644 source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index aedba4e895..bf6cf0951b 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -36,7 +36,55 @@ #include "includes.h" #include "ldb/include/includes.h" -#include "ldb/ldb_sqlite3/ldb_sqlite3.h" +#include + +struct lsqlite3_private { + int trans_count; + char **options; + sqlite3 *sqlite; +}; + +struct lsql_async_context { + struct ldb_module *module; + + /* search stuff */ + long long current_eid; + const char * const * attrs; + struct ldb_async_result *ares; + + /* async stuff */ + void *context; + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *); +}; + +static struct ldb_async_handle *init_lsql_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *)) +{ + struct lsql_async_context *ac; + struct ldb_async_handle *h; + + h = talloc_zero(lsqlite3, struct ldb_async_handle); + if (h == NULL) { + ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); + return NULL; + } + + ac = talloc(h, struct lsql_async_context); + if (ac == NULL) { + ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); + talloc_free(h); + return NULL; + } + + h->private_data = (void *)ac; + + ac->module = module; + ac->context = context; + ac->callback = callback; + + return h; +} /* * Macros used throughout @@ -78,7 +126,7 @@ static char *lsqlite3_tprintf(TALLOC_CTX *mem_ctx, const char *fmt, ...) return ret; } -static unsigned char base160tab[161] = { +static char base160tab[161] = { 48 ,49 ,50 ,51 ,52 ,53 ,54 ,55 ,56 ,57 , /* 0-9 */ 58 ,59 ,65 ,66 ,67 ,68 ,69 ,70 ,71 ,72 , /* : ; A-H */ 73 ,74 ,75 ,76 ,77 ,78 ,79 ,80 ,81 ,82 , /* I-R */ @@ -167,10 +215,9 @@ base160next_sql(sqlite3_context * hContext, { int i; int len; - unsigned char * pTab; - unsigned char * pBase160 = - strdup(sqlite3_value_text(argv[0])); - unsigned char * pStart = pBase160; + char * pTab; + char * pBase160 = strdup((const char *)sqlite3_value_text(argv[0])); + char * pStart = pBase160; /* * We need a minimum of four digits, and we will always get a multiple @@ -289,7 +336,7 @@ static char *parsetree_to_sql(struct ldb_module *module, * For simple searches, we want to retrieve the list of EIDs that * match the criteria. */ - attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr); + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -319,7 +366,7 @@ static char *parsetree_to_sql(struct ldb_module *module, /* DN query is a special ldb case */ char *cdn = ldb_dn_linearize_casefold(module->ldb, ldb_dn_explode(module->ldb, - value.data)); + (const char *)value.data)); return lsqlite3_tprintf(mem_ctx, "SELECT eid FROM ldb_entry " @@ -353,11 +400,11 @@ static char *parsetree_to_sql(struct ldb_module *module, wild_card_string[strlen(wild_card_string) - 1] = '\0'; } - attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.substring.attr); + attr = ldb_attr_casefold(mem_ctx, t->u.substring.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); - subval.data = wild_card_string; + subval.data = (void *)wild_card_string; subval.length = strlen(wild_card_string) + 1; /* Get a canonicalised copy of the data */ @@ -374,7 +421,7 @@ static char *parsetree_to_sql(struct ldb_module *module, value.data); case LDB_OP_GREATER: - attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr); + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -393,7 +440,7 @@ static char *parsetree_to_sql(struct ldb_module *module, attr); case LDB_OP_LESS: - attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr); + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -416,7 +463,7 @@ static char *parsetree_to_sql(struct ldb_module *module, return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry"); } - attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.present.attr); + attr = ldb_attr_casefold(mem_ctx, t->u.present.attr); if (attr == NULL) return NULL; return lsqlite3_tprintf(mem_ctx, @@ -425,7 +472,7 @@ static char *parsetree_to_sql(struct ldb_module *module, attr); case LDB_OP_APPROX: - attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr); + attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; h = ldb_attrib_handler(module->ldb, attr); @@ -564,10 +611,10 @@ static void lsqlite3_compare(sqlite3_context *ctx, int argc, sqlite3_value **argv) { struct ldb_context *ldb = (struct ldb_context *)sqlite3_user_data(ctx); - const unsigned char *val = sqlite3_value_text(argv[0]); - const unsigned char *func = sqlite3_value_text(argv[1]); - const unsigned char *cmp = sqlite3_value_text(argv[2]); - const unsigned char *attr = sqlite3_value_text(argv[3]); + const char *val = (const char *)sqlite3_value_text(argv[0]); + const char *func = (const char *)sqlite3_value_text(argv[1]); + const char *cmp = (const char *)sqlite3_value_text(argv[2]); + const char *attr = (const char *)sqlite3_value_text(argv[3]); const struct ldb_attrib_handler *h; struct ldb_val valX; struct ldb_val valY; @@ -577,9 +624,9 @@ static void lsqlite3_compare(sqlite3_context *ctx, int argc, /* greater */ case '>': /* >= */ h = ldb_attrib_handler(ldb, attr); - valX.data = cmp; + valX.data = (void *)cmp; valX.length = strlen(cmp); - valY.data = val; + valY.data = (void *)val; valY.length = strlen(val); ret = h->comparison_fn(ldb, ldb, &valY, &valX); if (ret >= 0) @@ -591,9 +638,9 @@ static void lsqlite3_compare(sqlite3_context *ctx, int argc, /* lesser */ case '<': /* <= */ h = ldb_attrib_handler(ldb, attr); - valX.data = cmp; + valX.data = (void *)cmp; valX.length = strlen(cmp); - valY.data = val; + valY.data = (void *)val; valY.length = strlen(val); ret = h->comparison_fn(ldb, ldb, &valY, &valX); if (ret <= 0) @@ -654,69 +701,72 @@ static int lsqlite3_eid_callback(void *result, int col_num, char **cols, char ** return SQLITE_OK; } -struct lsqlite3_msgs { - int count; - struct ldb_message **msgs; - long long current_eid; - const char * const * attrs; - TALLOC_CTX *mem_ctx; -}; - /* * add a single set of ldap message values to a ldb_message */ - static int lsqlite3_search_callback(void *result, int col_num, char **cols, char **names) { - struct lsqlite3_msgs *msgs = (struct lsqlite3_msgs *)result; + struct ldb_async_handle *handle = talloc_get_type(result, struct ldb_async_handle); + struct lsql_async_context *ac = talloc_get_type(handle->private_data, struct lsql_async_context); struct ldb_message *msg; long long eid; int i; /* eid, dn, attr_name, attr_value */ - if (col_num != 4) return SQLITE_ABORT; + if (col_num != 4) + return SQLITE_ABORT; eid = atoll(cols[0]); - if (eid != msgs->current_eid) { - msgs->msgs = talloc_realloc(msgs->mem_ctx, - msgs->msgs, - struct ldb_message *, - msgs->count + 2); - if (msgs->msgs == NULL) return SQLITE_ABORT; + if (eid != ac->current_eid) { /* here begin a new entry */ + + /* call the async callback for the last entry + * except the first time */ + if (ac->current_eid != 0) { + ac->ares->message = ldb_msg_canonicalize(ac->module->ldb, ac->ares->message); + if (ac->ares->message == NULL) + return SQLITE_ABORT; + + handle->status = ac->callback(ac->module->ldb, ac->context, ac->ares); + if (handle->status != LDB_SUCCESS) + return SQLITE_ABORT; + } - msgs->msgs[msgs->count] = talloc(msgs->msgs, struct ldb_message); - if (msgs->msgs[msgs->count] == NULL) return SQLITE_ABORT; + /* start over */ + ac->ares = talloc_zero(ac, struct ldb_async_result); + if (!ac->ares) + return SQLITE_ABORT; - msgs->msgs[msgs->count]->dn = NULL; - msgs->msgs[msgs->count]->num_elements = 0; - msgs->msgs[msgs->count]->elements = NULL; - msgs->msgs[msgs->count]->private_data = NULL; + ac->ares->message = ldb_msg_new(ac->ares); + if (!ac->ares->message) + return SQLITE_ABORT; - msgs->count++; - msgs->current_eid = eid; + ac->ares->type = LDB_REPLY_ENTRY; + ac->current_eid = eid; } - msg = msgs->msgs[msgs->count -1]; + msg = ac->ares->message; if (msg->dn == NULL) { msg->dn = ldb_dn_explode(msg, cols[1]); - if (msg->dn == NULL) return SQLITE_ABORT; + if (msg->dn == NULL) + return SQLITE_ABORT; } - if (msgs->attrs) { + if (ac->attrs) { int found = 0; - for (i = 0; msgs->attrs[i]; i++) { - if (strcasecmp(cols[2], msgs->attrs[i]) == 0) { + for (i = 0; ac->attrs[i]; i++) { + if (strcasecmp(cols[2], ac->attrs[i]) == 0) { found = 1; break; } } - if (!found) return 0; + if (!found) return SQLITE_OK; } - if (ldb_msg_add_string(msg, cols[2], cols[3]) != 0) + if (ldb_msg_add_string(msg, cols[2], cols[3]) != 0) { return SQLITE_ABORT; + } return SQLITE_OK; } @@ -787,33 +837,81 @@ done: * Interface functions referenced by lsqlite3_ops */ +static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares) +{ + struct ldb_result *res = NULL; + + if (!context) { + ldb_set_errstring(ldb, talloc_strdup(ldb, "NULL Context in callback")); + goto error; + } + + res = *((struct ldb_result **)context); + + if (!res || !ares) { + goto error; + } + + if (ares->type == LDB_REPLY_ENTRY) { + res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2); + if (! res->msgs) { + goto error; + } + + res->msgs[res->count + 1] = NULL; + + res->msgs[res->count] = talloc_steal(res->msgs, ares->message); + if (! res->msgs[res->count]) { + goto error; + } + + res->count++; + } else { + ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n"); + goto error; + } + + talloc_free(ares); + return LDB_SUCCESS; + +error: + if (ares) talloc_free(ares); + if (res) talloc_free(res); + if (context) *((struct ldb_result **)context) = NULL; + return LDB_ERR_OPERATIONS_ERROR; +} + /* search for matching records, by tree */ -static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_dn* basedn, - enum ldb_scope scope, struct ldb_parse_tree * tree, - const char * const * attrs, struct ldb_result ** res) +int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, + enum ldb_scope scope, struct ldb_parse_tree *tree, + const char * const *attrs, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + struct ldb_async_handle **handle) { - TALLOC_CTX *local_ctx; - struct lsqlite3_private *lsqlite3 = module->private_data; - struct lsqlite3_msgs msgs; + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_async_context *lsql_ac; char *norm_basedn; char *sqlfilter; char *errmsg; char *query = NULL; - int ret, i; + int ret; - /* create a local ctx */ - local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_search_bytree local context"); - if (local_ctx == NULL) { - return -1; + *handle = init_lsql_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + talloc_free(*handle); + return LDB_ERR_OPERATIONS_ERROR; } - if (basedn) { - norm_basedn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, basedn)); + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + + if (base) { + norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, base)); if (norm_basedn == NULL) { ret = LDB_ERR_INVALID_DN_SYNTAX; goto failed; } - } else norm_basedn = talloc_strdup(local_ctx, ""); + } else norm_basedn = talloc_strdup(lsql_ac, ""); if (*norm_basedn == '\0' && (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) { @@ -822,13 +920,13 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d } /* Convert filter into a series of SQL conditions (constraints) */ - sqlfilter = parsetree_to_sql(module, local_ctx, tree); + sqlfilter = parsetree_to_sql(module, lsql_ac, tree); switch(scope) { case LDB_SCOPE_DEFAULT: case LDB_SCOPE_SUBTREE: if (*norm_basedn != '\0') { - query = lsqlite3_tprintf(local_ctx, + query = lsqlite3_tprintf(lsql_ac, "SELECT entry.eid,\n" " entry.dn,\n" " av.attr_name,\n" @@ -852,7 +950,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d norm_basedn, sqlfilter); } else { - query = lsqlite3_tprintf(local_ctx, + query = lsqlite3_tprintf(lsql_ac, "SELECT entry.eid,\n" " entry.dn,\n" " av.attr_name,\n" @@ -876,7 +974,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d break; case LDB_SCOPE_BASE: - query = lsqlite3_tprintf(local_ctx, + query = lsqlite3_tprintf(lsql_ac, "SELECT entry.eid,\n" " entry.dn,\n" " av.attr_name,\n" @@ -900,7 +998,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d break; case LDB_SCOPE_ONELEVEL: - query = lsqlite3_tprintf(local_ctx, + query = lsqlite3_tprintf(lsql_ac, "SELECT entry.eid,\n" " entry.dn,\n" " av.attr_name,\n" @@ -926,7 +1024,6 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d } if (query == NULL) { - ret = LDB_ERR_OTHER; goto failed; } @@ -934,72 +1031,97 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d printf ("%s\n", query); / * */ - msgs.msgs = NULL; - msgs.count = 0; - msgs.current_eid = 0; - msgs.mem_ctx = local_ctx; - msgs.attrs = attrs; + lsql_ac->current_eid = 0; + lsql_ac->attrs = attrs; + lsql_ac->ares = NULL; + + (*handle)->state = LDB_ASYNC_PENDING; - ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, &msgs, &errmsg); + ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, *handle, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } - ret = LDB_ERR_OTHER; goto failed; } - for (i = 0; i < msgs.count; i++) { - msgs.msgs[i] = ldb_msg_canonicalize(module->ldb, msgs.msgs[i]); - if (msgs.msgs[i] == NULL) { + /* complete the last message if any */ + if (lsql_ac->ares) { + lsql_ac->ares->message = ldb_msg_canonicalize(module->ldb, lsql_ac->ares->message); + if (lsql_ac->ares->message == NULL) + goto failed; + + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares); + if ((*handle)->status != LDB_SUCCESS) goto failed; - } - } - - *res = talloc(module, struct ldb_result); - if (! *res) { - goto failed; } - (*res)->msgs = talloc_steal(*res, msgs.msgs); - (*res)->count = msgs.count; - (*res)->refs = NULL; - (*res)->controls = NULL; + (*handle)->state = LDB_ASYNC_DONE; - talloc_free(local_ctx); return LDB_SUCCESS; -/* If error, return error code; otherwise return number of results */ failed: - talloc_free(local_ctx); - return LDB_ERR_OTHER; + talloc_free(*handle); + return LDB_ERR_OPERATIONS_ERROR; } +static int lsql_search_bytree(struct ldb_module * module, const struct ldb_dn* base, + enum ldb_scope scope, struct ldb_parse_tree * tree, + const char * const * attrs, struct ldb_result ** res) +{ + struct ldb_async_handle *handle; + int ret; + + *res = talloc_zero(module, struct ldb_result); + if (! *res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = lsql_search_async(module, base, scope, tree, attrs, + res, &lsql_search_sync_callback, + &handle); + + if (ret == LDB_SUCCESS) { + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + talloc_free(handle); + } + + if (ret != LDB_SUCCESS) { + talloc_free(*res); + } + + return ret; +} /* add a record */ -static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg) +static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + struct ldb_async_handle **handle) { - TALLOC_CTX *local_ctx; - struct lsqlite3_private *lsqlite3 = module->private_data; + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_async_context *lsql_ac; long long eid; char *dn, *ndn; char *errmsg; char *query; - int ret; int i; - - /* create a local ctx */ - local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_add local context"); - if (local_ctx == NULL) { - return LDB_ERR_OTHER; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = init_lsql_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + goto failed; } + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { struct ldb_dn *c; - c = ldb_dn_explode(local_ctx, "@SUBCLASSES"); + c = ldb_dn_explode(lsql_ac, "@SUBCLASSES"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "insert subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; @@ -1018,14 +1140,14 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg } /* create linearized and normalized dns */ - dn = ldb_dn_linearize(local_ctx, msg->dn); - ndn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, msg->dn)); + dn = ldb_dn_linearize(lsql_ac, msg->dn); + ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, msg->dn)); if (dn == NULL || ndn == NULL) { ret = LDB_ERR_OTHER; goto failed; } - query = lsqlite3_tprintf(local_ctx, + query = lsqlite3_tprintf(lsql_ac, /* Add new entry */ "INSERT OR ABORT INTO ldb_entry " "('dn', 'norm_dn') " @@ -1046,7 +1168,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg goto failed; } - eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, ndn); + eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, lsql_ac, ndn); if (eid == -1) { ret = LDB_ERR_OTHER; goto failed; @@ -1059,7 +1181,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg int j; /* Get a case-folded copy of the attribute name */ - attr = ldb_attr_casefold(module->ldb, local_ctx, el->name); + attr = ldb_attr_casefold(lsql_ac, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; goto failed; @@ -1073,13 +1195,13 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg char *insert; /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value); + h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; goto failed; } - insert = lsqlite3_tprintf(local_ctx, + insert = lsqlite3_tprintf(lsql_ac, "INSERT OR ROLLBACK INTO ldb_attribute_values " "('eid', 'attr_name', 'norm_attr_name'," " 'attr_value', 'norm_attr_value') " @@ -1103,36 +1225,59 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg } } - talloc_free(local_ctx); + if (lsql_ac->callback) + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + return LDB_SUCCESS; failed: - talloc_free(local_ctx); + talloc_free(*handle); + return ret; +} + +static int lsql_add(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_async_handle *handle; + int ret; + + ret = lsql_add_async(module, msg, NULL, NULL, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); return ret; } /* modify a record */ -static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *msg) +static int lsql_modify_async(struct ldb_module *module, const struct ldb_message *msg, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + struct ldb_async_handle **handle) { - TALLOC_CTX *local_ctx; - struct lsqlite3_private *lsqlite3 = module->private_data; + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_async_context *lsql_ac; long long eid; char *errmsg; - int ret; int i; - - /* create a local ctx */ - local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_modify local context"); - if (local_ctx == NULL) { - return LDB_ERR_OTHER; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = init_lsql_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + goto failed; } + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { struct ldb_dn *c; - c = ldb_dn_explode(local_ctx, "@SUBCLASSES"); + c = ldb_dn_explode(lsql_ac, "@SUBCLASSES"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "modify subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; @@ -1158,7 +1303,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * int j; /* Get a case-folded copy of the attribute name */ - attr = ldb_attr_casefold(module->ldb, local_ctx, el->name); + attr = ldb_attr_casefold(lsql_ac, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; goto failed; @@ -1171,7 +1316,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * case LDB_FLAG_MOD_REPLACE: /* remove all attributes before adding the replacements */ - mod = lsqlite3_tprintf(local_ctx, + mod = lsqlite3_tprintf(lsql_ac, "DELETE FROM ldb_attribute_values " "WHERE eid = '%lld' " "AND norm_attr_name = '%q';", @@ -1200,13 +1345,13 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * struct ldb_val value; /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value); + h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; goto failed; } - mod = lsqlite3_tprintf(local_ctx, + mod = lsqlite3_tprintf(lsql_ac, "INSERT OR ROLLBACK INTO ldb_attribute_values " "('eid', 'attr_name', 'norm_attr_name'," " 'attr_value', 'norm_attr_value') " @@ -1235,7 +1380,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * case LDB_FLAG_MOD_DELETE: #warning "We should throw an error if the attribute we are trying to delete does not exist!" if (el->num_values == 0) { - mod = lsqlite3_tprintf(local_ctx, + mod = lsqlite3_tprintf(lsql_ac, "DELETE FROM ldb_attribute_values " "WHERE eid = '%lld' " "AND norm_attr_name = '%q';", @@ -1261,13 +1406,13 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * struct ldb_val value; /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value); + h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; goto failed; } - mod = lsqlite3_tprintf(local_ctx, + mod = lsqlite3_tprintf(lsql_ac, "DELETE FROM ldb_attribute_values " "WHERE eid = '%lld' " "AND norm_attr_name = '%q' " @@ -1294,42 +1439,60 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message * } } - talloc_free(local_ctx); + if (lsql_ac->callback) + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + return LDB_SUCCESS; failed: - talloc_free(local_ctx); + talloc_free(*handle); + return ret; +} + +static int lsql_modify(struct ldb_module *module, const struct ldb_message *msg) +{ + struct ldb_async_handle *handle; + int ret; + + ret = lsql_modify_async(module, msg, NULL, NULL, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); return ret; } /* delete a record */ -static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) +static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + struct ldb_async_handle **handle) { - TALLOC_CTX *local_ctx; - struct lsqlite3_private *lsqlite3 = module->private_data; + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_async_context *lsql_ac; long long eid; char *errmsg; char *query; - int ret; + int ret = LDB_ERR_OPERATIONS_ERROR; - /* ignore ltdb specials */ - if (ldb_dn_is_special(dn)) { - return LDB_SUCCESS; - } - /* create a local ctx */ - local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_delete local context"); - if (local_ctx == NULL) { - return LDB_ERR_OTHER; + *handle = init_lsql_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + goto failed; } + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; eid = lsqlite3_get_eid(module, dn); if (eid == -1) { - ret = LDB_ERR_OTHER; goto failed; } - query = lsqlite3_tprintf(local_ctx, + query = lsqlite3_tprintf(lsql_ac, /* Delete entry */ "DELETE FROM ldb_entry WHERE eid = %lld; " /* Delete attributes */ @@ -1346,55 +1509,76 @@ static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn) ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } - ret = LDB_ERR_OTHER; + ret = LDB_ERR_OPERATIONS_ERROR; goto failed; } - talloc_free(local_ctx); + if (lsql_ac->callback) + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + return LDB_SUCCESS; failed: - talloc_free(local_ctx); + talloc_free(*handle); return ret; } -/* rename a record */ -static int lsqlite3_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) +static int lsql_delete(struct ldb_module *module, const struct ldb_dn *dn) { - TALLOC_CTX *local_ctx; - struct lsqlite3_private *lsqlite3 = module->private_data; - char *new_dn, *new_cdn, *old_cdn; - char *errmsg; - char *query; + struct ldb_async_handle *handle; int ret; /* ignore ltdb specials */ - if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) { + if (ldb_dn_is_special(dn)) { return LDB_SUCCESS; } - /* create a local ctx */ - local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_rename local context"); - if (local_ctx == NULL) { - return LDB_ERR_OTHER; + ret = lsql_delete_async(module, dn, NULL, NULL, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; +} + +/* rename a record */ +static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), + struct ldb_async_handle **handle) +{ + struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); + struct lsql_async_context *lsql_ac; + char *new_dn, *new_cdn, *old_cdn; + char *errmsg; + char *query; + int ret = LDB_ERR_OPERATIONS_ERROR; + + *handle = init_lsql_handle(lsqlite3, module, context, callback); + if (*handle == NULL) { + goto failed; } + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + (*handle)->state = LDB_ASYNC_DONE; + (*handle)->status = LDB_SUCCESS; /* create linearized and normalized dns */ - old_cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, olddn)); - new_cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, newdn)); - new_dn = ldb_dn_linearize(local_ctx, newdn); + old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, olddn)); + new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, newdn)); + new_dn = ldb_dn_linearize(lsql_ac, newdn); if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) { - ret = LDB_ERR_OTHER; goto failed; } /* build the SQL query */ - query = lsqlite3_tprintf(local_ctx, + query = lsqlite3_tprintf(lsql_ac, "UPDATE ldb_entry SET dn = '%q', norm_dn = '%q' " "WHERE norm_dn = '%q';", new_dn, new_cdn, old_cdn); if (query == NULL) { - ret = LDB_ERR_OTHER; goto failed; } @@ -1405,20 +1589,43 @@ static int lsqlite3_rename(struct ldb_module *module, const struct ldb_dn *olddn ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); free(errmsg); } - ret = LDB_ERR_OTHER; + ret = LDB_ERR_OPERATIONS_ERROR; goto failed; } - /* clean up and exit */ - talloc_free(local_ctx); + if (lsql_ac->callback) + (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + return LDB_SUCCESS; failed: - talloc_free(local_ctx); + talloc_free(*handle); return ret; } -static int lsqlite3_start_trans(struct ldb_module * module) +static int lsql_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) +{ + struct ldb_async_handle *handle; + int ret; + + /* ignore ltdb specials */ + if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) { + return LDB_SUCCESS; + } + + + ret = lsql_rename_async(module, olddn, newdn, NULL, NULL, &handle); + + if (ret != LDB_SUCCESS) + return ret; + + ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + + talloc_free(handle); + return ret; +} + +static int lsql_start_trans(struct ldb_module * module) { int ret; char *errmsg; @@ -1440,7 +1647,7 @@ static int lsqlite3_start_trans(struct ldb_module * module) return 0; } -static int lsqlite3_end_trans(struct ldb_module *module) +static int lsql_end_trans(struct ldb_module *module) { int ret; char *errmsg; @@ -1464,7 +1671,7 @@ static int lsqlite3_end_trans(struct ldb_module *module) return 0; } -static int lsqlite3_del_trans(struct ldb_module *module) +static int lsql_del_trans(struct ldb_module *module) { struct lsqlite3_private *lsqlite3 = module->private_data; @@ -1762,10 +1969,19 @@ destructor(void *p) return 0; } +static int lsql_async_wait(struct ldb_module *module, struct ldb_async_handle *handle, enum ldb_async_wait_type type) +{ + return handle->status; +} -static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req) +static int lsql_request(struct ldb_module *module, struct ldb_request *req) { /* check for oustanding critical controls and return an error if found */ + + if (req->controls != NULL) { + ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_sqlite3 backend!\n"); + } + if (check_critical_controls(req->controls)) { return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; } @@ -1773,7 +1989,7 @@ static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req) switch (req->operation) { case LDB_REQ_SEARCH: - return lsqlite3_search_bytree(module, + return lsql_search_bytree(module, req->op.search.base, req->op.search.scope, req->op.search.tree, @@ -1781,40 +1997,74 @@ static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req) &req->op.search.res); case LDB_REQ_ADD: - return lsqlite3_add(module, req->op.add.message); + return lsql_add(module, req->op.add.message); case LDB_REQ_MODIFY: - return lsqlite3_modify(module, req->op.mod.message); + return lsql_modify(module, req->op.mod.message); case LDB_REQ_DELETE: - return lsqlite3_delete(module, req->op.del.dn); + return lsql_delete(module, req->op.del.dn); case LDB_REQ_RENAME: - return lsqlite3_rename(module, + return lsql_rename(module, req->op.rename.olddn, req->op.rename.newdn); + case LDB_ASYNC_SEARCH: + return lsql_search_async(module, + req->op.search.base, + req->op.search.scope, + req->op.search.tree, + req->op.search.attrs, + req->async.context, + req->async.callback, + &req->async.handle); +/* + case LDB_ASYNC_ADD: + return lsql_add_async(module, + req->op.add.message, + req->async.context, + req->async.callback, + &req->async.handle); + + case LDB_ASYNC_MODIFY: + return lsql_modify_async(module, + req->op.mod.message, + req->async.context, + req->async.callback, + &req->async.handle); +*/ + case LDB_ASYNC_DELETE: + return lsql_delete_async(module, + req->op.del.dn, + req->async.context, + req->async.callback, + &req->async.handle); + + case LDB_ASYNC_RENAME: + return lsql_rename_async(module, + req->op.rename.olddn, + req->op.rename.newdn, + req->async.context, + req->async.callback, + &req->async.handle); + default: return LDB_ERR_OPERATIONS_ERROR; } } -static int lsqlite3_init_2(struct ldb_module *module) -{ - return LDB_SUCCESS; -} - /* * Table of operations for the sqlite3 backend */ static const struct ldb_module_ops lsqlite3_ops = { .name = "sqlite", - .request = lsqlite3_request, - .start_transaction = lsqlite3_start_trans, - .end_transaction = lsqlite3_end_trans, - .del_transaction = lsqlite3_del_trans, - .second_stage_init = lsqlite3_init_2 + .request = lsql_request, + .start_transaction = lsql_start_trans, + .end_transaction = lsql_end_trans, + .del_transaction = lsql_del_trans, + .async_wait = lsql_async_wait, }; /* diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h deleted file mode 100644 index d14a1aa0e0..0000000000 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h +++ /dev/null @@ -1,7 +0,0 @@ -#include - -struct lsqlite3_private { - int trans_count; - char **options; - sqlite3 *sqlite; -}; -- cgit From 5d0aa16dfcf3047a52d3dd7e12ffb704a9725e83 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 5 Mar 2006 16:05:26 +0000 Subject: r13839: Use registration mechanism for backends as well (in the same sense my previous patch added it for modules). This is the next step towards LDB backends and modules as run-time loadable .so files. (This used to be commit fb2f70de4f6c4a9b13ad590cb4d3a9c858cede49) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index bf6cf0951b..883b21e0b5 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2070,7 +2070,7 @@ static const struct ldb_module_ops lsqlite3_ops = { /* * connect to the database */ -int lsqlite3_connect(struct ldb_context *ldb, +static int lsqlite3_connect(struct ldb_context *ldb, const char *url, unsigned int flags, const char *options[]) @@ -2137,3 +2137,7 @@ failed: return -1; } +int ldb_sqlite3_init(void) +{ + return ldb_register_backend("sqlite3", lsqlite3_connect); +} -- cgit From 7b82c4beb93375f79b6c06fc86bb31873baa187b Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 7 Mar 2006 21:08:09 +0000 Subject: r13992: change the way ldb_async_wait() works. I think I should change the name of this function to ldb_async_process(), any opinions ? (This used to be commit 3347322d1327cfa975ee9dccd4f2774e6e14fbcb) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 883b21e0b5..a8dc8fe3a2 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -70,6 +70,8 @@ static struct ldb_async_handle *init_lsql_handle(struct lsqlite3_private *lsqlit return NULL; } + h->module = module; + ac = talloc(h, struct lsql_async_context); if (ac == NULL) { ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); @@ -1969,7 +1971,7 @@ destructor(void *p) return 0; } -static int lsql_async_wait(struct ldb_module *module, struct ldb_async_handle *handle, enum ldb_async_wait_type type) +static int lsql_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type) { return handle->status; } -- cgit From 257598424e63c2cfa118b5ea84b7dc719d1dc5aa Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 7 Mar 2006 21:16:35 +0000 Subject: r13996: simplify ldb_async_wait() some more (This used to be commit ef1b3e6368179fe86ae07b8d00e4668090175551) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index a8dc8fe3a2..d9d9269de4 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1085,7 +1085,7 @@ static int lsql_search_bytree(struct ldb_module * module, const struct ldb_dn* b &handle); if (ret == LDB_SUCCESS) { - ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(handle, LDB_WAIT_ALL); talloc_free(handle); } @@ -1247,7 +1247,7 @@ static int lsql_add(struct ldb_module *module, const struct ldb_message *msg) if (ret != LDB_SUCCESS) return ret; - ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(handle, LDB_WAIT_ALL); talloc_free(handle); return ret; @@ -1461,7 +1461,7 @@ static int lsql_modify(struct ldb_module *module, const struct ldb_message *msg) if (ret != LDB_SUCCESS) return ret; - ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(handle, LDB_WAIT_ALL); talloc_free(handle); return ret; @@ -1540,7 +1540,7 @@ static int lsql_delete(struct ldb_module *module, const struct ldb_dn *dn) if (ret != LDB_SUCCESS) return ret; - ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(handle, LDB_WAIT_ALL); talloc_free(handle); return ret; @@ -1621,7 +1621,7 @@ static int lsql_rename(struct ldb_module *module, const struct ldb_dn *olddn, co if (ret != LDB_SUCCESS) return ret; - ret = ldb_async_wait(module->ldb, handle, LDB_WAIT_ALL); + ret = ldb_async_wait(handle, LDB_WAIT_ALL); talloc_free(handle); return ret; -- cgit From 3baf0606040419988f1a08c0da7f546c5904d8ca Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Fri, 10 Mar 2006 15:27:16 +0000 Subject: r14161: return early if we know the job is already finished (This used to be commit 09f6f552d73f782dc8d62cefad9c5f584b7b07d2) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index d9d9269de4..bcb830c38d 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -57,9 +57,9 @@ struct lsql_async_context { int (*callback)(struct ldb_context *, void *, struct ldb_async_result *); }; -static struct ldb_async_handle *init_lsql_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_async_result *)) +static struct ldb_async_handle *init_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, + void *context, + int (*callback)(struct ldb_context *, void *, struct ldb_async_result *)) { struct lsql_async_context *ac; struct ldb_async_handle *h; @@ -81,6 +81,9 @@ static struct ldb_async_handle *init_lsql_handle(struct lsqlite3_private *lsqlit h->private_data = (void *)ac; + h->state = LDB_ASYNC_INIT; + h->status = LDB_SUCCESS; + ac->module = module; ac->context = context; ac->callback = callback; @@ -899,7 +902,7 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, char *query = NULL; int ret; - *handle = init_lsql_handle(lsqlite3, module, context, callback); + *handle = init_handle(lsqlite3, module, context, callback); if (*handle == NULL) { talloc_free(*handle); return LDB_ERR_OPERATIONS_ERROR; @@ -1111,7 +1114,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, int i; int ret = LDB_ERR_OPERATIONS_ERROR; - *handle = init_lsql_handle(lsqlite3, module, context, callback); + *handle = init_handle(lsqlite3, module, context, callback); if (*handle == NULL) { goto failed; } @@ -1267,7 +1270,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message int i; int ret = LDB_ERR_OPERATIONS_ERROR; - *handle = init_lsql_handle(lsqlite3, module, context, callback); + *handle = init_handle(lsqlite3, module, context, callback); if (*handle == NULL) { goto failed; } @@ -1481,7 +1484,7 @@ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, int ret = LDB_ERR_OPERATIONS_ERROR; - *handle = init_lsql_handle(lsqlite3, module, context, callback); + *handle = init_handle(lsqlite3, module, context, callback); if (*handle == NULL) { goto failed; } @@ -1559,7 +1562,7 @@ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *old char *query; int ret = LDB_ERR_OPERATIONS_ERROR; - *handle = init_lsql_handle(lsqlite3, module, context, callback); + *handle = init_handle(lsqlite3, module, context, callback); if (*handle == NULL) { goto failed; } -- cgit From 971d30bb201f5c3faff5f575d26882eb79f7955a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 24 May 2006 07:34:11 +0000 Subject: r15854: more talloc_set_destructor() typesafe fixes (This used to be commit 61c6100617589ac6df4f527877241464cacbf8b3) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index bcb830c38d..06b76e812d 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1963,11 +1963,8 @@ failed: return -1; } -static int -destructor(void *p) -{ - struct lsqlite3_private *lsqlite3 = p; - +static int destructor(struct lsqlite3_private *lsqlite3) +{ if (lsqlite3->sqlite) { sqlite3_close(lsqlite3->sqlite); } -- cgit From 247af0d569594512a24e83156e257b8d4d356883 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 7 Jun 2006 21:03:38 +0000 Subject: r16083: Make it possible to initialise a backend module, without it setting up the whole ldb structure. Because the sequence number was a fn pointer on the main ldb context, turn it into a full request (currently sync). Andrew Bartlett (This used to be commit fbe7d0ca9031e292b2d2fae263233c973982980a) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 06b76e812d..053ccd1b21 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2073,9 +2073,10 @@ static const struct ldb_module_ops lsqlite3_ops = { * connect to the database */ static int lsqlite3_connect(struct ldb_context *ldb, - const char *url, - unsigned int flags, - const char *options[]) + const char *url, + unsigned int flags, + const char *options[], + struct ldb_module **module) { int i; int ret; @@ -2097,15 +2098,18 @@ static int lsqlite3_connect(struct ldb_context *ldb, talloc_set_destructor(lsqlite3, destructor); - ldb->modules = talloc(ldb, struct ldb_module); - if (!ldb->modules) { + + + *module = talloc(ldb, struct ldb_module); + if (!module) { + ldb_oom(ldb); goto failed; } - ldb->modules->ldb = ldb; - ldb->modules->prev = ldb->modules->next = NULL; - ldb->modules->private_data = lsqlite3; - ldb->modules->ops = &lsqlite3_ops; - + (*module)->ldb = ldb; + (*module)->prev = ldb->modules->next = NULL; + (*module)->private_data = lsqlite3; + (*module)->ops = &lsqlite3_ops; + if (options) { /* * take a copy of the options array, so we don't have to rely -- cgit From d912d6fcef28fad1c6e1c04a3a2eb4ed9e1a4ca3 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 8 Jun 2006 01:02:14 +0000 Subject: r16087: Fix silly cut-and-paste typo that cost me much of my afternoon... This only affects my new partitions module, which I will post soon, but should be fixed anyway. Andrew Bartlett (This used to be commit 8912c4e057eb3962321245cf49b92999afcc64fc) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 053ccd1b21..defd6fbbbc 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2106,7 +2106,7 @@ static int lsqlite3_connect(struct ldb_context *ldb, goto failed; } (*module)->ldb = ldb; - (*module)->prev = ldb->modules->next = NULL; + (*module)->prev = (*module)->next = NULL; (*module)->private_data = lsqlite3; (*module)->ops = &lsqlite3_ops; -- cgit From 7d7e43d94f26aa6c82b5553ab34d088a33bc99a6 Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Thu, 8 Jun 2006 03:57:57 +0000 Subject: r16090: Fix standalone build after the rename of enum ldb_request_type in r15944. Hey idra I think a better rename would be to keep the LDB_REQ suffix here to remain consistent with the other enums (e.g ldb_reply_type, ldb_async_wait_type and ldb_async_state). (This used to be commit d44ee8c43bd8f6f978330a8ded8bf30ffad494d6) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index defd6fbbbc..c9b453587e 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1990,7 +1990,7 @@ static int lsql_request(struct ldb_module *module, struct ldb_request *req) switch (req->operation) { - case LDB_REQ_SEARCH: + case LDB_SEARCH: return lsql_search_bytree(module, req->op.search.base, req->op.search.scope, @@ -1998,21 +1998,21 @@ static int lsql_request(struct ldb_module *module, struct ldb_request *req) req->op.search.attrs, &req->op.search.res); - case LDB_REQ_ADD: + case LDB_ADD: return lsql_add(module, req->op.add.message); - case LDB_REQ_MODIFY: + case LDB_MODIFY: return lsql_modify(module, req->op.mod.message); - case LDB_REQ_DELETE: + case LDB_DELETE: return lsql_delete(module, req->op.del.dn); - case LDB_REQ_RENAME: + case LDB_RENAME: return lsql_rename(module, req->op.rename.olddn, req->op.rename.newdn); - case LDB_ASYNC_SEARCH: + case LDB_SEARCH: return lsql_search_async(module, req->op.search.base, req->op.search.scope, @@ -2022,28 +2022,28 @@ static int lsql_request(struct ldb_module *module, struct ldb_request *req) req->async.callback, &req->async.handle); /* - case LDB_ASYNC_ADD: + case LDB_ADD: return lsql_add_async(module, req->op.add.message, req->async.context, req->async.callback, &req->async.handle); - case LDB_ASYNC_MODIFY: + case LDB_MODIFY: return lsql_modify_async(module, req->op.mod.message, req->async.context, req->async.callback, &req->async.handle); */ - case LDB_ASYNC_DELETE: + case LDB_DELETE: return lsql_delete_async(module, req->op.del.dn, req->async.context, req->async.callback, &req->async.handle); - case LDB_ASYNC_RENAME: + case LDB_RENAME: return lsql_rename_async(module, req->op.rename.olddn, req->op.rename.newdn, -- cgit From c93817b36d3ff7f44cb7b3e1d1a29e37ec12affe Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 22 Jul 2006 16:56:33 +0000 Subject: r17185: Oh, I wanted to do this for sooo long time. Finally acknowledge that ldb is inherently async and does not have a dual personality anymore Rename all ldb_async_XXX functions to ldb_XXX except for ldb_async_result, it is now ldb_reply to reflect the real function of this structure. Simo. (This used to be commit 25fc7354049d62efeba17681ef1cdd326bc3f2ef) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 90 +++++++++++++++---------------- 1 file changed, 45 insertions(+), 45 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index c9b453587e..c2ac9f47f4 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -44,27 +44,27 @@ struct lsqlite3_private { sqlite3 *sqlite; }; -struct lsql_async_context { +struct lsql_context { struct ldb_module *module; /* search stuff */ long long current_eid; const char * const * attrs; - struct ldb_async_result *ares; + struct ldb_reply *ares; /* async stuff */ void *context; - int (*callback)(struct ldb_context *, void *, struct ldb_async_result *); + int (*callback)(struct ldb_context *, void *, struct ldb_reply *); }; -static struct ldb_async_handle *init_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, +static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_async_result *)) + int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) { - struct lsql_async_context *ac; - struct ldb_async_handle *h; + struct lsql_context *ac; + struct ldb_handle *h; - h = talloc_zero(lsqlite3, struct ldb_async_handle); + h = talloc_zero(lsqlite3, struct ldb_handle); if (h == NULL) { ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); return NULL; @@ -72,7 +72,7 @@ static struct ldb_async_handle *init_handle(struct lsqlite3_private *lsqlite3, s h->module = module; - ac = talloc(h, struct lsql_async_context); + ac = talloc(h, struct lsql_context); if (ac == NULL) { ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); talloc_free(h); @@ -711,8 +711,8 @@ static int lsqlite3_eid_callback(void *result, int col_num, char **cols, char ** */ static int lsqlite3_search_callback(void *result, int col_num, char **cols, char **names) { - struct ldb_async_handle *handle = talloc_get_type(result, struct ldb_async_handle); - struct lsql_async_context *ac = talloc_get_type(handle->private_data, struct lsql_async_context); + struct ldb_handle *handle = talloc_get_type(result, struct ldb_handle); + struct lsql_context *ac = talloc_get_type(handle->private_data, struct lsql_context); struct ldb_message *msg; long long eid; int i; @@ -738,7 +738,7 @@ static int lsqlite3_search_callback(void *result, int col_num, char **cols, char } /* start over */ - ac->ares = talloc_zero(ac, struct ldb_async_result); + ac->ares = talloc_zero(ac, struct ldb_reply); if (!ac->ares) return SQLITE_ABORT; @@ -842,7 +842,7 @@ done: * Interface functions referenced by lsqlite3_ops */ -static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares) +static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) { struct ldb_result *res = NULL; @@ -891,11 +891,11 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, enum ldb_scope scope, struct ldb_parse_tree *tree, const char * const *attrs, void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), - struct ldb_async_handle **handle) + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); - struct lsql_async_context *lsql_ac; + struct lsql_context *lsql_ac; char *norm_basedn; char *sqlfilter; char *errmsg; @@ -908,7 +908,7 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); if (base) { norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, base)); @@ -1075,7 +1075,7 @@ static int lsql_search_bytree(struct ldb_module * module, const struct ldb_dn* b enum ldb_scope scope, struct ldb_parse_tree * tree, const char * const * attrs, struct ldb_result ** res) { - struct ldb_async_handle *handle; + struct ldb_handle *handle; int ret; *res = talloc_zero(module, struct ldb_result); @@ -1088,7 +1088,7 @@ static int lsql_search_bytree(struct ldb_module * module, const struct ldb_dn* b &handle); if (ret == LDB_SUCCESS) { - ret = ldb_async_wait(handle, LDB_WAIT_ALL); + ret = ldb_wait(handle, LDB_WAIT_ALL); talloc_free(handle); } @@ -1102,11 +1102,11 @@ static int lsql_search_bytree(struct ldb_module * module, const struct ldb_dn* b /* add a record */ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), - struct ldb_async_handle **handle) + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); - struct lsql_async_context *lsql_ac; + struct lsql_context *lsql_ac; long long eid; char *dn, *ndn; char *errmsg; @@ -1118,7 +1118,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, if (*handle == NULL) { goto failed; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); (*handle)->state = LDB_ASYNC_DONE; (*handle)->status = LDB_SUCCESS; @@ -1242,7 +1242,7 @@ failed: static int lsql_add(struct ldb_module *module, const struct ldb_message *msg) { - struct ldb_async_handle *handle; + struct ldb_handle *handle; int ret; ret = lsql_add_async(module, msg, NULL, NULL, &handle); @@ -1250,7 +1250,7 @@ static int lsql_add(struct ldb_module *module, const struct ldb_message *msg) if (ret != LDB_SUCCESS) return ret; - ret = ldb_async_wait(handle, LDB_WAIT_ALL); + ret = ldb_wait(handle, LDB_WAIT_ALL); talloc_free(handle); return ret; @@ -1260,11 +1260,11 @@ static int lsql_add(struct ldb_module *module, const struct ldb_message *msg) /* modify a record */ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message *msg, void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), - struct ldb_async_handle **handle) + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); - struct lsql_async_context *lsql_ac; + struct lsql_context *lsql_ac; long long eid; char *errmsg; int i; @@ -1274,7 +1274,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (*handle == NULL) { goto failed; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); (*handle)->state = LDB_ASYNC_DONE; (*handle)->status = LDB_SUCCESS; @@ -1456,7 +1456,7 @@ failed: static int lsql_modify(struct ldb_module *module, const struct ldb_message *msg) { - struct ldb_async_handle *handle; + struct ldb_handle *handle; int ret; ret = lsql_modify_async(module, msg, NULL, NULL, &handle); @@ -1464,7 +1464,7 @@ static int lsql_modify(struct ldb_module *module, const struct ldb_message *msg) if (ret != LDB_SUCCESS) return ret; - ret = ldb_async_wait(handle, LDB_WAIT_ALL); + ret = ldb_wait(handle, LDB_WAIT_ALL); talloc_free(handle); return ret; @@ -1473,11 +1473,11 @@ static int lsql_modify(struct ldb_module *module, const struct ldb_message *msg) /* delete a record */ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), - struct ldb_async_handle **handle) + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); - struct lsql_async_context *lsql_ac; + struct lsql_context *lsql_ac; long long eid; char *errmsg; char *query; @@ -1488,7 +1488,7 @@ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, if (*handle == NULL) { goto failed; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); (*handle)->state = LDB_ASYNC_DONE; (*handle)->status = LDB_SUCCESS; @@ -1530,7 +1530,7 @@ failed: static int lsql_delete(struct ldb_module *module, const struct ldb_dn *dn) { - struct ldb_async_handle *handle; + struct ldb_handle *handle; int ret; /* ignore ltdb specials */ @@ -1543,7 +1543,7 @@ static int lsql_delete(struct ldb_module *module, const struct ldb_dn *dn) if (ret != LDB_SUCCESS) return ret; - ret = ldb_async_wait(handle, LDB_WAIT_ALL); + ret = ldb_wait(handle, LDB_WAIT_ALL); talloc_free(handle); return ret; @@ -1552,11 +1552,11 @@ static int lsql_delete(struct ldb_module *module, const struct ldb_dn *dn) /* rename a record */ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn, void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_async_result *), - struct ldb_async_handle **handle) + int (*callback)(struct ldb_context *, void *, struct ldb_reply *), + struct ldb_handle **handle) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); - struct lsql_async_context *lsql_ac; + struct lsql_context *lsql_ac; char *new_dn, *new_cdn, *old_cdn; char *errmsg; char *query; @@ -1566,7 +1566,7 @@ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *old if (*handle == NULL) { goto failed; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_async_context); + lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); (*handle)->state = LDB_ASYNC_DONE; (*handle)->status = LDB_SUCCESS; @@ -1610,7 +1610,7 @@ failed: static int lsql_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) { - struct ldb_async_handle *handle; + struct ldb_handle *handle; int ret; /* ignore ltdb specials */ @@ -1624,7 +1624,7 @@ static int lsql_rename(struct ldb_module *module, const struct ldb_dn *olddn, co if (ret != LDB_SUCCESS) return ret; - ret = ldb_async_wait(handle, LDB_WAIT_ALL); + ret = ldb_wait(handle, LDB_WAIT_ALL); talloc_free(handle); return ret; @@ -1971,7 +1971,7 @@ static int destructor(struct lsqlite3_private *lsqlite3) return 0; } -static int lsql_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type) +static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) { return handle->status; } @@ -2066,7 +2066,7 @@ static const struct ldb_module_ops lsqlite3_ops = { .start_transaction = lsql_start_trans, .end_transaction = lsql_end_trans, .del_transaction = lsql_del_trans, - .async_wait = lsql_async_wait, + .wait = lsql_wait, }; /* -- cgit From 49f68caed20d2a7d1850e493005bdf85929d6365 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sat, 22 Jul 2006 17:21:59 +0000 Subject: r17186: "async" word abuse clean-up part 2 (This used to be commit c6aa60c7e69abf1f83efc150b1c3ed02751c45fc) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index c2ac9f47f4..153a6d27d4 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2018,38 +2018,38 @@ static int lsql_request(struct ldb_module *module, struct ldb_request *req) req->op.search.scope, req->op.search.tree, req->op.search.attrs, - req->async.context, - req->async.callback, - &req->async.handle); + req->context, + req->callback, + &req->handle); /* case LDB_ADD: return lsql_add_async(module, req->op.add.message, - req->async.context, - req->async.callback, - &req->async.handle); + req->context, + req->callback, + &req->handle); case LDB_MODIFY: return lsql_modify_async(module, req->op.mod.message, - req->async.context, - req->async.callback, - &req->async.handle); + req->context, + req->callback, + &req->handle); */ case LDB_DELETE: return lsql_delete_async(module, req->op.del.dn, - req->async.context, - req->async.callback, - &req->async.handle); + req->context, + req->callback, + &req->handle); case LDB_RENAME: return lsql_rename_async(module, req->op.rename.olddn, req->op.rename.newdn, - req->async.context, - req->async.callback, - &req->async.handle); + req->context, + req->callback, + &req->handle); default: return LDB_ERR_OPERATIONS_ERROR; -- cgit From faed8175063b16df94d5332581baf1af0562bb09 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Sun, 13 Aug 2006 07:33:57 +0000 Subject: r17514: Simplify the way to set ldb errors and add another helper function to set them. (This used to be commit 260868bae56194fcb98d55afc22fc66d96a303df) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 153a6d27d4..dcac88a6b9 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -66,7 +66,7 @@ static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct h = talloc_zero(lsqlite3, struct ldb_handle); if (h == NULL) { - ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); + ldb_set_errstring(module->ldb, "Out of Memory"); return NULL; } @@ -74,7 +74,7 @@ static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct ac = talloc(h, struct lsql_context); if (ac == NULL) { - ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory")); + ldb_set_errstring(module->ldb, "Out of Memory"); talloc_free(h); return NULL; } @@ -847,7 +847,7 @@ static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, str struct ldb_result *res = NULL; if (!context) { - ldb_set_errstring(ldb, talloc_strdup(ldb, "NULL Context in callback")); + ldb_set_errstring(ldb, "NULL Context in callback"); goto error; } @@ -1045,7 +1045,7 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, *handle, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, errmsg); free(errmsg); } goto failed; @@ -1166,7 +1166,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, errmsg); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1221,7 +1221,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, errmsg); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1334,7 +1334,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, errmsg); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1372,7 +1372,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, errmsg); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1398,7 +1398,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, errmsg); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1432,7 +1432,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, errmsg); free(errmsg); } ret = LDB_ERR_OTHER; @@ -1511,7 +1511,7 @@ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, errmsg); free(errmsg); } ret = LDB_ERR_OPERATIONS_ERROR; @@ -1591,7 +1591,7 @@ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *old ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { - ldb_set_errstring(module->ldb, talloc_strdup(module, errmsg)); + ldb_set_errstring(module->ldb, errmsg); free(errmsg); } ret = LDB_ERR_OPERATIONS_ERROR; -- cgit From 7f63cebd331793d059b1dbfd2f7d7ce38105c4fe Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 13 Sep 2006 00:10:38 +0000 Subject: r18436: converted ldb to use talloc_move() instead of talloc_steal() when appropriate. Note that I also removed the error checks that were being done on the result of talloc_steal(). They are pointless as talloc_steal() doesn't have any failure modes that wouldn't cause a segv anyway, and they tend to clutter the code (This used to be commit c0d9e7d473b8e3eb2524a9fc29cf88680f994b36) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index dcac88a6b9..9d71b9e8e8 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -865,11 +865,7 @@ static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, str res->msgs[res->count + 1] = NULL; - res->msgs[res->count] = talloc_steal(res->msgs, ares->message); - if (! res->msgs[res->count]) { - goto error; - } - + res->msgs[res->count] = talloc_move(res->msgs, ares->message); res->count++; } else { ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n"); -- cgit From 05cdd9ccafeeb384792b9ce7ca044bcec1bfc839 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 13 Sep 2006 02:33:51 +0000 Subject: r18439: 2nd try at a talloc_move() api. This type with the ** ptr interface exposed. Unfortunately this generates a large number of type punning warnings. We'll have to find some magic to hide those. (This used to be commit 254cbf09dee5a1e20c47e47a298f1a8d172b41b9) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 9d71b9e8e8..91256222b1 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -865,7 +865,7 @@ static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, str res->msgs[res->count + 1] = NULL; - res->msgs[res->count] = talloc_move(res->msgs, ares->message); + res->msgs[res->count] = talloc_move(res->msgs, &ares->message); res->count++; } else { ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n"); -- cgit From e36ea2e8ebe44079dd3989694f0235e77caf4fe2 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 17 Oct 2006 01:21:02 +0000 Subject: r19362: - don't need to store the baseinfo message after cache load - set better names on talloc structures in ldb modules, making leaks easier to track down (This used to be commit 3bf76db42dc6dde5d71083216dba819869b31c75) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 91256222b1..8dd25db1d6 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2101,6 +2101,7 @@ static int lsqlite3_connect(struct ldb_context *ldb, ldb_oom(ldb); goto failed; } + talloc_set_name_const(*module, "ldb_sqlite3 backend"); (*module)->ldb = ldb; (*module)->prev = (*module)->next = NULL; (*module)->private_data = lsqlite3; -- cgit From a32689315916b184ad4b9f01260e07e6f3e2b9bc Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 23 Oct 2006 00:17:44 +0000 Subject: r19461: Make sqlite3 work again (semi-async) Still not all tests pass (This used to be commit cbfc7305ad594c672a16a7f6f82758d17eb5ba62) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 550 +++++++++--------------------- 1 file changed, 158 insertions(+), 392 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 8dd25db1d6..4f9b0f6370 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -2,7 +2,7 @@ ldb database library Copyright (C) Derrell Lipman 2005 - Copyright (C) Simo Sorce 2005 + Copyright (C) Simo Sorce 2005-2006 ** NOTE! The following LGPL license applies to the ldb ** library. This does NOT imply that all of Samba is released @@ -57,9 +57,9 @@ struct lsql_context { int (*callback)(struct ldb_context *, void *, struct ldb_reply *); }; -static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct ldb_module *module, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *)) +static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, + struct ldb_module *module, + struct ldb_request *req) { struct lsql_context *ac; struct ldb_handle *h; @@ -85,8 +85,8 @@ static struct ldb_handle *init_handle(struct lsqlite3_private *lsqlite3, struct h->status = LDB_SUCCESS; ac->module = module; - ac->context = context; - ac->callback = callback; + ac->context = req->context; + ac->callback = req->callback; return h; } @@ -370,6 +370,7 @@ static char *parsetree_to_sql(struct ldb_module *module, } else if (strcasecmp(t->u.equality.attr, "dn") == 0) { /* DN query is a special ldb case */ char *cdn = ldb_dn_linearize_casefold(module->ldb, + mem_ctx, ldb_dn_explode(module->ldb, (const char *)value.data)); @@ -828,7 +829,7 @@ static long long lsqlite3_get_eid(struct ldb_module *module, const struct ldb_dn return -1; } - cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, dn)); + cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, local_ctx, dn)); if (!cdn) goto done; eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, cdn); @@ -842,53 +843,8 @@ done: * Interface functions referenced by lsqlite3_ops */ -static int lsql_search_sync_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) -{ - struct ldb_result *res = NULL; - - if (!context) { - ldb_set_errstring(ldb, "NULL Context in callback"); - goto error; - } - - res = *((struct ldb_result **)context); - - if (!res || !ares) { - goto error; - } - - if (ares->type == LDB_REPLY_ENTRY) { - res->msgs = talloc_realloc(res, res->msgs, struct ldb_message *, res->count + 2); - if (! res->msgs) { - goto error; - } - - res->msgs[res->count + 1] = NULL; - - res->msgs[res->count] = talloc_move(res->msgs, &ares->message); - res->count++; - } else { - ldb_debug(ldb, LDB_DEBUG_ERROR, "unrecognized async reply in ltdb_search_sync_callback!\n"); - goto error; - } - - talloc_free(ares); - return LDB_SUCCESS; - -error: - if (ares) talloc_free(ares); - if (res) talloc_free(res); - if (context) *((struct ldb_result **)context) = NULL; - return LDB_ERR_OPERATIONS_ERROR; -} - /* search for matching records, by tree */ -int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, - enum ldb_scope scope, struct ldb_parse_tree *tree, - const char * const *attrs, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +int lsql_search(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; @@ -898,32 +854,29 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, char *query = NULL; int ret; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - talloc_free(*handle); + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); - if (base) { - norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, base)); + if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) && + (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) + return LDB_ERR_OPERATIONS_ERROR; + + if (req->op.search.base) { + norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.search.base)); if (norm_basedn == NULL) { ret = LDB_ERR_INVALID_DN_SYNTAX; goto failed; } } else norm_basedn = talloc_strdup(lsql_ac, ""); - if (*norm_basedn == '\0' && - (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) { - ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto failed; - } - /* Convert filter into a series of SQL conditions (constraints) */ - sqlfilter = parsetree_to_sql(module, lsql_ac, tree); + sqlfilter = parsetree_to_sql(module, lsql_ac, req->op.search.tree); - switch(scope) { + switch(req->op.search.scope) { case LDB_SCOPE_DEFAULT: case LDB_SCOPE_SUBTREE: if (*norm_basedn != '\0') { @@ -1033,12 +986,12 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, / * */ lsql_ac->current_eid = 0; - lsql_ac->attrs = attrs; + lsql_ac->attrs = req->op.search.attrs; lsql_ac->ares = NULL; - (*handle)->state = LDB_ASYNC_PENDING; + req->handle->state = LDB_ASYNC_PENDING; - ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, *handle, &errmsg); + ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, req->handle, &errmsg); if (ret != SQLITE_OK) { if (errmsg) { ldb_set_errstring(module->ldb, errmsg); @@ -1053,70 +1006,39 @@ int lsql_search_async(struct ldb_module *module, const struct ldb_dn *base, if (lsql_ac->ares->message == NULL) goto failed; - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares); - if ((*handle)->status != LDB_SUCCESS) + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, lsql_ac->ares); + if (req->handle->status != LDB_SUCCESS) goto failed; } - (*handle)->state = LDB_ASYNC_DONE; + req->handle->state = LDB_ASYNC_DONE; return LDB_SUCCESS; failed: - talloc_free(*handle); return LDB_ERR_OPERATIONS_ERROR; } -static int lsql_search_bytree(struct ldb_module * module, const struct ldb_dn* base, - enum ldb_scope scope, struct ldb_parse_tree * tree, - const char * const * attrs, struct ldb_result ** res) -{ - struct ldb_handle *handle; - int ret; - - *res = talloc_zero(module, struct ldb_result); - if (! *res) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = lsql_search_async(module, base, scope, tree, attrs, - res, &lsql_search_sync_callback, - &handle); - - if (ret == LDB_SUCCESS) { - ret = ldb_wait(handle, LDB_WAIT_ALL); - talloc_free(handle); - } - - if (ret != LDB_SUCCESS) { - talloc_free(*res); - } - - return ret; -} - /* add a record */ -static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_add(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; + struct ldb_message *msg = req->op.add.message; long long eid; char *dn, *ndn; char *errmsg; char *query; int i; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { @@ -1126,26 +1048,28 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "insert subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto failed; + goto done; } /* c = ldb_dn_explode(local_ctx, "@INDEXLIST"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "should we handle indexes somehow ?" - goto failed; + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; } */ - /* Others are implicitly ignored */ - return LDB_SUCCESS; + /* Others return an error */ + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; } /* create linearized and normalized dns */ dn = ldb_dn_linearize(lsql_ac, msg->dn); - ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, msg->dn)); + ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, msg->dn)); if (dn == NULL || ndn == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } query = lsqlite3_tprintf(lsql_ac, @@ -1156,7 +1080,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, dn, ndn); if (query == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); @@ -1166,13 +1090,13 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, lsql_ac, ndn); if (eid == -1) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } for (i = 0; i < msg->num_elements; i++) { @@ -1185,7 +1109,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, attr = ldb_attr_casefold(lsql_ac, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } h = ldb_attrib_handler(module->ldb, el->name); @@ -1199,7 +1123,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } insert = lsqlite3_tprintf(lsql_ac, @@ -1211,7 +1135,7 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, el->values[j].data, value.data); if (insert == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg); @@ -1221,58 +1145,38 @@ static int lsql_add_async(struct ldb_module *module, struct ldb_message *msg, free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + if (lsql_ac->callback) { + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_add(struct ldb_module *module, const struct ldb_message *msg) -{ - struct ldb_handle *handle; - int ret; - - ret = lsql_add_async(module, msg, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } - /* modify a record */ -static int lsql_modify_async(struct ldb_module *module, const struct ldb_message *msg, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_modify(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; + struct ldb_message *msg = req->op.mod.message; long long eid; char *errmsg; int i; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { @@ -1282,17 +1186,18 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "modify subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto failed; + goto done; } - /* Others are implicitly ignored */ - return LDB_SUCCESS; + /* Others return an error */ + ret = LDB_ERR_UNWILLING_TO_PERFORM; + goto done; } eid = lsqlite3_get_eid(module, msg->dn); if (eid == -1) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } for (i = 0; i < msg->num_elements; i++) { @@ -1307,7 +1212,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message attr = ldb_attr_casefold(lsql_ac, el->name); if (attr == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } h = ldb_attrib_handler(module->ldb, el->name); @@ -1324,7 +1229,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message eid, attr); if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1334,7 +1239,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } /* MISSING break is INTENTIONAL */ @@ -1349,7 +1254,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } mod = lsqlite3_tprintf(lsql_ac, @@ -1362,7 +1267,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1372,7 +1277,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } @@ -1388,7 +1293,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message eid, attr); if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1398,7 +1303,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } @@ -1410,7 +1315,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } mod = lsqlite3_tprintf(lsql_ac, @@ -1422,7 +1327,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message if (mod == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg); @@ -1432,7 +1337,7 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message free(errmsg); } ret = LDB_ERR_OTHER; - goto failed; + goto done; } } @@ -1440,57 +1345,37 @@ static int lsql_modify_async(struct ldb_module *module, const struct ldb_message } } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + if (lsql_ac->callback) { + req->handle->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); + } - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_modify(struct ldb_module *module, const struct ldb_message *msg) -{ - struct ldb_handle *handle; - int ret; - - ret = lsql_modify_async(module, msg, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } /* delete a record */ -static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_delete(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; long long eid; char *errmsg; char *query; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; - eid = lsqlite3_get_eid(module, dn); + eid = lsqlite3_get_eid(module, req->op.del.dn); if (eid == -1) { - goto failed; + goto done; } query = lsqlite3_tprintf(lsql_ac, @@ -1501,7 +1386,7 @@ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, eid, eid); if (query == NULL) { ret = LDB_ERR_OTHER; - goto failed; + goto done; } ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg); @@ -1510,68 +1395,43 @@ static int lsql_delete_async(struct ldb_module *module, const struct ldb_dn *dn, ldb_set_errstring(module->ldb, errmsg); free(errmsg); } - ret = LDB_ERR_OPERATIONS_ERROR; - goto failed; + req->handle->status = LDB_ERR_OPERATIONS_ERROR; + goto done; } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); - - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_delete(struct ldb_module *module, const struct ldb_dn *dn) -{ - struct ldb_handle *handle; - int ret; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(dn)) { - return LDB_SUCCESS; + if (lsql_ac->callback) { + ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); } - - ret = lsql_delete_async(module, dn, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); + +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } /* rename a record */ -static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn, - void *context, - int (*callback)(struct ldb_context *, void *, struct ldb_reply *), - struct ldb_handle **handle) +static int lsql_rename(struct ldb_module *module, struct ldb_request *req) { struct lsqlite3_private *lsqlite3 = talloc_get_type(module->private_data, struct lsqlite3_private); struct lsql_context *lsql_ac; char *new_dn, *new_cdn, *old_cdn; char *errmsg; char *query; - int ret = LDB_ERR_OPERATIONS_ERROR; + int ret = LDB_SUCCESS; - *handle = init_handle(lsqlite3, module, context, callback); - if (*handle == NULL) { - goto failed; + req->handle = init_handle(lsqlite3, module, req); + if (req->handle == NULL) { + return LDB_ERR_OPERATIONS_ERROR; } - lsql_ac = talloc_get_type((*handle)->private_data, struct lsql_context); - (*handle)->state = LDB_ASYNC_DONE; - (*handle)->status = LDB_SUCCESS; + lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); + req->handle->state = LDB_ASYNC_DONE; + req->handle->status = LDB_SUCCESS; /* create linearized and normalized dns */ - old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, olddn)); - new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, newdn)); - new_dn = ldb_dn_linearize(lsql_ac, newdn); + old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.olddn)); + new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.newdn)); + new_dn = ldb_dn_linearize(lsql_ac, req->op.rename.newdn); if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) { - goto failed; + goto done; } /* build the SQL query */ @@ -1580,7 +1440,7 @@ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *old "WHERE norm_dn = '%q';", new_dn, new_cdn, old_cdn); if (query == NULL) { - goto failed; + goto done; } /* execute */ @@ -1591,38 +1451,15 @@ static int lsql_rename_async(struct ldb_module *module, const struct ldb_dn *old free(errmsg); } ret = LDB_ERR_OPERATIONS_ERROR; - goto failed; + goto done; } - if (lsql_ac->callback) - (*handle)->status = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); - - return LDB_SUCCESS; - -failed: - talloc_free(*handle); - return ret; -} - -static int lsql_rename(struct ldb_module *module, const struct ldb_dn *olddn, const struct ldb_dn *newdn) -{ - struct ldb_handle *handle; - int ret; - - /* ignore ltdb specials */ - if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) { - return LDB_SUCCESS; + if (lsql_ac->callback) { + ret = lsql_ac->callback(module->ldb, lsql_ac->context, NULL); } - - ret = lsql_rename_async(module, olddn, newdn, NULL, NULL, &handle); - - if (ret != LDB_SUCCESS) - return ret; - - ret = ldb_wait(handle, LDB_WAIT_ALL); - - talloc_free(handle); +done: + req->handle->state = LDB_ASYNC_DONE; return ret; } @@ -1687,6 +1524,41 @@ static int lsql_del_trans(struct ldb_module *module) return -1; } +static int destructor(struct lsqlite3_private *lsqlite3) +{ + if (lsqlite3->sqlite) { + sqlite3_close(lsqlite3->sqlite); + } + return 0; +} + +static int lsql_request(struct ldb_module *module, struct ldb_request *req) +{ + return LDB_ERR_OPERATIONS_ERROR; +} + +static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) +{ + return handle->status; +} + +/* + * Table of operations for the sqlite3 backend + */ +static const struct ldb_module_ops lsqlite3_ops = { + .name = "sqlite", + .search = lsql_search, + .add = lsql_add, + .modify = lsql_modify, + .del = lsql_delete, + .rename = lsql_rename, + .request = lsql_request, + .start_transaction = lsql_start_trans, + .end_transaction = lsql_end_trans, + .del_transaction = lsql_del_trans, + .wait = lsql_wait, +}; + /* * Static functions */ @@ -1796,12 +1668,12 @@ static int initialize(struct lsqlite3_private *lsqlite3, " ('TOP', '0001');"); /* Skip protocol indicator of url */ - if (strncmp(url, "sqlite://", 9) != 0) { + if (strncmp(url, "sqlite3://", 10) != 0) { return SQLITE_MISUSE; } /* Update pointer to just after the protocol indicator */ - url += 9; + url += 10; /* Try to open the (possibly empty/non-existent) database */ if ((ret = sqlite3_open(url, &lsqlite3->sqlite)) != SQLITE_OK) { @@ -1959,112 +1831,6 @@ failed: return -1; } -static int destructor(struct lsqlite3_private *lsqlite3) -{ - if (lsqlite3->sqlite) { - sqlite3_close(lsqlite3->sqlite); - } - return 0; -} - -static int lsql_wait(struct ldb_handle *handle, enum ldb_wait_type type) -{ - return handle->status; -} - -static int lsql_request(struct ldb_module *module, struct ldb_request *req) -{ - /* check for oustanding critical controls and return an error if found */ - - if (req->controls != NULL) { - ldb_debug(module->ldb, LDB_DEBUG_WARNING, "Controls should not reach the ldb_sqlite3 backend!\n"); - } - - if (check_critical_controls(req->controls)) { - return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION; - } - - switch (req->operation) { - - case LDB_SEARCH: - return lsql_search_bytree(module, - req->op.search.base, - req->op.search.scope, - req->op.search.tree, - req->op.search.attrs, - &req->op.search.res); - - case LDB_ADD: - return lsql_add(module, req->op.add.message); - - case LDB_MODIFY: - return lsql_modify(module, req->op.mod.message); - - case LDB_DELETE: - return lsql_delete(module, req->op.del.dn); - - case LDB_RENAME: - return lsql_rename(module, - req->op.rename.olddn, - req->op.rename.newdn); - - case LDB_SEARCH: - return lsql_search_async(module, - req->op.search.base, - req->op.search.scope, - req->op.search.tree, - req->op.search.attrs, - req->context, - req->callback, - &req->handle); -/* - case LDB_ADD: - return lsql_add_async(module, - req->op.add.message, - req->context, - req->callback, - &req->handle); - - case LDB_MODIFY: - return lsql_modify_async(module, - req->op.mod.message, - req->context, - req->callback, - &req->handle); -*/ - case LDB_DELETE: - return lsql_delete_async(module, - req->op.del.dn, - req->context, - req->callback, - &req->handle); - - case LDB_RENAME: - return lsql_rename_async(module, - req->op.rename.olddn, - req->op.rename.newdn, - req->context, - req->callback, - &req->handle); - - default: - return LDB_ERR_OPERATIONS_ERROR; - - } -} - -/* - * Table of operations for the sqlite3 backend - */ -static const struct ldb_module_ops lsqlite3_ops = { - .name = "sqlite", - .request = lsql_request, - .start_transaction = lsql_start_trans, - .end_transaction = lsql_end_trans, - .del_transaction = lsql_del_trans, - .wait = lsql_wait, -}; - /* * connect to the database */ -- cgit From 4889eb9f7aae9349e426d0f6d2217adff67eaebd Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 22 Nov 2006 00:59:34 +0000 Subject: r19831: Big ldb_dn optimization and interfaces enhancement patch This patch changes a lot of the code in ldb_dn.c, and also removes and add a number of manipulation functions around. The aim is to avoid validating a dn if not necessary as the validation code is necessarily slow. This is mainly to speed up internal operations where input is not user generated and so we can assume the DNs need no validation. The code is designed to keep the data as a string if possible. The code is not yet 100% perfect, but pass all the tests so far. A memleak is certainly present, I'll work on that next. Simo. (This used to be commit a580c871d3784602a9cce32d33419e63c8236e63) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 4f9b0f6370..7671b0d954 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -369,9 +369,8 @@ static char *parsetree_to_sql(struct ldb_module *module, } else if (strcasecmp(t->u.equality.attr, "dn") == 0) { /* DN query is a special ldb case */ - char *cdn = ldb_dn_linearize_casefold(module->ldb, - mem_ctx, - ldb_dn_explode(module->ldb, + char *cdn = ldb_dn_casefold(mem_ctx, + ldb_dn_new(mem_ctx, module->ldb, (const char *)value.data)); return lsqlite3_tprintf(mem_ctx, @@ -754,7 +753,7 @@ static int lsqlite3_search_callback(void *result, int col_num, char **cols, char msg = ac->ares->message; if (msg->dn == NULL) { - msg->dn = ldb_dn_explode(msg, cols[1]); + msg->dn = ldb_dn_new(msg, ac->module->ldb, cols[1]); if (msg->dn == NULL) return SQLITE_ABORT; } @@ -811,7 +810,7 @@ static long long lsqlite3_get_eid_ndn(sqlite3 *sqlite, void *mem_ctx, const char return eid; } -static long long lsqlite3_get_eid(struct ldb_module *module, const struct ldb_dn *dn) +static long long lsqlite3_get_eid(struct ldb_module *module, struct ldb_dn *dn) { TALLOC_CTX *local_ctx; struct lsqlite3_private *lsqlite3 = module->private_data; @@ -1044,7 +1043,7 @@ static int lsql_add(struct ldb_module *module, struct ldb_request *req) if (ldb_dn_is_special(msg->dn)) { struct ldb_dn *c; - c = ldb_dn_explode(lsql_ac, "@SUBCLASSES"); + c = ldb_dn_new(lsql_ac, module->ldb, "@SUBCLASSES"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "insert subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; @@ -1052,7 +1051,7 @@ static int lsql_add(struct ldb_module *module, struct ldb_request *req) } /* - c = ldb_dn_explode(local_ctx, "@INDEXLIST"); + c = ldb_dn_new(local_ctx, module->ldb, "@INDEXLIST"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "should we handle indexes somehow ?" ret = LDB_ERR_UNWILLING_TO_PERFORM; @@ -1182,7 +1181,7 @@ static int lsql_modify(struct ldb_module *module, struct ldb_request *req) if (ldb_dn_is_special(msg->dn)) { struct ldb_dn *c; - c = ldb_dn_explode(lsql_ac, "@SUBCLASSES"); + c = ldb_dn_new(lsql_ac, module->ldb, "@SUBCLASSES"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "modify subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; -- cgit From a9e31b33b55a873c2f01db5e348560176adf863d Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 22 Nov 2006 02:05:19 +0000 Subject: r19832: better prototypes for the linearization functions: - ldb_dn_get_linearized returns a const string - ldb_dn_alloc_linearized allocs astring with the linearized dn (This used to be commit 3929c086d5d0b3f08b1c4f2f3f9602c3f4a9a4bd) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 7671b0d954..4ea2eccded 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -369,8 +369,8 @@ static char *parsetree_to_sql(struct ldb_module *module, } else if (strcasecmp(t->u.equality.attr, "dn") == 0) { /* DN query is a special ldb case */ - char *cdn = ldb_dn_casefold(mem_ctx, - ldb_dn_new(mem_ctx, module->ldb, + const char *cdn = ldb_dn_get_casefold( + ldb_dn_new(mem_ctx, module->ldb, (const char *)value.data)); return lsqlite3_tprintf(mem_ctx, @@ -828,7 +828,7 @@ static long long lsqlite3_get_eid(struct ldb_module *module, struct ldb_dn *dn) return -1; } - cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, local_ctx, dn)); + cdn = ldb_dn_alloc_casefold(local_ctx, dn); if (!cdn) goto done; eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, cdn); @@ -865,7 +865,7 @@ int lsql_search(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; if (req->op.search.base) { - norm_basedn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.search.base)); + norm_basedn = ldb_dn_alloc_casefold(lsql_ac, req->op.search.base); if (norm_basedn == NULL) { ret = LDB_ERR_INVALID_DN_SYNTAX; goto failed; @@ -1064,8 +1064,8 @@ static int lsql_add(struct ldb_module *module, struct ldb_request *req) } /* create linearized and normalized dns */ - dn = ldb_dn_linearize(lsql_ac, msg->dn); - ndn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, msg->dn)); + dn = ldb_dn_alloc_linearized(lsql_ac, msg->dn); + ndn = ldb_dn_alloc_casefold(lsql_ac, msg->dn); if (dn == NULL || ndn == NULL) { ret = LDB_ERR_OTHER; goto done; @@ -1426,9 +1426,9 @@ static int lsql_rename(struct ldb_module *module, struct ldb_request *req) req->handle->status = LDB_SUCCESS; /* create linearized and normalized dns */ - old_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.olddn)); - new_cdn = ldb_dn_linearize(lsql_ac, ldb_dn_casefold(module->ldb, lsql_ac, req->op.rename.newdn)); - new_dn = ldb_dn_linearize(lsql_ac, req->op.rename.newdn); + old_cdn = ldb_dn_alloc_casefold(lsql_ac, req->op.rename.olddn); + new_cdn = ldb_dn_alloc_casefold(lsql_ac, req->op.rename.newdn); + new_dn = ldb_dn_alloc_linearized(lsql_ac, req->op.rename.newdn); if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) { goto done; } -- cgit From 538e3bf654692628610768466cf451cf5bbccf4c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 15 Dec 2006 13:12:18 +0000 Subject: r20185: - SMB_ENABLE() needs upper case YES/NO - fix compilation of the ldb_sqlite3 module metze (This used to be commit 39c41be0ac5bfa39c4ff3267b1a8291857e3a034) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 52 +++++++++++++++---------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 4ea2eccded..9f580de67b 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -283,7 +283,7 @@ static char *parsetree_to_sql(struct ldb_module *module, void *mem_ctx, const struct ldb_parse_tree *t) { - const struct ldb_attrib_handler *h; + const struct ldb_schema_attribute *a; struct ldb_val value, subval; char *wild_card_string; char *child, *tmp; @@ -343,10 +343,10 @@ static char *parsetree_to_sql(struct ldb_module *module, */ attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; - h = ldb_attrib_handler(module->ldb, attr); + a = ldb_schema_attribute_by_name(module->ldb, attr); /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); if (value.data == NULL) { return NULL; } @@ -407,13 +407,13 @@ static char *parsetree_to_sql(struct ldb_module *module, attr = ldb_attr_casefold(mem_ctx, t->u.substring.attr); if (attr == NULL) return NULL; - h = ldb_attrib_handler(module->ldb, attr); + a = ldb_schema_attribute_by_name(module->ldb, attr); subval.data = (void *)wild_card_string; subval.length = strlen(wild_card_string) + 1; /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, mem_ctx, &(subval), &value); + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(subval), &value); if (value.data == NULL) { return NULL; } @@ -428,10 +428,10 @@ static char *parsetree_to_sql(struct ldb_module *module, case LDB_OP_GREATER: attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; - h = ldb_attrib_handler(module->ldb, attr); + a = ldb_schema_attribute_by_name(module->ldb, attr); /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); if (value.data == NULL) { return NULL; } @@ -447,10 +447,10 @@ static char *parsetree_to_sql(struct ldb_module *module, case LDB_OP_LESS: attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; - h = ldb_attrib_handler(module->ldb, attr); + a = ldb_schema_attribute_by_name(module->ldb, attr); /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); if (value.data == NULL) { return NULL; } @@ -479,10 +479,10 @@ static char *parsetree_to_sql(struct ldb_module *module, case LDB_OP_APPROX: attr = ldb_attr_casefold(mem_ctx, t->u.equality.attr); if (attr == NULL) return NULL; - h = ldb_attrib_handler(module->ldb, attr); + a = ldb_schema_attribute_by_name(module->ldb, attr); /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); + a->syntax->canonicalise_fn(module->ldb, mem_ctx, &(t->u.equality.value), &value); if (value.data == NULL) { return NULL; } @@ -620,7 +620,7 @@ static void lsqlite3_compare(sqlite3_context *ctx, int argc, const char *func = (const char *)sqlite3_value_text(argv[1]); const char *cmp = (const char *)sqlite3_value_text(argv[2]); const char *attr = (const char *)sqlite3_value_text(argv[3]); - const struct ldb_attrib_handler *h; + const struct ldb_schema_attribute *a; struct ldb_val valX; struct ldb_val valY; int ret; @@ -628,12 +628,12 @@ static void lsqlite3_compare(sqlite3_context *ctx, int argc, switch (func[0]) { /* greater */ case '>': /* >= */ - h = ldb_attrib_handler(ldb, attr); + a = ldb_schema_attribute_by_name(ldb, attr); valX.data = (void *)cmp; valX.length = strlen(cmp); valY.data = (void *)val; valY.length = strlen(val); - ret = h->comparison_fn(ldb, ldb, &valY, &valX); + ret = a->syntax->comparison_fn(ldb, ldb, &valY, &valX); if (ret >= 0) sqlite3_result_int(ctx, 1); else @@ -642,12 +642,12 @@ static void lsqlite3_compare(sqlite3_context *ctx, int argc, /* lesser */ case '<': /* <= */ - h = ldb_attrib_handler(ldb, attr); + a = ldb_schema_attribute_by_name(ldb, attr); valX.data = (void *)cmp; valX.length = strlen(cmp); valY.data = (void *)val; valY.length = strlen(val); - ret = h->comparison_fn(ldb, ldb, &valY, &valX); + ret = a->syntax->comparison_fn(ldb, ldb, &valY, &valX); if (ret <= 0) sqlite3_result_int(ctx, 1); else @@ -860,7 +860,7 @@ int lsql_search(struct ldb_module *module, struct ldb_request *req) lsql_ac = talloc_get_type(req->handle->private_data, struct lsql_context); - if ((req->op.search.base == NULL || req->op.search.base->comp_num == 0) && + if ((( ! ldb_dn_is_valid(req->op.search.base)) || ldb_dn_is_null(req->op.search.base)) && (req->op.search.scope == LDB_SCOPE_BASE || req->op.search.scope == LDB_SCOPE_ONELEVEL)) return LDB_ERR_OPERATIONS_ERROR; @@ -1044,7 +1044,7 @@ static int lsql_add(struct ldb_module *module, struct ldb_request *req) struct ldb_dn *c; c = ldb_dn_new(lsql_ac, module->ldb, "@SUBCLASSES"); - if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { + if (ldb_dn_compare(msg->dn, c) == 0) { #warning "insert subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; goto done; @@ -1100,7 +1100,7 @@ static int lsql_add(struct ldb_module *module, struct ldb_request *req) for (i = 0; i < msg->num_elements; i++) { const struct ldb_message_element *el = &msg->elements[i]; - const struct ldb_attrib_handler *h; + const struct ldb_schema_attribute *a; char *attr; int j; @@ -1111,7 +1111,7 @@ static int lsql_add(struct ldb_module *module, struct ldb_request *req) goto done; } - h = ldb_attrib_handler(module->ldb, el->name); + a = ldb_schema_attribute_by_name(module->ldb, el->name); /* For each value of the specified attribute name... */ for (j = 0; j < el->num_values; j++) { @@ -1119,7 +1119,7 @@ static int lsql_add(struct ldb_module *module, struct ldb_request *req) char *insert; /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); + a->syntax->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; goto done; @@ -1182,7 +1182,7 @@ static int lsql_modify(struct ldb_module *module, struct ldb_request *req) struct ldb_dn *c; c = ldb_dn_new(lsql_ac, module->ldb, "@SUBCLASSES"); - if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { + if (ldb_dn_compare(msg->dn, c) == 0) { #warning "modify subclasses into object class tree" ret = LDB_ERR_UNWILLING_TO_PERFORM; goto done; @@ -1201,7 +1201,7 @@ static int lsql_modify(struct ldb_module *module, struct ldb_request *req) for (i = 0; i < msg->num_elements; i++) { const struct ldb_message_element *el = &msg->elements[i]; - const struct ldb_attrib_handler *h; + const struct ldb_schema_attribute *a; int flags = el->flags & LDB_FLAG_MOD_MASK; char *attr; char *mod; @@ -1214,7 +1214,7 @@ static int lsql_modify(struct ldb_module *module, struct ldb_request *req) goto done; } - h = ldb_attrib_handler(module->ldb, el->name); + a = ldb_schema_attribute_by_name(module->ldb, el->name); switch (flags) { @@ -1250,7 +1250,7 @@ static int lsql_modify(struct ldb_module *module, struct ldb_request *req) struct ldb_val value; /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); + a->syntax->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; goto done; @@ -1311,7 +1311,7 @@ static int lsql_modify(struct ldb_module *module, struct ldb_request *req) struct ldb_val value; /* Get a canonicalised copy of the data */ - h->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); + a->syntax->canonicalise_fn(module->ldb, lsql_ac, &(el->values[j]), &value); if (value.data == NULL) { ret = LDB_ERR_OTHER; goto done; -- cgit From 56ab0cd77c7abf777ebe5666a47fa3affea7d2ae Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 7 May 2007 15:05:04 +0000 Subject: r22746: fix the build of the sqlite module metze (This used to be commit cd958034df67a606492b69e55f1f4bc5fa95383b) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 9f580de67b..be3decfec2 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -33,8 +33,7 @@ * Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend) */ -#include "includes.h" -#include "ldb/include/includes.h" +#include "ldb_includes.h" #include -- cgit From b8d69a7ea2505b706ff7c74d7c97bc89d82dfa07 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 02:46:15 +0000 Subject: r23795: more v2->v3 conversion (This used to be commit 84b468b2f8f2dffda89593f816e8bc6a8b6d42ac) --- source4/lib/ldb/ldb_sqlite3/base160.c | 2 +- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/base160.c b/source4/lib/ldb/ldb_sqlite3/base160.c index 4286979123..f51ef6ad3e 100644 --- a/source4/lib/ldb/ldb_sqlite3/base160.c +++ b/source4/lib/ldb/ldb_sqlite3/base160.c @@ -6,7 +6,7 @@ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index be3decfec2..efb5c1da3f 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -11,7 +11,7 @@ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. + version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -- cgit From 6c973f4e8ccbcb6c9275f8a54e26abb19df7e15a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 10 Jul 2007 03:42:26 +0000 Subject: r23798: updated old Temple Place FSF addresses to new URL (This used to be commit 40c0919aaa9c1b14bbaebb95ecce53eb0380fdbb) --- source4/lib/ldb/ldb_sqlite3/base160.c | 3 +-- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/base160.c b/source4/lib/ldb/ldb_sqlite3/base160.c index f51ef6ad3e..423e2b6841 100644 --- a/source4/lib/ldb/ldb_sqlite3/base160.c +++ b/source4/lib/ldb/ldb_sqlite3/base160.c @@ -14,8 +14,7 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + License along with this library; if not, see . */ diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index efb5c1da3f..1ec3b1aabd 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -19,8 +19,7 @@ Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + License along with this library; if not, see . */ /* -- cgit From 995788536e5ba7b3a0e67e377a9769b279d0b8ae Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 20 Feb 2008 02:57:07 +0100 Subject: Remove more function-based inits. (This used to be commit b1a7810f3e70f9a831d9b8e85d531e448072adaf) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 1ec3b1aabd..8742e257f3 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1903,7 +1903,7 @@ failed: return -1; } -int ldb_sqlite3_init(void) -{ - return ldb_register_backend("sqlite3", lsqlite3_connect); -} +const struct ldb_backend_ops ldb_sqlite3_backend_ops = { + .name = "sqlite3", + .connect_fn = lsqlite3_connect +}; -- cgit From 39a817d310964f8e9a63cfb096b3ad24fa03bd5e Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Wed, 20 Feb 2008 04:33:43 +0100 Subject: Fix use of some modules (needed _PUBLIC_). (This used to be commit ce332130ea77159832da23bab760fa26921719e2) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 8742e257f3..214e7eec5f 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1903,7 +1903,7 @@ failed: return -1; } -const struct ldb_backend_ops ldb_sqlite3_backend_ops = { +_PUBLIC_ const struct ldb_backend_ops ldb_sqlite3_backend_ops = { .name = "sqlite3", .connect_fn = lsqlite3_connect }; -- cgit From e36b159e8c3d8b41823c09a612938cbf1b6e544b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 21 Feb 2008 15:51:40 +0100 Subject: ldb_sqlite: fix the build metze (This used to be commit 14c8e3101cc3b0138a551afdf3a94f4bb11bb21d) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 214e7eec5f..8742e257f3 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -1903,7 +1903,7 @@ failed: return -1; } -_PUBLIC_ const struct ldb_backend_ops ldb_sqlite3_backend_ops = { +const struct ldb_backend_ops ldb_sqlite3_backend_ops = { .name = "sqlite3", .connect_fn = lsqlite3_connect }; -- cgit From 5c6364ba0655316294833f192281d49a4de63b0c Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 18 Aug 2008 12:01:27 +1000 Subject: Remove references to the unused @SUBCLASS feature. This was removed from ldb_tdb a while ago Andrew Bartlett (This used to be commit fcb87e77860b449ac3483ccec5e6b5ed087540f2) --- source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 37 ++----------------------------- source4/lib/ldb/ldb_sqlite3/schema | 35 ----------------------------- 2 files changed, 2 insertions(+), 70 deletions(-) (limited to 'source4/lib/ldb/ldb_sqlite3') diff --git a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c index 8742e257f3..a0e63c8da1 100644 --- a/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c +++ b/source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c @@ -349,23 +349,7 @@ static char *parsetree_to_sql(struct ldb_module *module, return NULL; } - if (strcasecmp(t->u.equality.attr, "objectclass") == 0) { - /* - * For object classes, we want to search for all objectclasses - * that are subclasses as well. - */ - return lsqlite3_tprintf(mem_ctx, - "SELECT eid FROM ldb_attribute_values\n" - "WHERE norm_attr_name = 'OBJECTCLASS' " - "AND norm_attr_value IN\n" - " (SELECT class_name FROM ldb_object_classes\n" - " WHERE tree_key GLOB\n" - " (SELECT tree_key FROM ldb_object_classes\n" - " WHERE class_name = '%q'\n" - " ) || '*'\n" - " )\n", value.data); - - } else if (strcasecmp(t->u.equality.attr, "dn") == 0) { + if (strcasecmp(t->u.equality.attr, "dn") == 0) { /* DN query is a special ldb case */ const char *cdn = ldb_dn_get_casefold( ldb_dn_new(mem_ctx, module->ldb, @@ -1039,16 +1023,8 @@ static int lsql_add(struct ldb_module *module, struct ldb_request *req) /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { - struct ldb_dn *c; - - c = ldb_dn_new(lsql_ac, module->ldb, "@SUBCLASSES"); - if (ldb_dn_compare(msg->dn, c) == 0) { -#warning "insert subclasses into object class tree" - ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto done; - } - /* + struct ldb_dn *c; c = ldb_dn_new(local_ctx, module->ldb, "@INDEXLIST"); if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) { #warning "should we handle indexes somehow ?" @@ -1177,15 +1153,6 @@ static int lsql_modify(struct ldb_module *module, struct ldb_request *req) /* See if this is an ltdb special */ if (ldb_dn_is_special(msg->dn)) { - struct ldb_dn *c; - - c = ldb_dn_new(lsql_ac, module->ldb, "@SUBCLASSES"); - if (ldb_dn_compare(msg->dn, c) == 0) { -#warning "modify subclasses into object class tree" - ret = LDB_ERR_UNWILLING_TO_PERFORM; - goto done; - } - /* Others return an error */ ret = LDB_ERR_UNWILLING_TO_PERFORM; goto done; diff --git a/source4/lib/ldb/ldb_sqlite3/schema b/source4/lib/ldb/ldb_sqlite3/schema index 08dc50de08..ab7c5cc406 100644 --- a/source4/lib/ldb/ldb_sqlite3/schema +++ b/source4/lib/ldb/ldb_sqlite3/schema @@ -326,38 +326,3 @@ UPDATE ldb_attributes integer_p = 0 WHERE attr_name = 'dn' --- ---------------------------------------------------------------------- - -/* - * dn: @SUBCLASSES - * top: domain - * top: person - * domain: domainDNS - * person: organizationalPerson - * person: fooPerson - * organizationalPerson: user - * organizationalPerson: OpenLDAPperson - * user: computer - */ --- insertSubclass - -/* NOT YET UPDATED!!! * - - -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'domain', /* next_tree_key('top') */ '00010001'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'person', /* next_tree_key('top') */ '00010002'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'domainDNS', /* next_tree_key('domain') */ '000100010001'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'organizationalPerson', /* next_tree_key('person') */ '000100020001'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'fooPerson', /* next_tree_key('person') */ '000100020002'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'user', /* next_tree_key('organizationalPerson') */ '0001000200010001'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'OpenLDAPperson', /* next_tree_key('organizationPerson') */ '0001000200010002'; -INSERT OR REPLACE INTO ldb_object_classes (class_name, tree_key) - SELECT 'computer', /* next_tree_key('user') */ '0001000200010001'; - -- cgit