You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2013/01/06 03:33:39 UTC

svn commit: r1429457 [11/21] - in /subversion/branches/tree-read-api: ./ build/ build/ac-macros/ build/generator/templates/ build/win32/ contrib/server-side/svncutter/ doc/ subversion/bindings/cxxhl/include/ subversion/bindings/cxxhl/include/svncxxhl/ ...

Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c?rev=1429457&r1=1429456&r2=1429457&view=diff
==============================================================================
--- subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c Sun Jan  6 02:33:34 2013
@@ -46,6 +46,7 @@
 #include "conflicts.h"
 #include "wc_db_private.h"
 #include "workqueue.h"
+#include "token-map.h"
 
 #include "svn_private_config.h"
 #include "private/svn_sqlite.h"
@@ -104,9 +105,9 @@
 #define UNKNOWN_WC_ID ((apr_int64_t) -1)
 #define FORMAT_FROM_SDB (-1)
 
-/* Check if the column contains actual properties. The empty set of properties
-   is stored as "()", so we have properties if the size of the column is
-   larger than 2. */
+/* Check if column number I, a property-skel column, contains a non-empty
+   set of properties. The empty set of properties is stored as "()", so we
+   have properties if the size of the column is larger than 2. */
 #define SQLITE_PROPERTIES_AVAILABLE(stmt, i) \
                  (svn_sqlite__column_bytes(stmt, i) > 2)
 
@@ -117,6 +118,7 @@ svn_wc__db_op_depth_for_upgrade(const ch
 }
 
 
+/* Representation of a new base row for the NODES table */
 typedef struct insert_base_baton_t {
   /* common to all insertions into BASE */
   svn_wc__db_status_t status;
@@ -175,6 +177,7 @@ typedef struct insert_base_baton_t {
 } insert_base_baton_t;
 
 
+/* Representation of a new working row for the NODES table */
 typedef struct insert_working_baton_t {
   /* common to all insertions into WORKING (including NODE_DATA) */
   svn_wc__db_status_t presence;
@@ -216,6 +219,7 @@ typedef struct insert_working_baton_t {
 
 } insert_working_baton_t;
 
+/* Representation of a new row for the EXTERNALS table */
 typedef struct insert_external_baton_t {
   /* common to all insertions into EXTERNALS */
   svn_kind_t kind;
@@ -266,27 +270,6 @@ typedef struct insert_external_baton_t {
 } insert_external_baton_t;
 
 
-static const svn_token_map_t kind_map[] = {
-  { "file", svn_kind_file },
-  { "dir", svn_kind_dir },
-  { "symlink", svn_kind_symlink },
-  { "unknown", svn_kind_unknown },
-  { NULL }
-};
-
-/* Note: we only decode presence values from the database. These are a subset
-   of all the status values. */
-static const svn_token_map_t presence_map[] = {
-  { "normal", svn_wc__db_status_normal },
-  { "server-excluded", svn_wc__db_status_server_excluded },
-  { "excluded", svn_wc__db_status_excluded },
-  { "not-present", svn_wc__db_status_not_present },
-  { "incomplete", svn_wc__db_status_incomplete },
-  { "base-deleted", svn_wc__db_status_base_deleted },
-  { NULL }
-};
-
-
 /* Forward declarations  */
 static svn_error_t *
 add_work_items(svn_sqlite__db_t *sdb,
@@ -301,12 +284,6 @@ set_actual_props(apr_int64_t wc_id,
                  apr_pool_t *scratch_pool);
 
 static svn_error_t *
-mark_conflict(svn_wc__db_wcroot_t *wcroot,
-              const char *local_relpath,
-              const svn_skel_t *conflict_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,
@@ -342,7 +319,7 @@ read_info(svn_wc__db_status_t *status,
           svn_revnum_t *original_revision,
           svn_wc__db_lock_t **lock,
           svn_filesize_t *recorded_size,
-          apr_time_t *recorded_mod_time,
+          apr_time_t *recorded_time,
           const char **changelist,
           svn_boolean_t *conflicted,
           svn_boolean_t *op_root,
@@ -383,19 +360,14 @@ wclock_owns_lock(svn_boolean_t *own_lock
                  svn_boolean_t exact,
                  apr_pool_t *scratch_pool);
 
-/* Baton for db_is_switched */
-struct db_is_switched_baton_t
-{
-  svn_boolean_t *is_switched;
-  svn_kind_t *kind;
-};
-
 static svn_error_t *
-db_is_switched(void *baton,
+db_is_switched(svn_boolean_t *is_switched,
+               svn_kind_t *kind,
                svn_wc__db_wcroot_t *wcroot,
                const char *local_relpath,
                apr_pool_t *scratch_pool);
- 
+
+
 /* Return the absolute path, in local path style, of LOCAL_RELPATH
    in WCROOT.  */
 static const char *
@@ -493,11 +465,11 @@ fetch_repos_info(const char **repos_root
 }
 
 
-/* Set *REPOS_ID, *REVISION and *REPOS_RELPATH from the
-   given columns of the SQLITE statement STMT, or to NULL if the respective
+/* Set *REPOS_ID, *REVISION and *REPOS_RELPATH from the given columns of the
+   SQLITE statement STMT, or to NULL/SVN_INVALID_REVNUM if the respective
    column value is null.  Any of the output parameters may be NULL if not
    required.  */
-static svn_error_t *
+static void
 repos_location_from_columns(apr_int64_t *repos_id,
                             svn_revnum_t *revision,
                             const char **repos_relpath,
@@ -507,8 +479,6 @@ repos_location_from_columns(apr_int64_t 
                             int col_repos_relpath,
                             apr_pool_t *result_pool)
 {
-  svn_error_t *err = SVN_NO_ERROR;
-
   if (repos_id)
     {
       /* Fetch repository information via REPOS_ID. */
@@ -526,8 +496,6 @@ repos_location_from_columns(apr_int64_t 
       *repos_relpath = svn_sqlite__column_text(stmt, col_repos_relpath,
                                                result_pool);
     }
-
-  return err;
 }
 
 
@@ -614,6 +582,12 @@ blank_ibb(insert_base_baton_t *pibb)
 
 /* Extend any delete of the parent of LOCAL_RELPATH to LOCAL_RELPATH.
 
+   ### What about KIND and OP_DEPTH?  KIND ought to be redundant; I'm
+       discussing on dev@ whether we can let that be null for presence
+       == base-deleted.  OP_DEPTH is the op-depth of what, and why?
+       It is used to select the lowest working node higher than OP_DEPTH,
+       so, in terms of the API, OP_DEPTH means ...?
+
    Given a wc:
 
               0         1         2         3         4
@@ -637,17 +611,19 @@ blank_ibb(insert_base_baton_t *pibb)
    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.
+   When adding a node if the parent has a higher working node then the
+   parent node is deleted (or replaced) and the delete must be extended
+   to cover new 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_wc__db_wcroot_t *wcroot,
-                     const char *local_relpath,
-                     apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_extend_parent_delete(svn_wc__db_wcroot_t *wcroot,
+                                const char *local_relpath,
+                                svn_kind_t kind,
+                                int op_depth,
+                                apr_pool_t *scratch_pool)
 {
   svn_boolean_t have_row;
   svn_sqlite__stmt_t *stmt;
@@ -658,28 +634,29 @@ extend_parent_delete(svn_wc__db_wcroot_t
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_LOWEST_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, parent_relpath,
+                            op_depth));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   if (have_row)
     parent_op_depth = svn_sqlite__column_int(stmt, 0);
   SVN_ERR(svn_sqlite__reset(stmt));
   if (have_row)
     {
-      int op_depth;
+      int existing_op_depth;
 
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+                                op_depth));
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
       if (have_row)
-        op_depth = svn_sqlite__column_int(stmt, 0);
+        existing_op_depth = svn_sqlite__column_int(stmt, 0);
       SVN_ERR(svn_sqlite__reset(stmt));
-      if (!have_row || parent_op_depth < op_depth)
+      if (!have_row || parent_op_depth < existing_op_depth)
         {
           SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_INSTALL_WORKING_NODE_FOR_DELETE));
-          SVN_ERR(svn_sqlite__bindf(stmt, "isdt", wcroot->wc_id,
+                              STMT_INSTALL_WORKING_NODE_FOR_DELETE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "isdst", wcroot->wc_id,
                                     local_relpath, parent_op_depth,
-                                    presence_map,
-                                    svn_wc__db_status_base_deleted));
+                                    parent_relpath, kind_map, kind));
           SVN_ERR(svn_sqlite__update(NULL, stmt));
         }
     }
@@ -688,22 +665,24 @@ extend_parent_delete(svn_wc__db_wcroot_t
 }
 
 
-/* This is the reverse of extend_parent_delete.
+/* This is the reverse of svn_wc__db_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.
+   When removing a node if the parent has a higher working node then
+   the parent node and this node are both deleted or replaced and any
+   delete over this node must be removed.
  */
-static svn_error_t *
-retract_parent_delete(svn_wc__db_wcroot_t *wcroot,
-                      const char *local_relpath,
-                      apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot,
+                                 const char *local_relpath,
+                                 int op_depth,
+                                 apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_DELETE_LOWEST_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+                            op_depth));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   return SVN_NO_ERROR;
@@ -711,7 +690,9 @@ retract_parent_delete(svn_wc__db_wcroot_
 
 
 
-/* */
+/* Insert the base row represented by (insert_base_baton_t *) BATON.
+ *
+ * Implements svn_wc__db_txn_callback_t. */
 static svn_error_t *
 insert_base_node(void *baton,
                  svn_wc__db_wcroot_t *wcroot,
@@ -722,7 +703,7 @@ insert_base_node(void *baton,
   apr_int64_t repos_id = pibb->repos_id;
   svn_sqlite__stmt_t *stmt;
   svn_filesize_t recorded_size = SVN_INVALID_FILESIZE;
-  apr_int64_t recorded_mod_time;
+  apr_int64_t recorded_time;
 
   /* The directory at the WCROOT has a NULL parent_relpath. Otherwise,
      bind the appropriate parent_relpath. */
@@ -748,7 +729,7 @@ insert_base_node(void *baton,
         {
           /* Preserve size and modification time if caller asked us to. */
           recorded_size = get_recorded_size(stmt, 6);
-          recorded_mod_time = svn_sqlite__column_int64(stmt, 12);
+          recorded_time = svn_sqlite__column_int64(stmt, 12);
         }
       SVN_ERR(svn_sqlite__reset(stmt));
     }
@@ -766,7 +747,7 @@ insert_base_node(void *baton,
                             pibb->revision,
                             presence_map, pibb->status, /* 8 */
                             (pibb->kind == svn_kind_dir) ? /* 9 */
-                               svn_depth_to_word(pibb->depth) : NULL,
+                             svn_token__to_word(depth_map, pibb->depth) : NULL,
                             kind_map, pibb->kind, /* 10 */
                             pibb->changed_rev,    /* 11 */
                             pibb->changed_date,   /* 12 */
@@ -790,10 +771,14 @@ insert_base_node(void *baton,
       if (recorded_size != SVN_INVALID_FILESIZE)
         {
           SVN_ERR(svn_sqlite__bind_int64(stmt, 16, recorded_size));
-          SVN_ERR(svn_sqlite__bind_int64(stmt, 17, recorded_mod_time));
+          SVN_ERR(svn_sqlite__bind_int64(stmt, 17, recorded_time));
         }
     }
 
+  /* Set properties.  Must be null if presence not normal or incomplete. */
+  assert(pibb->status == svn_wc__db_status_normal
+         || pibb->status == svn_wc__db_status_incomplete
+         || pibb->props == NULL);
   SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props,
                                       scratch_pool));
 
@@ -850,13 +835,16 @@ insert_base_node(void *baton,
               || (pibb->status == svn_wc__db_status_incomplete))
           && ! pibb->file_external)
         {
-          SVN_ERR(extend_parent_delete(wcroot, local_relpath, scratch_pool));
+          SVN_ERR(svn_wc__db_extend_parent_delete(wcroot, local_relpath,
+                                                  pibb->kind, 0,
+                                                  scratch_pool));
         }
       else if (pibb->status == svn_wc__db_status_not_present
                || pibb->status == svn_wc__db_status_server_excluded
                || pibb->status == svn_wc__db_status_excluded)
         {
-          SVN_ERR(retract_parent_delete(wcroot, local_relpath, scratch_pool));
+          SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, 0,
+                                                   scratch_pool));
         }
     }
 
@@ -879,12 +867,15 @@ insert_base_node(void *baton,
 
   SVN_ERR(add_work_items(wcroot->sdb, pibb->work_items, scratch_pool));
   if (pibb->conflict)
-    SVN_ERR(mark_conflict(wcroot, local_relpath, pibb->conflict, scratch_pool));
+    SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
+                                              pibb->conflict, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
 
+/* Initialize the baton with appropriate "blank" values. This allows the
+   insertion function to leave certain columns null.  */
 static void
 blank_iwb(insert_working_baton_t *piwb)
 {
@@ -987,7 +978,9 @@ insert_incomplete_children(svn_sqlite__d
 }
 
 
-/* */
+/* Insert the working row represented by (insert_working_baton_t *) BATON.
+ *
+ * Implements svn_wc__db_txn_callback_t. */
 static svn_error_t *
 insert_working_node(void *baton,
                     svn_wc__db_wcroot_t *wcroot,
@@ -1013,7 +1006,7 @@ insert_working_node(void *baton,
                 parent_relpath,
                 presence_map, piwb->presence,
                 (piwb->kind == svn_kind_dir)
-                            ? svn_depth_to_word(piwb->depth) : NULL,
+                            ? svn_token__to_word(depth_map, piwb->depth) : NULL,
                 kind_map, piwb->kind,
                 piwb->changed_rev,
                 piwb->changed_date,
@@ -1036,6 +1029,10 @@ insert_working_node(void *baton,
       SVN_ERR(svn_sqlite__bind_revnum(stmt, 7, piwb->original_revnum));
     }
 
+  /* Set properties.  Must be null if presence not normal or incomplete. */
+  assert(piwb->presence == svn_wc__db_status_normal
+         || piwb->presence == svn_wc__db_status_incomplete
+         || piwb->props == NULL);
   SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool));
 
   SVN_ERR(svn_sqlite__insert(NULL, stmt));
@@ -1113,8 +1110,8 @@ insert_working_node(void *baton,
 
   SVN_ERR(add_work_items(wcroot->sdb, piwb->work_items, scratch_pool));
   if (piwb->conflict)
-    SVN_ERR(mark_conflict(wcroot, local_relpath, piwb->conflict,
-                          scratch_pool));
+    SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
+                                              piwb->conflict, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1237,6 +1234,41 @@ gather_repo_children(const apr_array_hea
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__db_get_children_op_depth(apr_hash_t **children,
+                                 svn_wc__db_wcroot_t *wcroot,
+                                 const char *local_relpath,
+                                 int op_depth,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  *children = apr_hash_make(result_pool);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_OP_DEPTH_CHILDREN));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", 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);
+      svn_kind_t *child_kind = apr_palloc(result_pool, sizeof(svn_kind_t));
+
+      *child_kind = svn_sqlite__column_token(stmt, 1, kind_map);
+      apr_hash_set(*children,
+                   svn_relpath_basename(child_relpath, result_pool),
+                   APR_HASH_KEY_STRING, child_kind);
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  return SVN_NO_ERROR;
+}
+
 
 /* Return TRUE if CHILD_ABSPATH is an immediate child of PARENT_ABSPATH.
  * Else, return FALSE. */
@@ -1390,25 +1422,21 @@ does_node_exist(svn_boolean_t *exists,
   return svn_error_trace(svn_sqlite__reset(stmt));
 }
 
-/* baton for init_db */
-struct init_db_baton
-{
-  /* output values */
-  apr_int64_t wc_id;
-  apr_int64_t repos_id;
-  /* input values */
-  const char *repos_root_url;
-  const char *repos_uuid;
-  const char *root_node_repos_relpath;
-  svn_revnum_t root_node_revision;
-  svn_depth_t root_node_depth;
-};
-
-/* Helper for create_db(). Initializes our wc.db schema */
+/* Helper for create_db(). Initializes our wc.db schema.
+ */
 static svn_error_t *
-init_db( void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool)
+init_db(/* output values */
+        apr_int64_t *repos_id,
+        apr_int64_t *wc_id,
+        /* input values */
+        svn_sqlite__db_t *db,
+        const char *repos_root_url,
+        const char *repos_uuid,
+        const char *root_node_repos_relpath,
+        svn_revnum_t root_node_revision,
+        svn_depth_t root_node_depth,
+        apr_pool_t *scratch_pool)
 {
-  struct init_db_baton *idb = baton;
   svn_sqlite__stmt_t *stmt;
 
   /* Create the database's schema.  */
@@ -1418,32 +1446,33 @@ init_db( void *baton, svn_sqlite__db_t *
   SVN_ERR(svn_sqlite__exec_statements(db, STMT_CREATE_EXTERNALS));
 
   /* Insert the repository. */
-  SVN_ERR(create_repos_id(&idb->repos_id, idb->repos_root_url, idb->repos_uuid,
+  SVN_ERR(create_repos_id(repos_id, repos_root_url, repos_uuid,
                           db, scratch_pool));
 
   /* Insert the wcroot. */
   /* ### Right now, this just assumes wc metadata is being stored locally. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_WCROOT));
-  SVN_ERR(svn_sqlite__insert(&idb->wc_id, stmt));
+  SVN_ERR(svn_sqlite__insert(wc_id, stmt));
 
-  if (idb->root_node_repos_relpath)
+  if (root_node_repos_relpath)
     {
       svn_wc__db_status_t status = svn_wc__db_status_normal;
 
-      if (idb->root_node_revision > 0)
+      if (root_node_revision > 0)
         status = svn_wc__db_status_incomplete; /* Will be filled by update */
 
       SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_NODE));
       SVN_ERR(svn_sqlite__bindf(stmt, "isdsisrtst",
-                                idb->wc_id,          /* 1 */
+                                *wc_id,              /* 1 */
                                 "",                  /* 2 */
                                 0,                   /* op_depth is 0 for base */
                                 NULL,                /* 4 */
-                                idb->repos_id,
-                                idb->root_node_repos_relpath,
-                                idb->root_node_revision,
+                                *repos_id,
+                                root_node_repos_relpath,
+                                root_node_revision,
                                 presence_map, status, /* 8 */
-                                svn_depth_to_word(idb->root_node_depth),
+                                svn_token__to_word(depth_map,
+                                                   root_node_depth),
                                 kind_map, svn_kind_dir /* 10 */));
 
       SVN_ERR(svn_sqlite__insert(NULL, stmt));
@@ -1476,23 +1505,16 @@ create_db(svn_sqlite__db_t **sdb,
           apr_pool_t *result_pool,
           apr_pool_t *scratch_pool)
 {
-  struct init_db_baton idb;
-
   SVN_ERR(svn_wc__db_util_open_db(sdb, dir_abspath, sdb_fname,
                                   svn_sqlite__mode_rwcreate, exclusive,
                                   NULL /* my_statements */,
                                   result_pool, scratch_pool));
 
-  idb.repos_root_url = repos_root_url;
-  idb.repos_uuid = repos_uuid;
-  idb.root_node_repos_relpath = root_node_repos_relpath;
-  idb.root_node_revision = root_node_revision;
-  idb.root_node_depth = root_node_depth;
-
-  SVN_ERR(svn_sqlite__with_lock(*sdb, init_db, &idb, scratch_pool));
-
-  *repos_id = idb.repos_id;
-  *wc_id = idb.wc_id;
+  SVN_SQLITE__WITH_LOCK(init_db(repos_id, wc_id,
+                                *sdb, repos_root_url, repos_uuid,
+                                root_node_repos_relpath, root_node_revision,
+                                root_node_depth, scratch_pool),
+                        *sdb);
 
   return SVN_NO_ERROR;
 }
@@ -2058,26 +2080,20 @@ svn_wc__db_base_add_not_present_node(svn
     kind, svn_wc__db_status_not_present, conflict, work_items, scratch_pool);
 }
 
-/* Baton for db_base_remove */
-struct base_remove_baton
-{
-  svn_wc__db_t *db; /* For checking conflicts */
-  svn_boolean_t keep_as_working;
-  svn_revnum_t not_present_revision;
-  svn_skel_t *conflict;
-  svn_skel_t *work_items;
-};
-
-/* This implements svn_wc__db_txn_callback_t */
+/* The body of svn_wc__db_base_remove().
+ */
 static svn_error_t *
-db_base_remove(void *baton,
-               svn_wc__db_wcroot_t *wcroot,
+db_base_remove(svn_wc__db_wcroot_t *wcroot,
                const char *local_relpath,
+               svn_wc__db_t *db, /* For checking conflicts */
+               svn_boolean_t keep_as_working,
+               svn_revnum_t not_present_revision,
+               svn_skel_t *conflict,
+               svn_skel_t *work_items,
                apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
-  struct base_remove_baton *rb = baton;
   svn_wc__db_status_t status;
   apr_int64_t repos_id;
   const char *repos_relpath;
@@ -2087,14 +2103,14 @@ db_base_remove(void *baton,
   SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, NULL,
                                             &repos_relpath, &repos_id,
                                             NULL, NULL, NULL, NULL, NULL,
-                                            NULL, NULL, NULL, NULL,
+                                            NULL, NULL, NULL, NULL, NULL,
                                             wcroot, local_relpath,
                                             scratch_pool, scratch_pool));
 
   if (status == svn_wc__db_status_normal
-      && rb->keep_as_working)
+      && keep_as_working)
     {
-      SVN_ERR(svn_wc__db_op_make_copy(rb->db,
+      SVN_ERR(svn_wc__db_op_make_copy(db,
                                       svn_dirent_join(wcroot->abspath,
                                                       local_relpath,
                                                       scratch_pool),
@@ -2148,12 +2164,12 @@ db_base_remove(void *baton,
 
               if (node_kind == svn_kind_dir)
                 SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
-                                                    rb->db, wcroot->abspath,
+                                                    db, wcroot->abspath,
                                                     node_abspath, FALSE,
                                                     iterpool, iterpool));
               else
                 SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
-                                                     rb->db,
+                                                     db,
                                                      wcroot->abspath,
                                                      node_abspath,
                                                      iterpool, iterpool));
@@ -2166,14 +2182,14 @@ db_base_remove(void *baton,
           SVN_ERR(svn_sqlite__reset(stmt));
 
           SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
-                                              rb->db, wcroot->abspath,
+                                              db, wcroot->abspath,
                                               local_abspath, FALSE,
                                               scratch_pool, iterpool));
           svn_pool_destroy(iterpool);
         }
       else
         SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
-                                             rb->db, wcroot->abspath,
+                                             db, wcroot->abspath,
                                              local_abspath,
                                              scratch_pool, scratch_pool));
 
@@ -2190,7 +2206,7 @@ db_base_remove(void *baton,
       SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
-  else if (! rb->keep_as_working)
+  else if (! keep_as_working)
     {
       /* Delete only the ACTUAL nodes that apply to a delete of a BASE node */
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -2229,7 +2245,8 @@ db_base_remove(void *baton,
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
-  SVN_ERR(retract_parent_delete(wcroot, local_relpath, scratch_pool));
+  SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, 0,
+                                           scratch_pool));
 
   /* Step 6: Delete actual node if we don't keep working */
   if (! keep_working)
@@ -2240,7 +2257,7 @@ db_base_remove(void *baton,
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
 
-  if (SVN_IS_VALID_REVNUM(rb->not_present_revision))
+  if (SVN_IS_VALID_REVNUM(not_present_revision))
     {
       struct insert_base_baton_t ibb;
       blank_ibb(&ibb);
@@ -2249,7 +2266,7 @@ db_base_remove(void *baton,
       ibb.status = svn_wc__db_status_not_present;
       ibb.kind = kind;
       ibb.repos_relpath = repos_relpath;
-      ibb.revision = rb->not_present_revision;
+      ibb.revision = not_present_revision;
 
       /* Depending upon KIND, any of these might get used. */
       ibb.children = NULL;
@@ -2260,9 +2277,10 @@ db_base_remove(void *baton,
       SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
     }
 
-  SVN_ERR(add_work_items(wcroot->sdb, rb->work_items, scratch_pool));
-  if (rb->conflict)
-    SVN_ERR(mark_conflict(wcroot, local_relpath, rb->conflict, scratch_pool));
+  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
+  if (conflict)
+    SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
+                                              conflict, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -2279,7 +2297,6 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  struct base_remove_baton rb;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -2287,14 +2304,10 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  rb.db = db;
-  rb.keep_as_working = keep_as_working;
-  rb.not_present_revision = not_present_revision;
-  rb.conflict = conflict;
-  rb.work_items = work_items;
-
-  SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, db_base_remove, &rb,
-                              scratch_pool));
+  SVN_WC__DB_WITH_TXN(db_base_remove(wcroot, local_relpath,
+                                     db, keep_as_working, not_present_revision,
+                                     conflict, work_items, scratch_pool),
+                      wcroot);
 
   /* If this used to be a directory we should remove children so pass
    * depth infinity. */
@@ -2319,6 +2332,7 @@ svn_wc__db_base_get_info_internal(svn_wc
                                   const char **target,
                                   svn_wc__db_lock_t **lock,
                                   svn_boolean_t *had_props,
+                                  apr_hash_t **props,
                                   svn_boolean_t *update_root,
                                   svn_wc__db_wcroot_t *wcroot,
                                   const char *local_relpath,
@@ -2337,8 +2351,9 @@ svn_wc__db_base_get_info_internal(svn_wc
 
   if (have_row)
     {
-      svn_kind_t node_kind = svn_sqlite__column_token(stmt, 3,
-                                                             kind_map);
+      svn_wc__db_status_t node_status = svn_sqlite__column_token(stmt, 2,
+                                                                 presence_map);
+      svn_kind_t node_kind = svn_sqlite__column_token(stmt, 3, kind_map);
 
       if (kind)
         {
@@ -2346,10 +2361,10 @@ svn_wc__db_base_get_info_internal(svn_wc
         }
       if (status)
         {
-          *status = svn_sqlite__column_token(stmt, 2, presence_map);
+          *status = node_status;
         }
-      err = repos_location_from_columns(repos_id, revision, repos_relpath,
-                                        stmt, 0, 4, 1, result_pool);
+      repos_location_from_columns(repos_id, revision, repos_relpath,
+                                  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)
@@ -2377,12 +2392,8 @@ svn_wc__db_base_get_info_internal(svn_wc
             }
           else
             {
-              const char *depth_str = svn_sqlite__column_text(stmt, 10, NULL);
-
-              if (depth_str == NULL)
-                *depth = svn_depth_unknown;
-              else
-                *depth = svn_depth_from_word(depth_str);
+              *depth = svn_sqlite__column_token_null(stmt, 10, depth_map,
+                                                     svn_depth_unknown);
             }
         }
       if (checksum)
@@ -2414,8 +2425,25 @@ svn_wc__db_base_get_info_internal(svn_wc
         {
           *had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 13);
         }
+      if (props)
+        {
+          if (node_status == svn_wc__db_status_normal
+              || node_status == svn_wc__db_status_incomplete)
+            {
+              SVN_ERR(svn_sqlite__column_properties(props, stmt, 13,
+                                                    result_pool, scratch_pool));
+              if (*props == NULL)
+                *props = apr_hash_make(result_pool);
+            }
+          else
+            {
+              assert(svn_sqlite__column_is_null(stmt, 13));
+              *props = NULL;
+            }
+        }
       if (update_root)
         {
+          /* It's an update root iff it's a file external. */
           *update_root = svn_sqlite__column_boolean(stmt, 14);
         }
     }
@@ -2447,6 +2475,7 @@ svn_wc__db_base_get_info(svn_wc__db_stat
                          const char **target,
                          svn_wc__db_lock_t **lock,
                          svn_boolean_t *had_props,
+                         apr_hash_t **props,
                          svn_boolean_t *update_root,
                          svn_wc__db_t *db,
                          const char *local_abspath,
@@ -2468,7 +2497,7 @@ svn_wc__db_base_get_info(svn_wc__db_stat
                                             changed_rev, changed_date,
                                             changed_author, depth,
                                             checksum, target, lock,
-                                            had_props, update_root,
+                                            had_props, props, update_root,
                                             wcroot, local_relpath,
                                             result_pool, scratch_pool));
   SVN_ERR_ASSERT(repos_id != INVALID_REPOS_ID);
@@ -2509,7 +2538,6 @@ svn_wc__db_base_get_children_info(apr_ha
       struct svn_wc__db_base_info_t *info;
       svn_error_t *err;
       apr_int64_t repos_id;
-      const char *depth_str;
       const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
       const char *name = svn_relpath_basename(child_relpath, result_pool);
 
@@ -2521,10 +2549,8 @@ svn_wc__db_base_get_children_info(apr_ha
       info->kind = svn_sqlite__column_token(stmt, 4, kind_map);
       info->revnum = svn_sqlite__column_revnum(stmt, 5);
 
-      depth_str = svn_sqlite__column_text(stmt, 6, NULL);
-
-      info->depth = (depth_str != NULL) ? svn_depth_from_word(depth_str)
-                                        : svn_depth_unknown;
+      info->depth = svn_sqlite__column_token_null(stmt, 6, depth_map,
+                                                  svn_depth_unknown);
 
       info->update_root = svn_sqlite__column_boolean(stmt, 7);
 
@@ -2557,32 +2583,24 @@ svn_wc__db_base_get_props(apr_hash_t **p
                           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_wc__db_status_t presence;
 
-  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
-                                 STMT_SELECT_BASE_PROPS, scratch_pool));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  if (!have_row)
+  SVN_ERR(svn_wc__db_base_get_info(&presence, NULL, NULL, NULL, NULL,
+                                   NULL, NULL, NULL, NULL, NULL,
+                                   NULL, NULL, NULL, NULL, props, NULL,
+                                   db, local_abspath,
+                                   result_pool, scratch_pool));
+  if (presence != svn_wc__db_status_normal
+      && presence != svn_wc__db_status_incomplete)
     {
-      err = svn_sqlite__reset(stmt);
-      return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, err,
-                               _("The node '%s' was not found."),
+      return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
+                               _("The node '%s' has a BASE status that"
+                                  " has no properties."),
                                svn_dirent_local_style(local_abspath,
                                                       scratch_pool));
     }
 
-  err = svn_sqlite__column_properties(props, stmt, 0, result_pool,
-                                      scratch_pool);
-  if (err == NULL && *props == NULL)
-    {
-      /* ### is this a DB constraint violation? the column "probably" should
-         ### never be null.  */
-      *props = apr_hash_make(result_pool);
-    }
-
-  return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+  return SVN_NO_ERROR;
 }
 
 
@@ -2697,6 +2715,7 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
                           const svn_checksum_t **checksum,
                           const char **target,
                           svn_boolean_t *had_props,
+                          apr_hash_t **props,
                           svn_wc__db_wcroot_t *wcroot,
                           const char *local_relpath,
                           int op_depth,
@@ -2715,8 +2734,9 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
 
   if (have_row)
     {
-      svn_kind_t node_kind = svn_sqlite__column_token(stmt, 3,
-                                                             kind_map);
+      svn_wc__db_status_t node_status = svn_sqlite__column_token(stmt, 2,
+                                                                 presence_map);
+      svn_kind_t node_kind = svn_sqlite__column_token(stmt, 3, kind_map);
 
       if (kind)
         {
@@ -2724,13 +2744,13 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
         }
       if (status)
         {
-          *status = svn_sqlite__column_token(stmt, 2, presence_map);
+          *status = node_status;
 
           if (op_depth > 0)
             SVN_ERR(convert_to_working_status(status, *status));
         }
-      err = repos_location_from_columns(repos_id, revision, repos_relpath,
-                                        stmt, 0, 4, 1, result_pool);
+      repos_location_from_columns(repos_id, revision, repos_relpath,
+                                  stmt, 0, 4, 1, result_pool);
 
       if (changed_rev)
         {
@@ -2753,12 +2773,8 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
             }
           else
             {
-              const char *depth_str = svn_sqlite__column_text(stmt, 10, NULL);
-
-              if (depth_str == NULL)
-                *depth = svn_depth_unknown;
-              else
-                *depth = svn_depth_from_word(depth_str);
+              *depth = svn_sqlite__column_token_null(stmt, 10, depth_map,
+                                                     svn_depth_unknown);
             }
         }
       if (checksum)
@@ -2790,6 +2806,22 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
         {
           *had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 13);
         }
+      if (props)
+        {
+          if (node_status == svn_wc__db_status_normal
+              || node_status == svn_wc__db_status_incomplete)
+            {
+              SVN_ERR(svn_sqlite__column_properties(props, stmt, 13,
+                                                    result_pool, scratch_pool));
+              if (*props == NULL)
+                *props = apr_hash_make(result_pool);
+            }
+          else
+            {
+              assert(svn_sqlite__column_is_null(stmt, 13));
+              *props = NULL;
+            }
+        }
     }
   else
     {
@@ -2804,11 +2836,7 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
 }
 
 
-/* Helper for creating SQLite triggers, running the main transaction
-   callback, and then dropping the triggers.  It guarantees that the
-   triggers will not survive the transaction.  This could be used for
-   any general prefix/postscript statements where the postscript
-   *must* be executed if the transaction completes. */
+/* Baton for passing args to with_triggers(). */
 struct with_triggers_baton_t {
   int create_trigger;
   int drop_trigger;
@@ -2816,7 +2844,13 @@ struct with_triggers_baton_t {
   void *cb_baton;
 };
 
-/* conforms to svn_wc__db_txn_callback_t  */
+/* Helper for creating SQLite triggers, running the main transaction
+   callback, and then dropping the triggers.  It guarantees that the
+   triggers will not survive the transaction.  This could be used for
+   any general prefix/postscript statements where the postscript
+   *must* be executed if the transaction completes.
+
+   Implements svn_wc__db_txn_callback_t. */
 static svn_error_t *
 with_triggers(void *baton,
               svn_wc__db_wcroot_t *wcroot,
@@ -2895,6 +2929,8 @@ with_finalization(svn_wc__db_wcroot_t *w
 }
 
 
+/* Initialize the baton with appropriate "blank" values. This allows the
+   insertion function to leave certain columns null.  */
 static void
 blank_ieb(insert_external_baton_t *ieb)
 {
@@ -2907,6 +2943,9 @@ blank_ieb(insert_external_baton_t *ieb)
   ieb->recorded_revision = SVN_INVALID_REVNUM;
 }
 
+/* Insert the externals row represented by (insert_external_baton_t *) BATON.
+ *
+ * Implements svn_wc__db_txn_callback_t. */
 static svn_error_t *
 insert_external_node(void *baton,
                      svn_wc__db_wcroot_t *wcroot,
@@ -2929,7 +2968,7 @@ insert_external_node(void *baton,
   /* And there must be no existing BASE node or it must be a file external */
   err = svn_wc__db_base_get_info_internal(&status, NULL, NULL, NULL, NULL,
                                           NULL, NULL, NULL, NULL, NULL,
-                                          NULL, NULL, NULL, &update_root,
+                                          NULL, NULL, NULL, NULL, &update_root,
                                           wcroot, local_relpath,
                                           scratch_pool, scratch_pool);
   if (err)
@@ -3246,25 +3285,21 @@ svn_wc__db_external_add_dir(svn_wc__db_t
                                 &ieb, scratch_pool));
 }
 
-/* Baton for db_external_remove */
-struct external_remove_baton
-{
-  const svn_skel_t *work_items;
-};
-
+/* The body of svn_wc__db_external_remove(). */
 static svn_error_t *
-db_external_remove(void *baton, svn_wc__db_wcroot_t *wcroot,
-                   const char *local_relpath, apr_pool_t *scratch_pool)
+db_external_remove(const svn_skel_t *work_items,
+                   svn_wc__db_wcroot_t *wcroot,
+                   const char *local_relpath,
+                   apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
-  struct external_remove_baton *rb = baton;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_DELETE_EXTERNAL));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
-  SVN_ERR(add_work_items(wcroot->sdb, rb->work_items, scratch_pool));
+  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
 
   /* ### What about actual? */
   return SVN_NO_ERROR;
@@ -3279,7 +3314,6 @@ svn_wc__db_external_remove(svn_wc__db_t 
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  struct external_remove_baton rb;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -3294,9 +3328,9 @@ svn_wc__db_external_remove(svn_wc__db_t 
 
   local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
 
-  rb.work_items = work_items;
-  SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, db_external_remove,
-                              &rb, scratch_pool));
+  SVN_WC__DB_WITH_TXN(db_external_remove(work_items, wcroot, local_relpath,
+                                         scratch_pool),
+                      wcroot);
 
   return SVN_NO_ERROR;
 }
@@ -3552,15 +3586,14 @@ svn_wc__db_externals_gather_definitions(
 
           if (depths)
             {
-              const char *depth_word = svn_sqlite__column_text(stmt, 2, NULL);
-              svn_depth_t depth = svn_depth_unknown;
-
-              if (depth_word)
-                depth = svn_depth_from_word(depth_word);
+              svn_depth_t depth
+                = svn_sqlite__column_token_null(stmt, 2, depth_map,
+                                                svn_depth_unknown);
 
               apr_hash_set(*depths, node_abspath,
                            APR_HASH_KEY_STRING,
-                           svn_depth_to_word(depth)); /* Use static string */
+                           svn_token__to_word(depth_map,
+                                              depth)); /* Use static string */
             }
         }
 
@@ -3781,7 +3814,7 @@ get_info_for_copy(apr_int64_t *copyfrom_
                                                     copyfrom_relpath,
                                                     copyfrom_id, NULL, NULL,
                                                     NULL, NULL, NULL, NULL,
-                                                    NULL, NULL, NULL,
+                                                    NULL, NULL, NULL, NULL,
                                                     wcroot, local_relpath,
                                                     result_pool,
                                                     scratch_pool));
@@ -3802,15 +3835,44 @@ get_info_for_copy(apr_int64_t *copyfrom_
 }
 
 
-/* Forward declarations for db_op_copy() to use.
-
-   ### these are just to avoid churn. a future commit should shuffle the
-   ### functions around.  */
+/* Set *OP_DEPTH to the highest op depth of WCROOT:LOCAL_RELPATH. */
 static svn_error_t *
 op_depth_of(int *op_depth,
             svn_wc__db_wcroot_t *wcroot,
-            const char *local_relpath);
+            const char *local_relpath)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
 
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_NODE_INFO));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  SVN_ERR_ASSERT(have_row);
+  *op_depth = svn_sqlite__column_int(stmt, 0);
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  return SVN_NO_ERROR;
+}
+
+
+/* Determine at which OP_DEPTH a copy of COPYFROM_REPOS_ID, COPYFROM_RELPATH at
+   revision COPYFROM_REVISION should be inserted as LOCAL_RELPATH. Do this
+   by checking if this would be a direct child of a copy of its parent
+   directory. If it is then set *OP_DEPTH to the op_depth of its parent.
+
+   If the node is not a direct copy at the same revision of the parent
+   *NP_OP_DEPTH will be set to the op_depth of the parent when a not-present
+   node should be inserted at this op_depth. This will be the case when the
+   parent already defined an incomplete child with the same name. Otherwise
+   *NP_OP_DEPTH will be set to -1.
+
+   If the parent node is not the parent of the to be copied node, then
+   *OP_DEPTH will be set to the proper op_depth for a new operation root.
+
+   Set *PARENT_OP_DEPTH to the op_depth of the parent.
+
+ */
 static svn_error_t *
 op_depth_for_copy(int *op_depth,
                   int *np_op_depth,
@@ -3820,7 +3882,86 @@ op_depth_for_copy(int *op_depth,
                   svn_revnum_t copyfrom_revision,
                   svn_wc__db_wcroot_t *wcroot,
                   const char *local_relpath,
-                  apr_pool_t *scratch_pool);
+                  apr_pool_t *scratch_pool)
+{
+  const char *parent_relpath, *name;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  int incomplete_op_depth = -1;
+  int min_op_depth = 1; /* Never touch BASE */
+
+  *op_depth = relpath_depth(local_relpath);
+  *np_op_depth = -1;
+
+  svn_relpath_split(&parent_relpath, &name, local_relpath, scratch_pool);
+  *parent_op_depth = relpath_depth(parent_relpath);
+
+  if (!copyfrom_relpath)
+    return SVN_NO_ERROR;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (have_row)
+    {
+      svn_wc__db_status_t status = svn_sqlite__column_token(stmt, 1,
+                                                            presence_map);
+
+      min_op_depth = svn_sqlite__column_int(stmt, 0);
+      if (status == svn_wc__db_status_incomplete)
+        incomplete_op_depth = min_op_depth;
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (have_row)
+    {
+      svn_wc__db_status_t presence = svn_sqlite__column_token(stmt, 1,
+                                                              presence_map);
+
+      *parent_op_depth = svn_sqlite__column_int(stmt, 0);
+      if (*parent_op_depth < min_op_depth)
+        {
+          /* We want to create a copy; not overwrite the lower layers */
+          SVN_ERR(svn_sqlite__reset(stmt));
+          return SVN_NO_ERROR;
+        }
+
+      /* You can only add children below a node that exists.
+         In WORKING that must be status added, which is represented
+         as presence normal */
+      SVN_ERR_ASSERT(presence == svn_wc__db_status_normal);
+
+      if ((incomplete_op_depth < 0)
+          || (incomplete_op_depth == *parent_op_depth))
+        {
+          apr_int64_t parent_copyfrom_repos_id
+            = svn_sqlite__column_int64(stmt, 10);
+          const char *parent_copyfrom_relpath
+            = svn_sqlite__column_text(stmt, 11, NULL);
+          svn_revnum_t parent_copyfrom_revision
+            = svn_sqlite__column_revnum(stmt, 12);
+
+          if (parent_copyfrom_repos_id == copyfrom_repos_id)
+            {
+              if (copyfrom_revision == parent_copyfrom_revision
+                  && !strcmp(copyfrom_relpath,
+                             svn_relpath_join(parent_copyfrom_relpath, name,
+                                              scratch_pool)))
+                *op_depth = *parent_op_depth;
+              else if (incomplete_op_depth > 0)
+                *np_op_depth = incomplete_op_depth;
+            }
+        }
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  return SVN_NO_ERROR;
+}
 
 
 /* Like svn_wc__db_op_copy(), but with WCROOT+LOCAL_RELPATH
@@ -4070,7 +4211,7 @@ db_op_copy(svn_wc__db_wcroot_t *src_wcro
   return SVN_NO_ERROR;
 }
 
-/* Baton for op_copy_txn */
+/* Baton for passing args to op_copy_txn(). */
 struct op_copy_baton
 {
   svn_wc__db_wcroot_t *src_wcroot;
@@ -4085,10 +4226,13 @@ struct op_copy_baton
   const char *dst_op_root_relpath;
 };
 
-/* Helper for svn_wc__db_op_copy.
-   Implements  svn_sqlite__transaction_callback_t */
+/* Helper for svn_wc__db_op_copy().
+ *
+ * Implements svn_sqlite__transaction_callback_t. */
 static svn_error_t *
-op_copy_txn(void * baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
+op_copy_txn(void * baton,
+            svn_sqlite__db_t *sdb,
+            apr_pool_t *scratch_pool)
 {
   struct op_copy_baton *ocb = baton;
   int move_op_depth;
@@ -4191,7 +4335,8 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
     svn_error_t *err;
     err = svn_wc__db_depth_get_info(&status, &kind, &node_revision,
                                     &node_repos_relpath, &node_repos_id,
-                                    NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                    NULL, NULL, NULL, NULL, NULL, NULL,
+                                    NULL, NULL,
                                     src_wcroot, src_relpath, src_op_depth,
                                     scratch_pool, scratch_pool);
 
@@ -4361,10 +4506,12 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
   return SVN_NO_ERROR;
 }
 
-/* Helper for svn_wc__db_op_copy_shadowed_layer.
-   Implements  svn_sqlite__transaction_callback_t */
+/* Helper for svn_wc__db_op_copy_shadowed_layer().
+ *
+ * Implements  svn_sqlite__transaction_callback_t. */
 static svn_error_t *
-op_copy_shadowed_layer_txn(void * baton, svn_sqlite__db_t *sdb,
+op_copy_shadowed_layer_txn(void *baton,
+                           svn_sqlite__db_t *sdb,
                            apr_pool_t *scratch_pool)
 {
   struct op_copy_baton *ocb = baton;
@@ -4408,7 +4555,8 @@ op_copy_shadowed_layer_txn(void * baton,
   /* Get some information from the parent */
   SVN_ERR(svn_wc__db_depth_get_info(NULL, NULL, &revision, &repos_relpath,
                                     &repos_id, NULL, NULL, NULL, NULL, NULL,
-                                    NULL, NULL, ocb->src_wcroot,
+                                    NULL, NULL, NULL,
+                                    ocb->src_wcroot,
                                     src_parent_relpath, src_op_depth,
                                     scratch_pool, scratch_pool));
 
@@ -4474,162 +4622,33 @@ svn_wc__db_op_copy_shadowed_layer(svn_wc
 }
 
 
-/* Set *OP_DEPTH to the highest op depth of WCROOT:LOCAL_RELPATH. */
-static svn_error_t *
-op_depth_of(int *op_depth,
-            svn_wc__db_wcroot_t *wcroot,
-            const char *local_relpath)
-{
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_NODE_INFO));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  SVN_ERR_ASSERT(have_row);
-  *op_depth = svn_sqlite__column_int(stmt, 0);
-  SVN_ERR(svn_sqlite__reset(stmt));
-
-  return SVN_NO_ERROR;
-}
-
-
 /* If there are any server-excluded base nodes then the copy must fail
    as it's not possible to commit such a copy.
    Return an error if there are any server-excluded nodes. */
 static svn_error_t *
 catch_copy_of_server_excluded(svn_wc__db_wcroot_t *wcroot,
-                              const char *local_relpath,
-                              apr_pool_t *scratch_pool)
-{
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  const char *server_excluded_relpath;
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_HAS_SERVER_EXCLUDED_DESCENDANTS));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is",
-                            wcroot->wc_id,
-                            local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  if (have_row)
-    server_excluded_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
-  SVN_ERR(svn_sqlite__reset(stmt));
-  if (have_row)
-    return svn_error_createf(SVN_ERR_AUTHZ_UNREADABLE, NULL,
-                             _("Cannot copy '%s' excluded by server"),
-                             path_for_error_message(wcroot,
-                                                    server_excluded_relpath,
-                                                    scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
-
-/* Determine at which OP_DEPTH a copy of COPYFROM_REPOS_ID, COPYFROM_RELPATH at
-   revision COPYFROM_REVISION should be inserted as LOCAL_RELPATH. Do this
-   by checking if this would be a direct child of a copy of its parent
-   directory. If it is then set *OP_DEPTH to the op_depth of its parent.
-
-   If the node is not a direct copy at the same revision of the parent
-   *NP_OP_DEPTH will be set to the op_depth of the parent when a not-present
-   node should be inserted at this op_depth. This will be the case when the
-   parent already defined an incomplete child with the same name. Otherwise
-   *NP_OP_DEPTH will be set to -1.
-
-   If the parent node is not the parent of the to be copied node, then
-   *OP_DEPTH will be set to the proper op_depth for a new operation root.
-
-   Set *PARENT_OP_DEPTH to the op_depth of the parent.
-
- */
-static svn_error_t *
-op_depth_for_copy(int *op_depth,
-                  int *np_op_depth,
-                  int *parent_op_depth,
-                  apr_int64_t copyfrom_repos_id,
-                  const char *copyfrom_relpath,
-                  svn_revnum_t copyfrom_revision,
-                  svn_wc__db_wcroot_t *wcroot,
-                  const char *local_relpath,
-                  apr_pool_t *scratch_pool)
+                              const char *local_relpath,
+                              apr_pool_t *scratch_pool)
 {
-  const char *parent_relpath, *name;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
-  int incomplete_op_depth = -1;
-  int min_op_depth = 1; /* Never touch BASE */
-
-  *op_depth = relpath_depth(local_relpath);
-  *np_op_depth = -1;
-
-  svn_relpath_split(&parent_relpath, &name, local_relpath, scratch_pool);
-  *parent_op_depth = relpath_depth(parent_relpath);
-
-  if (!copyfrom_relpath)
-    return SVN_NO_ERROR;
+  const char *server_excluded_relpath;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+                                    STMT_HAS_SERVER_EXCLUDED_DESCENDANTS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                            wcroot->wc_id,
+                            local_relpath));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   if (have_row)
-    {
-      svn_wc__db_status_t status = svn_sqlite__column_token(stmt, 1,
-                                                            presence_map);
-
-      min_op_depth = svn_sqlite__column_int(stmt, 0);
-      if (status == svn_wc__db_status_incomplete)
-        incomplete_op_depth = min_op_depth;
-    }
+    server_excluded_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
   SVN_ERR(svn_sqlite__reset(stmt));
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
   if (have_row)
-    {
-      svn_wc__db_status_t presence = svn_sqlite__column_token(stmt, 1,
-                                                              presence_map);
-
-      *parent_op_depth = svn_sqlite__column_int(stmt, 0);
-      if (*parent_op_depth < min_op_depth)
-        {
-          /* We want to create a copy; not overwrite the lower layers */
-          SVN_ERR(svn_sqlite__reset(stmt));
-          return SVN_NO_ERROR;
-        }
-
-      /* You can only add children below a node that exists.
-         In WORKING that must be status added, which is represented
-         as presence normal */
-      SVN_ERR_ASSERT(presence == svn_wc__db_status_normal);
-
-      if ((incomplete_op_depth < 0)
-          || (incomplete_op_depth == *parent_op_depth))
-        {
-          apr_int64_t parent_copyfrom_repos_id
-            = svn_sqlite__column_int64(stmt, 10);
-          const char *parent_copyfrom_relpath
-            = svn_sqlite__column_text(stmt, 11, NULL);
-          svn_revnum_t parent_copyfrom_revision
-            = svn_sqlite__column_revnum(stmt, 12);
-
-          if (parent_copyfrom_repos_id == copyfrom_repos_id)
-            {
-              if (copyfrom_revision == parent_copyfrom_revision
-                  && !strcmp(copyfrom_relpath,
-                             svn_relpath_join(parent_copyfrom_relpath, name,
-                                              scratch_pool)))
-                *op_depth = *parent_op_depth;
-              else if (incomplete_op_depth > 0)
-                *np_op_depth = incomplete_op_depth;
-            }
-        }
-    }
-  SVN_ERR(svn_sqlite__reset(stmt));
+    return svn_error_createf(SVN_ERR_AUTHZ_UNREADABLE, NULL,
+                             _("Cannot copy '%s' excluded by server"),
+                             path_for_error_message(wcroot,
+                                                    server_excluded_relpath,
+                                                    scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -4868,6 +4887,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t 
 svn_error_t *
 svn_wc__db_op_add_directory(svn_wc__db_t *db,
                             const char *local_abspath,
+                            const apr_hash_t *props,
                             const svn_skel_t *work_items,
                             apr_pool_t *scratch_pool)
 {
@@ -4891,6 +4911,11 @@ svn_wc__db_op_add_directory(svn_wc__db_t
   iwb.presence = svn_wc__db_status_normal;
   iwb.kind = svn_kind_dir;
   iwb.op_depth = relpath_depth(local_relpath);
+  if (props && apr_hash_count((apr_hash_t *)props))
+    {
+      iwb.update_actual_props = TRUE;
+      iwb.new_actual_props = props;
+    }
 
   iwb.work_items = work_items;
 
@@ -4908,6 +4933,7 @@ svn_wc__db_op_add_directory(svn_wc__db_t
 svn_error_t *
 svn_wc__db_op_add_file(svn_wc__db_t *db,
                        const char *local_abspath,
+                       const apr_hash_t *props,
                        const svn_skel_t *work_items,
                        apr_pool_t *scratch_pool)
 {
@@ -4931,6 +4957,11 @@ svn_wc__db_op_add_file(svn_wc__db_t *db,
   iwb.presence = svn_wc__db_status_normal;
   iwb.kind = svn_kind_file;
   iwb.op_depth = relpath_depth(local_relpath);
+  if (props && apr_hash_count((apr_hash_t *)props))
+    {
+      iwb.update_actual_props = TRUE;
+      iwb.new_actual_props = props;
+    }
 
   iwb.work_items = work_items;
 
@@ -4946,6 +4977,7 @@ svn_error_t *
 svn_wc__db_op_add_symlink(svn_wc__db_t *db,
                           const char *local_abspath,
                           const char *target,
+                          const apr_hash_t *props,
                           const svn_skel_t *work_items,
                           apr_pool_t *scratch_pool)
 {
@@ -4972,6 +5004,11 @@ svn_wc__db_op_add_symlink(svn_wc__db_t *
   iwb.presence = svn_wc__db_status_normal;
   iwb.kind = svn_kind_symlink;
   iwb.op_depth = relpath_depth(local_relpath);
+  if (props && apr_hash_count((apr_hash_t *)props))
+    {
+      iwb.update_actual_props = TRUE;
+      iwb.new_actual_props = props;
+    }
 
   iwb.target = target;
 
@@ -4984,13 +5021,14 @@ svn_wc__db_op_add_symlink(svn_wc__db_t *
   return SVN_NO_ERROR;
 }
 
+/* Baton for passing args to db_record_fileinfo(). */
 struct record_baton_t {
-  svn_filesize_t translated_size;
-  apr_time_t last_mod_time;
+  svn_filesize_t recorded_size;
+  apr_time_t recorded_time;
 };
 
 
-/* Record TRANSLATED_SIZE and LAST_MOD_TIME into top layer in NODES */
+/* Record RECORDED_SIZE and RECORDED_TIME into top layer in NODES */
 static svn_error_t *
 db_record_fileinfo(void *baton,
                    svn_wc__db_wcroot_t *wcroot,
@@ -5004,7 +5042,7 @@ db_record_fileinfo(void *baton,
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_UPDATE_NODE_FILEINFO));
   SVN_ERR(svn_sqlite__bindf(stmt, "isii", wcroot->wc_id, local_relpath,
-                            rb->translated_size, rb->last_mod_time));
+                            rb->recorded_size, rb->recorded_time));
   SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
   SVN_ERR_ASSERT(affected_rows == 1);
@@ -5016,8 +5054,8 @@ db_record_fileinfo(void *baton,
 svn_error_t *
 svn_wc__db_global_record_fileinfo(svn_wc__db_t *db,
                                   const char *local_abspath,
-                                  svn_filesize_t translated_size,
-                                  apr_time_t last_mod_time,
+                                  svn_filesize_t recorded_size,
+                                  apr_time_t recorded_time,
                                   apr_pool_t *scratch_pool)
 {
   svn_wc__db_wcroot_t *wcroot;
@@ -5030,8 +5068,8 @@ svn_wc__db_global_record_fileinfo(svn_wc
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  rb.translated_size = translated_size;
-  rb.last_mod_time = last_mod_time;
+  rb.recorded_size = recorded_size;
+  rb.recorded_time = recorded_time;
 
   SVN_ERR(db_record_fileinfo(&rb, wcroot, local_relpath, scratch_pool));
 
@@ -5042,18 +5080,12 @@ svn_wc__db_global_record_fileinfo(svn_wc
 }
 
 
-struct set_props_baton_t
-{
-  apr_hash_t *props;
-  svn_boolean_t clear_recorded_info;
-
-  const svn_skel_t *conflict;
-  const svn_skel_t *work_items;
-};
-
-
 /* Set the ACTUAL_NODE properties column for (WC_ID, LOCAL_RELPATH) to
- * PROPS. */
+ * PROPS.
+ *
+ * Note: PROPS=NULL means the actual props are the same as the pristine
+ * props; to indicate no properties when the pristine has some props,
+ * PROPS must be an empty hash. */
 static svn_error_t *
 set_actual_props(apr_int64_t wc_id,
                  const char *local_relpath,
@@ -5085,18 +5117,23 @@ set_actual_props(apr_int64_t wc_id,
 }
 
 
-/* Set the 'properties' column in the 'ACTUAL_NODE' table to BATON->props.
+/* The body of svn_wc__db_op_set_props().
+
+   Set the 'properties' column in the 'ACTUAL_NODE' table to BATON->props.
    Create an entry in the ACTUAL table for the node if it does not yet
    have one.
    To specify no properties, BATON->props must be an empty hash, not NULL.
-   BATON is of type 'struct set_props_baton_t'. */
+   BATON is of type 'struct set_props_baton_t'.
+*/
 static svn_error_t *
-set_props_txn(void *baton,
-              svn_wc__db_wcroot_t *wcroot,
+set_props_txn(svn_wc__db_wcroot_t *wcroot,
               const char *local_relpath,
+              apr_hash_t *props,
+              svn_boolean_t clear_recorded_info,
+              const svn_skel_t *conflict,
+              const svn_skel_t *work_items,
               apr_pool_t *scratch_pool)
 {
-  struct set_props_baton_t *spb = baton;
   apr_hash_t *pristine_props;
 
   /* Check if the props are modified. If no changes, then wipe out the
@@ -5104,31 +5141,32 @@ set_props_txn(void *baton,
      ACTUAL props are okay as provided, so go ahead and set them.  */
   SVN_ERR(db_read_pristine_props(&pristine_props, wcroot, local_relpath, FALSE,
                                  scratch_pool, scratch_pool));
-  if (spb->props && pristine_props)
+  if (props && pristine_props)
     {
       apr_array_header_t *prop_diffs;
 
-      SVN_ERR(svn_prop_diffs(&prop_diffs, spb->props, pristine_props,
+      SVN_ERR(svn_prop_diffs(&prop_diffs, props, pristine_props,
                              scratch_pool));
       if (prop_diffs->nelts == 0)
-        spb->props = NULL;
+        props = NULL;
     }
 
   SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath,
-                           spb->props, wcroot->sdb, scratch_pool));
+                           props, wcroot->sdb, scratch_pool));
 
-  if (spb->clear_recorded_info)
+  if (clear_recorded_info)
     {
       struct record_baton_t rb;
-      rb.translated_size = SVN_INVALID_FILESIZE;
-      rb.last_mod_time = 0;
+      rb.recorded_size = SVN_INVALID_FILESIZE;
+      rb.recorded_time = 0;
       SVN_ERR(db_record_fileinfo(&rb, wcroot, local_relpath, scratch_pool));
     }
 
   /* And finally.  */
-  SVN_ERR(add_work_items(wcroot->sdb, spb->work_items, scratch_pool));
-  if (spb->conflict)
-    SVN_ERR(mark_conflict(wcroot, local_relpath, spb->conflict, scratch_pool));
+  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
+  if (conflict)
+    SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
+                                              conflict, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -5143,7 +5181,6 @@ svn_wc__db_op_set_props(svn_wc__db_t *db
                         const svn_skel_t *work_items,
                         apr_pool_t *scratch_pool)
 {
-  struct set_props_baton_t spb;
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
 
@@ -5153,77 +5190,13 @@ svn_wc__db_op_set_props(svn_wc__db_t *db
                               db, local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  spb.props = props;
-  spb.clear_recorded_info = clear_recorded_info;
-  spb.conflict = conflict;
-  spb.work_items = work_items;
-
-  return svn_error_trace(svn_wc__db_with_txn(wcroot, local_relpath,
-                                             set_props_txn, &spb,
-                                             scratch_pool));
-}
-
-
-#ifdef SVN__SUPPORT_BASE_MERGE
-
-/* Set properties in a given table. The row must exist.  */
-static svn_error_t *
-set_properties(svn_wc__db_t *db,
-               const char *local_abspath,
-               const apr_hash_t *props,
-               int stmt_idx,
-               const char *table_name,
-               apr_pool_t *scratch_pool)
-{
-  svn_sqlite__stmt_t *stmt;
-  int affected_rows;
-
-  SVN_ERR_ASSERT(props != NULL);
-
-  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath, stmt_idx,
-                                 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_DB_ERROR, NULL,
-                             _("Can't store properties for '%s' in '%s'."),
-                             svn_dirent_local_style(local_abspath,
-                                                    scratch_pool),
-                             table_name);
-
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_wc__db_temp_base_set_props(svn_wc__db_t *db,
-                               const char *local_abspath,
-                               const apr_hash_t *props,
-                               apr_pool_t *scratch_pool)
-{
-  SVN_ERR(set_properties(db, local_abspath, props,
-                         STMT_UPDATE_NODE_BASE_PROPS,
-                         "base node", scratch_pool));
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_wc__db_temp_working_set_props(svn_wc__db_t *db,
-                                  const char *local_abspath,
-                                  const apr_hash_t *props,
-                                  apr_pool_t *scratch_pool)
-{
-  SVN_ERR(set_properties(db, local_abspath, props,
-                         STMT_UPDATE_NODE_WORKING_PROPS,
-                         "working node", scratch_pool));
+  SVN_WC__DB_WITH_TXN(set_props_txn(wcroot, local_relpath, props,
+                                    clear_recorded_info, conflict, work_items,
+                                    scratch_pool),
+                      wcroot);
   return SVN_NO_ERROR;
 }
 
-#endif /* SVN__SUPPORT_BASE_MERGE  */
-
 
 svn_error_t *
 svn_wc__db_op_modified(svn_wc__db_t *db,
@@ -5400,7 +5373,9 @@ struct set_changelist_baton_t
 };
 
 
-/* */
+/* The main part of svn_wc__db_op_set_changelist().
+ *
+ * Implements svn_wc__db_txn_callback_t. */
 static svn_error_t *
 set_changelist_txn(void *baton,
                    svn_wc__db_wcroot_t *wcroot,
@@ -5458,7 +5433,9 @@ set_changelist_txn(void *baton,
 }
 
 
-/* Implement work_callback_t. */
+/* Send notifications for svn_wc__db_op_set_changelist().
+ *
+ * Implements work_callback_t. */
 static svn_error_t *
 do_changelist_notify(void *baton,
                      svn_wc__db_wcroot_t *wcroot,
@@ -5554,11 +5531,11 @@ svn_wc__db_op_set_changelist(svn_wc__db_
 }
 
 /* Implementation of svn_wc__db_op_mark_conflict() */
-static svn_error_t *
-mark_conflict(svn_wc__db_wcroot_t *wcroot,
-              const char *local_relpath,
-              const svn_skel_t *conflict_skel,
-              apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_mark_conflict_internal(svn_wc__db_wcroot_t *wcroot,
+                                  const char *local_relpath,
+                                  const svn_skel_t *conflict_skel,
+                                  apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t got_row;
@@ -5617,7 +5594,8 @@ svn_wc__db_op_mark_conflict(svn_wc__db_t
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_ERR(mark_conflict(wcroot, local_relpath, conflict_skel, scratch_pool));
+  SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
+                                            conflict_skel, scratch_pool));
 
   /* ### Should be handled in the same transaction as setting the conflict */
   if (work_items)
@@ -5629,24 +5607,18 @@ svn_wc__db_op_mark_conflict(svn_wc__db_t
 
 }
 
-/* Baton for db_op_mark_resolved */
-struct op_mark_resolved_baton
-{
-  svn_boolean_t resolved_text;
-  svn_boolean_t resolved_props;
-  svn_boolean_t resolved_tree;
-  const svn_skel_t *work_items;
-  svn_wc__db_t *db;
-};
-
-/* Helper for svn_wc__db_op_mark_resolved */
+/* The body of svn_wc__db_op_mark_resolved().
+ */
 static svn_error_t *
-db_op_mark_resolved(void *baton,
-                   svn_wc__db_wcroot_t *wcroot,
-                   const char *local_relpath,
-                   apr_pool_t *scratch_pool)
+db_op_mark_resolved(svn_wc__db_wcroot_t *wcroot,
+                    const char *local_relpath,
+                    svn_wc__db_t *db,
+                    svn_boolean_t resolved_text,
+                    svn_boolean_t resolved_props,
+                    svn_boolean_t resolved_tree,
+                    const svn_skel_t *work_items,
+                    apr_pool_t *scratch_pool)
 {
-  struct op_mark_resolved_baton *rb = baton;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   int total_affected_rows = 0;
@@ -5690,10 +5662,10 @@ db_op_mark_resolved(void *baton,
   SVN_ERR(svn_sqlite__reset(stmt));
 
   SVN_ERR(svn_wc__conflict_skel_resolve(&resolved_all, conflicts,
-                                        rb->db, wcroot->abspath,
-                                        rb->resolved_text,
-                                        rb->resolved_props ? "" : NULL,
-                                        rb->resolved_tree,
+                                        db, wcroot->abspath,
+                                        resolved_text,
+                                        resolved_props ? "" : NULL,
+                                        resolved_tree,
                                         scratch_pool, scratch_pool));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -5719,7 +5691,7 @@ db_op_mark_resolved(void *baton,
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
 
-  SVN_ERR(add_work_items(wcroot->sdb, rb->work_items, scratch_pool));
+  SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -5735,7 +5707,6 @@ svn_wc__db_op_mark_resolved(svn_wc__db_t
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  struct op_mark_resolved_baton rb;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -5743,14 +5714,11 @@ svn_wc__db_op_mark_resolved(svn_wc__db_t
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  rb.resolved_props = resolved_props;
-  rb.resolved_text = resolved_text;
-  rb.resolved_tree = resolved_tree;
-  rb.work_items = work_items;
-  rb.db = db;
-
-  SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, db_op_mark_resolved,
-                              &rb, scratch_pool));
+  SVN_WC__DB_WITH_TXN(
+    db_op_mark_resolved(wcroot, local_relpath, db,
+                        resolved_text, resolved_props, resolved_tree,
+                        work_items, scratch_pool),
+    wcroot);
 
   SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool));
   return SVN_NO_ERROR;
@@ -5782,14 +5750,17 @@ clear_moved_to(const char *local_relpath
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_CLEAR_MOVED_TO_RELPATH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
-                            moved_from_relpath));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                            moved_from_relpath,
+                            relpath_depth(moved_from_relpath)));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   return SVN_NO_ERROR;
 }
 
-/* This implements svn_wc__db_txn_callback_t */
+/* One of the two alternative bodies of svn_wc__db_op_revert().
+ *
+ * Implements svn_wc__db_txn_callback_t. */
 static svn_error_t *
 op_revert_txn(void *baton,
               svn_wc__db_wcroot_t *wcroot,
@@ -5906,7 +5877,9 @@ op_revert_txn(void *baton,
 }
 
 
-/* This implements svn_wc__db_txn_callback_t */
+/* One of the two alternative bodies of svn_wc__db_op_revert().
+ *
+ * Implements svn_wc__db_txn_callback_t. */
 static svn_error_t *
 op_revert_recursive_txn(void *baton,
                         svn_wc__db_wcroot_t *wcroot,
@@ -6066,29 +6039,26 @@ svn_wc__db_op_revert(svn_wc__db_t *db,
   return SVN_NO_ERROR;
 }
 
-struct revert_list_read_baton {
-  svn_boolean_t *reverted;
-  apr_array_header_t *marker_paths;
-  svn_boolean_t *copied_here;
-  svn_kind_t *kind;
-  apr_pool_t *result_pool;
-  svn_wc__db_t *db;
-};
-
+/* The body of svn_wc__db_revert_list_read().
+ */
 static svn_error_t *
-revert_list_read(void *baton,
+revert_list_read(svn_boolean_t *reverted,
+                 const apr_array_header_t **marker_paths,
+                 svn_boolean_t *copied_here,
+                 svn_kind_t *kind,
                  svn_wc__db_wcroot_t *wcroot,
                  const char *local_relpath,
+                 svn_wc__db_t *db,
+                 apr_pool_t *result_pool,
                  apr_pool_t *scratch_pool)
 {
-  struct revert_list_read_baton *b = baton;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
 
-  *(b->reverted) = FALSE;
-  b->marker_paths = NULL;
-  *(b->copied_here) = FALSE;
-  *(b->kind) = svn_kind_unknown;
+  *reverted = FALSE;
+  *marker_paths = NULL;
+  *copied_here = FALSE;
+  *kind = svn_kind_unknown;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_REVERT_LIST));
@@ -6108,35 +6078,32 @@ revert_list_read(void *baton,
                                                   scratch_pool);
           if (conflict_data)
             {
-              const apr_array_header_t *marker_paths;
               svn_skel_t *conflicts = svn_skel__parse(conflict_data,
                                                       conflict_len,
                                                       scratch_pool);
 
-              SVN_ERR(svn_wc__conflict_read_markers(&marker_paths,
-                                                    b->db, wcroot->abspath,
+              SVN_ERR(svn_wc__conflict_read_markers(marker_paths,
+                                                    db, wcroot->abspath,
                                                     conflicts,
-                                                    b->result_pool,
+                                                    result_pool,
                                                     scratch_pool));
-              /* De-const-ify. */
-              b->marker_paths = (apr_array_header_t *)marker_paths;
             }
 
           if (!svn_sqlite__column_is_null(stmt, 1)) /* notify */
-            *(b->reverted) = TRUE;
+            *reverted = TRUE;
 
           SVN_ERR(svn_sqlite__step(&another_row, stmt));
         }
 
       if (!is_actual || another_row)
         {
-          *(b->reverted) = TRUE;
+          *reverted = TRUE;
           if (!svn_sqlite__column_is_null(stmt, 4)) /* repos_id */
             {
               int op_depth = svn_sqlite__column_int(stmt, 3);
-              *(b->copied_here) = (op_depth == relpath_depth(local_relpath));
+              *copied_here = (op_depth == relpath_depth(local_relpath));
             }
-          *(b->kind) = svn_sqlite__column_token(stmt, 2, kind_map);
+          *kind = svn_sqlite__column_token(stmt, 2, kind_map);
         }
 
     }
@@ -6165,43 +6132,35 @@ svn_wc__db_revert_list_read(svn_boolean_
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  struct revert_list_read_baton b;
-
-  b.reverted = reverted;
-  b.copied_here = copied_here;
-  b.kind = kind;
-  b.result_pool = result_pool;
-  b.db = db;
 
   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
                               db, local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, revert_list_read, &b,
-                              scratch_pool));
-  *marker_files = b.marker_paths;
+  SVN_WC__DB_WITH_TXN(
+    revert_list_read(reverted, marker_files, copied_here, kind,
+                     wcroot, local_relpath, db,
+                     result_pool, scratch_pool),
+    wcroot);
   return SVN_NO_ERROR;
 }
 
 
-struct revert_list_read_copied_children_baton {
-  const apr_array_header_t **children;
-  apr_pool_t *result_pool;
-};
-
+/* The body of svn_wc__db_revert_list_read_copied_children().
+ */
 static svn_error_t *
-revert_list_read_copied_children(void *baton,
-                                 svn_wc__db_wcroot_t *wcroot,
+revert_list_read_copied_children(svn_wc__db_wcroot_t *wcroot,
                                  const char *local_relpath,
+                                 const apr_array_header_t **children_p,
+                                 apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
 {
-  struct revert_list_read_copied_children_baton *b = baton;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   apr_array_header_t *children;
 
   children =
-    apr_array_make(b->result_pool, 0,
+    apr_array_make(result_pool, 0,
                   sizeof(svn_wc__db_revert_list_copied_child_info_t *));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -6214,11 +6173,11 @@ revert_list_read_copied_children(void *b
       svn_wc__db_revert_list_copied_child_info_t *child_info;
       const char *child_relpath;
 
-      child_info = apr_palloc(b->result_pool, sizeof(*child_info));
+      child_info = apr_palloc(result_pool, sizeof(*child_info));
 
       child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
       child_info->abspath = svn_dirent_join(wcroot->abspath, child_relpath,
-                                            b->result_pool);
+                                            result_pool);
       child_info->kind = svn_sqlite__column_token(stmt, 1, kind_map);
       APR_ARRAY_PUSH(
         children,
@@ -6228,7 +6187,7 @@ revert_list_read_copied_children(void *b
     }
    SVN_ERR(svn_sqlite__reset(stmt));
 
-  *b->children = children;
+  *children_p = children;
 
   return SVN_NO_ERROR;
 }
@@ -6243,18 +6202,15 @@ svn_wc__db_revert_list_read_copied_child
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
-  struct revert_list_read_copied_children_baton b;
-
-  b.children = children;
-  b.result_pool = result_pool;
 
   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
                               db, local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath,
-                              revert_list_read_copied_children, &b,
-                              scratch_pool));
+  SVN_WC__DB_WITH_TXN(
+    revert_list_read_copied_children(wcroot, local_relpath, children,
+                                     result_pool, scratch_pool),
+    wcroot);
   return SVN_NO_ERROR;
 }
 
@@ -6327,30 +6283,24 @@ svn_wc__db_revert_list_done(svn_wc__db_t
   return SVN_NO_ERROR;
 }
 
-/* Baton for remove_node_txn */
-struct remove_node_baton
-{
-  svn_wc__db_t *db;
-  svn_boolean_t left_changes;
-  svn_boolean_t destroy_wc;
-  svn_boolean_t destroy_changes;
-  svn_revnum_t not_present_rev;
-  svn_wc__db_status_t not_present_status;
-  svn_kind_t not_present_kind;
-  const svn_skel_t *conflict;
-  const svn_skel_t *work_items;
-  svn_cancel_func_t cancel_func;
-  void *cancel_baton;
-};
-
-/* Implements svn_wc__db_txn_callback_t for svn_wc__db_op_remove_node */
+/* The body of svn_wc__db_op_remove_node().
+ */
 static svn_error_t *
-remove_node_txn(void *baton,
+remove_node_txn(svn_boolean_t *left_changes,
                 svn_wc__db_wcroot_t *wcroot,
                 const char *local_relpath,
+                svn_wc__db_t *db,
+                svn_boolean_t destroy_wc,
+                svn_boolean_t destroy_changes,
+                svn_revnum_t not_present_rev,
+                svn_wc__db_status_t not_present_status,
+                svn_kind_t not_present_kind,
+                const svn_skel_t *conflict,
+                const svn_skel_t *work_items,
+                svn_cancel_func_t cancel_func,
+                void *cancel_baton,
                 apr_pool_t *scratch_pool)
 {
-  struct remove_node_baton *rnb = baton;
   svn_sqlite__stmt_t *stmt;
 
   apr_int64_t repos_id;
@@ -6360,19 +6310,22 @@ remove_node_txn(void *baton,
      function to be called on a wcroot! */
 
    /* db set when destroying wc */
-  SVN_ERR_ASSERT(!rnb->destroy_wc || rnb->db != NULL);
+  SVN_ERR_ASSERT(!destroy_wc || db != NULL);
+
+  if (left_changes)
+    *left_changes = FALSE;
 
   /* Need info for not_present node? */
-  if (SVN_IS_VALID_REVNUM(rnb->not_present_rev))
+  if (SVN_IS_VALID_REVNUM(not_present_rev))
     SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL, 
                                               &repos_relpath, &repos_id,
                                               NULL, NULL, NULL, NULL, NULL,
-                                              NULL, NULL, NULL, NULL,
+                                              NULL, NULL, NULL, NULL, NULL,
                                               wcroot, local_relpath,
                                               scratch_pool, scratch_pool));
 
-  if (rnb->destroy_wc
-      && (!rnb->destroy_changes || *local_relpath == '\0'))
+  if (destroy_wc
+      && (!destroy_changes || *local_relpath == '\0'))
     {
       svn_boolean_t have_row;
       apr_pool_t *iterpool;
@@ -6395,7 +6348,7 @@ remove_node_txn(void *baton,
           svn_kind_t child_kind;
           svn_boolean_t have_checksum;
           svn_filesize_t recorded_size;
-          apr_int64_t recorded_mod_time;
+          apr_int64_t recorded_time;
           const svn_io_dirent2_t *dirent;
           svn_boolean_t modified_p = TRUE;
           svn_skel_t *work_item = NULL;
@@ -6412,11 +6365,11 @@ remove_node_txn(void *baton,
             {
               have_checksum = !svn_sqlite__column_is_null(stmt, 2);
               recorded_size = get_recorded_size(stmt, 3);
-              recorded_mod_time = svn_sqlite__column_int64(stmt, 4);
+              recorded_time = svn_sqlite__column_int64(stmt, 4);
             }
 
-          if (rnb->cancel_func)
-            err = rnb->cancel_func(rnb->cancel_baton);
+          if (cancel_func)
+            err = cancel_func(cancel_baton);
 
           if (err)
             break;
@@ -6427,7 +6380,7 @@ remove_node_txn(void *baton,
           if (err)
             break;
 
-          if (rnb->destroy_changes
+          if (destroy_changes
               || dirent->kind != svn_node_file
               || child_kind != svn_kind_file)
             {
@@ -6437,31 +6390,34 @@ remove_node_txn(void *baton,
           else if (child_kind == svn_kind_file
                    && dirent->kind == svn_node_file
                    && dirent->filesize == recorded_size
-                   && dirent->mtime == recorded_mod_time)
+                   && dirent->mtime == recorded_time)
             {
               modified_p = FALSE; /* File matches recorded state */
             }
           else if (have_checksum)
             err = svn_wc__internal_file_modified_p(&modified_p,
-                                                   rnb->db, child_abspath,
+                                                   db, child_abspath,
                                                    FALSE, iterpool);
 
           if (err)
             break;
 
           if (modified_p)
-            rnb->left_changes = TRUE;
+            {
+              if (left_changes)
+                *left_changes = TRUE;
+            }
           else if (child_kind == svn_kind_dir)
             {
               err = svn_wc__wq_build_dir_remove(&work_item,
-                                                rnb->db, wcroot->abspath,
+                                                db, wcroot->abspath,
                                                 child_abspath, FALSE,
                                                 iterpool, iterpool);
             }
           else /* svn_kind_file || svn_kind_symlink */
             {
               err = svn_wc__wq_build_file_remove(&work_item,
-                                                 rnb->db, wcroot->abspath,
+                                                 db, wcroot->abspath,
                                                  child_abspath,
                                                  iterpool, iterpool);
             }
@@ -6483,7 +6439,7 @@ remove_node_txn(void *baton,
       SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
     }
 
-  if (rnb->destroy_wc && *local_relpath != '\0')
+  if (destroy_wc && *local_relpath != '\0')
     {
       /* Create work item for destroying the root */
       svn_wc__db_status_t status;
@@ -6506,9 +6462,9 @@ remove_node_txn(void *baton,
           if (kind == svn_kind_dir)
             {
               SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
-                                                  rnb->db, wcroot->abspath,
+                                                  db, wcroot->abspath,
                                                   local_abspath,
-                                                  rnb->destroy_changes
+                                                  destroy_changes
                                                       /* recursive */,
                                                   scratch_pool, scratch_pool));
             }
@@ -6516,23 +6472,25 @@ remove_node_txn(void *baton,
             {
               svn_boolean_t modified_p = FALSE;
 
-              if (!rnb->destroy_changes)
+              if (!destroy_changes)
                 {
                   SVN_ERR(svn_wc__internal_file_modified_p(&modified_p,
-                                                           rnb->db,
-                                                           local_abspath,
+                                                           db, local_abspath,
                                                            FALSE,
                                                            scratch_pool));
                 }
 
               if (!modified_p)
                 SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
-                                                     rnb->db, wcroot->abspath,
+                                                     db, wcroot->abspath,
                                                      local_abspath,
                                                      scratch_pool,
                                                      scratch_pool));
               else
-                rnb->left_changes = TRUE;
+                {
+                  if (left_changes)
+                    *left_changes = TRUE;
+                }

[... 3063 lines stripped ...]