diff options
Diffstat (limited to 'source4/lib/ldb/ldb_sqlite3')
-rw-r--r-- | source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c | 669 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h | 18 | ||||
-rw-r--r-- | source4/lib/ldb/ldb_sqlite3/schema | 207 |
3 files changed, 327 insertions, 567 deletions
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, |