r7601: ldb_sqlite3 work in progress
authorDerrell Lipman <derrell@samba.org>
Wed, 15 Jun 2005 02:43:42 +0000 (02:43 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:18:13 +0000 (13:18 -0500)
source/lib/ldb/common/ldb_explode_dn.c
source/lib/ldb/common/ldb_utf8.c
source/lib/ldb/include/ldb.h
source/lib/ldb/ldb_sqlite3/ldb_sqlite3.c
source/lib/ldb/ldb_tdb/ldb_tdb.c

index 5cea4424b0b655ee6f73e031aa142f15142e1ce3..79cbe12d61d326ba957ec92907c7d85276289788 100644 (file)
@@ -138,10 +138,13 @@ ldb_explode_dn(void * mem_ctx,
        }
 
         /* Copy the provided DN so we can manipulate it */
-       if ((dn_copy = p = talloc_strdup(mem_ctx, orig_dn)) == NULL) {
+        if ((p = ldb_dn_fold(mem_ctx, orig_dn,
+                             hUserData, case_fold_attr_fn)) == NULL) {
                 goto failed;
         }
 
+        dn_copy = p;
+        
         /* Our copy may end shorter than the original as we unescape chars */
        dn_end = dn_copy + orig_len + 1;
 
index dc25d6cf13e6763fee0548d0f56b839f05688fe9..35249c4b70801c0221aba02080389c2a4a80a353 100644 (file)
@@ -95,11 +95,13 @@ int ldb_attr_cmp(const char *dn1, const char *dn2)
   attribute values of case insensitive attributes. We also need to remove
   extraneous spaces between elements
 */
-char *ldb_dn_fold(struct ldb_module *module, const char *dn, int (*case_fold_attr_fn)(struct ldb_module * module, char * attr))
+char *ldb_dn_fold(void * mem_ctx,
+                  const char * dn,
+                  void * user_data,
+                  int (* case_fold_attr_fn)(void * user_data, char * attr))
 {
        const char *dn_orig = dn;
-       struct ldb_context *ldb = module->ldb;
-       TALLOC_CTX *tmp_ctx = talloc_new(ldb);
+       TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
        char *ret;
        size_t len;
 
@@ -133,14 +135,14 @@ char *ldb_dn_fold(struct ldb_module *module, const char *dn, int (*case_fold_att
                }
                if (*value == 0) goto failed;
 
-               case_fold_required = (* case_fold_attr_fn)(module, attr);
+               case_fold_required = (* case_fold_attr_fn)(user_data, attr);
 
-               attr = ldb_casefold(ldb, attr);
+               attr = ldb_casefold(tmp_ctx, attr);
                if (attr == NULL) goto failed;
                talloc_steal(tmp_ctx, attr);
 
                if (case_fold_required) {
-                       value = ldb_casefold(ldb, value);
+                       value = ldb_casefold(tmp_ctx, value);
                        if (value == NULL) goto failed;
                        talloc_steal(tmp_ctx, value);
                }               
@@ -156,12 +158,12 @@ char *ldb_dn_fold(struct ldb_module *module, const char *dn, int (*case_fold_att
                if (*dn == ',') dn++;
        }
 
-       talloc_steal(ldb, ret);
+       talloc_steal(mem_ctx, ret);
        talloc_free(tmp_ctx);
        return ret;
 
 failed:
        talloc_free(tmp_ctx);
-       return ldb_casefold(ldb, dn_orig);
+       return ldb_casefold(mem_ctx, dn_orig);
 }
 
index 4bf2f9581faa469dafc250adb4d9a92a23c73da7..fabaec5da22ddc71d36c4363259f9b883777c8fe 100644 (file)
@@ -275,7 +275,10 @@ int ldb_dn_cmp(const char *dn1, const char *dn2);
 int ldb_attr_cmp(const char *dn1, const char *dn2);
 
 /* case-fold a DN */
-char *ldb_dn_fold(struct ldb_module *module, const char *dn, int (*case_fold_attr_fn)(struct ldb_module * module, char * attr));
+char *ldb_dn_fold(void * mem_ctx,
+                  const char * dn,
+                  void * user_data,
+                  int (* case_fold_attr_fn)(void * user_data, char * attr));
 
 /* create an empty message */
 struct ldb_message *ldb_msg_new(void *mem_ctx);
index 09ba24022f2f916cc392829b362715e999eee05e..51830db94cae4647f204cb13f7f50bd86905e281 100644 (file)
@@ -167,9 +167,11 @@ static int
 parsetree_to_attrlist(struct lsqlite3_private * lsqlite3,
                       const struct ldb_parse_tree * t);
 
+#ifdef NEED_TABLE_LIST
 static char *
 build_attr_table_list(void * hTalloc,
                       struct lsqlite3_private * lsqlite3);
+#endif
 
 static int
 msg_to_sql(struct ldb_module * module,
@@ -295,36 +297,140 @@ failed:
 /* rename a record */
 static int
 lsqlite3_rename(struct ldb_module * module,
-                const char * olddn,
-                const char * newdn)
+                const char * pOldDN,
+                const char * pNewDN)
 {
-       /* ignore ltdb specials */
-       if (olddn[0] == '@' ||newdn[0] == '@') {
-               return 0;
-       }
-        
-#warning "lsqlite3_rename() is not yet supported"
+       struct lsqlite3_private *   lsqlite3 = module->private_data;
+
+        /* Case-fold each of the DNs */
+        pOldDN = ldb_dn_fold(module->ldb, pOldDN,
+                             module, case_fold_attr_required);
+        pNewDN = ldb_dn_fold(module->ldb, pNewDN,
+                             module, case_fold_attr_required);
 
-        return -1;
+        QUERY_NOROWS(lsqlite3,
+                     FALSE,
+                     "UPDATE ldb_entry "
+                     "  SET dn = %Q "
+                     "  WHERE dn = %Q;",
+                     pNewDN, pOldDN);
+
+        return 0;
 }
 
 /* delete a record */
 static int
-lsqlite3_delete(struct ldb_module *module,
-                const char *dn)
+lsqlite3_delete(struct ldb_module * module,
+                const char * pDN)
 {
+        int                         ret;
+        int                         bLoop;
+        long long                   eid;
+        char *                      pSql;
+        const char *                pAttrName;
+        sqlite3_stmt *              pStmt;
        struct lsqlite3_private *   lsqlite3 = module->private_data;
 
-       /* ignore ltdb specials */
-       if (dn[0] == '@') {
-               return 0;
-       }
-        
         /* Begin a transaction */
         QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;");
 
+        /* Determine the eid of the DN being deleted */
+        QUERY_INT(lsqlite3,
+                  eid,
+                  TRUE,
+                  "SELECT eid\n"
+                  "  FROM ldb_entry\n"
+                  "  WHERE dn = %Q;",
+                  pDN);
+        
+        /* Obtain the list of attribute names in use by this DN */
+        if ((pSql = talloc_asprintf(module->ldb,
+                                    "SELECT attr_name "
+                                    "  FROM ldb_attribute_values "
+                                    "  WHERE eid = %lld;",
+                                    eid)) == NULL) {
+                return -1;
+        }
+
+        /*
+         * Prepare and execute the SQL statement.  Loop allows retrying on
+         * certain errors, e.g. SQLITE_SCHEMA occurs if the schema changes,
+         * requiring retrying the operation.
+         */
+        for (bLoop = TRUE; bLoop; ) {
+                /* Compile the SQL statement into sqlite virtual machine */
+                if ((ret = sqlite3_prepare(lsqlite3->sqlite,
+                                           pSql,
+                                           -1,
+                                           &pStmt,
+                                           NULL)) == SQLITE_SCHEMA) {
+                        continue;
+                } else if (ret != SQLITE_OK) {
+                        ret = -1;
+                        break;
+                }
+                
+                /* Loop through the returned rows */
+                for (ret = SQLITE_ROW; ret == SQLITE_ROW; ) {
+                        
+                        /* Get the next row */
+                        if ((ret = sqlite3_step(pStmt)) == SQLITE_ROW) {
+                                
+                                /* Get the values from this row */
+                                pAttrName = sqlite3_column_text(pStmt, 0);
+                                
+                                /*
+                                 * Delete any entries from the specified
+                                 * attribute table that pertain to this eid.
+                                 */
+                                QUERY_NOROWS(lsqlite3,
+                                             TRUE,
+                                             "DELETE FROM ldb_attr_%q "
+                                             "  WHERE eid = %lld;",
+                                             pAttrName, eid);
+                        }
+                }
+                
+                if (ret == SQLITE_SCHEMA) {
+                        (void) sqlite3_finalize(pStmt);
+                        continue;
+                } else if (ret != SQLITE_DONE) {
+                        (void) sqlite3_finalize(pStmt);
+                        ret = -1;
+                        break;
+                }
+                
+                /* Free the virtual machine */
+                if ((ret = sqlite3_finalize(pStmt)) == SQLITE_SCHEMA) {
+                        (void) sqlite3_finalize(pStmt);
+                        continue;
+                } else if (ret != SQLITE_OK) {
+                        (void) sqlite3_finalize(pStmt);
+                        ret = -1;
+                        break;
+                }
+                
+                /*
+                 * Normal condition is only one time through loop.  Loop is
+                 * rerun in error conditions, via "continue", above.
+                 */
+                ret = 0;
+                bLoop = FALSE;
+        }
+        
+        /* Delete the descendants records */
+        QUERY_NOROWS(lsqlite3,
+                     TRUE,
+                     "DELETE FROM ldb_descendants "
+                     "  WHERE deid = %lld;",
+                     eid);
 
-#warning "lsqlite3_delete() is not yet supported"
+        /* Delete attribute/value table entries pertaining to this DN */
+        QUERY_NOROWS(lsqlite3,
+                     TRUE,
+                     "DELETE FROM ldb_attribute_value "
+                     "  WHERE eid = %lld;",
+                     eid);
 
         /* Commit the transaction */
         QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;");
@@ -348,7 +454,9 @@ lsqlite3_search_bytree(struct ldb_module * module,
         long long                   prevEID;
         char *                      pSql = NULL;
        char *                      pSqlConstraints;
+#ifdef NEED_TABLE_LIST
         char *                      pTableList;
+#endif
         char *                      hTalloc = NULL;
         const char *                pDN;
         const char *                pAttrName;
@@ -362,6 +470,18 @@ lsqlite3_search_bytree(struct ldb_module * module,
                pBaseDN = "";
        }
         
+        /* Allocate a temporary talloc context */
+       if ((hTalloc = talloc_new(module->ldb)) == NULL) {
+                return -1;
+        }
+        
+        /* Case-fold the base DN */
+        if ((pBaseDN = ldb_dn_fold(hTalloc, pBaseDN,
+                                   module, case_fold_attr_required)) == NULL) {
+                talloc_free(hTalloc);
+                return -1;
+            }
+
         /* Begin a transaction */
         QUERY_NOROWS(lsqlite3, FALSE, "BEGIN IMMEDIATE;");
         
@@ -375,19 +495,14 @@ lsqlite3_search_bytree(struct ldb_module * module,
                              "  WHERE attr_value = %Q;",
                              pBaseDN)) == SQLITE_DONE) {
                 QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;");
+                talloc_free(hTalloc);
                 return 0;
         } else if (ret != SQLITE_OK) {
                 QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;");
+                talloc_free(hTalloc);
                 return -1;
         }
         
-        /* Allocate a temporary talloc context */
-       if ((hTalloc = talloc_new(module->ldb)) == NULL) {
-                ret = -1;
-                talloc_free(pTree);
-                goto cleanup;
-        }
-        
         /* Convert filter into a series of SQL conditions (constraints) */
        pSqlConstraints = parsetree_to_sql(module, hTalloc, pTree);
         
@@ -453,14 +568,15 @@ lsqlite3_search_bytree(struct ldb_module * module,
                 goto cleanup;
         }
         
+#ifdef NEED_TABLE_LIST
         /*
          * Build the attribute table list from the list of unique names.
          */
-        
         if ((pTableList = build_attr_table_list(hTalloc, lsqlite3)) == NULL) {
                 ret = -1;
                 goto cleanup;
         }
+#endif
         
         switch(scope) {
         case LDB_SCOPE_DEFAULT:
@@ -534,6 +650,11 @@ lsqlite3_search_bytree(struct ldb_module * module,
                 break;
         }
         
+        if (pSql == NULL) {
+                ret = -1;
+                goto cleanup;
+        }
+
         if (lsqlite3_debug) {
                 printf("%s\n", pSql);
         }
@@ -630,12 +751,12 @@ lsqlite3_search_bytree(struct ldb_module * module,
                 bLoop = FALSE;
         }
         
-        /* End the transaction */
-        QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;");
-        
         /* We're alll done with this query */
         sqlite3_free(pSql);
         
+        /* End the transaction */
+        QUERY_NOROWS(lsqlite3, FALSE, "END TRANSACTION;");
+        
         /* Were there any results? */
         if (ret != 0 || allocated == 0) {
                 /* Nope.  We can free the results. */
@@ -733,9 +854,11 @@ lsqlite3_add(struct ldb_module *module,
 
 /* modify a record */
 static int
-lsqlite3_modify(struct ldb_module *module,
-                const struct ldb_message *msg)
+lsqlite3_modify(struct ldb_module * module,
+                const struct ldb_message * msg)
 {
+        char *                      pDN;
+        long long                   eid;
        struct lsqlite3_private *   lsqlite3 = module->private_data;
         
        /* ignore ltdb specials */
@@ -746,7 +869,25 @@ lsqlite3_modify(struct ldb_module *module,
         /* Begin a transaction */
         QUERY_NOROWS(lsqlite3, FALSE, "BEGIN EXCLUSIVE;");
         
-#warning "modify() not yet implemented"
+        /* Case-fold the DN so we can compare it to what's in the database */
+        pDN = ldb_dn_fold(module->ldb, msg->dn,
+                          module, case_fold_attr_required);
+
+        /* Determine the eid of the DN being deleted */
+        QUERY_INT(lsqlite3,
+                  eid,
+                  TRUE,
+                  "SELECT eid\n"
+                  "  FROM ldb_entry\n"
+                  "  WHERE dn = %Q;",
+                  pDN);
+        
+        /* Apply the message attributes */
+       if (msg_to_sql(module, msg, eid, TRUE) != 0) {
+                QUERY_NOROWS(lsqlite3, FALSE, "ROLLBACK;");
+                return -1;
+        }
+        
 
         /* Everything worked.  Commit it! */
         QUERY_NOROWS(lsqlite3, TRUE, "COMMIT;");
@@ -1409,7 +1550,8 @@ parsetree_to_sql(struct ldb_module *module,
                 }
                 
                 child = ret;
-                ret = talloc_asprintf("(\n"
+                ret = talloc_asprintf(hTalloc,
+                                      "(\n"
                                       "%s\n"
                                       ")\n",
                                       child);
@@ -1436,7 +1578,8 @@ parsetree_to_sql(struct ldb_module *module,
                         talloc_free(child);
                 }
                 child = ret;
-                ret = talloc_asprintf("(\n"
+                ret = talloc_asprintf(hTalloc,
+                                      "(\n"
                                       "%s\n"
                                       ")\n",
                                       child);
@@ -1495,7 +1638,7 @@ parsetree_to_sql(struct ldb_module *module,
 
                 ret = talloc_strdup(hTalloc, p);
                 sqlite3_free(p);
-                
+
        } else if (strcasecmp(t->u.simple.attr, "objectclass") == 0) {
                /*
                  * For object classes, we want to search for all objectclasses
@@ -1543,6 +1686,7 @@ parsetree_to_sql(struct ldb_module *module,
                 ret = talloc_strdup(hTalloc, p);
                 sqlite3_free(p);
        }
+
        return ret;
 }
 
@@ -1619,6 +1763,7 @@ parsetree_to_attrlist(struct lsqlite3_private * lsqlite3,
 }
 
 
+#ifdef NEED_TABLE_LIST
 /*
  * Use the already-generated FILTER_ATTR_TABLE to create a list of attribute
  * table names that will be used in search queries.
@@ -1724,6 +1869,7 @@ build_attr_table_list(void * hTalloc,
 
         return pTableList;
 }
+#endif
 
 
 /*
@@ -1847,6 +1993,7 @@ new_dn(struct ldb_module * module,
         char *                      p;
         char *                      pPartialDN;
         long long                   eid;
+        long long                   peid;
         struct ldb_dn *             pExplodedDN;
         struct ldb_dn_component *   pComponent;
        struct ldb_context *        ldb = module->ldb;
@@ -1906,9 +2053,35 @@ new_dn(struct ldb_module * module,
                              nComponent == 0 ? "" : "OR IGNORE",
                              eid, pPartialDN);
                 
-                /* Get the EID of the just inserted row (the next parent) */
+                /* Save the parent EID */
+                peid = eid;
+                
+                /* Get the EID of the just inserted row */
                 eid = sqlite3_last_insert_rowid(lsqlite3->sqlite);
 
+                /*
+                 * Popoulate the descendant table
+                 */
+
+                /* This table has an entry for itself as well as descendants */
+                QUERY_NOROWS(lsqlite3,
+                             FALSE,
+                             "INSERT INTO ldb_descendants "
+                             "    (aeid, deid) "
+                             "  VALUES "
+                             "    (%lld, %lld);",
+                             eid, eid);
+                
+                /* Now insert rows for all of our ancestors */
+                QUERY_NOROWS(lsqlite3,
+                             FALSE,
+                             "INSERT INTO ldb_descendants "
+                             "    (aeid, deid) "
+                             "  SELECT aeid, %lld "
+                             "    FROM ldb_descendants "
+                             "    WHERE aeid = %lld;",
+                             eid, peid);
+
                 /* If this is the final component, also add DN attribute */
                 if (nComponent == 0) {
                         QUERY_NOROWS(lsqlite3,
index 0366809c3387ecd2745ced543a36f9ce9e5e1ad0..6516787a5a41fb393e9e12e2c8cebcc5222505c7 100644 (file)
   callback function used in call to ldb_dn_fold() for determining whether an
   attribute type requires case folding.
 */
-static int ltdb_case_fold_attr_required(struct ldb_module *module, char *attr)
+static int ltdb_case_fold_attr_required(void * user_data, char *attr)
 {
+    struct ldb_module *module = user_data;
+
     return ltdb_attribute_flags(module, attr) & LTDB_FLAG_CASE_INSENSITIVE;
 }
 
@@ -106,7 +108,8 @@ struct TDB_DATA ltdb_key(struct ldb_module *module, const char *dn)
                }
                talloc_free(attr_name);
        } else {
-                dn_folded = ldb_dn_fold(module, dn, ltdb_case_fold_attr_required);
+                dn_folded = ldb_dn_fold(module->ldb, dn,
+                                        module, ltdb_case_fold_attr_required);
        }
 
        if (!dn_folded) {