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/08/11 18:43:31 UTC

svn commit: r984468 [16/25] - in /subversion/branches/ignore-mergeinfo: ./ build/ build/generator/ build/generator/templates/ notes/ notes/tree-conflicts/ notes/wc-ng/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subvers...

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=984468&r1=984467&r2=984468&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c Wed Aug 11 16:43:22 2010
@@ -52,8 +52,7 @@
 #include "private/svn_token.h"
 
 
-#define NOT_IMPLEMENTED() \
-  return svn_error__malfunction(TRUE, __FILE__, __LINE__, "Not implemented.")
+#define NOT_IMPLEMENTED() SVN__NOT_IMPLEMENTED()
 
 
 /*
@@ -105,31 +104,30 @@
 #define UNKNOWN_WC_ID ((apr_int64_t) -1)
 #define FORMAT_FROM_SDB (-1)
 
-
-/* Assert that the given PDH is usable.
-   NOTE: the expression is multiply-evaluated!!  */
-#define VERIFY_USABLE_PDH(pdh) SVN_ERR_ASSERT(  \
-    (pdh)->wcroot != NULL                       \
-    && (pdh)->wcroot->format == SVN_WC__VERSION)
-
-
-/* ### since we're putting the pristine files per-dir, then we don't need
-   ### to create subdirectories in order to keep the directory size down.
-   ### when we can aggregate pristine files across dirs/wcs, then we will
-   ### need to undo the SKIP. */
-#define SVN__SKIP_SUBDIR
-
-WC_QUERIES_SQL_DECLARE_STATEMENTS(statements);
-
-
 /* This is a character used to escape itself and the globbing character in
    globbing sql expressions below.  See escape_sqlite_like().
 
    NOTE: this should match the character used within wc-metadata.sql  */
 #define LIKE_ESCAPE_CHAR     "#"
 
+/* Calculates the depth of the relpath below "" */
+APR_INLINE static int relpath_op_depth(const char *relpath)
+{
+  int n = 1;
+  if (*relpath == '\0')
+    return 0;
 
-typedef struct {
+  do
+  {
+    if (*relpath == '/')
+      n++;
+  }
+  while (*(++relpath));
+
+  return n;
+}
+
+typedef struct insert_base_baton_t {
   /* common to all insertions into BASE */
   svn_wc__db_status_t status;
   svn_wc__db_kind_t kind;
@@ -144,6 +142,7 @@ typedef struct {
   svn_revnum_t changed_rev;
   apr_time_t changed_date;
   const char *changed_author;
+  apr_hash_t *dav_cache;
 
   /* for inserting directories */
   const apr_array_header_t *children;
@@ -281,7 +280,7 @@ escape_sqlite_like(const char * const st
    to hold CHECKSUM's pristine file, relating to the pristine store
    configured for the working copy indicated by PDH. The returned path
    does not necessarily currently exist.
-#ifndef SVN__SKIP_SUBDIR
+#ifdef SVN_WC__SINGLE_DB
    Iff CREATE_SUBDIR is TRUE, then this function will make sure that the
    parent directory of PRISTINE_ABSPATH exists. This is only useful when
    about to create a new pristine.
@@ -297,7 +296,7 @@ get_pristine_fname(const char **pristine
 {
   const char *base_dir_abspath;
   const char *hexdigest = svn_checksum_to_cstring(sha1_checksum, scratch_pool);
-#ifndef SVN__SKIP_SUBDIR
+#ifdef SVN_WC__SINGLE_DB
   char subdir[3];
 #endif
 
@@ -319,7 +318,7 @@ get_pristine_fname(const char **pristine
   /* We should have a valid checksum and (thus) a valid digest. */
   SVN_ERR_ASSERT(hexdigest != NULL);
 
-#ifndef SVN__SKIP_SUBDIR
+#ifdef SVN_WC__SINGLE_DB
   /* Get the first two characters of the digest, for the subdir. */
   subdir[0] = hexdigest[0];
   subdir[1] = hexdigest[1];
@@ -344,7 +343,7 @@ get_pristine_fname(const char **pristine
   /* The file is located at DIR/.svn/pristine/XX/XXYYZZ... */
   *pristine_abspath = svn_dirent_join_many(result_pool,
                                            base_dir_abspath,
-#ifndef SVN__SKIP_SUBDIR
+#ifdef SVN_WC__SINGLE_DB
                                            subdir,
 #endif
                                            hexdigest,
@@ -525,24 +524,17 @@ navigate_to_parent(svn_wc__db_pdh_t **pa
                    svn_boolean_t verify_parent_stub,
                    apr_pool_t *scratch_pool)
 {
-  const char *parent_abspath;
-  const char *local_relpath;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t got_row;
 
-  if ((*parent_pdh = child_pdh->parent) != NULL
-      && (*parent_pdh)->wcroot != NULL)
-    return SVN_NO_ERROR;
+  SVN_ERR(svn_wc__db_pdh_navigate_to_parent(parent_pdh,
+                                            db,
+                                            child_pdh,
+                                            smode,
+                                            scratch_pool));
 
-  /* Make sure we don't see the root as its own parent */
-  SVN_ERR_ASSERT(!svn_dirent_is_root(child_pdh->local_abspath,
-                                     strlen(child_pdh->local_abspath)));
-
-  parent_abspath = svn_dirent_dirname(child_pdh->local_abspath, scratch_pool);
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(parent_pdh, &local_relpath, db,
-                              parent_abspath, smode,
-                              scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(*parent_pdh);
+  if (!verify_parent_stub)
+    return SVN_NO_ERROR;
 
   /* Check that the parent has an entry for the child */
   SVN_ERR(svn_sqlite__get_statement(&stmt, (*parent_pdh)->wcroot->sdb,
@@ -553,15 +545,12 @@ navigate_to_parent(svn_wc__db_pdh_t **pa
   SVN_ERR(svn_sqlite__step(&got_row, stmt));
   SVN_ERR(svn_sqlite__reset(stmt));
 
-  if (!got_row && verify_parent_stub)
+  if (!got_row)
     return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
                               _("'%s' does not have a parent."),
                               svn_dirent_local_style(child_pdh->local_abspath,
                                                      scratch_pool));
 
-  if (got_row)
-    child_pdh->parent = *parent_pdh;
-
   return SVN_NO_ERROR;
 }
 
@@ -625,29 +614,27 @@ insert_base_node(void *baton, svn_sqlite
 {
   const insert_base_baton_t *pibb = baton;
   svn_sqlite__stmt_t *stmt;
+#ifdef SVN_WC__NODE_DATA
+  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);
 
   /* ### we can't handle this right now  */
   SVN_ERR_ASSERT(pibb->conflict == NULL);
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_BASE_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", pibb->wc_id, pibb->local_relpath));
-
-  if (TRUE /* maybe_bind_repos() */)
-    {
-      SVN_ERR(svn_sqlite__bind_int64(stmt, 3, pibb->repos_id));
-      SVN_ERR(svn_sqlite__bind_text(stmt, 4, pibb->repos_relpath));
-    }
-
-  /* The directory at the WCROOT has a NULL parent_relpath. Otherwise,
-     bind the appropriate parent_relpath. */
-  if (*pibb->local_relpath != '\0')
-    SVN_ERR(svn_sqlite__bind_text(stmt, 5,
-                                  svn_relpath_dirname(pibb->local_relpath,
-                                                      scratch_pool)));
-
-  SVN_ERR(svn_sqlite__bind_token(stmt, 6, presence_map, pibb->status));
-  SVN_ERR(svn_sqlite__bind_token(stmt, 7, kind_map, pibb->kind));
-  SVN_ERR(svn_sqlite__bind_int64(stmt, 8, pibb->revision));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isisstti",
+                            pibb->wc_id, pibb->local_relpath,
+                            pibb->repos_id,
+                            pibb->repos_relpath,
+                            parent_relpath,
+                            presence_map, pibb->status,
+                            kind_map, pibb->kind,
+                            pibb->revision));
 
   SVN_ERR(svn_sqlite__bind_properties(stmt, 9, pibb->props, scratch_pool));
 
@@ -676,14 +663,63 @@ insert_base_node(void *baton, svn_sqlite
         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));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt_node, sdb, STMT_INSERT_NODE_DATA));
+  SVN_ERR(svn_sqlite__bindf(stmt_node, "isistt",
+                            pibb->wc_id, pibb->local_relpath,
+                            (apr_int64_t)0, /* op_depth is 0 for base */
+                            parent_relpath,
+                            presence_map, pibb->status,
+                            kind_map, pibb->kind));
+
+  if (SVN_IS_VALID_REVNUM(pibb->changed_rev))
+    SVN_ERR(svn_sqlite__bind_int64(stmt_node, 7, pibb->changed_rev));
+  if (pibb->changed_date)
+    SVN_ERR(svn_sqlite__bind_int64(stmt_node, 8, pibb->changed_date));
+  if (pibb->changed_author)
+    SVN_ERR(svn_sqlite__bind_text(stmt_node, 9, pibb->changed_author));
+
+  if (pibb->kind == svn_wc__db_kind_dir)
+    {
+      SVN_ERR(svn_sqlite__bind_text(stmt_node, 10,
+                                    svn_depth_to_word(pibb->depth)));
+    }
+  else if (pibb->kind == svn_wc__db_kind_file)
+    {
+      SVN_ERR(svn_sqlite__bind_checksum(stmt_node, 11, pibb->checksum,
+                                        scratch_pool));
+    }
+  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_node, 12, pibb->target));
+    }
+
+  /* Don't bind original_repos_id, original_repos_path and original_revision */
+
+  SVN_ERR(svn_sqlite__bind_properties(stmt_node, 16, pibb->props,
+                                      scratch_pool));
+
+  SVN_ERR(svn_sqlite__insert(NULL, stmt_node));
+#endif
+
   if (pibb->kind == svn_wc__db_kind_dir && pibb->children)
     {
       int i;
 
       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
                                         STMT_INSERT_BASE_NODE_INCOMPLETE));
+#ifdef SVN_WC__NODE_DATA
+      SVN_ERR(svn_sqlite__get_statement(&stmt_node, sdb,
+                                        STMT_INSERT_NODE_DATA_INCOMPLETE));
+#endif
 
       for (i = pibb->children->nelts; i--; )
         {
@@ -697,6 +733,17 @@ insert_base_node(void *baton, svn_sqlite
                                     pibb->local_relpath,
                                     (apr_int64_t)pibb->revision));
           SVN_ERR(svn_sqlite__insert(NULL, stmt));
+
+#ifdef SVN_WC__NODE_DATA
+          SVN_ERR(svn_sqlite__bindf(stmt_node, "isis",
+                                    pibb->wc_id,
+                                    svn_relpath_join(pibb->local_relpath,
+                                                     name,
+                                                     scratch_pool),
+                                    (apr_int64_t)0 /* BASE */,
+                                    pibb->local_relpath));
+          SVN_ERR(svn_sqlite__insert(NULL, stmt_node));
+#endif
         }
     }
 
@@ -725,10 +772,18 @@ insert_incomplete_working_children(svn_s
                                    apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
+#ifdef SVN_WC__NODE_DATA
+  svn_sqlite__stmt_t *stmt_node;
+#endif
   int i;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
                                     STMT_INSERT_WORKING_NODE_INCOMPLETE));
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt_node, sdb,
+                                    STMT_INSERT_NODE_DATA_INCOMPLETE));
+#endif
+
 
   for (i = children->nelts; i--; )
     {
@@ -740,6 +795,18 @@ insert_incomplete_working_children(svn_s
                                                  scratch_pool),
                                 local_relpath));
       SVN_ERR(svn_sqlite__insert(NULL, stmt));
+
+#ifdef SVN_WC__NODE_DATA
+      SVN_ERR(svn_sqlite__bindf(stmt_node, "isis",
+                                wc_id,
+                                svn_relpath_join(local_relpath, name,
+                                                 scratch_pool),
+#ifndef SINGLE_DB
+                                (apr_int64_t) 2, /* non-THIS_DIR working */
+#endif
+                                local_relpath));
+      SVN_ERR(svn_sqlite__insert(NULL, stmt_node));
+#endif
     }
 
   return SVN_NO_ERROR;
@@ -754,6 +821,10 @@ insert_working_node(void *baton,
   const insert_working_baton_t *piwb = baton;
   const char *parent_relpath;
   svn_sqlite__stmt_t *stmt;
+#ifdef SVN_WC__NODE_DATA
+  svn_sqlite__stmt_t *stmt_node;
+  apr_int64_t op_depth;
+#endif
 
   /* We cannot insert a WORKING_NODE row at the wcroot.  */
   /* ### actually, with per-dir DB, we can... */
@@ -820,6 +891,63 @@ insert_working_node(void *baton,
 
   SVN_ERR(svn_sqlite__insert(NULL, stmt));
 
+
+#ifdef SVN_WC__NODE_DATA
+#ifndef SINGLE_DB
+  op_depth = (parent_relpath == NULL) ? 1   /* THIS_DIR */
+                                      : 2;  /* immediate children */
+#endif
+  SVN_ERR(svn_sqlite__get_statement(&stmt_node, sdb, STMT_INSERT_NODE_DATA));
+  SVN_ERR(svn_sqlite__bindf(stmt_node, "isistt",
+                            piwb->wc_id, piwb->local_relpath,
+                            op_depth,
+                            parent_relpath,
+                            presence_map, piwb->presence,
+                            kind_map, piwb->kind));
+
+  if (SVN_IS_VALID_REVNUM(piwb->changed_rev))
+    SVN_ERR(svn_sqlite__bind_int64(stmt_node, 7, piwb->changed_rev));
+  if (piwb->changed_date)
+    SVN_ERR(svn_sqlite__bind_int64(stmt_node, 8, piwb->changed_date));
+  if (piwb->changed_author)
+    SVN_ERR(svn_sqlite__bind_text(stmt_node, 9, piwb->changed_author));
+
+  if (piwb->kind == svn_wc__db_kind_dir)
+    {
+      SVN_ERR(svn_sqlite__bind_text(stmt_node, 10,
+                                    svn_depth_to_word(piwb->depth)));
+    }
+  else if (piwb->kind == svn_wc__db_kind_file)
+    {
+      SVN_ERR(svn_sqlite__bind_checksum(stmt_node, 11, 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, 12, piwb->target));
+    }
+
+  if (piwb->original_repos_relpath != NULL)
+    {
+      SVN_ERR(svn_sqlite__bind_int64(stmt_node, 13, piwb->original_repos_id));
+      SVN_ERR(svn_sqlite__bind_text(stmt_node, 14,
+                    piwb->original_repos_relpath));
+      SVN_ERR(svn_sqlite__bind_int64(stmt_node, 15, piwb->original_revnum));
+    }
+
+
+  /* Don't bind original_repos_id, original_repos_path and original_revision */
+
+
+  SVN_ERR(svn_sqlite__bind_properties(stmt_node, 16, piwb->props,
+                      scratch_pool));
+
+  SVN_ERR(svn_sqlite__insert(NULL, stmt_node));
+#endif
+
+
   if (piwb->kind == svn_wc__db_kind_dir && piwb->children)
     SVN_ERR(insert_incomplete_working_children(sdb, piwb->wc_id,
                                                piwb->local_relpath,
@@ -1139,6 +1267,7 @@ which_trees_exist(svn_boolean_t *base_ex
    we return a WC_ID and verify some additional constraints.  */
 static svn_error_t *
 prop_upgrade_trees(svn_boolean_t *base_exists,
+                   svn_wc__db_status_t *base_presence,
                    svn_boolean_t *working_exists,
                    svn_wc__db_status_t *work_presence,
                    apr_int64_t *wc_id,
@@ -1170,6 +1299,7 @@ prop_upgrade_trees(svn_boolean_t *base_e
   else
     {
       *base_exists = TRUE;  /* value == 0  */
+      *base_presence = svn_sqlite__column_token(stmt, 1, presence_map);
     }
 
   /* Return the WC_ID that was assigned.  */
@@ -1186,6 +1316,8 @@ prop_upgrade_trees(svn_boolean_t *base_e
          fetch the 'presence' column value.  */
       if (svn_sqlite__column_int(stmt, 0))
         *work_presence = svn_sqlite__column_token(stmt, 1, presence_map);
+      else
+        *base_presence = svn_sqlite__column_token(stmt, 1, presence_map);
 
       /* During an upgrade, there should be just one working copy, so both
          rows should refer to the same value.  */
@@ -1217,6 +1349,11 @@ 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__NODE_DATA
+  /* Create the NODE_DATA table for the experimental schema */
+  SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_CREATE_NODE_DATA));
+#endif
+
   /* Insert the repository. */
   SVN_ERR(create_repos_id(repos_id, repos_root_url, repos_uuid, *sdb,
                           scratch_pool));
@@ -1342,6 +1479,33 @@ svn_wc__db_from_relpath(const char **loc
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__db_get_wcroot(const char **wcroot_abspath,
+                      svn_wc__db_t *db,
+                      const char *wri_abspath,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
+{
+  svn_wc__db_pdh_t *pdh;
+  const char *unused_relpath;
+
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &unused_relpath, db,
+                              wri_abspath, svn_sqlite__mode_readonly,
+                              scratch_pool, scratch_pool));
+
+  /* Can't use VERIFY_USABLE_PDH, as this should be usable to detect
+     where call upgrade */
+
+  if (pdh->wcroot == NULL)
+    return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
+                             _("The node '%s' is not in a workingcopy."),
+                             svn_dirent_local_style(wri_abspath,
+                                                    scratch_pool));
+
+  *wcroot_abspath = apr_pstrdup(result_pool, pdh->wcroot->abspath);
+
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_wc__db_base_add_directory(svn_wc__db_t *db,
@@ -1356,6 +1520,7 @@ svn_wc__db_base_add_directory(svn_wc__db
                               const char *changed_author,
                               const apr_array_header_t *children,
                               svn_depth_t depth,
+                              apr_hash_t *dav_cache,
                               const svn_skel_t *conflict,
                               const svn_skel_t *work_items,
                               apr_pool_t *scratch_pool)
@@ -1402,6 +1567,7 @@ svn_wc__db_base_add_directory(svn_wc__db
   ibb.children = children;
   ibb.depth = depth;
 
+  ibb.dav_cache = dav_cache;
   ibb.conflict = conflict;
   ibb.work_items = work_items;
 
@@ -1432,6 +1598,7 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
                          const char *changed_author,
                          const svn_checksum_t *checksum,
                          svn_filesize_t translated_size,
+                         apr_hash_t *dav_cache,
                          const svn_skel_t *conflict,
                          const svn_skel_t *work_items,
                          apr_pool_t *scratch_pool)
@@ -1476,6 +1643,7 @@ svn_wc__db_base_add_file(svn_wc__db_t *d
   ibb.checksum = checksum;
   ibb.translated_size = translated_size;
 
+  ibb.dav_cache = dav_cache;
   ibb.conflict = conflict;
   ibb.work_items = work_items;
 
@@ -1504,6 +1672,7 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
                             apr_time_t changed_date,
                             const char *changed_author,
                             const char *target,
+                            apr_hash_t *dav_cache,
                             const svn_skel_t *conflict,
                             const svn_skel_t *work_items,
                             apr_pool_t *scratch_pool)
@@ -1547,6 +1716,7 @@ svn_wc__db_base_add_symlink(svn_wc__db_t
 
   ibb.target = target;
 
+  ibb.dav_cache = dav_cache;
   ibb.conflict = conflict;
   ibb.work_items = work_items;
 
@@ -1739,6 +1909,14 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
 
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_DELETE_NODE_DATA_BASE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+
+  SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
   flush_entries(pdh);
 
 #ifndef SINGLE_DB
@@ -1758,6 +1936,16 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
 
           SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+          SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                            STMT_DELETE_NODE_DATA_BASE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id,
+                                    svn_dirent_basename(local_abspath,
+                                                        scratch_pool)));
+
+          SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
           flush_entries(pdh);
         }
       else if (err && err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)
@@ -2141,14 +2329,21 @@ svn_wc__db_base_set_dav_cache(svn_wc__db
                               apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
+  int affected_rows;
 
   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));
 
-  /* ### we should assert that 1 row was affected.  */
+  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));
 
-  return svn_error_return(svn_sqlite__step_done(stmt));
+  return SVN_NO_ERROR;
 }
 
 
@@ -2238,7 +2433,6 @@ svn_wc__db_pristine_get_path(const char 
   VERIFY_USABLE_PDH(pdh);
 
   SVN_ERR(svn_wc__db_pristine_check(&present, db, wri_abspath, sha1_checksum,
-                                    svn_wc__db_checkmode_usable,
                                     scratch_pool));
   if (! present)
     return svn_error_createf(SVN_ERR_WC_DB_ERROR, NULL,
@@ -2346,6 +2540,7 @@ svn_wc__db_pristine_install(svn_wc__db_t
   const char *pristine_abspath;
   apr_finfo_t finfo;
   svn_sqlite__stmt_t *stmt;
+  svn_node_kind_t kind;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(tempfile_abspath));
   SVN_ERR_ASSERT(sha1_checksum != NULL);
@@ -2371,9 +2566,20 @@ svn_wc__db_pristine_install(svn_wc__db_t
                              TRUE /* create_subdir */,
                              scratch_pool, scratch_pool));
 
+
+  SVN_ERR(svn_io_check_path(pristine_abspath, &kind, scratch_pool));
+
+  if (kind == svn_node_file)
+    {
+      /* Remove the tempfile, it's already there */
+      return svn_error_return(
+                  svn_io_remove_file2(tempfile_abspath,
+                                      FALSE, scratch_pool));
+    }
+
   /* Put the file into its target location.  */
-  SVN_ERR(svn_io_file_rename(tempfile_abspath, pristine_abspath,
-                             scratch_pool));
+    SVN_ERR(svn_io_file_rename(tempfile_abspath, pristine_abspath,
+                               scratch_pool));
 
   SVN_ERR(svn_io_stat(&finfo, pristine_abspath, APR_FINFO_SIZE,
                       scratch_pool));
@@ -2469,6 +2675,32 @@ svn_wc__db_pristine_get_sha1(const svn_c
 }
 
 
+/* Delete the pristine text referenced by SHA1_CHECKSUM in the database
+ * referenced by PDH. */
+static svn_error_t *
+pristine_remove(svn_wc__db_pdh_t *pdh,
+                const svn_checksum_t *sha1_checksum,
+                apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  const char *pristine_abspath;
+
+  /* Remove the DB row. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_DELETE_PRISTINE));
+  SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
+  SVN_ERR(svn_sqlite__update(NULL, stmt));
+
+  /* Remove the file */
+  SVN_ERR(get_pristine_fname(&pristine_abspath, pdh->wcroot->abspath,
+                             sha1_checksum, TRUE /* create_subdir */,
+                             scratch_pool, scratch_pool));
+  SVN_ERR(svn_io_remove_file2(pristine_abspath, TRUE /* ignore_enoent */,
+                              scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_wc__db_pristine_remove(svn_wc__db_t *db,
                            const char *wri_abspath,
@@ -2494,6 +2726,21 @@ svn_wc__db_pristine_remove(svn_wc__db_t 
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
+  /* If the work queue is not empty, don't delete any pristine text because
+   * the work queue may contain a reference to it. */
+  {
+    svn_sqlite__stmt_t *stmt;
+    svn_boolean_t have_row;
+
+    SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                      STMT_LOOK_FOR_WORK));
+    SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    SVN_ERR(svn_sqlite__reset(stmt));
+
+    if (have_row)
+      return SVN_NO_ERROR;
+  }
+
   /* Find whether the SHA-1 (or the MD-5) is referenced; set IS_REFERENCED. */
   {
     const svn_checksum_t *md5_checksum;
@@ -2513,24 +2760,10 @@ svn_wc__db_pristine_remove(svn_wc__db_t 
     SVN_ERR(svn_sqlite__reset(stmt));
   }
 
-  /* If not referenced, remove first the PRISTINE table row, then the file. */
+  /* If not referenced, remove the PRISTINE table row and the file. */
   if (! is_referenced)
     {
-      svn_sqlite__stmt_t *stmt;
-      const char *pristine_abspath;
-
-      /* Remove the DB row. */
-      SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                        STMT_DELETE_PRISTINE));
-      SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool));
-      SVN_ERR(svn_sqlite__update(NULL, stmt));
-
-      /* Remove the file */
-      SVN_ERR(get_pristine_fname(&pristine_abspath, pdh->wcroot->abspath,
-                                 sha1_checksum,
-                                 TRUE /* create_subdir */,
-                                 scratch_pool, scratch_pool));
-      SVN_ERR(svn_io_remove_file2(pristine_abspath, TRUE, scratch_pool));
+      SVN_ERR(pristine_remove(pdh, sha1_checksum, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -2581,7 +2814,6 @@ svn_wc__db_pristine_check(svn_boolean_t 
                           svn_wc__db_t *db,
                           const char *wri_abspath,
                           const svn_checksum_t *sha1_checksum,
-                          svn_wc__db_checkmode_t mode,
                           apr_pool_t *scratch_pool)
 {
   svn_wc__db_pdh_t *pdh;
@@ -2847,15 +3079,7 @@ get_info_for_copy(apr_int64_t *copyfrom_
         *copyfrom_relpath = svn_relpath_join(*copyfrom_relpath, base_name,
                                              result_pool);
     }
-  else if (*status != svn_wc__db_status_added)
-    {
-      *copyfrom_relpath = repos_relpath;
-      *copyfrom_rev = revision;
-      SVN_ERR(create_repos_id(copyfrom_id,
-                              repos_root_url, repos_uuid,
-                              pdh->wcroot->sdb, scratch_pool));
-    }
-  else
+  else if (*status == svn_wc__db_status_added)
     {
       const char *op_root_abspath;
       const char *original_repos_relpath, *original_root_url, *original_uuid;
@@ -2891,6 +3115,66 @@ get_info_for_copy(apr_int64_t *copyfrom_
           *copyfrom_id = 0;
         }
     }
+  else if (*status == svn_wc__db_status_deleted)
+    {
+      const char *work_del_abspath;
+
+      SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL, NULL,
+                                       &work_del_abspath,
+                                       db, local_abspath,
+                                       scratch_pool, scratch_pool));
+      if (work_del_abspath)
+        {
+          const char *op_root_abspath;
+          const char *original_repos_relpath, *original_root_url;
+          const char *original_uuid;
+          svn_revnum_t original_revision;
+          const char *parent_del_abspath = svn_dirent_dirname(work_del_abspath,
+                                                              scratch_pool);
+
+          /* Similar to, but not the same as, the _scan_addition and
+             _join above.  Can we use get_copyfrom here? */
+          SVN_ERR(svn_wc__db_scan_addition(NULL, &op_root_abspath,
+                                           NULL /* repos_relpath */,
+                                           NULL /* repos_root_url */,
+                                           NULL /* repos_uuid */,
+                                           &original_repos_relpath,
+                                           &original_root_url, &original_uuid,
+                                           &original_revision,
+                                           db, parent_del_abspath,
+                                           scratch_pool, scratch_pool));
+          *copyfrom_relpath
+            = svn_relpath_join(original_repos_relpath,
+                               svn_dirent_skip_ancestor(op_root_abspath,
+                                                        local_abspath),
+                               scratch_pool);
+          *copyfrom_rev = original_revision;
+          SVN_ERR(create_repos_id(copyfrom_id,
+                                  original_root_url, original_uuid,
+                                  pdh->wcroot->sdb, scratch_pool));
+        }
+      else
+        {
+          *copyfrom_relpath = repos_relpath;
+          *copyfrom_rev = revision;
+          if (!repos_root_url || !repos_uuid)
+            SVN_ERR(svn_wc__db_scan_base_repos(NULL,
+                                               &repos_root_url, &repos_uuid,
+                                               db, local_abspath,
+                                               scratch_pool, scratch_pool));
+          SVN_ERR(create_repos_id(copyfrom_id,
+                                  repos_root_url, repos_uuid,
+                                  pdh->wcroot->sdb, scratch_pool));
+        }
+    }
+  else
+    {
+      *copyfrom_relpath = repos_relpath;
+      *copyfrom_rev = revision;
+      SVN_ERR(create_repos_id(copyfrom_id,
+                              repos_root_url, repos_uuid,
+                              pdh->wcroot->sdb, scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2966,6 +3250,7 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
     }
 
 
+#ifndef SVN_WC__SINGLE_DB
   /* When copying a directory the destination may not exist, if so we
      only copy the parent stub */
   if (kind == svn_wc__db_kind_dir && !*src_relpath && *dst_relpath)
@@ -2982,6 +3267,7 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
       src_relpath = svn_dirent_basename(src_abspath, NULL);
       kind = svn_wc__db_kind_subdir;
     }
+#endif
 
   /* Get the children for a directory if this is not the parent stub */
   if (kind == svn_wc__db_kind_dir)
@@ -3487,6 +3773,7 @@ svn_wc__db_op_set_props(svn_wc__db_t *db
                                          scratch_pool));
 }
 
+#ifdef SVN__SUPPORT_BASE_MERGE
 
 /* Set properties in a given table. The row must exist.  */
 static svn_error_t *
@@ -3525,6 +3812,11 @@ svn_wc__db_temp_base_set_props(svn_wc__d
                                const apr_hash_t *props,
                                apr_pool_t *scratch_pool)
 {
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(set_properties(db, local_abspath, props,
+                         STMT_UPDATE_NODE_DATA_BASE_PROPS,
+                         "base node", scratch_pool));
+#endif
   return svn_error_return(set_properties(db, local_abspath, props,
                                          STMT_UPDATE_BASE_PROPS,
                                          "base_node",
@@ -3538,12 +3830,18 @@ svn_wc__db_temp_working_set_props(svn_wc
                                   const apr_hash_t *props,
                                   apr_pool_t *scratch_pool)
 {
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(set_properties(db, local_abspath, props,
+                         STMT_UPDATE_NODE_DATA_WORKING_PROPS,
+                         "working node", scratch_pool));
+#endif
   return svn_error_return(set_properties(db, local_abspath, props,
                                          STMT_UPDATE_WORKING_PROPS,
                                          "working_node",
                                          scratch_pool));
 }
 
+#endif /* SVN__SUPPORT_BASE_MERGE  */
 
 svn_error_t *
 svn_wc__db_op_delete(svn_wc__db_t *db,
@@ -3966,11 +4264,18 @@ svn_wc__db_temp_op_remove_entry(svn_wc__
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_NODE_DATA_LAYERS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isi", wc_id, local_relpath, (apr_int64_t)0));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_ACTUAL_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
 
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifndef SINGLE_DB
   /* Check if we should also remove it from the parent db */
   if (*local_relpath == '\0')
     {
@@ -3993,11 +4298,20 @@ svn_wc__db_temp_op_remove_entry(svn_wc__
       SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                        STMT_DELETE_NODE_DATA_LAYERS));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isi",
+                                wc_id, local_relpath, (apr_int64_t)0));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_ACTUAL_NODE));
       SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
 
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
+#endif
 
   return SVN_NO_ERROR;
 }
@@ -4026,6 +4340,14 @@ svn_wc__db_temp_op_remove_working(svn_wc
   SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_DELETE_NODE_DATA_WORKING));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
+#ifndef SINGLE_DB
   /* Check if we should remove it from the parent db as well. */
   if (*local_relpath == '\0')
     {
@@ -4041,11 +4363,19 @@ svn_wc__db_temp_op_remove_working(svn_wc
                                         STMT_DELETE_WORKING_NODE));
       SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
-    }
-
-  return SVN_NO_ERROR;
-}
-
+
+#ifdef SVN_WC__NODE_DATA
+      SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                        STMT_DELETE_NODE_DATA_WORKING));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+    }
+#endif
+
+  return SVN_NO_ERROR;
+}
+
 
 static svn_error_t *
 update_depth_values(svn_wc__db_pdh_t *pdh,
@@ -4058,9 +4388,11 @@ update_depth_values(svn_wc__db_pdh_t *pd
   /* Flush any entries before we start monkeying the database.  */
   flush_entries(pdh);
 
+#ifndef SVN_WC__SINGLE_DB
   /* Parent stubs have only two depth options: excluded, or infinity.  */
   if (*local_relpath != '\0' && !excluded)
     depth = svn_depth_infinity;
+#endif
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     excluded
@@ -4071,6 +4403,17 @@ update_depth_values(svn_wc__db_pdh_t *pd
     SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_depth_to_word(depth)));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    excluded
+                                      ? STMT_UPDATE_NODE_BASE_EXCLUDED
+                                      : STMT_UPDATE_NODE_BASE_DEPTH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+  if (!excluded)
+    SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_depth_to_word(depth)));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     excluded
                                       ? STMT_UPDATE_WORKING_EXCLUDED
@@ -4080,6 +4423,17 @@ update_depth_values(svn_wc__db_pdh_t *pd
     SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_depth_to_word(depth)));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    excluded
+                                      ? STMT_UPDATE_NODE_WORKING_EXCLUDED
+                                      : STMT_UPDATE_NODE_WORKING_DEPTH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+  if (!excluded)
+    SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_depth_to_word(depth)));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
   return SVN_NO_ERROR;
 }
 
@@ -4106,6 +4460,7 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
 
   SVN_ERR(update_depth_values(pdh, local_relpath, depth));
 
+#ifndef SINGLE_DB
   /* If we're in the subdir, then navigate to the parent to set its
      depth value.  */
   if (*local_relpath == '\0')
@@ -4128,6 +4483,7 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
       local_relpath = svn_dirent_basename(local_abspath, scratch_pool);
       SVN_ERR(update_depth_values(pdh, local_relpath, depth));
     }
+#endif
 
   return SVN_NO_ERROR;
 }
@@ -4156,6 +4512,14 @@ db_working_update_presence(svn_wc__db_st
                             presence_map, status));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_UPDATE_NODE_WORKING_PRESENCE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "ist", pdh->wcroot->wc_id, local_relpath,
+                            presence_map, status));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
   flush_entries(pdh);
 
 #ifndef SINGLE_DB
@@ -4173,6 +4537,15 @@ db_working_update_presence(svn_wc__db_st
                                 presence_map, status));
       SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+      SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                        STMT_UPDATE_NODE_WORKING_PRESENCE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "ist", pdh->wcroot->wc_id,
+                                svn_dirent_basename(local_abspath, NULL),
+                                presence_map, status));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
       flush_entries(pdh);
     }
 #endif
@@ -4202,6 +4575,14 @@ db_working_actual_remove(svn_wc__db_t *d
                                     STMT_DELETE_WORKING_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
+
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_DELETE_NODE_DATA_WORKING));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     STMT_DELETE_ACTUAL_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
@@ -4209,6 +4590,7 @@ db_working_actual_remove(svn_wc__db_t *d
 
   flush_entries(pdh);
 
+#ifndef SINGLE_DB
   if (*local_relpath == '\0')
     {
       /* ### Delete parent stub. Remove when db is centralised. */
@@ -4223,8 +4605,17 @@ db_working_actual_remove(svn_wc__db_t *d
                                 pdh->wcroot->wc_id, local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+      SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                        STMT_DELETE_NODE_DATA_WORKING));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                pdh->wcroot->wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
       flush_entries(pdh);
     }
+#endif
 
   return SVN_NO_ERROR;
 }
@@ -4255,6 +4646,7 @@ db_working_insert(svn_wc__db_status_t st
 
   flush_entries(pdh);
 
+#ifndef SINGLE_DB
   if (*local_relpath == '\0')
     {
       /* ### Insert parent stub. Remove when db is centralised. */
@@ -4274,6 +4666,7 @@ db_working_insert(svn_wc__db_status_t st
 
       flush_entries(pdh);
     }
+#endif
 
   return SVN_NO_ERROR;
 }
@@ -5126,6 +5519,16 @@ relocate_txn(void *baton, svn_sqlite__db
                             like_arg, new_repos_id));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                               STMT_UPDATE_NODE_DATA_RECURSIVE_ORIGINAL_REPO));
+  SVN_ERR(svn_sqlite__bindf(stmt, "issii",
+                            rb->wc_id, rb->local_relpath,
+                            like_arg, rb->old_repos_id,
+                            new_repos_id));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
   /* Do a bunch of stuff which is conditional on us actually having a
      base_node in the first place. */
   if (rb->have_base_node)
@@ -5330,8 +5733,9 @@ struct commit_baton {
   const char *local_relpath;
 
   svn_revnum_t new_revision;
-  apr_time_t new_date;
-  const char *new_author;
+  svn_revnum_t changed_rev;
+  apr_time_t changed_date;
+  const char *changed_author;
   const svn_checksum_t *new_checksum;
   const apr_array_header_t *new_children;
   apr_hash_t *new_dav_cache;
@@ -5461,29 +5865,30 @@ commit_node(void *baton, svn_sqlite__db_
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, cb->pdh->wcroot->sdb,
                                     STMT_APPLY_CHANGES_TO_BASE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "issttisb",
+  SVN_ERR(svn_sqlite__bindf(stmt, "issttiisb",
                             cb->pdh->wcroot->wc_id, cb->local_relpath,
                             parent_relpath,
                             presence_map, new_presence,
                             kind_map, new_kind,
                             (apr_int64_t)cb->new_revision,
-                            cb->new_author,
+                            (apr_int64_t)cb->changed_rev,
+                            cb->changed_author,
                             prop_blob.data, prop_blob.len));
 
   /* ### for now, always set the repos_id/relpath. we should make these
      ### null whenever possible. but that also means we'd have to check
      ### on whether this node is switched, so the values would need to
      ### remain unchanged.  */
-  SVN_ERR(svn_sqlite__bind_int64(stmt, 9, cb->repos_id));
-  SVN_ERR(svn_sqlite__bind_text(stmt, 10, cb->repos_relpath));
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 10, cb->repos_id));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 11, cb->repos_relpath));
 
-  SVN_ERR(svn_sqlite__bind_checksum(stmt, 11, cb->new_checksum,
+  SVN_ERR(svn_sqlite__bind_checksum(stmt, 12, cb->new_checksum,
                                     scratch_pool));
-  if (cb->new_date > 0)
-    SVN_ERR(svn_sqlite__bind_int64(stmt, 12, cb->new_date));
-  SVN_ERR(svn_sqlite__bind_text(stmt, 13, new_depth_str));
-  /* ### 14. target.  */
-  SVN_ERR(svn_sqlite__bind_properties(stmt, 15, cb->new_dav_cache,
+  if (cb->changed_date > 0)
+    SVN_ERR(svn_sqlite__bind_int64(stmt, 13, cb->changed_date));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 14, new_depth_str));
+  /* ### 15. target.  */
+  SVN_ERR(svn_sqlite__bind_properties(stmt, 16, cb->new_dav_cache,
                                       scratch_pool));
 
   SVN_ERR(svn_sqlite__step_done(stmt));
@@ -5496,6 +5901,14 @@ commit_node(void *baton, svn_sqlite__db_
       SVN_ERR(svn_sqlite__bindf(stmt, "is",
                                 cb->pdh->wcroot->wc_id, cb->local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
+
+#ifdef SVN_WC__NODE_DATA
+      SVN_ERR(svn_sqlite__get_statement(&stmt, cb->pdh->wcroot->sdb,
+                                        STMT_DELETE_NODE_DATA_WORKING));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                cb->pdh->wcroot->wc_id, cb->local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
     }
 
   if (have_act)
@@ -5596,6 +6009,7 @@ determine_repos_info(apr_int64_t *repos_
   /* The parent MUST have a BASE node (otherwise, THIS node cannot be
      processed for a commit). Move up and re-query.   */
 
+#ifndef SVN_WC__SINGLE_DB
   if (*local_relpath == '\0')
     {
       /* There is no entry for "" in the BASE_NODE table, so this directory
@@ -5608,16 +6022,17 @@ determine_repos_info(apr_int64_t *repos_
       local_relpath = "";
     }
   else
+#endif
     {
       /* This was a child node within this wcroot. We want to look at the
-         BASE node of the directory, which is local_relpath == "".  */
-      local_relpath = "";
+         BASE node of the directory.  */
+      local_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
     }
 
   /* The REPOS_ID will be the same (### until we support mixed-repos)  */
   SVN_ERR(scan_upwards_for_repos(repos_id, &repos_parent_relpath,
                                  pdh->wcroot, pdh->local_abspath,
-                                 "" /* local_relpath. see above.  */,
+                                 local_relpath,
                                  scratch_pool, scratch_pool));
 
   *repos_relpath = svn_relpath_join(repos_parent_relpath, name, result_pool);
@@ -5630,8 +6045,9 @@ svn_error_t *
 svn_wc__db_global_commit(svn_wc__db_t *db,
                          const char *local_abspath,
                          svn_revnum_t new_revision,
-                         apr_time_t new_date,
-                         const char *new_author,
+                         svn_revnum_t changed_revision,
+                         apr_time_t changed_date,
+                         const char *changed_author,
                          const svn_checksum_t *new_checksum,
                          const apr_array_header_t *new_children,
                          apr_hash_t *new_dav_cache,
@@ -5657,8 +6073,10 @@ svn_wc__db_global_commit(svn_wc__db_t *d
   cb.local_relpath = local_relpath;
 
   cb.new_revision = new_revision;
-  cb.new_date = new_date;
-  cb.new_author = new_author;
+
+  cb.changed_rev = changed_revision; 
+  cb.changed_date = changed_date;
+  cb.changed_author = changed_author;
   cb.new_checksum = new_checksum;
   cb.new_children = new_children;
   cb.new_dav_cache = new_dav_cache;
@@ -6161,7 +6579,7 @@ svn_wc__db_scan_addition(svn_wc__db_stat
         {
           /* The current node is a directory, so move to the parent dir.  */
           SVN_ERR(navigate_to_parent(&pdh, db, pdh, svn_sqlite__mode_readonly,
-                                     TRUE, scratch_pool));
+                                     FALSE, scratch_pool));
         }
       current_abspath = pdh->local_abspath;
       current_relpath = svn_wc__db_pdh_compute_relpath(pdh, NULL);
@@ -6393,7 +6811,7 @@ svn_wc__db_scan_deletion(const char **ba
         {
           /* The current node is a directory, so move to the parent dir.  */
           SVN_ERR(navigate_to_parent(&pdh, db, pdh, svn_sqlite__mode_readonly,
-                                     TRUE, scratch_pool));
+                                     FALSE, scratch_pool));
         }
       current_abspath = pdh->local_abspath;
       current_relpath = svn_wc__db_pdh_compute_relpath(pdh, NULL);
@@ -6460,6 +6878,7 @@ svn_wc__db_upgrade_apply_dav_cache(svn_s
 
 svn_error_t *
 svn_wc__db_upgrade_apply_props(svn_sqlite__db_t *sdb,
+                               const char *dir_abspath,
                                const char *local_relpath,
                                apr_hash_t *base_props,
                                apr_hash_t *revert_props,
@@ -6468,6 +6887,7 @@ svn_wc__db_upgrade_apply_props(svn_sqlit
                                apr_pool_t *scratch_pool)
 {
   svn_boolean_t have_base;
+  svn_wc__db_status_t base_presence;
   svn_boolean_t have_work;
   svn_wc__db_status_t work_presence;
   apr_int64_t wc_id;
@@ -6502,15 +6922,18 @@ svn_wc__db_upgrade_apply_props(svn_sqlit
   */
 
   /* Collect information about this node.  */
-  SVN_ERR(prop_upgrade_trees(&have_base, &have_work, &work_presence, &wc_id,
-                             sdb, local_relpath));
+  SVN_ERR(prop_upgrade_trees(&have_base, &base_presence,
+                             &have_work, &work_presence,
+                             &wc_id, sdb, local_relpath));
 
   /* Detect the buggy scenario described above. We cannot upgrade this
      working copy if we have no idea where BASE_PROPS should go.  */
   if (original_format > SVN_WC__NO_REVERT_FILES
       && revert_props == NULL
       && have_work
-      && work_presence == svn_wc__db_status_normal)
+      && work_presence == svn_wc__db_status_normal
+      && have_base
+      && base_presence != svn_wc__db_status_not_present)
     {
       /* There should be REVERT_PROPS, so it appears that we just ran into
          the described bug. Sigh.  */
@@ -6518,10 +6941,14 @@ svn_wc__db_upgrade_apply_props(svn_sqlit
                                _("The properties of '%s' are in an "
                                  "indeterminate state and cannot be "
                                  "upgraded. See issue #2530."),
-                               local_relpath);
+                               svn_dirent_local_style(
+                                 svn_dirent_join(dir_abspath, local_relpath,
+                                                 scratch_pool), scratch_pool));
     }
 
-  if (have_base)
+  if (have_base
+      && (base_presence == svn_wc__db_status_normal
+          || base_presence == svn_wc__db_status_incomplete))
     {
       apr_hash_t *props = revert_props ? revert_props : base_props;
 
@@ -6544,13 +6971,14 @@ svn_wc__db_upgrade_apply_props(svn_sqlit
 
       /* Do we have a replaced node? It has properties: an empty set for
          adds, and a non-empty set for copies/moves.  */
-      if (work_presence == svn_wc__db_status_normal
-          && original_format > SVN_WC__NO_REVERT_FILES)
+      if (original_format > SVN_WC__NO_REVERT_FILES
+          && (work_presence == svn_wc__db_status_normal
+              || work_presence == svn_wc__db_status_incomplete))
         {
           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
                                             STMT_UPDATE_WORKING_PROPS));
           SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
-          SVN_ERR(svn_sqlite__bind_properties(stmt, 3, revert_props,
+          SVN_ERR(svn_sqlite__bind_properties(stmt, 3, base_props,
                                               scratch_pool));
           SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
@@ -6562,6 +6990,17 @@ svn_wc__db_upgrade_apply_props(svn_sqlit
     }
 
   /* If there are WORKING_PROPS, then they always go into ACTUAL_NODE.  */
+  if (working_props != NULL
+      && base_props != NULL)
+    {
+      apr_array_header_t *diffs;
+
+      SVN_ERR(svn_prop_diffs(&diffs, working_props, base_props, scratch_pool));
+
+      if (diffs->nelts == 0)
+        working_props = NULL; /* No differences */
+    }
+
   if (working_props != NULL)
     {
       struct set_props_baton spb = { 0 };
@@ -6781,6 +7220,7 @@ svn_wc__db_temp_get_format(int *format,
   pdh = svn_wc__db_pdh_get_or_create(db, local_dir_abspath, FALSE,
                                      scratch_pool);
 
+#ifndef SINGLE_DB
   /* ### for per-dir layouts, the wcroot should be this directory. under
      ### wc-ng, the wcroot may have become set for this missing subdir.  */
   if (pdh != NULL && pdh->wcroot != NULL
@@ -6790,6 +7230,7 @@ svn_wc__db_temp_get_format(int *format,
          got set, but has since been constructed.  */
       pdh->wcroot = NULL;
     }
+#endif
 
   /* If the PDH isn't present, or have wcroot information, then do a full
      upward traversal to find the wcroot.  */
@@ -6808,7 +7249,11 @@ svn_wc__db_temp_get_format(int *format,
       /* ### for per-dir layouts, the wcroot should be this directory,
          ### so bail if the PDH is a parent (and, thus, local_relpath is
          ### something besides "").  */
-      if (err || *local_relpath != '\0')
+      if (err
+#ifndef SVN_WC__SINGLE_DB
+          || *local_relpath != '\0'
+#endif
+          )
         {
           if (err && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
             return svn_error_return(err);
@@ -6819,7 +7264,9 @@ svn_wc__db_temp_get_format(int *format,
              hanging off a parent though.
              Don't clear the wcroot of a parent if we just found a
              relative path here or we get multiple wcroot issues. */
+#ifndef SVN_WC__SINGLE_DB
           if (err)
+#endif
             pdh->wcroot = NULL;
 
           /* Remap the returned error.  */
@@ -6892,6 +7339,7 @@ svn_wc__db_temp_forget_directory(svn_wc_
       apr_ssize_t klen;
       void *val;
       svn_wc__db_pdh_t *pdh;
+      svn_error_t *err;
 
       apr_hash_this(hi, &key, &klen, &val);
       pdh = val;
@@ -6899,7 +7347,26 @@ svn_wc__db_temp_forget_directory(svn_wc_
       if (!svn_dirent_is_ancestor(local_dir_abspath, pdh->local_abspath))
         continue;
 
-      SVN_ERR(svn_wc__db_wclock_remove(db, pdh->local_abspath, scratch_pool));
+#ifndef SVN_WC__SINGLE_DB
+      if (pdh->locked)
+#endif
+        {
+          err = svn_wc__db_wclock_release(db, pdh->local_abspath,
+                                          scratch_pool);
+          if (err
+              && (err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY
+                  || err->apr_err == SVN_ERR_WC_NOT_LOCKED))
+            {
+              svn_error_clear(err);
+            }
+          else
+            SVN_ERR(err);
+        }
+
+#ifndef SVN_WC__SINGLE_DB
+      SVN_ERR_ASSERT(!pdh->locked);
+#endif
+
       apr_hash_set(db->dir_data, key, klen, NULL);
 
       if (pdh->wcroot && pdh->wcroot->sdb &&
@@ -7052,10 +7519,12 @@ svn_wc__db_temp_borrow_sdb(svn_sqlite__d
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
+#ifndef SVN_WC__SINGLE_DB
   /* We better be looking at the proper wcroot for this directory.
      If we ended up with a stub, then the subdirectory (and its SDB!)
      are missing.  */
   SVN_ERR_ASSERT(*local_relpath == '\0');
+#endif
 
   *sdb = pdh->wcroot->sdb;
 
@@ -7114,6 +7583,7 @@ svn_wc__db_temp_is_dir_deleted(svn_boole
   return svn_error_return(svn_sqlite__reset(stmt));
 }
 
+#ifndef SVN_WC__SINGLE_DB
 svn_error_t *
 svn_wc__db_temp_determine_keep_local(svn_boolean_t *keep_local,
                                      svn_wc__db_t *db,
@@ -7160,6 +7630,7 @@ svn_wc__db_temp_set_keep_local(svn_wc__d
 
   return svn_error_return(svn_sqlite__step_done(stmt));
 }
+#endif
 
 svn_error_t *
 svn_wc__db_read_conflict_victims(const apr_array_header_t **victims,
@@ -7496,45 +7967,283 @@ svn_wc__db_temp_wcroot_tempdir(const cha
   return SVN_NO_ERROR;
 }
 
-
-svn_error_t *
-svn_wc__db_wclock_set(svn_wc__db_t *db,
-                      const char *local_abspath,
-                      int levels_to_lock,
-                      apr_pool_t *scratch_pool)
+/* Baton for wclock_obtain_cb() */
+struct wclock_obtain_baton
 {
+  svn_wc__db_t *db;
   svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
+  const char *local_abspath;
+  int levels_to_lock;
+  svn_boolean_t steal_lock;
+};
+
+/* Helper for wclock_obtain_cb() to steal an existing lock */
+static svn_error_t *
+wclock_steal(svn_wc__db_wcroot_t *wcroot,
+             const char *local_relpath,
+             apr_pool_t *scratch_pool)
+{
   svn_sqlite__stmt_t *stmt;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_DELETE_WC_LOCK));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
+  return SVN_NO_ERROR;
+}
+
+/* svn_sqlite__transaction_callback_t for svn_wc__db_wclock_obtain() */
+static svn_error_t *
+wclock_obtain_cb(void *baton,
+                 svn_sqlite__db_t* sdb,
+                 apr_pool_t *scratch_pool)
+{
+  struct wclock_obtain_baton *bt = baton;
+  svn_sqlite__stmt_t *stmt;
+  svn_wc__db_wcroot_t *wcroot = bt->pdh->wcroot;
   svn_error_t *err;
+  const char *lock_relpath;
+  int max_depth;
+  int lock_depth;
+  svn_boolean_t got_row;
+  const char *filter;
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+#ifdef SVN_WC__SINGLE_DB
+  svn_wc__db_wclock_t lock;
+  svn_boolean_t have_base, have_working;
 
-  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);
+  SVN_ERR(which_trees_exist(&have_base, &have_working, sdb,
+                            bt->pdh->wcroot->wc_id, bt->local_relpath));
 
+  if (!have_base && !have_working)
+    return svn_error_createf(
+                SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                _("The node '%s' was not found."),
+                svn_dirent_local_style(bt->local_abspath, scratch_pool));
+#else
   /* ### Can only lock this directory in the per-dir layout.  This is
      ### a temporary restriction until metadata gets centralised.
      ### Perhaps this should be a runtime error, rather than an
      ### assert?  Perhaps check the path is versioned? */
-  SVN_ERR_ASSERT(*local_relpath == '\0');
+  SVN_ERR_ASSERT(*bt->local_relpath == '\0');
+#endif
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+  if (*bt->local_relpath == '\0')
+    filter = "%";
+  else
+    filter = apr_pstrcat(scratch_pool,
+                         escape_sqlite_like(bt->local_relpath, scratch_pool),
+                         "/%",
+                         NULL);
+
+  /* Check if there are nodes locked below the new lock root */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_FIND_WC_LOCK));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, filter));
+
+  lock_depth = relpath_op_depth(bt->local_relpath);
+  max_depth = lock_depth + bt->levels_to_lock;
+
+  SVN_ERR(svn_sqlite__step(&got_row, stmt));
+
+  while (got_row)
+    {
+      const char *lock_abspath;
+      svn_boolean_t own_lock;
+
+      lock_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+
+      /* If we are not locking with depth infinity, check if this lock
+         voids our lock request */
+      if (bt->levels_to_lock >= 0
+          && relpath_op_depth(lock_relpath) > max_depth)
+        {
+          SVN_ERR(svn_sqlite__step(&got_row, stmt));
+          continue;
+        }
+
+      lock_abspath = svn_dirent_join(wcroot->abspath,
+                                     lock_relpath, scratch_pool);
+
+      /* Check if we are the lock owner, because we should be able to
+         extend our lock. */
+      err = svn_wc__db_wclock_owns_lock(&own_lock, bt->db, lock_abspath,
+                                        TRUE, scratch_pool);
+
+      if (err)
+        SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+
+      if (!own_lock && !bt->steal_lock)
+        {
+          SVN_ERR(svn_sqlite__reset(stmt));
+          err = svn_error_createf(SVN_ERR_WC_LOCKED, NULL,
+                                   _("'%s' is already locked."),
+                                   svn_dirent_local_style(lock_abspath,
+                                                          scratch_pool));
+          return svn_error_createf(SVN_ERR_WC_LOCKED, err,
+                                   _("Working copy '%s' locked."),
+                                   svn_dirent_local_style(bt->local_abspath,
+                                                          scratch_pool));
+        }
+      else if (!own_lock)
+        {
+          err = wclock_steal(wcroot, lock_relpath, scratch_pool);
+
+          if (err)
+            SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+        }
+
+      SVN_ERR(svn_sqlite__step(&got_row, stmt));
+    }
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  if (bt->steal_lock)
+    SVN_ERR(wclock_steal(wcroot, bt->local_relpath, scratch_pool));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_WC_LOCK));
+  lock_relpath = bt->local_relpath;
+
+  while (TRUE)
+    {
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, lock_relpath));
+
+      SVN_ERR(svn_sqlite__step(&got_row, stmt));
+
+      if (got_row)
+        {
+          int levels = svn_sqlite__column_int(stmt, 0);
+          if (levels >= 0)
+            levels += relpath_op_depth(lock_relpath);
+
+          SVN_ERR(svn_sqlite__reset(stmt));
+
+          if (levels == -1 || levels >= lock_depth)
+            {
+
+              err = svn_error_createf(
+                              SVN_ERR_WC_LOCKED, NULL,
+                              _("'%s' is already locked."),
+                              svn_dirent_local_style(
+                                       svn_dirent_join(wcroot->abspath,
+                                                       lock_relpath,
+                                                       scratch_pool),
+                              scratch_pool));
+              return svn_error_createf(
+                              SVN_ERR_WC_LOCKED, err,
+                              _("Working copy '%s' locked."),
+                              svn_dirent_local_style(bt->local_abspath,
+                                                     scratch_pool));
+            }
+
+          break; /* There can't be interesting locks on higher nodes */
+        }
+      else
+        SVN_ERR(svn_sqlite__reset(stmt));
+
+      if (!*lock_relpath)
+        break;
+
+      lock_relpath = svn_relpath_dirname(lock_relpath, scratch_pool);
+    }
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_INSERT_WC_LOCK));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isi", pdh->wcroot->wc_id, local_relpath,
-                            (apr_int64_t) levels_to_lock));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isi", wcroot->wc_id,
+                            bt->local_relpath,
+                            (apr_int64_t) bt->levels_to_lock));
   err = svn_sqlite__insert(NULL, stmt);
   if (err)
     return svn_error_createf(SVN_ERR_WC_LOCKED, err,
                              _("Working copy '%s' locked"),
-                             svn_dirent_local_style(local_abspath,
+                             svn_dirent_local_style(bt->local_abspath,
                                                     scratch_pool));
 
+  /* And finally store that we obtained the lock */
+#ifdef SVN_WC__SINGLE_DB
+  lock.local_relpath = apr_pstrdup(wcroot->owned_locks->pool,
+                                   bt->local_relpath);
+  lock.levels = bt->levels_to_lock;
+  APR_ARRAY_PUSH(wcroot->owned_locks, svn_wc__db_wclock_t) = lock;
+#else
+  bt->pdh->locked = TRUE;
+#endif
+
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__db_wclock_obtain(svn_wc__db_t *db,
+                         const char *local_abspath,
+                         int levels_to_lock,
+                         svn_boolean_t steal_lock,
+                         apr_pool_t *scratch_pool)
+{
+  struct wclock_obtain_baton baton;
+
+  SVN_ERR_ASSERT(levels_to_lock >= -1);
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&baton.pdh, &baton.local_relpath,
+                                             db, local_abspath,
+                                             svn_sqlite__mode_readwrite,
+                                             scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(baton.pdh);
+
+  if (!steal_lock)
+#ifndef SVN_WC__SINGLE_DB
+    {
+      if (baton.pdh->locked)
+        return svn_error_createf(SVN_ERR_WC_LOCKED, NULL,
+                                 _("'%s' is already locked."),
+                                 svn_dirent_local_style(local_abspath,
+                                                        scratch_pool));
+    }
+#else
+    {
+      int i;
+      svn_wc__db_wcroot_t *wcroot = baton.pdh->wcroot;
+      int depth = relpath_op_depth(baton.local_relpath);
+
+      for (i = 0; i < wcroot->owned_locks->nelts; i++)
+        {
+          svn_wc__db_wclock_t* lock = &APR_ARRAY_IDX(wcroot->owned_locks,
+                                                     i, svn_wc__db_wclock_t);
+
+          if (svn_relpath_is_ancestor(lock->local_relpath, baton.local_relpath)
+              && (lock->levels == -1
+                  || (lock->levels + relpath_op_depth(lock->local_relpath)) 
+                            >= depth))
+            {
+              const char *lock_abspath
+                  = svn_dirent_join(baton.pdh->wcroot->abspath,
+                                    lock->local_relpath,
+                                    scratch_pool);
+
+              return svn_error_createf(SVN_ERR_WC_LOCKED, NULL,
+                                       _("'%s' is already locked via '%s'."),
+                                       svn_dirent_local_style(local_abspath,
+                                                              scratch_pool),
+                                       svn_dirent_local_style(lock_abspath,
+                                                              scratch_pool));
+            }
+        }
+    }
+#endif
+
+  baton.db = db;
+  baton.local_abspath = local_abspath;
+  baton.steal_lock = steal_lock;
+  baton.levels_to_lock = levels_to_lock;
+
+  return svn_error_return(
+            svn_sqlite__with_transaction(baton.pdh->wcroot->sdb,
+                                         wclock_obtain_cb,
+                                         &baton,
+                                         scratch_pool));
+}
+
 
 /* */
 static svn_error_t *
@@ -7556,6 +8265,8 @@ is_wclocked(svn_boolean_t *locked,
       *locked = FALSE;
       return SVN_NO_ERROR;
     }
+  else
+    SVN_ERR(err);
 
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
@@ -7597,60 +8308,165 @@ svn_wc__db_wclocked(svn_boolean_t *locke
 
 
 svn_error_t *
-svn_wc__db_wclock_remove(svn_wc__db_t *db,
-                         const char *local_abspath,
-                         apr_pool_t *scratch_pool)
+svn_wc__db_wclock_release(svn_wc__db_t *db,
+                          const char *local_abspath,
+                          apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+#ifdef SVN_WC__SINGLE_DB
+  int i;
+  apr_array_header_t *owned_locks;
+#endif
 
-  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
-                                 STMT_DELETE_WC_LOCK, scratch_pool));
-  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));
 
-  /* If we've just removed the "physical" lock, we also need to ensure we
-     don't continue to think we own the lock. */
-  pdh = svn_wc__db_pdh_get_or_create(db, local_abspath, FALSE, scratch_pool);
-  if (pdh)
-    pdh->locked = FALSE;
+  VERIFY_USABLE_PDH(pdh);
 
-  return SVN_NO_ERROR;
-}
+  /* First check and remove the owns-lock information as failure in
+     removing the db record implies that we have to steal the lock later. */
+#ifndef SVN_WC__SINGLE_DB
+  if (*local_relpath != '\0')
+    {
+      svn_wc__db_status_t status;
+      svn_wc__db_kind_t kind;
+      SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL,
+                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                   NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                   NULL, NULL, NULL, NULL,
+                                   db, local_abspath,
+                                   scratch_pool, scratch_pool));
 
+      if (kind == svn_wc__db_kind_dir)
+        switch (status)
+          {
+            case svn_wc__db_status_not_present:
+            case svn_wc__db_status_absent:
+            case svn_wc__db_status_excluded:
+              return SVN_NO_ERROR; /* These directories don't have an
+                                      administrative area */
+            case svn_wc__db_status_obstructed:
+            case svn_wc__db_status_obstructed_add:
+            case svn_wc__db_status_obstructed_delete:
+              return SVN_NO_ERROR; /* Administrative area missing
+                                      -> Lock gone */
+            default:
+              break;
+          }
+      SVN_ERR_ASSERT(*local_relpath == '\0');
+    }
 
-svn_error_t *
-svn_wc__db_temp_mark_locked(svn_wc__db_t *db,
-                            const char *local_dir_abspath,
-                            apr_pool_t *scratch_pool)
-{
-  svn_wc__db_pdh_t *pdh;
+  if (!pdh->locked)
+    return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL,
+                             _("Working copy not locked at '%s'."),
+                             svn_dirent_local_style(local_abspath,
+                                                    scratch_pool));
+  pdh->locked = FALSE;
+#else
+  owned_locks = pdh->wcroot->owned_locks;
+  for (i = 0; i < owned_locks->nelts; i++)
+    {
+      svn_wc__db_wclock_t *lock = &APR_ARRAY_IDX(owned_locks, i,
+                                                 svn_wc__db_wclock_t);
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
+      if (strcmp(lock->local_relpath, local_relpath) == 0)
+        break;
+    }
 
-  pdh = svn_wc__db_pdh_get_or_create(db, local_dir_abspath, TRUE,
-                                     scratch_pool);
-  pdh->locked = TRUE;
+  if (i >= owned_locks->nelts)
+    return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL,
+                             _("Working copy not locked at '%s'."),
+                             svn_dirent_local_style(local_abspath,
+                                                    scratch_pool));
+
+  if (i < owned_locks->nelts)
+    {
+      owned_locks->nelts--;
+
+      /* Move the last item in the array to the deleted place */
+      if (owned_locks->nelts > 0)
+        APR_ARRAY_IDX(owned_locks, i, svn_wc__db_wclock_t) =
+           APR_ARRAY_IDX(owned_locks, owned_locks->nelts, svn_wc__db_wclock_t);
+    }
+#endif
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_DELETE_WC_LOCK));
+
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+
+  SVN_ERR(svn_sqlite__step_done(stmt));
 
   return SVN_NO_ERROR;
 }
 
-
 svn_error_t *
-svn_wc__db_temp_own_lock(svn_boolean_t *own_lock,
-                         svn_wc__db_t *db,
-                         const char *local_dir_abspath,
-                         apr_pool_t *scratch_pool)
+svn_wc__db_wclock_owns_lock(svn_boolean_t *own_lock,
+                            svn_wc__db_t *db,
+                            const char *local_abspath,
+                            svn_boolean_t exact,
+                            apr_pool_t *scratch_pool)
 {
   svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+#ifdef SVN_WC__SINGLE_DB
+  apr_array_header_t *owned_locks;
+  int lock_level, i;
+#endif
 
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_dir_abspath));
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+                              local_abspath, svn_sqlite__mode_readwrite,
+                              scratch_pool, scratch_pool));
 
-  pdh = svn_wc__db_pdh_get_or_create(db, local_dir_abspath, FALSE,
-                                     scratch_pool);
-  *own_lock = (pdh != NULL && pdh->locked);
+  if (!pdh->wcroot)
+    return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
+                             _("The node '%s' was not found."),
+                             svn_dirent_local_style(local_abspath,
+                                                    scratch_pool));
 
-  return SVN_NO_ERROR;
+  VERIFY_USABLE_PDH(pdh);
+  *own_lock = FALSE;
+#ifndef SVN_WC__SINGLE_DB
+  /* In !SINGLE_DB mode we only allow locking the directories */
+  if (*local_relpath == '\0')
+    *own_lock = (pdh != NULL && pdh->locked);
+#else
+  owned_locks = pdh->wcroot->owned_locks;
+  lock_level = relpath_op_depth(local_relpath);
+
+  if (exact)
+    for (i = 0; i < owned_locks->nelts; i++)
+      {
+        svn_wc__db_wclock_t *lock = &APR_ARRAY_IDX(owned_locks, i,
+                                                   svn_wc__db_wclock_t);
 
+        if (strcmp(lock->local_relpath, local_relpath) == 0)
+          {
+            *own_lock = TRUE;
+            return SVN_NO_ERROR;
+          }
+      }
+  else
+    for (i = 0; i < owned_locks->nelts; i++)
+      {
+        svn_wc__db_wclock_t* lock = &APR_ARRAY_IDX(owned_locks, i,
+                                                   svn_wc__db_wclock_t);
+
+        if (svn_relpath_is_ancestor(lock->local_relpath, local_relpath)
+            && (lock->levels == -1
+                || ((relpath_op_depth(lock->local_relpath) + lock->levels)
+                            >= lock_level)))
+          {
+            *own_lock = TRUE;
+            return SVN_NO_ERROR;
+          }
+      }
+#endif
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -7662,6 +8478,9 @@ svn_wc__db_temp_op_set_base_incomplete(s
   svn_sqlite__stmt_t *stmt;
   svn_wc__db_pdh_t *pdh;
   int affected_rows;
+#ifdef SVN_WC__NODE_DATA
+  int affected_node_rows;
+#endif
   svn_wc__db_status_t base_status;
 
   SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, NULL, NULL, NULL, NULL,
@@ -7675,16 +8494,25 @@ svn_wc__db_temp_op_set_base_incomplete(s
 
   SVN_ERR(get_statement_for_path(&stmt, db, local_dir_abspath,
                                  STMT_UPDATE_BASE_PRESENCE, scratch_pool));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 3, incomplete ? "incomplete" : "normal"));
+  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(get_statement_for_path(&stmt, db, local_dir_abspath,
+                                 STMT_UPDATE_NODE_BASE_PRESENCE, scratch_pool));
   SVN_ERR(svn_sqlite__bind_text(stmt, 3, incomplete ? "incomplete" : "normal"));
+  SVN_ERR(svn_sqlite__update(&affected_node_rows, stmt));
 
-  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+  SVN_ERR_ASSERT(affected_rows == affected_node_rows);
+#endif
 
   if (affected_rows > 0)
    {
      pdh = svn_wc__db_pdh_get_or_create(db, local_dir_abspath, FALSE,
                                         scratch_pool);
-     flush_entries(pdh);
+
+     if (pdh != NULL)
+       flush_entries(pdh);
    }
 
   return SVN_NO_ERROR;
@@ -7906,12 +8734,19 @@ make_copy_txn(void *baton,
       /* Remove current WORKING_NODE record */
       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
                                         STMT_DELETE_WORKING_NODE));
-
       SVN_ERR(svn_sqlite__bindf(stmt, "is",
                                 mcb->pdh->wcroot->wc_id,
                                 mcb->local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC_NODE_DATA
+      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                        STMT_DELETE_NODE_DATA_WORKING));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                mcb->pdh->wcroot->wc_id,
+                                mcb->local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
     }
 
   if (add_working_normal)
@@ -7991,6 +8826,14 @@ make_copy_txn(void *baton,
           SVN_ERR(svn_sqlite__bindf(stmt, "is",
                                     pdh->wcroot->wc_id, local_relpath));
           SVN_ERR(svn_sqlite__step_done(stmt));
+
+#ifdef SVN_WC__NODE_DATA
+          SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                            STMT_DELETE_NODE_DATA_WORKING));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
         }
 
       if (add_working_normal)
@@ -8012,6 +8855,14 @@ make_copy_txn(void *baton,
                                     pdh->wcroot->wc_id, local_relpath));
           SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+          SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                            STMT_DELETE_NODE_DATA_WORKING));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
           /* And insert the right data */
           SVN_ERR(svn_sqlite__get_statement(
                         &stmt, pdh->wcroot->sdb,
@@ -8039,6 +8890,14 @@ make_copy_txn(void *baton,
                                     pdh->wcroot->wc_id, local_relpath));
           SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+          SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                            STMT_DELETE_NODE_DATA_WORKING));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
           /* And insert the right data */
           SVN_ERR(svn_sqlite__get_statement(
                         &stmt, pdh->wcroot->sdb,
@@ -8053,22 +8912,29 @@ make_copy_txn(void *baton,
   /* Remove the BASE_NODE if the caller asked us to do that */
   if (mcb->remove_base)
     {
-      const char *local_relpath;
-      svn_wc__db_pdh_t *pdh;
-
       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
                                         STMT_DELETE_BASE_NODE));
-
       SVN_ERR(svn_sqlite__bindf(stmt, "is",
                                 mcb->pdh->wcroot->wc_id,
                                 mcb->local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                        STMT_DELETE_NODE_DATA_BASE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                mcb->pdh->wcroot->wc_id,
+                                mcb->local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
 
 #ifndef SINGLE_DB
       /* Remove BASE_NODE_STUB */
       if (*mcb->local_relpath == '\0')
         {
+          const char *local_relpath;
+          svn_wc__db_pdh_t *pdh;
+
           SVN_ERR(navigate_to_parent(&pdh, mcb->db, mcb->pdh,
                                      svn_sqlite__mode_readwrite,
                                      FALSE, iterpool));
@@ -8080,6 +8946,14 @@ make_copy_txn(void *baton,
           SVN_ERR(svn_sqlite__bindf(stmt, "is",
                                     pdh->wcroot->wc_id, local_relpath));
           SVN_ERR(svn_sqlite__step_done(stmt));
+
+#ifdef SVN_WC__NODE_DATA
+          SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                            STMT_DELETE_NODE_DATA_BASE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
         }
 #endif
     }
@@ -8119,6 +8993,67 @@ svn_wc__db_temp_op_make_copy(svn_wc__db_
   return SVN_NO_ERROR;
 }
 
+/* Return the copyfrom info for LOCAL_ABSPATH resolving inheritance. */
+static svn_error_t *
+get_copyfrom(apr_int64_t *copyfrom_repos_id,
+             const char **copyfrom_relpath,
+             svn_revnum_t *copyfrom_revnum,
+             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_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_readwrite,
+                                             scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(pdh);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_SELECT_WORKING_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)
+    {
+      *copyfrom_repos_id = 0;  /* What's a good value to return? */
+      *copyfrom_relpath = NULL;
+      *copyfrom_revnum = SVN_INVALID_REVNUM;
+      SVN_ERR(svn_sqlite__reset(stmt));
+      return SVN_NO_ERROR;
+    }
+
+  if (svn_sqlite__column_is_null(stmt, 9 /* copyfrom_repos_id */))
+    {
+      /* Resolve inherited copyfrom */
+      const char *parent_abspath, *name, *parent_copyfrom_relpath;
+
+      SVN_ERR(svn_sqlite__reset(stmt));
+      svn_dirent_split(&parent_abspath, &name, local_abspath, scratch_pool);
+      SVN_ERR(get_copyfrom(copyfrom_repos_id, &parent_copyfrom_relpath,
+                           copyfrom_revnum,
+                           db, parent_abspath, scratch_pool, scratch_pool));
+      if (parent_copyfrom_relpath)
+        *copyfrom_relpath = svn_relpath_join(parent_copyfrom_relpath, name,
+                                             scratch_pool);
+      else
+        *copyfrom_relpath = NULL;
+      return SVN_NO_ERROR;
+    }
+
+  *copyfrom_repos_id = svn_sqlite__column_int64(stmt, 9);
+  *copyfrom_relpath = svn_sqlite__column_text(stmt, 10, scratch_pool);
+  *copyfrom_revnum = svn_sqlite__column_revnum(stmt, 11);
+
+  return SVN_NO_ERROR;
+}
+
 
 svn_error_t *
 svn_wc__db_temp_elide_copyfrom(svn_wc__db_t *db,
@@ -8134,13 +9069,10 @@ svn_wc__db_temp_elide_copyfrom(svn_wc__d
   svn_revnum_t original_revision;
   const char *parent_abspath;
   const char *name;
-  svn_error_t *err;
-  const char *op_root_abspath;
+  apr_int64_t parent_repos_id;
   const char *parent_repos_relpath;
-  const char *parent_uuid;
   svn_revnum_t parent_revision;
   const char *implied_relpath;
-  const char *original_uuid;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -8168,27 +9100,13 @@ svn_wc__db_temp_elide_copyfrom(svn_wc__d
 
   SVN_ERR(svn_sqlite__reset(stmt));
 
-  /* If this node is copied/moved, then there MUST be a parent. The above
-     copyfrom values cannot be set on a wcroot.  */
   svn_dirent_split(&parent_abspath, &name, local_abspath, scratch_pool);
-  err = svn_wc__db_scan_addition(NULL, &op_root_abspath, NULL, NULL, NULL,
-                                 &parent_repos_relpath,
-                                 NULL,
-                                 &parent_uuid,
-                                 &parent_revision,
-                                 db, parent_abspath,
-                                 scratch_pool, scratch_pool);
-  if (err)
-    {
-      if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
-        return svn_error_return(err);
-      svn_error_clear(err);
 
-      /* ### hunh? sometimes the parent is missing? stupid semi-stable
-         ### state crap, probably. don't bother trying to reset the
-         ### copyfrom data for this case.  */
-      return SVN_NO_ERROR;
-    }
+  SVN_ERR(get_copyfrom(&parent_repos_id, &parent_repos_relpath,
+                       &parent_revision,
+                       db, parent_abspath, scratch_pool, scratch_pool));
+  if (parent_revision == SVN_INVALID_REVNUM)
+    return SVN_NO_ERROR;
 
   /* Now we need to determine if the child's values are derivable from
      the parent values.  */
@@ -8209,19 +9127,11 @@ svn_wc__db_temp_elide_copyfrom(svn_wc__d
   /* Given the relpath from OP_ROOT_ABSPATH down to LOCAL_ABSPATH, compute
      an implied REPOS_RELPATH. If that does not match the RELPATH we found,
      then we can exit (the child is a new copy root).  */
-  implied_relpath = svn_relpath_join(parent_repos_relpath,
-                                     svn_dirent_skip_ancestor(op_root_abspath,
-                                                              local_abspath),
-                                     scratch_pool);
+  implied_relpath = svn_relpath_join(parent_repos_relpath, name, scratch_pool);
   if (strcmp(implied_relpath, original_repos_relpath) != 0)
     return SVN_NO_ERROR;
 
-  /* Everything matches up. Grab the details for ORIGINAL_REPOS_ID and
-     compare to the parent.  */
-  SVN_ERR(fetch_repos_info(NULL, &original_uuid,
-                           pdh->wcroot->sdb, original_repos_id,
-                           scratch_pool));
-  if (strcmp(original_uuid, parent_uuid) != 0)
+  if (original_repos_id != parent_repos_id)
     return SVN_NO_ERROR;
 
   /* The child's copyfrom information is derivable from the parent.
@@ -8301,6 +9211,13 @@ svn_wc__db_temp_remove_subdir_record(svn
   SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, name));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_DELETE_NODE_DATA_BASE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, name));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
+
   return SVN_NO_ERROR;
 }
 
@@ -8509,9 +9426,11 @@ svn_wc__db_temp_set_parent_stub_to_norma
 {
   svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
-  svn_sqlite__stmt_t *stmt;
   const char *parent_abspath, *base;
+#ifndef SINGLE_DB
+  svn_sqlite__stmt_t *stmt;
   int affected_rows;
+#endif
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)
                  && !svn_dirent_is_root(local_abspath, strlen(local_abspath)));
@@ -8535,16 +9454,32 @@ svn_wc__db_temp_set_parent_stub_to_norma
       SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                        STMT_DELETE_WORKING_NODE));
       SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, base));
+      SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef NODE_DATA
+      SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                       STMT_DELETE_NODE_DATA_WORKING));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, base));
       SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
     }
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     STMT_UPDATE_BASE_PRESENCE_KIND));
-
   SVN_ERR(svn_sqlite__bindf(stmt, "istt", pdh->wcroot->wc_id, base,
                             presence_map, svn_wc__db_status_normal,
                             kind_map, svn_wc__db_kind_subdir));
+#ifdef NODE_DATA
+  /* When activating this bit, I get test failures;
+     working copies seem to get disconnected from their parents...
+     Need to investigate */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_UPDATE_NODE_BASE_PRESENCE_KIND));
+  SVN_ERR(svn_sqlite__bindf(stmt, "istt", pdh->wcroot->wc_id, base,
+                            presence_map, svn_wc__db_status_normal,
+                            kind_map, svn_wc__db_kind_subdir));
+#endif
+
 
   SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
@@ -8686,6 +9621,7 @@ struct set_new_dir_to_incomplete_baton
   const char *repos_root_url;
   const char *repos_uuid;
   svn_revnum_t revision;
+  svn_depth_t depth;
 };
 
 static svn_error_t *
@@ -8707,20 +9643,26 @@ set_new_dir_to_incomplete_baton_txn(void
   /* Delete the working node */
   SVN_ERR(svn_sqlite__get_statement(&stmt, dtb->pdh->wcroot->sdb,
                                     STMT_DELETE_WORKING_NODE));
-
   SVN_ERR(svn_sqlite__bindf(stmt, "is", dtb->pdh->wcroot->wc_id,
                                         dtb->local_relpath));
-
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   /* Delete the base node if there is a not present one */
   SVN_ERR(svn_sqlite__get_statement(&stmt, dtb->pdh->wcroot->sdb,
                                     STMT_DELETE_BASE_NODE));
-
   SVN_ERR(svn_sqlite__bindf(stmt, "is", dtb->pdh->wcroot->wc_id,
                                         dtb->local_relpath));
+  SVN_ERR(svn_sqlite__step_done(stmt));
 
+#ifdef SVN_WC__NODE_DATA
+  /* Delete the base and working node data */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, dtb->pdh->wcroot->sdb,
+                                    STMT_DELETE_NODE_DATA_LAYERS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isi", dtb->pdh->wcroot->wc_id,
+                            dtb->local_relpath,
+                            (apr_int64_t)0));
   SVN_ERR(svn_sqlite__step_done(stmt));
+#endif
 
 
   /* Insert the incomplete base node */
@@ -8734,6 +9676,10 @@ set_new_dir_to_incomplete_baton_txn(void
                                             parent_relpath,
                                             (apr_int64_t)dtb->revision));
 
+  /* If depth is not unknown: record depth */
+  if (dtb->depth >= svn_depth_empty && dtb->depth <= svn_depth_infinity)
+    SVN_ERR(svn_sqlite__bind_text(stmt, 7, svn_depth_to_word(dtb->depth)));
+
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   return SVN_NO_ERROR;
@@ -8746,6 +9692,7 @@ svn_wc__db_temp_op_set_new_dir_to_incomp
                                              const char *repos_root_url,
                                              const char *repos_uuid,
                                              svn_revnum_t revision,
+                                             svn_depth_t depth,
                                              apr_pool_t *scratch_pool)
 {

[... 10 lines stripped ...]