r13609: Get in the initial work on making ldb async
[kai/samba.git] / source / lib / ldb / ldb_sqlite3 / ldb_sqlite3.c
index 1a855e08501655012c6fa7f81243e8e4c07ee34a..48d849746fe2479f8d0f5955d6a4d33e7d12f4da 100644 (file)
  *  Author: Derrell Lipman (based on Andrew Tridgell's LDAP backend)
  */
 
-#include <stdarg.h>
 #include "includes.h"
-#include "ldb/include/ldb.h"
-#include "ldb/include/ldb_private.h"
+#include "ldb/include/includes.h"
+
 #include "ldb/ldb_sqlite3/ldb_sqlite3.h"
 
 /*
@@ -290,7 +289,7 @@ static char *parsetree_to_sql(struct ldb_module *module,
                 * For simple searches, we want to retrieve the list of EIDs that
                 * match the criteria.
                */
-               attr = ldb_casefold(mem_ctx, t->u.equality.attr);
+               attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr);
                if (attr == NULL) return NULL;
                h = ldb_attrib_handler(module->ldb, attr);
 
@@ -354,7 +353,7 @@ static char *parsetree_to_sql(struct ldb_module *module,
                        wild_card_string[strlen(wild_card_string) - 1] = '\0';
                }
 
-               attr = ldb_casefold(mem_ctx, t->u.substring.attr);
+               attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.substring.attr);
                if (attr == NULL) return NULL;
                h = ldb_attrib_handler(module->ldb, attr);
 
@@ -375,7 +374,7 @@ static char *parsetree_to_sql(struct ldb_module *module,
                                        value.data);
 
        case LDB_OP_GREATER:
-               attr = ldb_casefold(mem_ctx, t->u.equality.attr);
+               attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr);
                if (attr == NULL) return NULL;
                h = ldb_attrib_handler(module->ldb, attr);
 
@@ -388,13 +387,13 @@ static char *parsetree_to_sql(struct ldb_module *module,
                return lsqlite3_tprintf(mem_ctx,
                                        "SELECT eid FROM ldb_attribute_values "
                                        "WHERE norm_attr_name = '%q' "
-                                       "AND norm_attr_value LIKE '>=%q' ESCAPE '%q' ",
+                                       "AND ldap_compare(norm_attr_value, '>=', '%q', '%q') ",
                                        attr,
                                        value.data,
                                        attr);
 
        case LDB_OP_LESS:
-               attr = ldb_casefold(mem_ctx, t->u.equality.attr);
+               attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr);
                if (attr == NULL) return NULL;
                h = ldb_attrib_handler(module->ldb, attr);
 
@@ -407,7 +406,7 @@ static char *parsetree_to_sql(struct ldb_module *module,
                return lsqlite3_tprintf(mem_ctx,
                                        "SELECT eid FROM ldb_attribute_values "
                                        "WHERE norm_attr_name = '%q' "
-                                       "AND norm_attr_value LIKE '<=%q' ESCAPE '%q' ",
+                                       "AND ldap_compare(norm_attr_value, '<=', '%q', '%q') ",
                                        attr,
                                        value.data,
                                        attr);
@@ -417,7 +416,7 @@ static char *parsetree_to_sql(struct ldb_module *module,
                        return talloc_strdup(mem_ctx, "SELECT eid FROM ldb_entry");
                }
 
-               attr = ldb_casefold(mem_ctx, t->u.present.attr);
+               attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.present.attr);
                if (attr == NULL) return NULL;
 
                return lsqlite3_tprintf(mem_ctx,
@@ -426,7 +425,7 @@ static char *parsetree_to_sql(struct ldb_module *module,
                                        attr);
 
        case LDB_OP_APPROX:
-               attr = ldb_casefold(mem_ctx, t->u.equality.attr);
+               attr = ldb_attr_casefold(module->ldb, mem_ctx, t->u.equality.attr);
                if (attr == NULL) return NULL;
                h = ldb_attrib_handler(module->ldb, attr);
 
@@ -439,7 +438,7 @@ static char *parsetree_to_sql(struct ldb_module *module,
                return lsqlite3_tprintf(mem_ctx,
                                        "SELECT eid FROM ldb_attribute_values "
                                        "WHERE norm_attr_name = '%q' "
-                                       "AND norm_attr_value LIKE '~%q' ESCAPE '%q' ",
+                                       "AND ldap_compare(norm_attr_value, '~%', 'q', '%q') ",
                                        attr,
                                        value.data,
                                        attr);
@@ -457,57 +456,6 @@ static char *parsetree_to_sql(struct ldb_module *module,
        return NULL;
 }
 
-/* obtain a named lock */
-static int
-lsqlite3_lock(struct ldb_module * module,
-              const char * lockname)
-{
-       struct lsqlite3_private *   lsqlite3 = module->private_data;
-
-/* FIXME
-       if (lockname == NULL) {
-               return -1;
-       }
-        
-        if (strcmp(lockname, "transaction") == 0) {
-                if (lsqlite3->lock_count == 0) {
-                        if (query_norows(lsqlite3, "BEGIN EXCLUSIVE;") != 0) {
-                                return -1;
-                        }
-                }
-                ++lsqlite3->lock_count;
-        }
-*/
-       return 0;
-}
-
-/* release a named lock */
-static int
-lsqlite3_unlock(struct ldb_module *module,
-                const char *lockname)
-{
-       struct lsqlite3_private *   lsqlite3 = module->private_data;
-
-/* FIXME
-       if (lockname == NULL) {
-               return -1;
-       }
-        
-        if (strcmp(lockname, "transaction") == 0) {
-                if (lsqlite3->lock_count == 1) {
-                        if (query_norows(lsqlite3, "COMMIT;") != 0) {
-                                query_norows(lsqlite3, "ROLLBACK;");
-                        }
-                } else if (lsqlite3->lock_count > 0) {
-                        --lsqlite3->lock_count;
-                }
-        } else if (strcmp(lockname, "rollback") == 0) {
-                query_norows(lsqlite3, "ROLLBACK;");
-        }
-*/
-        return 0;
-}
-
 /*
  * query_int()
  *
@@ -606,34 +554,33 @@ query_int(const struct lsqlite3_private * lsqlite3,
 
 /*
  * This is a bad hack to support ldap style comparisons whithin sqlite.
- * This function substitues the X LIKE Y ESCAPE Z expression
- * X is an expression + value to compare against (eg: ">=test")
- * Y is the attribute in the row currently under test
- * Z is the attribute name the value of which we want to test
+ * val is the attribute in the row currently under test
+ * func is the desired test "<=" ">=" "~" ":"
+ * cmp is the value to compare against (eg: "test")
+ * attr is the attribute name the value of which we want to test
  */
 
 static void lsqlite3_compare(sqlite3_context *ctx, int argc,
                                        sqlite3_value **argv)
 {
        struct ldb_context *ldb = (struct ldb_context *)sqlite3_user_data(ctx);
-       const unsigned char *X = sqlite3_value_text(argv[0]);
-       const unsigned char *Y = sqlite3_value_text(argv[1]);
-       const unsigned char *Z = sqlite3_value_text(argv[2]);
-       const unsigned char *p;
+       const unsigned char *val = sqlite3_value_text(argv[0]);
+       const unsigned char *func = sqlite3_value_text(argv[1]);
+       const unsigned char *cmp = sqlite3_value_text(argv[2]);
+       const unsigned char *attr = sqlite3_value_text(argv[3]);
        const struct ldb_attrib_handler *h;
        struct ldb_val valX;
        struct ldb_val valY;
        int ret;
 
-       switch (X[0]) {
+       switch (func[0]) {
        /* greater */
        case '>': /* >= */
-               p = &(X[2]);
-               h = ldb_attrib_handler(ldb, Z);
-               valX.data = p;
-               valX.length = strlen(p);
-               valY.data = Y;
-               valY.length = strlen(Y);
+               h = ldb_attrib_handler(ldb, attr);
+               valX.data = cmp;
+               valX.length = strlen(cmp);
+               valY.data = val;
+               valY.length = strlen(val);
                ret = h->comparison_fn(ldb, ldb, &valY, &valX);
                if (ret >= 0)
                        sqlite3_result_int(ctx, 1);
@@ -643,12 +590,11 @@ static void lsqlite3_compare(sqlite3_context *ctx, int argc,
 
        /* lesser */
        case '<': /* <= */
-               p = &(X[2]);
-               h = ldb_attrib_handler(ldb, Z);
-               valX.data = p;
-               valX.length = strlen(p);
-               valY.data = Y;
-               valY.length = strlen(Y);
+               h = ldb_attrib_handler(ldb, attr);
+               valX.data = cmp;
+               valX.length = strlen(cmp);
+               valY.data = val;
+               valY.length = strlen(val);
                ret = h->comparison_fn(ldb, ldb, &valY, &valX);
                if (ret <= 0)
                        sqlite3_result_int(ctx, 1);
@@ -687,7 +633,7 @@ static int lsqlite3_safe_rollback(sqlite3 *sqlite)
        ret = sqlite3_exec(sqlite, "ROLLBACK;", NULL, NULL, &errmsg);
        if (ret != SQLITE_OK) {
                if (errmsg) {
-                       printf("lsqlite3_safe_rollback: Serious Error: %s\n", errmsg);
+                       printf("lsqlite3_safe_rollback: Error: %s\n", errmsg);
                        free(errmsg);
                }
                return -1;
@@ -769,26 +715,8 @@ static int lsqlite3_search_callback(void *result, int col_num, char **cols, char
                if (!found) return 0;
        }
 
-       msg->elements = talloc_realloc(msg,
-                                      msg->elements,
-                                      struct ldb_message_element,
-                                      msg->num_elements + 1);
-       if (msg->elements == NULL) return SQLITE_ABORT;
-
-       msg->elements[msg->num_elements].flags = 0;
-       msg->elements[msg->num_elements].name = talloc_strdup(msg->elements, cols[2]);
-       if (msg->elements[msg->num_elements].name == NULL) return SQLITE_ABORT;
-
-       msg->elements[msg->num_elements].num_values = 1;
-       msg->elements[msg->num_elements].values = talloc_array(msg->elements,
-                                                               struct ldb_val, 1);
-       if (msg->elements[msg->num_elements].values == NULL) return SQLITE_ABORT;
-
-       msg->elements[msg->num_elements].values[0].length = strlen(cols[3]);
-       msg->elements[msg->num_elements].values[0].data = talloc_strdup(msg->elements, cols[3]);
-       if (msg->elements[msg->num_elements].values[0].data == NULL) return SQLITE_ABORT;
-
-       msg->num_elements++;
+       if (ldb_msg_add_string(msg, cols[2], cols[3]) != 0)
+               return SQLITE_ABORT;
 
        return SQLITE_OK;
 }
@@ -862,7 +790,7 @@ done:
 /* search for matching records, by tree */
 static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_dn* basedn,
                                  enum ldb_scope scope, struct ldb_parse_tree * tree,
-                                 const char * const * attrs, struct ldb_message *** res)
+                                 const char * const * attrs, struct ldb_result ** res)
 {
        TALLOC_CTX *local_ctx;
        struct lsqlite3_private *lsqlite3 = module->private_data;
@@ -870,23 +798,28 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d
        char *norm_basedn;
        char *sqlfilter;
        char *errmsg;
-       char *query;
+       char *query = NULL;
         int ret, i;
 
        /* create a local ctx */
-       local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_search_by_tree local context");
+       local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_search_bytree local context");
        if (local_ctx == NULL) {
                return -1;
        }
 
        if (basedn) {
                norm_basedn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, basedn));
-               if (norm_basedn == NULL) goto failed;
+               if (norm_basedn == NULL) {
+                       ret = LDB_ERR_INVALID_DN_SYNTAX;
+                       goto failed;
+               }
        } else norm_basedn = talloc_strdup(local_ctx, "");
 
        if (*norm_basedn == '\0' &&
-               (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL))
+               (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) {
+                       ret = LDB_ERR_UNWILLING_TO_PERFORM;
                        goto failed;
+               }
 
         /* Convert filter into a series of SQL conditions (constraints) */
        sqlfilter = parsetree_to_sql(module, local_ctx, tree);
@@ -993,7 +926,7 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d
         }
 
         if (query == NULL) {
-                ret = -1;
+                ret = LDB_ERR_OTHER;
                 goto failed;
         }
 
@@ -1010,64 +943,37 @@ static int lsqlite3_search_bytree(struct ldb_module * module, const struct ldb_d
        ret = sqlite3_exec(lsqlite3->sqlite, query, lsqlite3_search_callback, &msgs, &errmsg);
        if (ret != SQLITE_OK) {
                if (errmsg) {
-                       printf("lsqlite3_search_bytree: Fatal Error: %s\n", errmsg);
+                       ldb_set_errstring(module, talloc_strdup(module, errmsg));
                        free(errmsg);
                }
+               ret = LDB_ERR_OTHER;
                goto failed;
        }
 
        for (i = 0; i < msgs.count; i++) {
                msgs.msgs[i] = ldb_msg_canonicalize(module->ldb, msgs.msgs[i]);
-               if (msgs.msgs[i] ==  NULL) goto failed;
+               if (msgs.msgs[i] ==  NULL) {
+                       goto failed;
+               }
        }
 
-       *res = talloc_steal(module, msgs.msgs);
-       ret = msgs.count;
+       *res = talloc(module, struct ldb_result);
+       if (! *res) {
+               goto failed;
+       }
+
+       (*res)->msgs = talloc_steal(*res, msgs.msgs);
+       (*res)->count = msgs.count;
+       (*res)->refs = NULL;
+       (*res)->controls = NULL;
 
        talloc_free(local_ctx);
-       return ret;
+       return LDB_SUCCESS;
 
 /* If error, return error code; otherwise return number of results */
 failed:
         talloc_free(local_ctx);
-       return -1;
-}
-
-/* search for matching records, by expression */
-static int lsqlite3_search(struct ldb_module * module, const struct ldb_dn *basedn,
-                          enum ldb_scope scope, const char * expression,
-                          const char * const *attrs, struct ldb_message *** res)
-{
-        struct ldb_parse_tree * tree;
-        int ret;
-        
-        /* Handle tdb specials */
-        if (ldb_dn_is_special(basedn)) {
-#warning "handle tdb specials"
-                return 0;
-        }
-
-#if 0 
-/* (|(objectclass=*)(dn=*)) is  passed by the command line tool now instead */
-        /* Handle the special case of requesting all */
-        if (pExpression != NULL && *pExpression == '\0') {
-                pExpression = "dn=*";
-        }
-#endif
-
-        /* Parse the filter expression into a tree we can work with */
-       if ((tree = ldb_parse_tree(module->ldb, expression)) == NULL) {
-                return -1;
-       }
-        
-        /* Now use the bytree function for the remainder of processing */
-        ret = lsqlite3_search_bytree(module, basedn, scope, tree, attrs, res);
-        
-        /* Free the parse tree */
-       talloc_free(tree);
-        
-        /* All done. */
-        return ret;
+       return LDB_ERR_OTHER;
 }
 
 
@@ -1080,14 +986,13 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg
        char *dn, *ndn;
        char *errmsg;
        char *query;
-       int rollback = 0;
        int ret;
        int i;
         
        /* create a local ctx */
        local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_add local context");
        if (local_ctx == NULL) {
-               return -1;
+               return LDB_ERR_OTHER;
        }
 
         /* See if this is an ltdb special */
@@ -1097,6 +1002,7 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg
                c = ldb_dn_explode(local_ctx, "@SUBCLASSES");
                if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) {
 #warning "insert subclasses into object class tree"
+                       ret = LDB_ERR_UNWILLING_TO_PERFORM;
                        goto failed;
                }
 
@@ -1108,37 +1014,43 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg
                }
 */
                 /* Others are implicitly ignored */
-                return 0;
+                return LDB_SUCCESS;
        }
 
        /* create linearized and normalized dns */
        dn = ldb_dn_linearize(local_ctx, msg->dn);
        ndn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, msg->dn));
-       if (dn == NULL || ndn == NULL) goto failed;
+       if (dn == NULL || ndn == NULL) {
+               ret = LDB_ERR_OTHER;
+               goto failed;
+       }
 
        query = lsqlite3_tprintf(local_ctx,
-                                  /* Begin the transaction */
-                                  "BEGIN EXCLUSIVE; "
                                   /* Add new entry */
                                   "INSERT OR ABORT INTO ldb_entry "
                                   "('dn', 'norm_dn') "
                                   "VALUES ('%q', '%q');",
                                dn, ndn);
-       if (query == NULL) goto failed;
+       if (query == NULL) {
+               ret = LDB_ERR_OTHER;
+               goto failed;
+       }
 
        ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK) {
                if (errmsg) {
-                       printf("lsqlite3_add: exec error: %s\n", errmsg);
+                       ldb_set_errstring(module, talloc_strdup(module, errmsg));
                        free(errmsg);
                }
-               lsqlite3_safe_rollback(lsqlite3->sqlite); 
+               ret = LDB_ERR_OTHER;
                goto failed;
        }
-       rollback = 1;
 
        eid = lsqlite3_get_eid_ndn(lsqlite3->sqlite, local_ctx, ndn);
-       if (eid == -1) goto failed;
+       if (eid == -1) {
+               ret = LDB_ERR_OTHER;
+               goto failed;
+       }
 
        for (i = 0; i < msg->num_elements; i++) {
                const struct ldb_message_element *el = &msg->elements[i];
@@ -1147,8 +1059,11 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg
                int j;
 
                /* Get a case-folded copy of the attribute name */
-               attr = ldb_casefold(local_ctx, el->name);
-               if (attr == NULL) goto failed;
+               attr = ldb_attr_casefold(module->ldb, local_ctx, el->name);
+               if (attr == NULL) {
+                       ret = LDB_ERR_OTHER;
+                       goto failed;
+               }
 
                h = ldb_attrib_handler(module->ldb, el->name);
 
@@ -1159,7 +1074,10 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg
 
                        /* Get a canonicalised copy of the data */
                        h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value);
-                       if (value.data == NULL) goto failed;
+                       if (value.data == NULL) {
+                               ret = LDB_ERR_OTHER;
+                               goto failed;
+                       }
 
                        insert = lsqlite3_tprintf(local_ctx,
                                        "INSERT OR ROLLBACK INTO ldb_attribute_values "
@@ -1168,35 +1086,29 @@ static int lsqlite3_add(struct ldb_module *module, const struct ldb_message *msg
                                        "VALUES ('%lld', '%q', '%q', '%q', '%q');",
                                        eid, el->name, attr,
                                        el->values[j].data, value.data);
-                       if (insert == NULL) goto failed;
+                       if (insert == NULL) {
+                               ret = LDB_ERR_OTHER;
+                               goto failed;
+                       }
 
                        ret = sqlite3_exec(lsqlite3->sqlite, insert, NULL, NULL, &errmsg);
                        if (ret != SQLITE_OK) {
                                if (errmsg) {
-                                       printf("lsqlite3_add: insert error: %s\n", errmsg);
+                                       ldb_set_errstring(module, talloc_strdup(module, errmsg));
                                        free(errmsg);
                                }
+                               ret = LDB_ERR_OTHER;
                                goto failed;
                        }
                }
        }
 
-       ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg);
-       if (ret != SQLITE_OK) {
-               if (errmsg) {
-                       printf("lsqlite3_add: commit error: %s\n", errmsg);
-                       free(errmsg);
-               }
-               goto failed;
-       }
-
        talloc_free(local_ctx);
-        return 0;
+        return LDB_SUCCESS;
 
 failed:
-       if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite); 
        talloc_free(local_ctx);
-       return -1;
+       return ret;
 }
 
 
@@ -1207,14 +1119,13 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
        struct lsqlite3_private *lsqlite3 = module->private_data;
         long long eid;
        char *errmsg;
-       int rollback = 0;
        int ret;
        int i;
         
        /* create a local ctx */
        local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_modify local context");
        if (local_ctx == NULL) {
-               return -1;
+               return LDB_ERR_OTHER;
        }
 
         /* See if this is an ltdb special */
@@ -1224,31 +1135,17 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
                c = ldb_dn_explode(local_ctx, "@SUBCLASSES");
                if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) {
 #warning "modify subclasses into object class tree"
-                       goto failed;
-               }
-
-               c = ldb_dn_explode(local_ctx, "@INDEXLIST");
-               if (ldb_dn_compare(module->ldb, msg->dn, c) == 0) {
-#warning "should we handle indexes somehow ?"
+                       ret = LDB_ERR_UNWILLING_TO_PERFORM;
                        goto failed;
                }
 
                 /* Others are implicitly ignored */
-                return 0;
-       }
-
-       ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN EXCLUSIVE;", NULL, NULL, &errmsg);
-       if (ret != SQLITE_OK) {
-               if (errmsg) {
-                       printf("lsqlite3_modify: error: %s\n", errmsg);
-                       free(errmsg);
-               }
-               goto failed;
+                return LDB_SUCCESS;
        }
-       rollback = 1;
 
        eid = lsqlite3_get_eid(module, msg->dn);
        if (eid == -1) {
+               ret = LDB_ERR_OTHER;
                goto failed;
        }
 
@@ -1261,8 +1158,9 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
                int j;
 
                /* Get a case-folded copy of the attribute name */
-               attr = ldb_casefold(local_ctx, el->name);
+               attr = ldb_attr_casefold(module->ldb, local_ctx, el->name);
                if (attr == NULL) {
+                       ret = LDB_ERR_OTHER;
                        goto failed;
                }
 
@@ -1278,14 +1176,18 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
                                                "WHERE eid = '%lld' "
                                                "AND norm_attr_name = '%q';",
                                                eid, attr);
-                       if (mod == NULL) goto failed;
+                       if (mod == NULL) {
+                               ret = LDB_ERR_OTHER;
+                               goto failed;
+                       }
 
                        ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
                        if (ret != SQLITE_OK) {
                                if (errmsg) {
-                                       printf("lsqlite3_modify: error: %s\n", errmsg);
+                                       ldb_set_errstring(module, talloc_strdup(module, errmsg));
                                        free(errmsg);
                                }
+                               ret = LDB_ERR_OTHER;
                                goto failed;
                         }
 
@@ -1300,6 +1202,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
                                /* Get a canonicalised copy of the data */
                                h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value);
                                if (value.data == NULL) {
+                                       ret = LDB_ERR_OTHER;
                                        goto failed;
                                }
 
@@ -1311,14 +1214,18 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
                                        eid, el->name, attr,
                                        el->values[j].data, value.data);
 
-                               if (mod == NULL) goto failed;
+                               if (mod == NULL) {
+                                       ret = LDB_ERR_OTHER;
+                                       goto failed;
+                               }
 
                                ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
                                if (ret != SQLITE_OK) {
                                        if (errmsg) {
-                                               printf("lsqlite3_modify: error: %s\n", errmsg);
+                                               ldb_set_errstring(module, talloc_strdup(module, errmsg));
                                                free(errmsg);
                                        }
+                                       ret = LDB_ERR_OTHER;
                                        goto failed;
                                }
                        }
@@ -1333,14 +1240,18 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
                                                        "WHERE eid = '%lld' "
                                                        "AND norm_attr_name = '%q';",
                                                        eid, attr);
-                               if (mod == NULL) goto failed;
+                               if (mod == NULL) {
+                                       ret = LDB_ERR_OTHER;
+                                       goto failed;
+                               }
 
                                ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
                                if (ret != SQLITE_OK) {
                                        if (errmsg) {
-                                               printf("lsqlite3_modify: error: %s\n", errmsg);
+                                               ldb_set_errstring(module, talloc_strdup(module, errmsg));
                                                free(errmsg);
                                        }
+                                       ret = LDB_ERR_OTHER;
                                        goto failed;
                                }
                        }
@@ -1352,6 +1263,7 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
                                /* Get a canonicalised copy of the data */
                                h->canonicalise_fn(module->ldb, local_ctx, &(el->values[j]), &value);
                                if (value.data == NULL) {
+                                       ret = LDB_ERR_OTHER;
                                        goto failed;
                                }
 
@@ -1362,14 +1274,18 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
                                        "AND norm_attr_value = '%q';",
                                        eid, attr, value.data);
 
-                               if (mod == NULL) goto failed;
+                               if (mod == NULL) {
+                                       ret = LDB_ERR_OTHER;
+                                       goto failed;
+                               }
 
                                ret = sqlite3_exec(lsqlite3->sqlite, mod, NULL, NULL, &errmsg);
                                if (ret != SQLITE_OK) {
                                        if (errmsg) {
-                                               printf("lsqlite3_modify: error: %s\n", errmsg);
+                                               ldb_set_errstring(module, talloc_strdup(module, errmsg));
                                                free(errmsg);
                                        }
+                                       ret = LDB_ERR_OTHER;
                                        goto failed;
                                }
                        }
@@ -1378,22 +1294,12 @@ static int lsqlite3_modify(struct ldb_module *module, const struct ldb_message *
                }
        }
 
-       ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg);
-       if (ret != SQLITE_OK) {
-               if (errmsg) {
-                       printf("lsqlite3_modify: error: %s\n", errmsg);
-                       free(errmsg);
-               }
-               goto failed;
-       }
-
        talloc_free(local_ctx);
-        return 0;
+        return LDB_SUCCESS;
 
 failed:
-       if (rollback) lsqlite3_safe_rollback(lsqlite3->sqlite); 
        talloc_free(local_ctx);
-       return -1;
+       return ret;
 }
 
 /* delete a record */
@@ -1408,46 +1314,48 @@ static int lsqlite3_delete(struct ldb_module *module, const struct ldb_dn *dn)
 
        /* ignore ltdb specials */
        if (ldb_dn_is_special(dn)) {
-               return 0;
+               return LDB_SUCCESS;
        }
 
        /* create a local ctx */
        local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_delete local context");
        if (local_ctx == NULL) {
-               return -1;
+               return LDB_ERR_OTHER;
        }
 
        eid = lsqlite3_get_eid(module, dn);
-       if (eid == -1) goto failed;
+       if (eid == -1) {
+               ret = LDB_ERR_OTHER;
+               goto failed;
+       }
 
        query = lsqlite3_tprintf(local_ctx,
-                                  /* Begin the transaction */
-                                  "BEGIN EXCLUSIVE; "
                                   /* Delete entry */
                                   "DELETE FROM ldb_entry WHERE eid = %lld; "
                                   /* Delete attributes */
-                                  "DELETE FROM ldb_attribute_values WHERE eid = %lld; "
-                                  /* Commit */
-                                  "COMMIT;",
+                                  "DELETE FROM ldb_attribute_values WHERE eid = %lld; ",
                                eid, eid);
-       if (query == NULL) goto failed;
+       if (query == NULL) {
+               ret = LDB_ERR_OTHER;
+               goto failed;
+       }
 
        ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK) {
                if (errmsg) {
-                       printf("lsqlite3_delete: error getting eid: %s\n", errmsg);
+                       ldb_set_errstring(module, talloc_strdup(module, errmsg));
                        free(errmsg);
                }
-               lsqlite3_safe_rollback(lsqlite3->sqlite);
+               ret = LDB_ERR_OTHER;
                goto failed;
        }
 
        talloc_free(local_ctx);
-        return 0;
+        return LDB_SUCCESS;
 
 failed:
        talloc_free(local_ctx);
-       return -1;
+       return ret;
 }
 
 /* rename a record */
@@ -1462,64 +1370,121 @@ static int lsqlite3_rename(struct ldb_module *module, const struct ldb_dn *olddn
 
        /* ignore ltdb specials */
        if (ldb_dn_is_special(olddn) || ldb_dn_is_special(newdn)) {
-               return 0;
+               return LDB_SUCCESS;
        }
 
        /* create a local ctx */
        local_ctx = talloc_named(lsqlite3, 0, "lsqlite3_rename local context");
        if (local_ctx == NULL) {
-               return -1;
+               return LDB_ERR_OTHER;
        }
 
        /* create linearized and normalized dns */
        old_cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, olddn));
        new_cdn = ldb_dn_linearize(local_ctx, ldb_dn_casefold(module->ldb, newdn));
        new_dn = ldb_dn_linearize(local_ctx, newdn);
-       if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) goto failed;
+       if (old_cdn == NULL || new_cdn == NULL || new_dn == NULL) {
+               ret = LDB_ERR_OTHER;
+               goto failed;
+       }
 
        /* build the SQL query */
        query = lsqlite3_tprintf(local_ctx,
                                 "UPDATE ldb_entry SET dn = '%q', norm_dn = '%q' "
                                 "WHERE norm_dn = '%q';",
                                 new_dn, new_cdn, old_cdn);
-       if (query == NULL) goto failed;
+       if (query == NULL) {
+               ret = LDB_ERR_OTHER;
+               goto failed;
+       }
 
        /* execute */
        ret = sqlite3_exec(lsqlite3->sqlite, query, NULL, NULL, &errmsg);
        if (ret != SQLITE_OK) {
                if (errmsg) {
-                       printf("lsqlite3_rename: sqlite3_exec error: %s\n", errmsg);
+                       ldb_set_errstring(module, talloc_strdup(module, errmsg));
                        free(errmsg);
                }
+               ret = LDB_ERR_OTHER;
                goto failed;
        }
 
        /* clean up and exit */
        talloc_free(local_ctx);
-        return 0;
+        return LDB_SUCCESS;
 
 failed:
        talloc_free(local_ctx);
-       return -1;
+       return ret;
 }
-/* return extended error information */
-static const char *
-lsqlite3_errstring(struct ldb_module *module)
+
+static int lsqlite3_start_trans(struct ldb_module * module)
 {
+       int ret;
+       char *errmsg;
        struct lsqlite3_private *   lsqlite3 = module->private_data;
-        
-       return sqlite3_errmsg(lsqlite3->sqlite);
+
+       if (lsqlite3->trans_count == 0) {
+               ret = sqlite3_exec(lsqlite3->sqlite, "BEGIN IMMEDIATE;", NULL, NULL, &errmsg);
+               if (ret != SQLITE_OK) {
+                       if (errmsg) {
+                               printf("lsqlite3_start_trans: error: %s\n", errmsg);
+                               free(errmsg);
+                       }
+                       return -1;
+               }
+       };
+
+       lsqlite3->trans_count++;
+
+       return 0;
+}
+
+static int lsqlite3_end_trans(struct ldb_module *module)
+{
+       int ret;
+       char *errmsg;
+       struct lsqlite3_private *lsqlite3 = module->private_data;
+
+       if (lsqlite3->trans_count > 0) {
+               lsqlite3->trans_count--;
+       } else return -1;
+
+       if (lsqlite3->trans_count == 0) {
+               ret = sqlite3_exec(lsqlite3->sqlite, "COMMIT;", NULL, NULL, &errmsg);
+               if (ret != SQLITE_OK) {
+                       if (errmsg) {
+                               printf("lsqlite3_end_trans: error: %s\n", errmsg);
+                               free(errmsg);
+                       }
+                       return -1;
+               }
+       }
+
+        return 0;
 }
 
+static int lsqlite3_del_trans(struct ldb_module *module)
+{
+       struct lsqlite3_private *lsqlite3 = module->private_data;
+
+       if (lsqlite3->trans_count > 0) {
+               lsqlite3->trans_count--;
+       } else return -1;
 
+       if (lsqlite3->trans_count == 0) {
+               return lsqlite3_safe_rollback(lsqlite3->sqlite);
+       }
 
+       return -1;
+}
 
 /*
  * Static functions
  */
 
 static int initialize(struct lsqlite3_private *lsqlite3,
-                       struct ldb_context *ldb, const char *url)
+                     struct ldb_context *ldb, const char *url, int flags)
 {
        TALLOC_CTX *local_ctx;
         long long queryInt;
@@ -1645,14 +1610,16 @@ static int initialize(struct lsqlite3_private *lsqlite3,
                goto failed;
        }
         
-       /* DANGEROUS */
-       ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg);
-       if (ret != SQLITE_OK) {
-               if (errmsg) {
-                       printf("lsqlite3 initializaion error: %s\n", errmsg);
-                       free(errmsg);
+       if (flags & LDB_FLG_NOSYNC) {
+               /* DANGEROUS */
+               ret = sqlite3_exec(lsqlite3->sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, &errmsg);
+               if (ret != SQLITE_OK) {
+                       if (errmsg) {
+                               printf("lsqlite3 initializaion error: %s\n", errmsg);
+                               free(errmsg);
+                       }
+                       goto failed;
                }
-               goto failed;
        }
         
        /* */
@@ -1694,8 +1661,8 @@ static int initialize(struct lsqlite3_private *lsqlite3,
         /* Create a function, callable from sql, to perform various comparisons */
         if ((ret =
              sqlite3_create_function(lsqlite3->sqlite, /* handle */
-                                     "like",           /* function name */
-                                     3,                /* number of args */
+                                     "ldap_compare",   /* function name */
+                                     4,                /* number of args */
                                      SQLITE_ANY,       /* preferred text type */
                                      ldb  ,            /* user data */
                                      lsqlite3_compare, /* called func */
@@ -1796,21 +1763,58 @@ destructor(void *p)
 }
 
 
+static int lsqlite3_request(struct ldb_module *module, struct ldb_request *req)
+{
+       /* check for oustanding critical controls and return an error if found */
+       if (check_critical_controls(req->controls)) {
+               return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
+       }
+       
+       switch (req->operation) {
+
+       case LDB_REQ_SEARCH:
+               return lsqlite3_search_bytree(module,
+                                         req->op.search.base,
+                                         req->op.search.scope, 
+                                         req->op.search.tree, 
+                                         req->op.search.attrs, 
+                                         &req->op.search.res);
+
+       case LDB_REQ_ADD:
+               return lsqlite3_add(module, req->op.add.message);
+
+       case LDB_REQ_MODIFY:
+               return lsqlite3_modify(module, req->op.mod.message);
+
+       case LDB_REQ_DELETE:
+               return lsqlite3_delete(module, req->op.del.dn);
+
+       case LDB_REQ_RENAME:
+               return lsqlite3_rename(module,
+                                       req->op.rename.olddn,
+                                       req->op.rename.newdn);
+
+       default:
+               return LDB_ERR_OPERATIONS_ERROR;
+
+       }
+}
+
+static int lsqlite3_init_2(struct ldb_module *module)
+{
+       return LDB_SUCCESS;
+}
 
 /*
  * Table of operations for the sqlite3 backend
  */
 static const struct ldb_module_ops lsqlite3_ops = {
-       .name          = "sqlite",
-       .search        = lsqlite3_search,
-       .search_bytree = lsqlite3_search_bytree,
-       .add_record    = lsqlite3_add,
-       .modify_record = lsqlite3_modify,
-       .delete_record = lsqlite3_delete,
-       .rename_record = lsqlite3_rename,
-       .named_lock    = lsqlite3_lock,
-       .named_unlock  = lsqlite3_unlock,
-       .errstring     = lsqlite3_errstring
+       .name              = "sqlite",
+       .request           = lsqlite3_request,
+       .start_transaction = lsqlite3_start_trans,
+       .end_transaction   = lsqlite3_end_trans,
+       .del_transaction   = lsqlite3_del_trans,
+       .second_stage_init = lsqlite3_init_2
 };
 
 /*
@@ -1832,8 +1836,9 @@ int lsqlite3_connect(struct ldb_context *ldb,
         
        lsqlite3->sqlite = NULL;
        lsqlite3->options = NULL;
+       lsqlite3->trans_count = 0;
         
-       ret = initialize(lsqlite3, ldb, url);
+       ret = initialize(lsqlite3, ldb, url, flags);
        if (ret != SQLITE_OK) {
                goto failed;
        }