You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/12/11 01:16:08 UTC

svn commit: r1044548 [16/39] - in /subversion/branches/ignore-mergeinfo: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/ contrib/hook-scripts/ contrib/server-side/ notes/api-errata/ notes/api-err...

Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c?rev=1044548&r1=1044547&r2=1044548&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c Sat Dec 11 00:15:55 2010
@@ -101,6 +101,7 @@
  * wc_id  a WCROOT id associated with a node
  */
 
+#define INVALID_REPOS_ID ((apr_int64_t) -1)
 #define UNKNOWN_WC_ID ((apr_int64_t) -1)
 #define FORMAT_FROM_SDB (-1)
 
@@ -111,7 +112,7 @@
 #define LIKE_ESCAPE_CHAR     "#"
 
 /* Calculates the depth of the relpath below "" */
-APR_INLINE static int relpath_op_depth(const char *relpath)
+APR_INLINE static int relpath_depth(const char *relpath)
 {
   int n = 1;
   if (*relpath == '\0')
@@ -127,6 +128,11 @@ APR_INLINE static int relpath_op_depth(c
   return n;
 }
 
+int svn_wc__db_op_depth_for_upgrade(const char *local_relpath)
+{
+  return relpath_depth(local_relpath);
+}
+
 typedef struct insert_base_baton_t {
   /* common to all insertions into BASE */
   svn_wc__db_status_t status;
@@ -225,8 +231,100 @@ add_work_items(svn_sqlite__db_t *sdb,
                const svn_skel_t *skel,
                apr_pool_t *scratch_pool);
 
+static svn_error_t *
+insert_incomplete_children(svn_sqlite__db_t *sdb,
+                           apr_int64_t wc_id,
+                           const char *local_relpath,
+                           apr_int64_t repos_id,
+                           const char *repos_relpath,
+                           svn_revnum_t revision,
+                           const apr_array_header_t *children,
+                           apr_int64_t op_depth,
+                           apr_pool_t *scratch_pool);
 
-/* */
+static svn_error_t *
+db_read_pristine_props(apr_hash_t **props,
+                       svn_wc__db_pdh_t *pdh,
+                       const char *local_relpath,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool);
+
+static svn_error_t *
+read_info(svn_wc__db_status_t *status,
+          svn_wc__db_kind_t *kind,
+          svn_revnum_t *revision,
+          const char **repos_relpath,
+          apr_int64_t *repos_id,
+          svn_revnum_t *changed_rev,
+          apr_time_t *changed_date,
+          const char **changed_author,
+          apr_time_t *last_mod_time,
+          svn_depth_t *depth,
+          const svn_checksum_t **checksum,
+          svn_filesize_t *translated_size,
+          const char **target,
+          const char **changelist,
+          const char **original_repos_relpath,
+          apr_int64_t *original_repos_id,
+          svn_revnum_t *original_revision,
+          svn_boolean_t *props_mod,
+          svn_boolean_t *have_base,
+          svn_boolean_t *have_work,
+          svn_boolean_t *conflicted,
+          svn_wc__db_lock_t **lock,
+          svn_wc__db_pdh_t *pdh,
+          const char *local_relpath,
+          apr_pool_t *result_pool,
+          apr_pool_t *scratch_pool);
+
+#ifndef SVN_WC__OP_DEPTH
+static svn_error_t *
+elide_copyfrom(svn_wc__db_pdh_t *pdh,
+               const char *local_relpath,
+               apr_pool_t *scratch_pool);
+#endif
+
+static svn_error_t *
+scan_addition(svn_wc__db_status_t *status,
+              const char **op_root_relpath,
+              const char **repos_relpath,
+              apr_int64_t *repos_id,
+              const char **original_repos_relpath,
+              apr_int64_t *original_repos_id,
+              svn_revnum_t *original_revision,
+              svn_wc__db_pdh_t *pdh,
+              const char *local_relpath,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool);
+
+static svn_error_t *
+scan_deletion(const char **base_del_relpath,
+              const char **moved_to_relpath,
+              const char **work_del_relpath,
+              svn_wc__db_pdh_t *pdh,
+              const char *local_relpath,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool);
+
+static svn_error_t *
+convert_to_working_status(svn_wc__db_status_t *working_status,
+                          svn_wc__db_status_t status);
+
+/* Return the absolute path, in local path style, of LOCAL_RELPATH in WCROOT. */
+static const char *
+path_for_error_message(const svn_wc__db_wcroot_t *wcroot,
+                       const char *local_relpath,
+                       apr_pool_t *result_pool)
+{
+  const char *local_abspath
+    = svn_dirent_join(wcroot->abspath, local_relpath, result_pool);
+
+  return svn_dirent_local_style(local_abspath, result_pool);
+}
+
+
+/* Return a file size from column SLOT of the SQLITE statement STMT, or
+ * SVN_INVALID_FILESIZE if the column value is NULL. */
 static svn_filesize_t
 get_translated_size(svn_sqlite__stmt_t *stmt, int slot)
 {
@@ -236,6 +334,34 @@ get_translated_size(svn_sqlite__stmt_t *
 }
 
 
+/* Return a lock info structure constructed from the given columns of the
+ * SQLITE statement STMT, or return NULL if the token column value is null. */
+static svn_wc__db_lock_t *
+lock_from_columns(svn_sqlite__stmt_t *stmt,
+                  int col_token,
+                  int col_owner,
+                  int col_comment,
+                  int col_date,
+                  apr_pool_t *result_pool)
+{
+  svn_wc__db_lock_t *lock;
+
+  if (svn_sqlite__column_is_null(stmt, col_token))
+    {
+      lock = NULL;
+    }
+  else
+    {
+      lock = apr_pcalloc(result_pool, sizeof(svn_wc__db_lock_t));
+      lock->token = svn_sqlite__column_text(stmt, col_token, result_pool);
+      lock->owner = svn_sqlite__column_text(stmt, col_owner, result_pool);
+      lock->comment = svn_sqlite__column_text(stmt, col_comment, result_pool);
+      lock->date = svn_sqlite__column_int64(stmt, col_date);
+    }
+  return lock;
+}
+
+
 /* */
 static const char *
 escape_sqlite_like(const char * const str, apr_pool_t *result_pool)
@@ -274,6 +400,25 @@ escape_sqlite_like(const char * const st
   return result;
 }
 
+/* Return a string that can be used as the argument to a SQLite 'LIKE'
+ * operator, in order to match any path that is a child of LOCAL_RELPATH
+ * (at any depth below LOCAL_RELPATH), *excluding* LOCAL_RELPATH itself.
+ * LOCAL_RELPATH may be the empty string, in which case the result will
+ * match any path except the empty path.
+ *
+ * Allocate the result either statically or in RESULT_POOL.  */
+static const char *construct_like_arg(const char *local_relpath,
+                                      apr_pool_t *result_pool)
+{
+  if (local_relpath[0] == '\0')
+    return "_%";
+
+  return apr_pstrcat(result_pool,
+                     escape_sqlite_like(local_relpath, result_pool),
+                     "/%", (char *)NULL);
+}
+
+
 
 /* Returns in PRISTINE_ABSPATH a new string allocated from RESULT_POOL,
    holding the local absolute path to the file location that is dedicated
@@ -346,7 +491,10 @@ get_pristine_fname(const char **pristine
 }
 
 
-/* */
+/* Look up REPOS_ID in SDB and set *REPOS_ROOT_URL and/or *REPOS_UUID to
+ * its root URL and UUID respectively.  If REPOS_ID is INVALID_REPOS_ID,
+ * use NULL for both URL and UUID.  Either or both output parameters may be
+ * NULL if not wanted. */
 static svn_error_t *
 fetch_repos_info(const char **repos_root_url,
                  const char **repos_uuid,
@@ -357,6 +505,18 @@ fetch_repos_info(const char **repos_root
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
 
+  if (!repos_root_url && !repos_uuid)
+    return SVN_NO_ERROR;
+
+  if (repos_id == INVALID_REPOS_ID)
+    {
+      if (repos_root_url)
+        *repos_root_url = NULL;
+      if (repos_uuid)
+        *repos_uuid = NULL;
+      return SVN_NO_ERROR;
+    }
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
                                     STMT_SELECT_REPOSITORY_BY_ID));
   SVN_ERR(svn_sqlite__bindf(stmt, "i", repos_id));
@@ -374,318 +534,83 @@ fetch_repos_info(const char **repos_root
   return svn_error_return(svn_sqlite__reset(stmt));
 }
 
-#ifdef SVN_WC__NODES
-
-/* Can't verify if we only have the NODES table */
-#ifndef SVN_WC__NODES_ONLY
-
-/* */
-static svn_error_t *
-assert_text_columns_equal(svn_sqlite__stmt_t *stmt1,
-                          svn_sqlite__stmt_t *stmt2,
-                          int column,
-                          apr_pool_t *scratch_pool)
-{
-  const char *val1 = svn_sqlite__column_text(stmt1, column, scratch_pool);
-  const char *val2 = svn_sqlite__column_text(stmt2, column, scratch_pool);
-
-  if (val1 != NULL && val2 != NULL) {
-    if (strcmp(val1, val2) != 0)
-      return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
-          "Value in statement 1 (%s) differs from value in statement 2 (%s)",
-                             val1, val2);
-  } else if (val1 == NULL && val2 == NULL) {
-    /* Do nothing: equal */
-  } else
-      return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
-          "Value in statement 1 (%s) differs from value in statement 2 (%s)",
-                             val1, val2);
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-assert_blob_columns_equal(svn_sqlite__stmt_t *stmt1,
-                          svn_sqlite__stmt_t *stmt2,
-                          int column,
-                          apr_pool_t *scratch_pool)
-{
-  apr_size_t len1, len2;
-  const void *val1 = svn_sqlite__column_blob(stmt1, column, &len1, NULL);
-  const void *val2 = svn_sqlite__column_blob(stmt2, column, &len2, NULL);
-
-  if (!len1 && !len2)
-    return SVN_NO_ERROR;
-
-  if (len1 != len2 || memcmp(val1, val2, len1))
-    return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
-                             "Blob of length %ld in statement 1 differs "
-                             "from blob of length %ld in statement 2",
-                             len1, len2);
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-assert_base_rows_match(svn_boolean_t have_row1,
-                       svn_boolean_t have_row2,
-                       svn_sqlite__stmt_t *stmt1,
-                       svn_sqlite__stmt_t *stmt2,
-                       const char *relpath,
-                       apr_pool_t *scratch_pool)
-{
-
-  if (have_row1 != have_row2)
-    SVN_ERR(svn_error_createf(
-              SVN_ERR_WC_CORRUPT, NULL,
-              "Different results from BASE (%d) and NODES queries (%d), "
-              "for local_relpath %s",
-              have_row1, have_row2, relpath));
-
-  if (have_row1) {
-    SVN_ERR_ASSERT(svn_sqlite__column_int64(stmt1, 0)
-                   == svn_sqlite__column_int64(stmt2, 0));
-
-    SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 1, scratch_pool));
-
-    SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 2, scratch_pool));
-
-    SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 3, scratch_pool));
-
-    SVN_ERR_ASSERT(svn_sqlite__column_revnum(stmt1, 4)
-                   == svn_sqlite__column_revnum(stmt2, 4));
-
-    SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 5, scratch_pool));
-
-    SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 6, scratch_pool));
-
-    SVN_ERR_ASSERT(svn_sqlite__column_revnum(stmt1, 7)
-                   == svn_sqlite__column_revnum(stmt2, 7));
-
-
-    SVN_ERR_ASSERT(svn_sqlite__column_int64(stmt1, 8)
-                   == svn_sqlite__column_int64(stmt2, 8));
-
-    SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 9, scratch_pool));
-
-    SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 10, scratch_pool));
-
-    SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 11, scratch_pool));
-
-    SVN_ERR_ASSERT(svn_sqlite__column_int64(stmt1, 12)
-                   == svn_sqlite__column_int64(stmt2, 12));
-
-    /* verify props */
-    SVN_ERR(assert_blob_columns_equal(stmt1, stmt2, 13, scratch_pool));
-  }
-
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-assert_working_rows_match(svn_boolean_t have_row1,
-                          svn_boolean_t have_row2,
-                          svn_sqlite__stmt_t *stmt1,
-                          svn_sqlite__stmt_t *stmt2,
-                          const char *relpath,
-                          apr_pool_t *scratch_pool)
+/* Set *REPOS_ID, *REVISION and *REPOS_RELPATH from the
+ * given columns of the SQLITE statement STMT, or to NULL if the respective
+ * column value is null.  Any of the output parameters may be NULL if not
+ * required. */
+static svn_error_t *
+repos_location_from_columns(apr_int64_t *repos_id,
+                            svn_revnum_t *revision,
+                            const char **repos_relpath,
+                            svn_wc__db_pdh_t *pdh,
+                            svn_sqlite__stmt_t *stmt,
+                            int col_repos_id,
+                            int col_revision,
+                            int col_repos_relpath,
+                            apr_pool_t *result_pool)
 {
-  if (have_row1 != have_row2)
-    SVN_ERR(svn_error_createf(
-              SVN_ERR_WC_CORRUPT, NULL,
-              "Different results from WORKING (%d) and NODES queries (%d), "
-              "for local_relpath %s",
-              have_row1, have_row2, relpath));
-
-  if (!have_row1)
-    return SVN_NO_ERROR;
+  svn_error_t *err = SVN_NO_ERROR;
 
-  /* presence */
-  SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 0, scratch_pool));
-  /* kind */
-  SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 1, scratch_pool));
-  /* checksum */
-  SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 2, scratch_pool));
-  /* translated_size */
-  SVN_ERR_ASSERT(svn_sqlite__column_int64(stmt1, 3)
-                 == svn_sqlite__column_int64(stmt2, 3));
-  /* changed_rev */
-  SVN_ERR_ASSERT(svn_sqlite__column_int64(stmt1, 4)
-                 == svn_sqlite__column_int64(stmt2, 4));
-  /* changed_date */
-  SVN_ERR_ASSERT(svn_sqlite__column_int64(stmt1, 5)
-                 == svn_sqlite__column_int64(stmt2, 5));
-  /* changed_author */
-  SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 6, scratch_pool));
-  /* depth */
-  SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 7, scratch_pool));
-  /* symlink_target */
-  /* copyfrom_repos_id */
-  SVN_ERR_ASSERT(svn_sqlite__column_int64(stmt1, 9)
-                 == svn_sqlite__column_int64(stmt2, 9));
-  /* copyfrom_repos_path */
-  SVN_ERR(assert_text_columns_equal(stmt1, stmt2, 7, scratch_pool));
-  /* copyfrom_revnum */
-  SVN_ERR_ASSERT(svn_sqlite__column_int64(stmt1, 11)
-                 == svn_sqlite__column_int64(stmt2, 11));
-  /* moved_here */
-  /* moved_to */
-  /* last_mod_time */
-  SVN_ERR_ASSERT(svn_sqlite__column_int64(stmt1, 14)
-                 == svn_sqlite__column_int64(stmt2, 14));
-  /* properties */
-#if 0
-  /* Disabled for now as base-deleted don't match */
-  SVN_ERR(assert_blob_columns_equal(stmt1, stmt2, 15, scratch_pool));
-#endif
+  if (repos_id)
+    {
+      /* Fetch repository information via REPOS_ID. */
+      if (svn_sqlite__column_is_null(stmt, col_repos_id))
+        *repos_id = INVALID_REPOS_ID;
+      else
+        *repos_id = svn_sqlite__column_int64(stmt, col_repos_id);
+    }
+  if (revision)
+    {
+      *revision = svn_sqlite__column_revnum(stmt, col_revision);
+    }
+  if (repos_relpath)
+    {
+      *repos_relpath = svn_sqlite__column_text(stmt, col_repos_relpath,
+                                               result_pool);
+    }
 
-  return SVN_NO_ERROR;
+  return err;
 }
 
-#endif /* SVN_WC__NODES_ONLY */
 
-#endif /* SVN_WC__NODES */
-
-/* Scan from LOCAL_RELPATH upwards through parent nodes until we find a parent
-   that has values in the 'repos_id' and 'repos_relpath' columns.  Return
-   that information in REPOS_ID and REPOS_RELPATH (either may be NULL).
-   Use LOCAL_ABSPATH for diagnostics */
+/* Set *REPOS_ID and *REPOS_RELPATH to the BASE node of LOCAL_RELPATH.
+ * Either of REPOS_ID and REPOS_RELPATH may be NULL if not wanted. */
 static svn_error_t *
 scan_upwards_for_repos(apr_int64_t *repos_id,
                        const char **repos_relpath,
                        const svn_wc__db_wcroot_t *wcroot,
-                       const char *local_abspath,
                        const char *local_relpath,
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool)
 {
-  const char *relpath_suffix = "";
-  const char *current_basename = svn_dirent_basename(local_relpath,
-                                                     scratch_pool);
-  const char *current_relpath = local_relpath;
   svn_sqlite__stmt_t *stmt;
-
-#ifdef SVN_WC__NODES
-  svn_sqlite__stmt_t *data_stmt;
-#endif
+  svn_boolean_t have_row;
 
   SVN_ERR_ASSERT(wcroot->sdb != NULL && wcroot->wc_id != UNKNOWN_WC_ID);
   SVN_ERR_ASSERT(repos_id != NULL || repos_relpath != NULL);
 
-#ifndef SVN_WC__NODES_ONLY
-  /* ### is it faster to fetch fewer columns? */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_BASE_NODE));
-#endif
-
-#ifdef SVN_WC__NODES
-  SVN_ERR(svn_sqlite__get_statement(&data_stmt, wcroot->sdb,
-                                    STMT_SELECT_BASE_NODE_1));
-#endif
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_BASE_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
-  while (TRUE)
+  if (!have_row)
     {
-      svn_boolean_t have_row;
-#ifdef SVN_WC__NODES
-      svn_boolean_t have_data_row;
-#endif
-
-#ifndef SVN_WC__NODES_ONLY
-      /* Get the current node's repository information.  */
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
-      SVN_ERR(svn_sqlite__step(&have_row, stmt));
-#endif
-
-#ifdef SVN_WC__NODES
-
-      /* Get the current node's repository information.  */
-      SVN_ERR(svn_sqlite__bindf(data_stmt, "is",
-                                wcroot->wc_id, current_relpath));
-      SVN_ERR(svn_sqlite__step(&have_data_row, data_stmt));
-
-#ifndef SVN_WC__NODES_ONLY
-      /* When switching to NODES_ONLY, stop verifying our results. */
-      SVN_ERR(assert_base_rows_match(have_row, have_data_row,
-                                     stmt, data_stmt,
-                                     current_relpath,
-                                     scratch_pool));
-      SVN_ERR(svn_sqlite__reset(data_stmt));
-#else
-      have_row = have_data_row;
-      stmt = data_stmt;
-#endif
-#endif
-
-      if (!have_row)
-        {
-          svn_error_t *err;
-
-          /* If we moved upwards at least once, or we're looking at the
-             root directory of this WCROOT, then something is wrong.  */
-          if (*relpath_suffix != '\0' || *local_relpath == '\0')
-            {
-              err = svn_error_createf(
-                SVN_ERR_WC_CORRUPT, NULL,
-                _("Parent(s) of '%s' should have been present."),
-                svn_dirent_local_style(local_abspath, scratch_pool));
-            }
-          else
-            {
-              err = svn_error_createf(
-                SVN_ERR_WC_PATH_NOT_FOUND, NULL,
-                _("The node '%s' was not found."),
-                svn_dirent_local_style(local_abspath, scratch_pool));
-            }
-
-#ifdef SVN_WC__NODES
-#endif
-          return svn_error_compose_create(err, svn_sqlite__reset(stmt));
-        }
-
-      /* Did we find some non-NULL repository columns? */
-      if (!svn_sqlite__column_is_null(stmt, 0))
-        {
-          /* If one is non-NULL, then so should the other. */
-          SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 1));
-
-          if (repos_id)
-            *repos_id = svn_sqlite__column_int64(stmt, 0);
-
-          /* Given the node's relpath, append all the segments that
-             we stripped as we scanned upwards. */
-          if (repos_relpath)
-            *repos_relpath = svn_relpath_join(svn_sqlite__column_text(stmt, 1,
-                                                                      NULL),
-                                              relpath_suffix,
-                                              result_pool);
-          return svn_sqlite__reset(stmt);
-        }
-#ifndef SVN_WC__NODES_ONLY
-      SVN_ERR(svn_sqlite__reset(stmt));
-#endif
-      if (*current_relpath == '\0')
-        {
-          /* We scanned all the way up, and did not find the information.
-             Something is corrupt in the database. */
-          return svn_error_createf(
-            SVN_ERR_WC_CORRUPT, NULL,
-            _("Parent(s) of '%s' should have repository information."),
-            svn_relpath_local_style(local_abspath, scratch_pool));
-        }
+      svn_error_t *err = svn_error_createf(
+            SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+            _("The node '%s' was not found."),
+            path_for_error_message(wcroot, local_relpath, scratch_pool));
 
-      /* Strip a path segment off the end, and append it to the suffix
-         that we'll use when we finally find a base relpath.  */
-      svn_relpath_split(&current_relpath, &current_basename, current_relpath,
-                        scratch_pool);
-      relpath_suffix = svn_relpath_join(relpath_suffix, current_basename,
-                                        scratch_pool);
+      return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+    }
 
-      /* Loop to try the parent.  */
+  SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 0));
+  SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 1));
 
-      /* ### strictly speaking, moving to the parent could send us to a
-         ### different SDB, and (thus) we would need to fetch STMT again.
-         ### but we happen to know the parent is *always* in the same db,
-         ### and will have the repos info.  */
-    }
+  if (repos_id)
+    *repos_id = svn_sqlite__column_int64(stmt, 0);
+  if (repos_relpath)
+    *repos_relpath = svn_sqlite__column_text(stmt, 1, result_pool);
+  return svn_sqlite__reset(stmt);
 }
 
 
@@ -718,6 +643,26 @@ get_statement_for_path(svn_sqlite__stmt_
 }
 
 
+/* For a given REPOS_ROOT_URL/REPOS_UUID pair, set *REPOS_ID to the existing
+   REPOS_ID value. If one does not exist, throw an error. */
+static svn_error_t *
+fetch_repos_id(apr_int64_t *repos_id,
+               const char *repos_root_url,
+               const char *repos_uuid,
+               svn_sqlite__db_t *sdb,
+               apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *get_stmt;
+
+  SVN_ERR(svn_sqlite__get_statement(&get_stmt, sdb, STMT_SELECT_REPOSITORY));
+  SVN_ERR(svn_sqlite__bindf(get_stmt, "s", repos_root_url));
+  SVN_ERR(svn_sqlite__step_row(get_stmt));
+
+  *repos_id = svn_sqlite__column_int64(get_stmt, 0);
+  return svn_error_return(svn_sqlite__reset(get_stmt));
+}
+
+
 /* For a given REPOS_ROOT_URL/REPOS_UUID pair, return the existing REPOS_ID
    value. If one does not exist, then create a new one. */
 static svn_error_t *
@@ -771,151 +716,172 @@ blank_ibb(insert_base_baton_t *pibb)
 }
 
 
+/* Extend any delete of the parent of LOCAL_RELPATH to LOCAL_RELPATH.
+
+   Given a wc:
+
+              0         1         2         3         4
+              normal
+   A          normal          
+   A/B        normal              normal
+   A/B/C                          not-pres  normal
+   A/B/C/D                                            normal
+
+   That is checkout, delete A/B, copy a replacement A/B, delete copied
+   child A/B/C, add replacement A/B/C, add A/B/C/D.
+
+   Now an update that adds base nodes for A/B/C, A/B/C/D and A/B/C/D/E
+   must extend the A/B deletion:
+   
+              0         1         2         3         4
+              normal
+   A          normal
+   A/B        normal              normal
+   A/B/C      normal              not-pres  normal
+   A/B/C/D    normal              base-del            normal
+   A/B/C/D/E  normal              base-del
+
+   When adding a base node if the parent has a working node then the
+   parent base is deleted and this must be extended to cover new base
+   node.
+
+   In the example above A/B/C/D and A/B/C/D/E are the nodes that get
+   the extended delete, A/B/C is already deleted.
+ */
+static svn_error_t *
+extend_parent_delete(svn_sqlite__db_t *sdb,
+                     apr_int64_t wc_id,
+                     const char *local_relpath,
+                     apr_pool_t *scratch_pool)
+{
+  svn_boolean_t have_row;
+  svn_sqlite__stmt_t *stmt;
+  apr_int64_t parent_op_depth;
+  const char *parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
+
+  SVN_ERR_ASSERT(local_relpath[0]);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                    STMT_SELECT_LOWEST_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (have_row)
+    parent_op_depth = svn_sqlite__column_int64(stmt, 0);
+  SVN_ERR(svn_sqlite__reset(stmt));
+  if (have_row)
+    {
+      apr_int64_t op_depth;
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+      if (have_row)
+        op_depth = svn_sqlite__column_int64(stmt, 0);
+      SVN_ERR(svn_sqlite__reset(stmt));
+      if (!have_row || parent_op_depth < op_depth)
+        {
+          SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                          STMT_INSERT_WORKING_NODE_FROM_BASE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "isit", wc_id,
+                                    local_relpath, parent_op_depth,
+                                    presence_map,
+                                    svn_wc__db_status_base_deleted));
+          SVN_ERR(svn_sqlite__update(NULL, stmt));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* This is the reverse of extend_parent_delete.
+
+   When removing a base node if the parent has a working node then the
+   parent base and this node are both deleted and so the delete of
+   this node must be removed.
+ */
+static svn_error_t *
+retract_parent_delete(svn_sqlite__db_t *sdb,
+                      apr_int64_t wc_id,
+                      const char *local_relpath,
+                      apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                    STMT_DELETE_LOWEST_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
+  return SVN_NO_ERROR;
+}
+
+
+
 /* */
 static svn_error_t *
 insert_base_node(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
   const insert_base_baton_t *pibb = baton;
-#ifndef SVN_WC__NODES_ONLY
   svn_sqlite__stmt_t *stmt;
-#endif
-#ifdef SVN_WC__NODES
-  svn_sqlite__stmt_t *stmt_node;
-#endif
   /* The directory at the WCROOT has a NULL parent_relpath. Otherwise,
      bind the appropriate parent_relpath. */
   const char *parent_relpath =
     (*pibb->local_relpath == '\0') ? NULL
     : svn_relpath_dirname(pibb->local_relpath, scratch_pool);
 
+  SVN_ERR_ASSERT(pibb->repos_id != INVALID_REPOS_ID);
+  SVN_ERR_ASSERT(pibb->repos_relpath != NULL);
+
   /* ### we can't handle this right now  */
   SVN_ERR_ASSERT(pibb->conflict == NULL);
 
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_BASE_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isissttr",
-                            pibb->wc_id, pibb->local_relpath,
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isisisr"
+                            "tstr"               /* 8 - 11 */
+                            "isnnnnns",          /* 12 - 19 */
+                            pibb->wc_id,         /* 1 */
+                            pibb->local_relpath, /* 2 */
+                            (apr_int64_t)0, /* op_depth is 0 for base */
+                            parent_relpath,      /* 4 */
                             pibb->repos_id,
                             pibb->repos_relpath,
-                            parent_relpath,
-                            presence_map, pibb->status,
-                            kind_map, pibb->kind,
-                            pibb->revision));
+                            pibb->revision,
+                            presence_map, pibb->status, /* 8 */
+                            (pibb->kind == svn_wc__db_kind_dir) ? /* 9 */
+                               svn_depth_to_word(pibb->depth) : NULL,
+                            kind_map, pibb->kind, /* 10 */
+                            pibb->changed_rev,    /* 11 */
+                            pibb->changed_date,   /* 12 */
+                            pibb->changed_author, /* 13 */
+                            (pibb->kind == svn_wc__db_kind_symlink) ?
+                                pibb->target : NULL)); /* 19 */
 
-  SVN_ERR(svn_sqlite__bind_properties(stmt, 9, pibb->props, scratch_pool));
+  if (pibb->kind == svn_wc__db_kind_file) {
+    SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, pibb->checksum, scratch_pool));
+    if (pibb->translated_size != SVN_INVALID_FILESIZE)
+      SVN_ERR(svn_sqlite__bind_int64(stmt, 16, pibb->translated_size));
+  }
 
-  if (SVN_IS_VALID_REVNUM(pibb->changed_rev))
-    SVN_ERR(svn_sqlite__bind_int64(stmt, 10, pibb->changed_rev));
-  if (pibb->changed_date)
-    SVN_ERR(svn_sqlite__bind_int64(stmt, 11, pibb->changed_date));
-  if (pibb->changed_author)
-    SVN_ERR(svn_sqlite__bind_text(stmt, 12, pibb->changed_author));
-
-  if (pibb->kind == svn_wc__db_kind_dir)
-    {
-      SVN_ERR(svn_sqlite__bind_text(stmt, 13, svn_depth_to_word(pibb->depth)));
-    }
-  else if (pibb->kind == svn_wc__db_kind_file)
-    {
-      SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, pibb->checksum,
-                                        scratch_pool));
-      if (pibb->translated_size != SVN_INVALID_FILESIZE)
-        SVN_ERR(svn_sqlite__bind_int64(stmt, 15, pibb->translated_size));
-    }
-  else if (pibb->kind == svn_wc__db_kind_symlink)
-    {
-      /* Note: incomplete nodes may have a NULL target.  */
-      if (pibb->target)
-        SVN_ERR(svn_sqlite__bind_text(stmt, 16, pibb->target));
-    }
-
-  if (pibb->dav_cache)
-    SVN_ERR(svn_sqlite__bind_properties(stmt, 17, pibb->dav_cache,
-                                        scratch_pool));
-
-  SVN_ERR(svn_sqlite__insert(NULL, stmt));
-#endif
-
-#ifdef SVN_WC__NODES
-  SVN_ERR(svn_sqlite__get_statement(&stmt_node, sdb, STMT_INSERT_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt_node, "isisisr"
-                            "tstr"               /* 8 - 11 */
-                            "isnnnnns",          /* 12 - 19 */
-                            pibb->wc_id,         /* 1 */
-                            pibb->local_relpath, /* 2 */
-                            (apr_int64_t)0, /* op_depth is 0 for base */
-                            parent_relpath,      /* 4 */
-                            pibb->repos_id,
-                            pibb->repos_relpath,
-                            pibb->revision,
-                            presence_map, pibb->status, /* 8 */
-                            (pibb->kind == svn_wc__db_kind_dir) ? /* 9 */
-                               svn_depth_to_word(pibb->depth) : NULL,
-                            kind_map, pibb->kind, /* 10 */
-                            pibb->changed_rev,    /* 11 */
-                            pibb->changed_date,   /* 12 */
-                            pibb->changed_author, /* 13 */
-                            (pibb->kind == svn_wc__db_kind_symlink) ?
-                                pibb->target : NULL)); /* 19 */
-
-  if (pibb->kind == svn_wc__db_kind_file) {
-    SVN_ERR(svn_sqlite__bind_checksum(stmt_node, 14, pibb->checksum,
-                                      scratch_pool));
-    if (pibb->translated_size != SVN_INVALID_FILESIZE)
-      SVN_ERR(svn_sqlite__bind_int64(stmt_node, 16, pibb->translated_size));
-  }
-
-  SVN_ERR(svn_sqlite__bind_properties(stmt_node, 15, pibb->props,
+  SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props,
                                       scratch_pool));
   if (pibb->dav_cache)
-    SVN_ERR(svn_sqlite__bind_properties(stmt_node, 18, pibb->dav_cache,
+    SVN_ERR(svn_sqlite__bind_properties(stmt, 18, pibb->dav_cache,
                                         scratch_pool));
 
-  SVN_ERR(svn_sqlite__insert(NULL, stmt_node));
-#endif
+  SVN_ERR(svn_sqlite__insert(NULL, stmt));
 
   if (pibb->kind == svn_wc__db_kind_dir && pibb->children)
-    {
-      int i;
-
-#ifndef SVN_WC__NODES_ONLY
-      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                        STMT_INSERT_BASE_NODE_INCOMPLETE));
-#endif
-#ifdef SVN_WC__NODES
-      SVN_ERR(svn_sqlite__get_statement(&stmt_node, sdb,
-                                        STMT_INSERT_NODE));
-#endif
-
-      for (i = pibb->children->nelts; i--; )
-        {
-          const char *name = APR_ARRAY_IDX(pibb->children, i, const char *);
+    SVN_ERR(insert_incomplete_children(sdb, pibb->wc_id,
+                                       pibb->local_relpath,
+                                       pibb->repos_id,
+                                       pibb->repos_relpath,
+                                       pibb->revision,
+                                       pibb->children,
+                                       0 /* BASE */,
+                                       scratch_pool));
 
-#ifndef SVN_WC__NODES_ONLY
-          SVN_ERR(svn_sqlite__bindf(stmt, "issr",
-                                    pibb->wc_id,
-                                    svn_relpath_join(pibb->local_relpath,
-                                                     name,
-                                                     scratch_pool),
-                                    pibb->local_relpath,
-                                    (apr_int64_t)pibb->revision));
-          SVN_ERR(svn_sqlite__insert(NULL, stmt));
-#endif
-#ifdef SVN_WC__NODES
-          SVN_ERR(svn_sqlite__bindf(stmt_node, "isisnnrsns",
-                                    pibb->wc_id,
-                                    svn_relpath_join(pibb->local_relpath,
-                                                     name,
-                                                     scratch_pool),
-                                    (apr_int64_t)0 /* BASE */,
-                                    pibb->local_relpath, /* parent_relpath */
-                                    pibb->revision,
-                                    "incomplete",
-                                    "unknown"));
-          SVN_ERR(svn_sqlite__insert(NULL, stmt_node));
-#endif
-        }
-    }
+  if (parent_relpath)
+    SVN_ERR(extend_parent_delete(sdb, pibb->wc_id, pibb->local_relpath,
+                                 scratch_pool));
 
   SVN_ERR(add_work_items(sdb, pibb->work_items, scratch_pool));
 
@@ -934,93 +900,57 @@ blank_iwb(insert_working_baton_t *piwb)
      value, but... meh. We'll avoid them if ORIGINAL_REPOS_RELPATH==NULL.  */
 }
 
-/* */
-static svn_error_t *
-copy_working_from_base(void *baton,
-                       svn_sqlite__db_t *sdb,
-                       apr_pool_t *scratch_pool)
-{
-  const insert_working_baton_t *piwb = baton;
-  svn_sqlite__stmt_t *stmt;
-
-#ifdef SVN_WC__NODES
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                         STMT_INSERT_WORKING_NODE_FROM_BASE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isit", piwb->wc_id,
-                            piwb->local_relpath,
-                            piwb->op_depth,
-                            presence_map, piwb->presence));
-  SVN_ERR(svn_sqlite__insert(NULL, stmt));
-
-#endif
-
-#ifndef SVN_WC__NODES_ONLY
-  /* Run the sequence below instead, which copies all the columns, including
-     those with the restrictions */
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                    STMT_INSERT_WORKING_NODE_FROM_BASE_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "ist", piwb->wc_id, piwb->local_relpath,
-                            presence_map, piwb->presence));
-  SVN_ERR(svn_sqlite__step_done(stmt));
-#endif
-
-  return SVN_NO_ERROR;
-}
-
 
-
-static svn_error_t *
-insert_incomplete_working_children(svn_sqlite__db_t *sdb,
-                                   apr_int64_t wc_id,
-                                   const char *local_relpath,
-                                   const apr_array_header_t *children,
-                                   apr_pool_t *scratch_pool)
+/* Insert a row in NODES for each (const char *) child name in CHILDREN,
+   whose parent directory is LOCAL_RELPATH, at op_depth=OP_DEPTH.  Set each
+   child's presence to 'incomplete', kind to 'unknown', repos_id to REPOS_ID,
+   repos_path by appending the child name to REPOS_PATH, and revision to
+   REVISION (which should match the parent's revision).
+
+   If REPOS_ID is INVALID_REPOS_ID, set each child's repos_id to null. */
+static svn_error_t *
+insert_incomplete_children(svn_sqlite__db_t *sdb,
+                           apr_int64_t wc_id,
+                           const char *local_relpath,
+                           apr_int64_t repos_id,
+                           const char *repos_path,
+                           svn_revnum_t revision,
+                           const apr_array_header_t *children,
+                           apr_int64_t op_depth,
+                           apr_pool_t *scratch_pool)
 {
-#ifndef SVN_WC__NODES_ONLY
   svn_sqlite__stmt_t *stmt;
-#endif
-#ifdef SVN_WC__NODES
-  svn_sqlite__stmt_t *stmt_node;
-#endif
   int i;
 
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                    STMT_INSERT_WORKING_NODE_INCOMPLETE));
-#endif
-#ifdef SVN_WC__NODES
-  SVN_ERR(svn_sqlite__get_statement(&stmt_node, sdb,
-                                    STMT_INSERT_NODE));
-#endif
+  SVN_ERR_ASSERT(repos_path != NULL || op_depth > 0);
+  SVN_ERR_ASSERT((repos_id != INVALID_REPOS_ID)
+                 == (repos_path != NULL));
 
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE));
 
   for (i = children->nelts; i--; )
     {
       const char *name = APR_ARRAY_IDX(children, i, const char *);
 
-#ifndef SVN_WC__NODES_ONLY
-      SVN_ERR(svn_sqlite__bindf(stmt, "iss",
+      SVN_ERR(svn_sqlite__bindf(stmt, "isisnnrsns",
                                 wc_id,
                                 svn_relpath_join(local_relpath, name,
                                                  scratch_pool),
-                                local_relpath));
-      SVN_ERR(svn_sqlite__insert(NULL, stmt));
-#endif
-#ifdef SVN_WC__NODES
-      SVN_ERR(svn_sqlite__bindf(stmt_node, "isisnnnsns",
-                                wc_id,
-                                svn_relpath_join(local_relpath, name,
-                                                 scratch_pool),
-                                (apr_int64_t) 2, /* ### op_depth
-                                                    non-THIS_DIR working */
+                                op_depth,
                                 local_relpath,
+                                revision,
                                 "incomplete", /* 8, presence */
                                 "unknown"));  /* 10, kind */
 
-      SVN_ERR(svn_sqlite__insert(NULL, stmt_node));
-#endif
+      if (repos_id != INVALID_REPOS_ID)
+        {
+          SVN_ERR(svn_sqlite__bind_int64(stmt, 5, repos_id));
+          SVN_ERR(svn_sqlite__bind_text(stmt, 6,
+                                        svn_relpath_join(repos_path, name,
+                                                         scratch_pool)));
+        }
+
+      SVN_ERR(svn_sqlite__insert(NULL, stmt));
     }
 
   return SVN_NO_ERROR;
@@ -1034,89 +964,20 @@ insert_working_node(void *baton,
 {
   const insert_working_baton_t *piwb = baton;
   const char *parent_relpath;
-#ifndef SVN_WC__NODES_ONLY
   svn_sqlite__stmt_t *stmt;
-#endif
-#ifdef SVN_WC__NODES
-  svn_sqlite__stmt_t *stmt_node;
-  apr_int64_t op_depth;
-#endif
+
+  SVN_ERR_ASSERT(piwb->op_depth > 0);
 
   /* We cannot insert a WORKING_NODE row at the wcroot.  */
-  /* ### actually, with per-dir DB, we can... */
   SVN_ERR_ASSERT(*piwb->local_relpath != '\0');
-  if (*piwb->local_relpath == '\0')
-    parent_relpath = NULL;
-  else
-    parent_relpath = svn_relpath_dirname(piwb->local_relpath, scratch_pool);
-
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isstt",
-                            piwb->wc_id, piwb->local_relpath,
-                            parent_relpath,
-                            presence_map, piwb->presence,
-                            kind_map, piwb->kind));
-
-  if (piwb->original_repos_relpath != NULL)
-    {
-      SVN_ERR_ASSERT(piwb->original_repos_id > 0);
-      SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(piwb->original_revnum));
-
-      SVN_ERR(svn_sqlite__bind_int64(stmt, 6, piwb->original_repos_id));
-      SVN_ERR(svn_sqlite__bind_text(stmt, 7, piwb->original_repos_relpath));
-      SVN_ERR(svn_sqlite__bind_int64(stmt, 8, piwb->original_revnum));
-    }
-
-  /* Do not bind 'moved_here' (9), nor 'moved_to' (10).  */
-
-  /* 'checksum' (11) is bound below.  */
-
-  /* Do not bind 'translated_size' (12).  */
-
-  if (SVN_IS_VALID_REVNUM(piwb->changed_rev))
-    SVN_ERR(svn_sqlite__bind_int64(stmt, 13, piwb->changed_rev));
-  if (piwb->changed_date)
-    SVN_ERR(svn_sqlite__bind_int64(stmt, 14, piwb->changed_date));
-  if (piwb->changed_author)
-    SVN_ERR(svn_sqlite__bind_text(stmt, 15, piwb->changed_author));
-
-  if (piwb->kind == svn_wc__db_kind_dir)
-    {
-      SVN_ERR(svn_sqlite__bind_text(stmt, 16, svn_depth_to_word(piwb->depth)));
-    }
-  else if (piwb->kind == svn_wc__db_kind_file)
-    {
-      SVN_ERR(svn_sqlite__bind_checksum(stmt, 11, piwb->checksum,
-                                        scratch_pool));
-    }
-  else if (piwb->kind == svn_wc__db_kind_symlink)
-    {
-      SVN_ERR_ASSERT(piwb->target != NULL);
-
-      SVN_ERR(svn_sqlite__bind_text(stmt, 20, piwb->target));
-    }
-
-  /* Do not bind 'last_mod_time' (17).  */
-
-  SVN_ERR(svn_sqlite__bind_properties(stmt, 18, piwb->props, scratch_pool));
-
-  /* Do not bind 'keep_local' (19).  */
-  /* 'symlink_target' (20) is bound above.  */
+  parent_relpath = svn_relpath_dirname(piwb->local_relpath, scratch_pool);
 
-  SVN_ERR(svn_sqlite__insert(NULL, stmt));
-
-#endif
-
-#ifdef SVN_WC__NODES
-  op_depth = (parent_relpath == NULL) ? 1   /* THIS_DIR */
-                                      : 2;  /* immediate children */
-  SVN_ERR(svn_sqlite__get_statement(&stmt_node, sdb, STMT_INSERT_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt_node, "isisnnntstrisn"
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isisnnntstrisn"
                 "nnnn" /* properties translated_size last_mod_time dav_cache */
                 "s",
                 piwb->wc_id, piwb->local_relpath,
-                op_depth,
+                piwb->op_depth,
                 parent_relpath,
                 presence_map, piwb->presence,
                 (piwb->kind == svn_wc__db_kind_dir)
@@ -1131,37 +992,41 @@ insert_working_node(void *baton,
 
   if (piwb->kind == svn_wc__db_kind_file)
     {
-      SVN_ERR(svn_sqlite__bind_checksum(stmt_node, 14, piwb->checksum,
+      SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, piwb->checksum,
                                         scratch_pool));
     }
   else if (piwb->kind == svn_wc__db_kind_symlink)
     {
       /* Note: incomplete nodes may have a NULL target.  */
       if (piwb->target)
-        SVN_ERR(svn_sqlite__bind_text(stmt_node, 19, piwb->target));
+        SVN_ERR(svn_sqlite__bind_text(stmt, 19, piwb->target));
     }
 
   if (piwb->original_repos_relpath != NULL)
     {
-      SVN_ERR(svn_sqlite__bind_int64(stmt_node, 5, piwb->original_repos_id));
-      SVN_ERR(svn_sqlite__bind_text(stmt_node, 6,
-                    piwb->original_repos_relpath));
-      SVN_ERR(svn_sqlite__bind_int64(stmt_node, 7, piwb->original_revnum));
+      SVN_ERR(svn_sqlite__bind_int64(stmt, 5, piwb->original_repos_id));
+      SVN_ERR(svn_sqlite__bind_text(stmt, 6, piwb->original_repos_relpath));
+      SVN_ERR(svn_sqlite__bind_int64(stmt, 7, piwb->original_revnum));
     }
 
 
-  SVN_ERR(svn_sqlite__bind_properties(stmt_node, 15, piwb->props,
-                      scratch_pool));
-
-  SVN_ERR(svn_sqlite__insert(NULL, stmt_node));
-#endif
+  SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool));
 
+  SVN_ERR(svn_sqlite__insert(NULL, stmt));
 
+  /* Insert incomplete children, if specified.
+     The children are part of the same op and so have the same op_depth.
+     (The only time we'd want a different depth is during a recursive
+     simple add, but we never insert children here during a simple add.) */
   if (piwb->kind == svn_wc__db_kind_dir && piwb->children)
-    SVN_ERR(insert_incomplete_working_children(sdb, piwb->wc_id,
-                                               piwb->local_relpath,
-                                               piwb->children,
-                                               scratch_pool));
+    SVN_ERR(insert_incomplete_children(sdb, piwb->wc_id,
+                                       piwb->local_relpath,
+                                       INVALID_REPOS_ID /* inherit repos_id */,
+                                       NULL /* inherit repos_path */,
+                                       piwb->original_revnum,
+                                       piwb->children,
+                                       piwb->op_depth,
+                                       scratch_pool));
 
   SVN_ERR(add_work_items(sdb, piwb->work_items, scratch_pool));
 
@@ -1169,25 +1034,6 @@ insert_working_node(void *baton,
 }
 
 
-/* Return the number of children under PARENT_RELPATH in the given WC_ID.
-   The table is implicitly defined by the STMT_IDX query.  */
-static svn_error_t *
-count_children(int *count,
-               int stmt_idx,
-               svn_sqlite__db_t *sdb,
-               apr_int64_t wc_id,
-               const char *parent_relpath)
-{
-  svn_sqlite__stmt_t *stmt;
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, stmt_idx));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath));
-  SVN_ERR(svn_sqlite__step_row(stmt));
-  *count = svn_sqlite__column_int(stmt, 0);
-  return svn_error_return(svn_sqlite__reset(stmt));
-}
-
-
 /* Each name is allocated in RESULT_POOL and stored into CHILDREN as a key
    pointed to the same name.  */
 static svn_error_t *
@@ -1218,226 +1064,65 @@ add_children_to_hash(apr_hash_t *childre
 }
 
 
-/* When children of PARENT_RELPATH are in both BASE_NODE and WORKING_NODE,
-   this function can be used to union those two sets, returning the set
-   in *CHILDREN (allocated in RESULT_POOL).  */
+/* Return in *CHILDREN all of the children of the directory LOCAL_RELPATH,
+   of any status, in all op-depths in the NODES table. */
 static svn_error_t *
-union_children(const apr_array_header_t **children,
-               svn_sqlite__db_t *sdb,
-               apr_int64_t wc_id,
-               const char *parent_relpath,
-               apr_pool_t *result_pool,
-               apr_pool_t *scratch_pool)
+gather_children(const apr_array_header_t **children,
+                svn_wc__db_pdh_t *pdh,
+                const char *local_relpath,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
 {
-  /* ### it would be nice to pre-size this hash table.  */
-  apr_hash_t *names = apr_hash_make(scratch_pool);
-#ifdef SVN_WC__NODES
-  apr_hash_t *names_nodes = apr_hash_make(scratch_pool);
-#endif
+  apr_hash_t *names_hash = apr_hash_make(scratch_pool);
   apr_array_header_t *names_array;
 
-  /* All of the names get allocated in RESULT_POOL.  */
-  SVN_ERR(add_children_to_hash(names, STMT_SELECT_BASE_NODE_CHILDREN,
-                               sdb, wc_id, parent_relpath, result_pool));
-  SVN_ERR(add_children_to_hash(names, STMT_SELECT_WORKING_NODE_CHILDREN,
-                               sdb, wc_id, parent_relpath, result_pool));
-#ifdef SVN_WC__NODES
-  SVN_ERR(add_children_to_hash(names_nodes, STMT_SELECT_BASE_NODE_CHILDREN_1,
-                               sdb, wc_id, parent_relpath, result_pool));
-  SVN_ERR(add_children_to_hash(names_nodes, STMT_SELECT_WORKING_NODE_CHILDREN_1,
-                               sdb, wc_id, parent_relpath, result_pool));
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR_ASSERT(apr_hash_count(names) == apr_hash_count(names_nodes));
-#else
-  names = names_nodes;
-#endif
-#endif
+  /* All of the names get allocated in RESULT_POOL.  It
+     appears to be faster to use the hash to remove duplicates than to
+     use DISTINCT in the SQL query. */
+  SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_NODE_CHILDREN,
+                               pdh->wcroot->sdb, pdh->wcroot->wc_id,
+                               local_relpath, result_pool));
 
-  SVN_ERR(svn_hash_keys(&names_array, names, result_pool));
+  SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool));
   *children = names_array;
-
   return SVN_NO_ERROR;
 }
 
-
-/* Return all the children of PARENT_RELPATH from a single table, implicitly
-   defined by STMT_IDX. If the caller happens to know the count of children,
-   it should be passed as START_SIZE to pre-allocate space in the *CHILDREN
-   return value.
-
-   If the caller doesn't know the count, then it should pass a reasonable
-   idea of how many children may be present.  */
-static svn_error_t *
-single_table_children(const apr_array_header_t **children,
-                      int stmt_idx,
-                      int start_size,
-                      svn_sqlite__db_t *sdb,
-                      apr_int64_t wc_id,
-                      const char *parent_relpath,
-                      apr_pool_t *result_pool)
+/* Set *CHILDREN to a new array of (const char *) names of the repository
+   children of the directory PDH:LOCAL_RELPATH - that is, the children at
+   the same op-depth. */
+static svn_error_t *
+gather_repo_children(const apr_array_header_t **children,
+                     svn_wc__db_pdh_t *pdh,
+                     const char *local_relpath,
+                     apr_int64_t op_depth,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
 {
+  apr_array_header_t *result
+    = apr_array_make(result_pool, 0, sizeof(const char *));
   svn_sqlite__stmt_t *stmt;
-  apr_array_header_t *child_names;
   svn_boolean_t have_row;
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, stmt_idx));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath));
-
-  /* ### should test the node to ensure it is a directory */
-
-  child_names = apr_array_make(result_pool, start_size, sizeof(const char *));
-
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_SELECT_OP_DEPTH_CHILDREN));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isi", pdh->wcroot->wc_id, local_relpath,
+                            op_depth));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   while (have_row)
     {
       const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
 
-      APR_ARRAY_PUSH(child_names, const char *) =
-        svn_relpath_basename(child_relpath, result_pool);
+      /* Allocate the name in RESULT_POOL so we won't have to copy it. */
+      APR_ARRAY_PUSH(result, const char *)
+        = svn_relpath_basename(child_relpath, result_pool);
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
+  SVN_ERR(svn_sqlite__reset(stmt));
 
-  *children = child_names;
-
-  return svn_sqlite__reset(stmt);
-}
-
-
-/* Return in *CHILDREN all of the children of the directory LOCAL_ABSPATH.
-   If BASE_ONLY is true, then *only* the children from BASE_NODE are
-   returned (those in WORKING_NODE are ignored). The result children are
-   allocated in RESULT_POOl.  */
-static svn_error_t *
-gather_children(const apr_array_header_t **children,
-                svn_boolean_t base_only,
-                svn_wc__db_t *db,
-                const char *local_abspath,
-                apr_pool_t *result_pool,
-                apr_pool_t *scratch_pool)
-{
-  svn_wc__db_pdh_t *pdh;
-  const char *local_relpath;
-  int base_count;
-  int working_count;
-#ifdef SVN_WC__NODES
-  int base_count_nodes, working_count_nodes;
-  const apr_array_header_t *children_nodes;
-#endif
-
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                                             local_abspath,
-                                             svn_sqlite__mode_readonly,
-                                             scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(pdh);
-
-  if (base_only)
-    {
-      /* 10 is based on Subversion's average of 8.7 files per versioned
-         directory in its repository.
-
-         ### note "files". should redo count with subdirs included */
-#ifndef SVN_WC__NODES_ONLY
-      SVN_ERR(single_table_children(children, STMT_SELECT_BASE_NODE_CHILDREN,
-                                    10 /* start_size */,
-                                    pdh->wcroot->sdb, pdh->wcroot->wc_id,
-                                    local_relpath, result_pool));
-#endif
-#ifdef SVN_WC__NODES
-      SVN_ERR(single_table_children(&children_nodes,
-                                    STMT_SELECT_BASE_NODE_CHILDREN_1,
-                                    10 /* start_size */,
-                                    pdh->wcroot->sdb, pdh->wcroot->wc_id,
-                                    local_relpath, result_pool));
-#ifndef SVN_WC__NODES_ONLY
-      SVN_ERR_ASSERT((*children)->nelts == children_nodes->nelts);
-#else
-      *children = children_nodes;
-#endif
-#endif
-      return SVN_NO_ERROR;
-    }
-
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(count_children(&base_count, STMT_COUNT_BASE_NODE_CHILDREN,
-                         pdh->wcroot->sdb, pdh->wcroot->wc_id, local_relpath));
-  SVN_ERR(count_children(&working_count, STMT_COUNT_WORKING_NODE_CHILDREN,
-                         pdh->wcroot->sdb, pdh->wcroot->wc_id, local_relpath));
-#endif
-#ifdef SVN_WC__NODES
-  SVN_ERR(count_children(&base_count_nodes, STMT_COUNT_BASE_NODE_CHILDREN_1,
-                         pdh->wcroot->sdb, pdh->wcroot->wc_id, local_relpath));
-  SVN_ERR(count_children(&working_count_nodes,
-                         STMT_COUNT_WORKING_NODE_CHILDREN_1,
-                         pdh->wcroot->sdb, pdh->wcroot->wc_id, local_relpath));
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR_ASSERT(base_count == base_count_nodes);
-  SVN_ERR_ASSERT(working_count == working_count_nodes);
-#else
-  base_count = base_count_nodes;
-  working_count = working_count_nodes;
-#endif
-#endif
-
-  if (base_count == 0)
-    {
-      if (working_count == 0)
-        {
-          *children = apr_array_make(result_pool, 0, sizeof(const char *));
-          return SVN_NO_ERROR;
-        }
-
-#ifndef SVN_WC__NODES_ONLY
-      SVN_ERR(single_table_children(children, STMT_SELECT_WORKING_NODE_CHILDREN,
-                                    working_count,
-                                    pdh->wcroot->sdb, pdh->wcroot->wc_id,
-                                    local_relpath, result_pool));
-#endif
-#ifdef SVN_WC__NODES
-      SVN_ERR(single_table_children(&children_nodes,
-                                    STMT_SELECT_WORKING_NODE_CHILDREN,
-                                    working_count,
-                                    pdh->wcroot->sdb, pdh->wcroot->wc_id,
-                                    local_relpath, result_pool));
-#ifndef SVN_WC__NODES_ONLY
-      SVN_ERR_ASSERT((*children)->nelts == children_nodes->nelts);
-#else
-      *children = children_nodes;
-#endif
-#endif
-      return SVN_NO_ERROR;
-    }
-  if (working_count == 0)
-    {
-#ifndef SVN_WC__NODES_ONLY
-      SVN_ERR(single_table_children(children, STMT_SELECT_BASE_NODE_CHILDREN,
-                                    base_count,
-                                    pdh->wcroot->sdb, pdh->wcroot->wc_id,
-                                    local_relpath, result_pool));
-#endif
-#ifdef SVN_WC__NODES
-      SVN_ERR(single_table_children(&children_nodes,
-                                    STMT_SELECT_BASE_NODE_CHILDREN_1,
-                                    base_count,
-                                    pdh->wcroot->sdb, pdh->wcroot->wc_id,
-                                    local_relpath, result_pool));
-#ifndef SVN_WC__NODES_ONLY
-      SVN_ERR_ASSERT((*children)->nelts == children_nodes->nelts);
-#else
-      *children = children_nodes;
-#endif
-#endif
-      return SVN_NO_ERROR;
-    }
-
-  /* ### it would be nice to pass BASE_COUNT and WORKING_COUNT, but there is
-     ### nothing union_children() can do with those.  */
-  return svn_error_return(union_children(children, 
-                                         pdh->wcroot->sdb, pdh->wcroot->wc_id,
-                                         local_relpath,
-                                         result_pool, scratch_pool));
+  *children = result;
+  return SVN_NO_ERROR;
 }
 
 
@@ -1535,33 +1220,14 @@ which_trees_exist(svn_boolean_t *base_ex
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
-#ifdef SVN_WC__NODES
-  svn_sqlite__stmt_t *stmt_nodes;
-  svn_boolean_t have_nodes_row;
-#endif
 
   *base_exists = FALSE;
   *working_exists = FALSE;
 
-#ifndef SVN_WC__NODES_ONLY
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
                                     STMT_DETERMINE_TREE_FOR_RECORDING));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
-#endif
-
-#ifdef SVN_WC__NODES
-  SVN_ERR(svn_sqlite__get_statement(&stmt_nodes, sdb,
-                                    STMT_DETERMINE_TREE_FOR_RECORDING_1));
-  SVN_ERR(svn_sqlite__bindf(stmt_nodes, "is", wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_nodes_row, stmt_nodes));
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(svn_sqlite__reset(stmt_nodes));
-#else
-  stmt = stmt_nodes;
-  have_row = have_nodes_row;
-#endif
-#endif
 
   if (have_row)
     {
@@ -1607,7 +1273,6 @@ prop_upgrade_trees(svn_boolean_t *base_e
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_PLAN_PROP_UPGRADE));
   SVN_ERR(svn_sqlite__bindf(stmt, "s", local_relpath));
-
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
   /* During a property upgrade, there better be a row corresponding to
@@ -1674,10 +1339,8 @@ create_db(svn_sqlite__db_t **sdb,
   /* Create the database's schema.  */
   SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_CREATE_SCHEMA));
 
-#ifdef SVN_WC__NODES
   /* Create the NODES table for the experimental schema */
   SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_CREATE_NODES));
-#endif
 
   /* Insert the repository. */
   SVN_ERR(create_repos_id(repos_id, repos_root_url, repos_uuid, *sdb,
@@ -2218,109 +1881,101 @@ svn_wc__db_base_add_not_present_node(svn
     kind, svn_wc__db_status_not_present, conflict, work_items, scratch_pool);
 }
 
+struct base_remove_baton {
+  const char *local_relpath;
+  apr_int64_t wc_id;
+};
 
-svn_error_t *
-svn_wc__db_base_remove(svn_wc__db_t *db,
-                       const char *local_abspath,
-                       apr_pool_t *scratch_pool)
+static svn_error_t *
+db_base_remove(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
-  svn_wc__db_pdh_t *pdh;
-  const char *local_relpath;
+  struct base_remove_baton *brb = baton;
   svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_BASE_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", brb->wc_id, brb->local_relpath));
+  SVN_ERR(svn_sqlite__step_done(stmt));
 
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              local_abspath, svn_sqlite__mode_readwrite,
-                              scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(pdh);
-
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                    STMT_DELETE_BASE_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
-
-  SVN_ERR(svn_sqlite__step_done(stmt));
-#endif
+  SVN_ERR(retract_parent_delete(sdb, brb->wc_id, brb->local_relpath,
+                                scratch_pool));
 
-#ifdef SVN_WC__NODES
-  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                    STMT_DELETE_BASE_NODE_1));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
-
-  SVN_ERR(svn_sqlite__step_done(stmt));
-#endif
-
-  SVN_ERR(flush_entries(db, pdh, local_abspath, scratch_pool));
+  /* If there is no working node then any actual node must be deleted,
+     unless it marks a conflict */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", brb->wc_id, brb->local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  SVN_ERR(svn_sqlite__reset(stmt));
+  if (!have_row)
+    {
+      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                    STMT_DELETE_ACTUAL_NODE_WITHOUT_CONFLICT));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", brb->wc_id, brb->local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+    }
 
   return SVN_NO_ERROR;
 }
 
-
 svn_error_t *
-svn_wc__db_base_get_info(svn_wc__db_status_t *status,
-                         svn_wc__db_kind_t *kind,
-                         svn_revnum_t *revision,
-                         const char **repos_relpath,
-                         const char **repos_root_url,
-                         const char **repos_uuid,
-                         svn_revnum_t *changed_rev,
-                         apr_time_t *changed_date,
-                         const char **changed_author,
-                         apr_time_t *last_mod_time,
-                         svn_depth_t *depth,
-                         const svn_checksum_t **checksum,
-                         svn_filesize_t *translated_size,
-                         const char **target,
-                         svn_wc__db_lock_t **lock,
-                         svn_wc__db_t *db,
-                         const char *local_abspath,
-                         apr_pool_t *result_pool,
-                         apr_pool_t *scratch_pool)
+svn_wc__db_base_remove(svn_wc__db_t *db,
+                       const char *local_abspath,
+                       apr_pool_t *scratch_pool)
 {
   svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-#ifdef SVN_WC__NODES
-  svn_sqlite__stmt_t *stmt_nodes;
-  svn_boolean_t have_node_row;
-#endif
-  svn_error_t *err = SVN_NO_ERROR;
+  struct base_remove_baton brb;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
   SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              local_abspath, svn_sqlite__mode_readonly,
+                              local_abspath, svn_sqlite__mode_readwrite,
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
-#ifndef SVN_WC__NODES_ONLY
+  brb.local_relpath = local_relpath;
+  brb.wc_id = pdh->wcroot->wc_id;
+
+  SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb,
+                                       db_base_remove, &brb,
+                                       scratch_pool));
+
+  SVN_ERR(flush_entries(db, pdh, local_abspath, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+/* Like svn_wc__db_base_get_info(), but taking PDH+LOCAL_RELPATH instead of
+ * DB+LOCAL_ABSPATH and outputting REPOS_ID instead of URL+UUID. */
+static svn_error_t *
+base_get_info(svn_wc__db_status_t *status,
+              svn_wc__db_kind_t *kind,
+              svn_revnum_t *revision,
+              const char **repos_relpath,
+              apr_int64_t *repos_id,
+              svn_revnum_t *changed_rev,
+              apr_time_t *changed_date,
+              const char **changed_author,
+              apr_time_t *last_mod_time,
+              svn_depth_t *depth,
+              const svn_checksum_t **checksum,
+              svn_filesize_t *translated_size,
+              const char **target,
+              svn_wc__db_lock_t **lock,
+              svn_wc__db_pdh_t *pdh,
+              const char *local_relpath,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  svn_error_t *err = SVN_NO_ERROR;
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     lock ? STMT_SELECT_BASE_NODE_WITH_LOCK
                                          : STMT_SELECT_BASE_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
-#endif
-
-#ifdef SVN_WC__NODES
-  SVN_ERR(svn_sqlite__get_statement(&stmt_nodes, pdh->wcroot->sdb,
-                                    lock ? STMT_SELECT_BASE_NODE_WITH_LOCK_1
-                                         : STMT_SELECT_BASE_NODE_1));
-  SVN_ERR(svn_sqlite__bindf(stmt_nodes, "is",
-                            pdh->wcroot->wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_node_row, stmt_nodes));
-
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(assert_base_rows_match(have_row, have_node_row, stmt, stmt_nodes,
-                                 local_relpath, scratch_pool));
-#else
-  /* Lets assume the two queries return compatible data */
-  have_row = have_node_row;
-  stmt = stmt_nodes;
-#endif
-
-#endif /* SVN_WC__NODES */
 
   if (have_row)
     {
@@ -2335,51 +1990,13 @@ svn_wc__db_base_get_info(svn_wc__db_stat
         {
           *status = svn_sqlite__column_token(stmt, 2, presence_map);
         }
-      if (revision)
-        {
-          *revision = svn_sqlite__column_revnum(stmt, 4);
-        }
-      if (repos_relpath)
-        {
-          *repos_relpath = svn_sqlite__column_text(stmt, 1, result_pool);
-        }
+      err = repos_location_from_columns(repos_id, revision, repos_relpath,
+                                        pdh, stmt, 0, 4, 1, result_pool);
+      SVN_ERR_ASSERT(!repos_id || *repos_id != INVALID_REPOS_ID);
+      SVN_ERR_ASSERT(!repos_relpath || *repos_relpath);
       if (lock)
         {
-          if (svn_sqlite__column_is_null(stmt, 14))
-            {
-              *lock = NULL;
-            }
-          else
-            {
-              *lock = apr_pcalloc(result_pool, sizeof(svn_wc__db_lock_t));
-              (*lock)->token = svn_sqlite__column_text(stmt, 14, result_pool);
-              if (!svn_sqlite__column_is_null(stmt, 15))
-                (*lock)->owner = svn_sqlite__column_text(stmt, 15,
-                                                         result_pool);
-              if (!svn_sqlite__column_is_null(stmt, 16))
-                (*lock)->comment = svn_sqlite__column_text(stmt, 16,
-                                                           result_pool);
-              if (!svn_sqlite__column_is_null(stmt, 17))
-                (*lock)->date = svn_sqlite__column_int64(stmt, 17);
-            }
-        }
-      if (repos_root_url || repos_uuid)
-        {
-          /* Fetch repository information via REPOS_ID. */
-          if (svn_sqlite__column_is_null(stmt, 0))
-            {
-              if (repos_root_url)
-                *repos_root_url = NULL;
-              if (repos_uuid)
-                *repos_uuid = NULL;
-            }
-          else
-            {
-              err = fetch_repos_info(repos_root_url, repos_uuid,
-                                     pdh->wcroot->sdb,
-                                     svn_sqlite__column_int64(stmt, 0),
-                                     result_pool);
-            }
+          *lock = lock_from_columns(stmt, 14, 15, 16, 17, result_pool);
         }
       if (changed_rev)
         {
@@ -2428,7 +2045,8 @@ svn_wc__db_base_get_info(svn_wc__db_stat
                 err = svn_error_createf(
                         err->apr_err, err,
                         _("The node '%s' has a corrupt checksum value."),
-                        svn_dirent_local_style(local_abspath, scratch_pool));
+                        path_for_error_message(pdh->wcroot, local_relpath,
+                                               scratch_pool));
             }
         }
       if (translated_size)
@@ -2447,110 +2065,59 @@ svn_wc__db_base_get_info(svn_wc__db_stat
     {
       err = svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
                               _("The node '%s' was not found."),
-                              svn_dirent_local_style(local_abspath,
+                              path_for_error_message(pdh->wcroot, local_relpath,
                                                      scratch_pool));
     }
 
-#ifdef SVN_WC__NODES
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(svn_sqlite__reset(stmt_nodes));
-#endif
-#endif
-
   /* Note: given the composition, no need to wrap for tracing.  */
   return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 }
 
+
 svn_error_t *
-svn_wc__db_base_get_info_from_parent(svn_wc__db_status_t *status,
-                                     svn_wc__db_kind_t *kind,
-                                     svn_revnum_t *revision,
-                                     const char **repos_relpath,
-                                     const char **repos_root_url,
-                                     const char **repos_uuid,
-                                     svn_wc__db_t *db,
-                                     const char *local_abspath,
-                                     apr_pool_t *result_pool,
-                                     apr_pool_t *scratch_pool)
+svn_wc__db_base_get_info(svn_wc__db_status_t *status,
+                         svn_wc__db_kind_t *kind,
+                         svn_revnum_t *revision,
+                         const char **repos_relpath,
+                         const char **repos_root_url,
+                         const char **repos_uuid,
+                         svn_revnum_t *changed_rev,
+                         apr_time_t *changed_date,
+                         const char **changed_author,
+                         apr_time_t *last_mod_time,
+                         svn_depth_t *depth,
+                         const svn_checksum_t **checksum,
+                         svn_filesize_t *translated_size,
+                         const char **target,
+                         svn_wc__db_lock_t **lock,
+                         svn_wc__db_t *db,
+                         const char *local_abspath,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
 {
   svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  svn_error_t *err = SVN_NO_ERROR;
-  const char *parent_abspath;
+  apr_int64_t repos_id;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
-  parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
-
   SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              parent_abspath, svn_sqlite__mode_readonly,
+                              local_abspath, svn_sqlite__mode_readonly,
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
-  local_relpath = svn_relpath_join(local_relpath,
-                                   svn_dirent_basename(local_abspath, NULL),
-                                   scratch_pool);
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                    STMT_SELECT_BASE_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-
-  if (have_row)
-    {
-      svn_wc__db_kind_t node_kind = svn_sqlite__column_token(stmt, 3,
-                                                             kind_map);
-
-      if (kind)
-        {
-          *kind = node_kind;
-        }
-      if (status)
-        {
-          *status = svn_sqlite__column_token(stmt, 2, presence_map);
-        }
-      if (revision)
-        {
-          *revision = svn_sqlite__column_revnum(stmt, 4);
-        }
-      if (repos_relpath)
-        {
-          *repos_relpath = svn_sqlite__column_text(stmt, 1, result_pool);
-        }
-      if (repos_root_url || repos_uuid)
-        {
-          /* Fetch repository information via REPOS_ID. */
-          if (svn_sqlite__column_is_null(stmt, 0))
-            {
-              if (repos_root_url)
-                *repos_root_url = NULL;
-              if (repos_uuid)
-                *repos_uuid = NULL;
-            }
-          else
-            {
-              err = fetch_repos_info(repos_root_url, repos_uuid,
-                                     pdh->wcroot->sdb,
-                                     svn_sqlite__column_int64(stmt, 0),
-                                     result_pool);
-            }
-        }
-    }
-  else
-    {
-      err = svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
-                              _("The node '%s' was not found."),
-                              svn_dirent_local_style(local_abspath,
-                                                     scratch_pool));
-    }
+  SVN_ERR(base_get_info(status, kind, revision, repos_relpath, &repos_id,
+                        changed_rev, changed_date, changed_author,
+                        last_mod_time, depth, checksum, translated_size,
+                        target, lock,
+                        pdh, local_relpath, result_pool, scratch_pool));
+  SVN_ERR_ASSERT(repos_id != INVALID_REPOS_ID);
+  SVN_ERR(fetch_repos_info(repos_root_url, repos_uuid,
+                           pdh->wcroot->sdb, repos_id, result_pool));
 
-  /* Note: given the composition, no need to wrap for tracing.  */
-  return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+  return SVN_NO_ERROR;
 }
 
-
 svn_error_t *
 svn_wc__db_base_get_prop(const svn_string_t **propval,
                          svn_wc__db_t *db,
@@ -2587,29 +2154,10 @@ svn_wc__db_base_get_props(apr_hash_t **p
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   svn_error_t *err;
-#ifdef SVN_WC__NODES
-  svn_sqlite__stmt_t *stmt_node;
-  svn_boolean_t have_node_row;
-#endif
 
-#ifndef SVN_WC__NODES_ONLY
   SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
                                  STMT_SELECT_BASE_PROPS, scratch_pool));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
-#endif
-#ifdef SVN_WC__NODES
-  SVN_ERR(get_statement_for_path(&stmt_node, db, local_abspath,
-                                 STMT_SELECT_BASE_PROPS_1, scratch_pool));
-  SVN_ERR(svn_sqlite__step(&have_node_row, stmt_node));
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR_ASSERT(have_row == have_node_row);
-  SVN_ERR(assert_blob_columns_equal(stmt, stmt_node, 0, scratch_pool));
-  SVN_ERR(svn_sqlite__reset(stmt_node));
-#else
-  stmt = stmt_node;
-  have_row = have_node_row;
-#endif
-#endif
   if (!have_row)
     {
       err = svn_sqlite__reset(stmt);
@@ -2639,8 +2187,19 @@ svn_wc__db_base_get_children(const apr_a
                              apr_pool_t *result_pool,
                              apr_pool_t *scratch_pool)
 {
-  return gather_children(children, TRUE,
-                         db, local_abspath, result_pool, scratch_pool);
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+                                             local_abspath,
+                                             svn_sqlite__mode_readonly,
+                                             scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(pdh);
+
+  return gather_repo_children(children, pdh, local_relpath, 0,
+                              result_pool, scratch_pool);
 }
 
 
@@ -2653,20 +2212,6 @@ svn_wc__db_base_set_dav_cache(svn_wc__db
   svn_sqlite__stmt_t *stmt;
   int affected_rows;
 
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
-                                 STMT_UPDATE_BASE_DAV_CACHE, scratch_pool));
-  SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
-
-  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
-
-  if (affected_rows != 1)
-    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
-                             _("The node '%s' was not found."),
-                             svn_dirent_local_style(local_abspath,
-                                                    scratch_pool));
-#endif
-#ifdef SVN_WC__NODES
   SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
                                  STMT_UPDATE_BASE_NODE_DAV_CACHE,
                                  scratch_pool));
@@ -2679,7 +2224,6 @@ svn_wc__db_base_set_dav_cache(svn_wc__db
                              _("The node '%s' was not found."),
                              svn_dirent_local_style(local_abspath,
                                                     scratch_pool));
-#endif
 
   return SVN_NO_ERROR;
 }
@@ -2727,28 +2271,14 @@ svn_wc__db_base_clear_dav_cache_recursiv
                                              scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
-  if (local_relpath[0] == 0)
-    like_arg = "%";
-  else
-    like_arg = apr_pstrcat(scratch_pool,
-                           escape_sqlite_like(local_relpath, scratch_pool),
-                           "/%", NULL);
+  like_arg = construct_like_arg(local_relpath, scratch_pool);
 
-#ifndef SVN_WC__NODES_ONLY
-  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                    STMT_CLEAR_BASE_RECURSIVE_DAV_CACHE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "iss", pdh->wcroot->wc_id, local_relpath,
-                            like_arg));
-  SVN_ERR(svn_sqlite__step_done(stmt));
-#endif
-#ifdef SVN_WC__NODES
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     STMT_CLEAR_BASE_NODE_RECURSIVE_DAV_CACHE));
   SVN_ERR(svn_sqlite__bindf(stmt, "iss", pdh->wcroot->wc_id, local_relpath,
                             like_arg));
 
   SVN_ERR(svn_sqlite__step_done(stmt));
-#endif
 
   return SVN_NO_ERROR;
 }
@@ -3136,22 +2666,21 @@ svn_wc__db_pristine_cleanup(svn_wc__db_t
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
-  /* Find the pristines in the DB */
+  /* Find each unreferenced pristine in the DB and remove it. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                    STMT_SELECT_PRISTINE_ROWS));
+                                    STMT_SELECT_UNREFERENCED_PRISTINES));
   while (1)
     {
       svn_boolean_t have_row;
-      const svn_checksum_t *checksum;
+      const svn_checksum_t *sha1_checksum;
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
       if (! have_row)
         break;
 
-      SVN_ERR(svn_sqlite__column_checksum(&checksum, stmt, 0,
+      SVN_ERR(svn_sqlite__column_checksum(&sha1_checksum, stmt, 0,
                                           scratch_pool));
-      SVN_ERR(svn_wc__db_pristine_remove(db, wri_abspath, checksum,
-                                         scratch_pool));
+      SVN_ERR(pristine_remove(pdh, sha1_checksum, scratch_pool));
     }
   SVN_ERR(svn_sqlite__reset(stmt));
 
@@ -3215,57 +2744,21 @@ svn_wc__db_pristine_check(svn_boolean_t 
 }
 
 
-svn_error_t *
-svn_wc__db_pristine_repair(svn_wc__db_t *db,
-                           const char *wri_abspath,
-                           const svn_checksum_t *sha1_checksum,
-                           apr_pool_t *scratch_pool)
-{
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
-  SVN_ERR_ASSERT(sha1_checksum != NULL);
-  SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
-
-  NOT_IMPLEMENTED();
-}
-
-
-svn_error_t *
-svn_wc__db_repos_ensure(apr_int64_t *repos_id,
-                        svn_wc__db_t *db,
-                        const char *local_abspath,
-                        const char *repos_root_url,
-                        const char *repos_uuid,
-                        apr_pool_t *scratch_pool)
-{
-  svn_wc__db_pdh_t *pdh;
-  const char *local_relpath;
-
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              local_abspath, svn_sqlite__mode_readwrite,
-                              scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(pdh);
-
-  return svn_error_return(create_repos_id(repos_id, repos_root_url,
-                                          repos_uuid, pdh->wcroot->sdb,
-                                          scratch_pool));
-}
-
-/* Temporary helper for svn_wc__db_op_copy to handle copying from one
-   db to another, it becomes redundant when we centralise. */
+/* Helper for svn_wc__db_op_copy to handle copying from one db to
+   another */
 static svn_error_t *
-temp_cross_db_copy(svn_wc__db_t *db,
-                   const char *src_abspath,
-                   svn_wc__db_pdh_t *src_pdh,
-                   const char *src_relpath,
-                   svn_wc__db_pdh_t *dst_pdh,
-                   const char *dst_relpath,
-                   svn_wc__db_status_t dst_status,
-                   svn_wc__db_kind_t kind,
-                   const apr_array_header_t *children,
-                   apr_int64_t copyfrom_id,
-                   const char *copyfrom_relpath,
-                   svn_revnum_t copyfrom_rev,
-                   apr_pool_t *scratch_pool)
+cross_db_copy(svn_wc__db_pdh_t *src_pdh,
+              const char *src_relpath,
+              svn_wc__db_pdh_t *dst_pdh,
+              const char *dst_relpath,
+              svn_wc__db_status_t dst_status,
+              apr_int64_t dst_op_depth,
+              svn_wc__db_kind_t kind,
+              const apr_array_header_t *children,
+              apr_int64_t copyfrom_id,
+              const char *copyfrom_relpath,
+              svn_revnum_t copyfrom_rev,
+              apr_pool_t *scratch_pool)
 {
   insert_working_baton_t iwb;
   svn_revnum_t changed_rev;
@@ -3281,32 +2774,30 @@ temp_cross_db_copy(svn_wc__db_t *db,
                  || kind == svn_wc__db_kind_dir
                  );
 
-  SVN_ERR(svn_wc__db_read_info(NULL /* status */,
-                               NULL /* kind */,
-                               NULL /* revision */,
-                               NULL /* repos_relpath */,
-                               NULL /* repos_root_url */,
-                               NULL /* repos_uuid */,
-                               &changed_rev, &changed_date, &changed_author,
-                               NULL /* last_mod_time */,
-                               &depth,
-                               &checksum,
-                               NULL /* translated_size */,
-                               NULL /* target */,
-                               NULL /* changelist */,
-                               NULL /* original_repos_relpath */,
-                               NULL /* original_root_url */,
-                               NULL /* original_uuid */,
-                               NULL /* original_revision */,
-                               NULL /* props_mod */,
-                               NULL /* have_base */,
-                               NULL /* have_work */,
-                               NULL /* conflicted */,
-                               NULL /* lock */,
-                               db, src_abspath, scratch_pool, scratch_pool));
+  SVN_ERR(read_info(NULL /* status */,
+                    NULL /* kind */,
+                    NULL /* revision */,
+                    NULL /* repos_relpath */,
+                    NULL /* repos_id */,
+                    &changed_rev, &changed_date, &changed_author,
+                    NULL /* last_mod_time */,
+                    &depth,
+                    &checksum,
+                    NULL /* translated_size */,
+                    NULL /* target */,
+                    NULL /* changelist */,
+                    NULL /* original_repos_relpath */,
+                    NULL /* original_repos_id */,
+                    NULL /* original_revision */,
+                    NULL /* props_mod */,
+                    NULL /* have_base */,
+                    NULL /* have_work */,
+                    NULL /* conflicted */,
+                    NULL /* lock */,
+                    src_pdh, src_relpath, scratch_pool, scratch_pool));
 
-  SVN_ERR(svn_wc__get_pristine_props(&props, db, src_abspath,
-                                     scratch_pool, scratch_pool));
+  SVN_ERR(db_read_pristine_props(&props, src_pdh, src_relpath,
+                                 scratch_pool, scratch_pool));
 
   blank_iwb(&iwb);
   iwb.presence = dst_status;
@@ -3323,6 +2814,8 @@ temp_cross_db_copy(svn_wc__db_t *db,
   iwb.original_revnum = copyfrom_rev;
   iwb.moved_here = FALSE;
 
+  iwb.op_depth = dst_op_depth;
+
   iwb.checksum = checksum;
   iwb.children = children;
   iwb.depth = depth;
@@ -3380,50 +2873,47 @@ get_info_for_copy(apr_int64_t *copyfrom_
                   svn_wc__db_kind_t *kind,
                   svn_boolean_t *have_work,
                   svn_wc__db_pdh_t *pdh,
-                  svn_wc__db_t *db,
-                  const char *local_abspath,
+                  const char *local_relpath,
                   apr_pool_t *result_pool,
                   apr_pool_t *scratch_pool)
 {
-  const char *repos_relpath, *repos_root_url, *repos_uuid;
+  const char *repos_relpath;
   svn_revnum_t revision;
 
-  SVN_ERR(svn_wc__db_read_info(status, kind, &revision,
-                               &repos_relpath, &repos_root_url, &repos_uuid,
-                               NULL /* changed_rev */,
-                               NULL /* changed_date */,
-                               NULL /* changed_author */,
-                               NULL /* last_mod_time */,
-                               NULL /* depth */,
-                               NULL /* checksum */,
-                               NULL /* translated_size */,
-                               NULL /* target */,
-                               NULL /* changelist */,
-                               NULL /* original_repos_relpath */,
-                               NULL /* original_root_url */,
-                               NULL /* original_uuid */,
-                               NULL /* original_revision */,
-                               NULL /* props_mod */,
-                               NULL /* have_base */,
-                               have_work,
-                               NULL /* conflicted */,
-                               NULL /* lock */,
-                               db, local_abspath, result_pool, scratch_pool));
+  SVN_ERR(read_info(status, kind, &revision, &repos_relpath, copyfrom_id,
+                    NULL /* changed_rev */,
+                    NULL /* changed_date */,
+                    NULL /* changed_author */,
+                    NULL /* last_mod_time */,
+                    NULL /* depth */,
+                    NULL /* checksum */,
+                    NULL /* translated_size */,
+                    NULL /* target */,
+                    NULL /* changelist */,
+                    NULL /* original_repos_relpath */,
+                    NULL /* original_repos_id */,
+                    NULL /* original_revision */,
+                    NULL /* props_mod */,
+                    NULL /* have_base */,
+                    have_work,
+                    NULL /* conflicted */,
+                    NULL /* lock */,
+                    pdh, local_relpath, result_pool, scratch_pool));
 
   if (*status == svn_wc__db_status_excluded)
     {
       /* The parent cannot be excluded, so look at the parent and then
          adjust the relpath */
-      const char *parent_abspath, *base_name;
+      const char *parent_relpath, *base_name;
       svn_wc__db_status_t parent_status;
       svn_wc__db_kind_t parent_kind;
       svn_boolean_t parent_have_work;
 
-      svn_dirent_split(&parent_abspath, &base_name, local_abspath,
+      svn_dirent_split(&parent_relpath, &base_name, local_relpath,
                        scratch_pool);
       SVN_ERR(get_info_for_copy(copyfrom_id, copyfrom_relpath, copyfrom_rev,
                                 &parent_status, &parent_kind, &parent_have_work,
-                                pdh, db, parent_abspath,
+                                pdh, parent_relpath,
                                 scratch_pool, scratch_pool));
       if (*copyfrom_relpath)
         *copyfrom_relpath = svn_relpath_join(*copyfrom_relpath, base_name,
@@ -3431,142 +2921,108 @@ get_info_for_copy(apr_int64_t *copyfrom_
     }
   else if (*status == svn_wc__db_status_added)
     {
-      const char *op_root_abspath;
-      const char *original_repos_relpath, *original_root_url, *original_uuid;
-      svn_revnum_t original_revision;
-
-      SVN_ERR(svn_wc__db_scan_addition(status, &op_root_abspath,
-                                       NULL /* repos_relpath */,
-                                       NULL /* repos_root_url */,
-                                       NULL /* repos_uuid */,
-                                       &original_repos_relpath,
-                                       &original_root_url, &original_uuid,
-                                       &original_revision,
-                                       db, local_abspath,

[... 5771 lines stripped ...]