mirror of
https://github.com/samba-team/samba.git
synced 2025-11-25 00:23:52 +03:00
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 commit is contained in:
committed by
Gerald (Jerry) Carter
parent
c19d5706f4
commit
1dd8650055
@@ -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 {
|
||||
@@ -167,6 +167,22 @@ int ldb_rename(struct ldb_context *ldb, const char *olddn, const char *newdn)
|
||||
return ldb->modules->ops->rename_record(ldb->modules, olddn, 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
|
||||
*/
|
||||
|
||||
@@ -254,6 +254,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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
#include <sqlite3.h>
|
||||
|
||||
struct lsqlite3_private {
|
||||
char **options;
|
||||
const char *basedn;
|
||||
char ** options;
|
||||
const char * basedn;
|
||||
sqlite3 * sqlite;
|
||||
int lock_count;
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
value INTEGER
|
||||
);
|
||||
|
||||
-- Unique identifier of the parent LDB entry
|
||||
peid INTEGER REFERENCES ldb_entry,
|
||||
CREATE TABLE ldb_object
|
||||
(
|
||||
/* tree_key is auto-generated by the insert trigger */
|
||||
tree_key TEXT PRIMARY KEY,
|
||||
|
||||
-- Distinguished name of this entry
|
||||
parent_tree_key TEXT,
|
||||
dn TEXT,
|
||||
|
||||
-- Time when the entry was created
|
||||
create_timestamp INTEGER,
|
||||
|
||||
-- Time when the entry was last modified
|
||||
modify_timestamp INTEGER
|
||||
);
|
||||
|
||||
attr_name TEXT REFERENCES ldb_attributes,
|
||||
attr_value 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.
|
||||
* 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
|
||||
*/
|
||||
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
|
||||
);
|
||||
object_type INTEGER,
|
||||
|
||||
/*
|
||||
* We keep a full listing of attribute/value pairs here
|
||||
* 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.
|
||||
*/
|
||||
CREATE TABLE ldb_attribute_values
|
||||
(
|
||||
eid INTEGER REFERENCES ldb_entry,
|
||||
|
||||
attr_name TEXT, -- see ldb_attr_ATTRIBUTE_NAME
|
||||
|
||||
attr_value TEXT
|
||||
);
|
||||
|
||||
max_child_num INTEGER,
|
||||
|
||||
/*
|
||||
* There is one attribute table per searchable attribute.
|
||||
* Automatically maintained meta-data (a gift for metze)
|
||||
*/
|
||||
/*
|
||||
CREATE TABLE ldb_attr_ATTRIBUTE_NAME
|
||||
(
|
||||
-- The unique identifier of the LDB entry
|
||||
eid INTEGER REFERENCES ldb_entry,
|
||||
object_guid TEXT UNIQUE,
|
||||
timestamp INTEGER, -- originating_time
|
||||
invoke_id TEXT, -- GUID: originating_invocation_id
|
||||
usn INTEGER, -- hyper: originating_usn
|
||||
|
||||
-- Normalized attribute value
|
||||
attr_value TEXT
|
||||
/* 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,
|
||||
parent_tree_key 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,
|
||||
|
||||
/* 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';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
|
||||
export LDB_URL="sqlite://sqltest.ldb"
|
||||
export LDB_URL="sqlite:///var/tmp/test.ldb"
|
||||
|
||||
rm -f sqltest.ldb
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user