summaryrefslogtreecommitdiff
path: root/source4/lib/ldb
diff options
context:
space:
mode:
authorDerrell Lipman <derrell@samba.org>2005-06-22 02:39:07 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:18:41 -0500
commitfdc0450db25021eddcc65d032fd3fd8ca5976928 (patch)
tree936ca067bde179cb18c349f858ec371a65ae5502 /source4/lib/ldb
parent8a68f96f8cea2c53c8babf2ec826dfc6ef1cc199 (diff)
downloadsamba-fdc0450db25021eddcc65d032fd3fd8ca5976928.tar.gz
samba-fdc0450db25021eddcc65d032fd3fd8ca5976928.tar.bz2
samba-fdc0450db25021eddcc65d032fd3fd8ca5976928.zip
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)
Diffstat (limited to 'source4/lib/ldb')
-rw-r--r--source4/lib/ldb/common/ldb.c18
-rw-r--r--source4/lib/ldb/include/ldb.h10
-rw-r--r--source4/lib/ldb/ldb_sqlite3/base160.c3
-rw-r--r--source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.c1102
-rw-r--r--source4/lib/ldb/ldb_sqlite3/ldb_sqlite3.h8
-rw-r--r--source4/lib/ldb/ldb_sqlite3/schema367
-rwxr-xr-xsource4/lib/ldb/tests/test-sqlite3.sh2
-rw-r--r--source4/lib/ldb/tools/ldbtest.c10
8 files changed, 1156 insertions, 364 deletions
diff --git a/source4/lib/ldb/common/ldb.c b/source4/lib/ldb/common/ldb.c
index e268a8d0d7..63526dfe2e 100644
--- a/source4/lib/ldb/common/ldb.c
+++ b/source4/lib/ldb/common/ldb.c
@@ -76,7 +76,7 @@ int ldb_connect(struct ldb_context *ldb, const char *url, unsigned int flags, co
#endif
#if HAVE_SQLITE3
else if (strncmp(url, "sqlite:", 7) == 0) {
- ldb_ctx = lsqlite3_connect(url, flags, options);
+ ret = lsqlite3_connect(ldb, url, flags, options);
}
#endif
else {
@@ -168,6 +168,22 @@ int ldb_rename(struct ldb_context *ldb, const char *olddn, const char *newdn)
}
/*
+ create a named lock
+*/
+int ldb_lock(struct ldb_context *ldb, const char *lockname)
+{
+ return ldb->modules->ops->named_lock(ldb->modules, lockname);
+}
+
+/*
+ release a named lock
+*/
+int ldb_unlock(struct ldb_context *ldb, const char *lockname)
+{
+ return ldb->modules->ops->named_unlock(ldb->modules, lockname);
+}
+
+/*
return extended error information
*/
const char *ldb_errstring(struct ldb_context *ldb)
diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h
index 3102676327..1b5c7c4f57 100644
--- a/source4/lib/ldb/include/ldb.h
+++ b/source4/lib/ldb/include/ldb.h
@@ -255,6 +255,16 @@ int ldb_modify(struct ldb_context *ldb,
int ldb_rename(struct ldb_context *ldb, const char *olddn, const char *newdn);
/*
+ create a named lock
+*/
+int ldb_lock(struct ldb_context *ldb, const char *lockname);
+
+/*
+ release a named lock
+*/
+int ldb_unlock(struct ldb_context *ldb, const char *lockname);
+
+/*
delete a record from the database
*/
int ldb_delete(struct ldb_context *ldb, const char *dn);
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 <sqlite3.h>
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';
+
diff --git a/source4/lib/ldb/tests/test-sqlite3.sh b/source4/lib/ldb/tests/test-sqlite3.sh
index cf443bb8a1..95babeac8d 100755
--- a/source4/lib/ldb/tests/test-sqlite3.sh
+++ b/source4/lib/ldb/tests/test-sqlite3.sh
@@ -1,7 +1,7 @@
#!/bin/sh
-export LDB_URL="sqlite://sqltest.ldb"
+export LDB_URL="sqlite:///var/tmp/test.ldb"
rm -f sqltest.ldb
diff --git a/source4/lib/ldb/tools/ldbtest.c b/source4/lib/ldb/tools/ldbtest.c
index 7c7164c785..aff1eaadda 100644
--- a/source4/lib/ldb/tools/ldbtest.c
+++ b/source4/lib/ldb/tools/ldbtest.c
@@ -64,6 +64,11 @@ static void add_records(struct ldb_context *ldb,
struct ldb_message msg;
int i;
+ if (ldb_lock(ldb, "transaction") != 0) {
+ printf("transaction lock failed\n");
+ exit(1);
+ }
+
for (i=0;i<count;i++) {
struct ldb_message_element el[6];
struct ldb_val vals[6][1];
@@ -131,6 +136,11 @@ static void add_records(struct ldb_context *ldb,
talloc_free(tmp_ctx);
}
+ if (ldb_unlock(ldb, "transaction") != 0) {
+ printf("transaction unlock failed\n");
+ exit(1);
+ }
+
printf("\n");
}