Modified: subversion/branches/svn-info-detail/subversion/libsvn_wc/wc_db.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/svn-info-detail/subversion/libsvn_wc/wc_db.c?rev=1661981&r1=1661980&r2=1661981&view=diff
==============================================================================
--- subversion/branches/svn-info-detail/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/svn-info-detail/subversion/libsvn_wc/wc_db.c Tue Feb 24 
15:23:33 2015
@@ -278,10 +278,9 @@ add_work_items(svn_sqlite__db_t *sdb,
                apr_pool_t *scratch_pool);
 
 static svn_error_t *
-set_actual_props(apr_int64_t wc_id,
+set_actual_props(svn_wc__db_wcroot_t *wcroot,
                  const char *local_relpath,
                  apr_hash_t *props,
-                 svn_sqlite__db_t *db,
                  apr_pool_t *scratch_pool);
 
 static svn_error_t *
@@ -487,35 +486,6 @@ repos_location_from_columns(apr_int64_t
     }
 }
 
-
-/* Get the statement given by STMT_IDX, and bind the appropriate wc_id and
-   local_relpath based upon LOCAL_ABSPATH.  Store it in *STMT, and use
-   SCRATCH_POOL for temporary allocations.
-
-   Note: WC_ID and LOCAL_RELPATH must be arguments 1 and 2 in the statement. */
-static svn_error_t *
-get_statement_for_path(svn_sqlite__stmt_t **stmt,
-                       svn_wc__db_t *db,
-                       const char *local_abspath,
-                       int stmt_idx,
-                       apr_pool_t *scratch_pool)
-{
-  svn_wc__db_wcroot_t *wcroot;
-  const char *local_relpath;
-
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
-  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_sqlite__get_statement(stmt, wcroot->sdb, stmt_idx));
-  SVN_ERR(svn_sqlite__bindf(*stmt, "is", wcroot->wc_id, local_relpath));
-
-  return SVN_NO_ERROR;
-}
-
-
 /* For a given REPOS_ROOT_URL/REPOS_UUID pair, return the existing REPOS_ID
    value. If one does not exist, then create a new one. */
 static svn_error_t *
@@ -743,6 +713,7 @@ insert_base_node(const insert_base_baton
   svn_sqlite__stmt_t *stmt;
   svn_filesize_t recorded_size = SVN_INVALID_FILESIZE;
   apr_int64_t recorded_time;
+  svn_boolean_t present;
 
   /* The directory at the WCROOT has a NULL parent_relpath. Otherwise,
      bind the appropriate parent_relpath. */
@@ -773,6 +744,9 @@ insert_base_node(const insert_base_baton
       SVN_ERR(svn_sqlite__reset(stmt));
     }
 
+  present = (pibb->status == svn_wc__db_status_normal
+             || pibb->status == svn_wc__db_status_incomplete);
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "isdsisr"
                             "tstr"               /* 8 - 11 */
@@ -785,15 +759,16 @@ insert_base_node(const insert_base_baton
                             pibb->repos_relpath,
                             pibb->revision,
                             presence_map, pibb->status, /* 8 */
-                            (pibb->kind == svn_node_dir) ? /* 9 */
-                             svn_token__to_word(depth_map, pibb->depth) : NULL,
+                            (pibb->kind == svn_node_dir && present) /* 9 */
+                              ? svn_token__to_word(depth_map, pibb->depth)
+                              : NULL,
                             kind_map, pibb->kind, /* 10 */
                             pibb->changed_rev,    /* 11 */
                             pibb->changed_date,   /* 12 */
                             pibb->changed_author, /* 13 */
-                            (pibb->kind == svn_node_symlink) ?
+                            (pibb->kind == svn_node_symlink && present) ?
                                 pibb->target : NULL)); /* 19 */
-  if (pibb->kind == svn_node_file)
+  if (pibb->kind == svn_node_file && present)
     {
       if (!pibb->checksum
           && pibb->status != svn_wc__db_status_not_present
@@ -818,11 +793,14 @@ insert_base_node(const insert_base_baton
   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));
+  if (present)
+    {
+      SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props,
+                                          scratch_pool));
 
-  SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, pibb->iprops,
+      SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, pibb->iprops,
                                       scratch_pool));
+    }
 
   if (pibb->dav_cache)
     SVN_ERR(svn_sqlite__bind_properties(stmt, 18, pibb->dav_cache,
@@ -852,8 +830,8 @@ insert_base_node(const insert_base_baton
             new_actual_props = NULL;
         }
 
-      SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, new_actual_props,
-                               wcroot->sdb, scratch_pool));
+      SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props,
+                               scratch_pool));
     }
 
   if (pibb->kind == svn_node_dir && pibb->children)
@@ -1027,6 +1005,7 @@ insert_working_node(const insert_working
   const char *moved_to_relpath = NULL;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
+  svn_boolean_t present;
 
   SVN_ERR_ASSERT(piwb->op_depth > 0);
 
@@ -1045,6 +1024,9 @@ insert_working_node(const insert_working
     moved_to_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
   SVN_ERR(svn_sqlite__reset(stmt));
 
+  present = (piwb->presence == svn_wc__db_status_normal
+             || piwb->presence == svn_wc__db_status_incomplete);
+
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnntstrisn"
                 "nnnn" /* properties translated_size last_mod_time dav_cache */
@@ -1053,14 +1035,14 @@ insert_working_node(const insert_working
                 piwb->op_depth,
                 parent_relpath,
                 presence_map, piwb->presence,
-                (piwb->kind == svn_node_dir)
+                (piwb->kind == svn_node_dir && present)
                             ? svn_token__to_word(depth_map, piwb->depth) : 
NULL,
                 kind_map, piwb->kind,
                 piwb->changed_rev,
                 piwb->changed_date,
                 piwb->changed_author,
                 /* Note: incomplete nodes may have a NULL target.  */
-                (piwb->kind == svn_node_symlink)
+                (piwb->kind == svn_node_symlink && present)
                             ? piwb->target : NULL,
                 moved_to_relpath));
 
@@ -1069,7 +1051,7 @@ insert_working_node(const insert_working
       SVN_ERR(svn_sqlite__bind_int(stmt, 8, TRUE));
     }
 
-  if (piwb->kind == svn_node_file)
+  if (piwb->kind == svn_node_file && present)
     {
       SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, piwb->checksum,
                                         scratch_pool));
@@ -1086,7 +1068,8 @@ insert_working_node(const insert_working
   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));
+  if (present && piwb->original_repos_relpath)
+    SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool));
 
   SVN_ERR(svn_sqlite__insert(NULL, stmt));
 
@@ -1123,8 +1106,8 @@ insert_working_node(const insert_working
             new_actual_props = NULL;
         }
 
-      SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, new_actual_props,
-                               wcroot->sdb, scratch_pool));
+      SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props,
+                               scratch_pool));
     }
 
   if (piwb->kind == svn_node_dir)
@@ -1170,119 +1153,40 @@ insert_working_node(const insert_working
 }
 
 
-/* Each name is allocated in RESULT_POOL and stored into CHILDREN as a key
-   pointed to the same name.  */
-static svn_error_t *
-add_children_to_hash(apr_hash_t *children,
-                     int stmt_idx,
-                     svn_sqlite__db_t *sdb,
-                     apr_int64_t wc_id,
-                     const char *parent_relpath,
-                     apr_pool_t *result_pool)
-{
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, stmt_idx));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  while (have_row)
-    {
-      const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
-      const char *name = svn_relpath_basename(child_relpath, result_pool);
-
-      svn_hash_sets(children, name, name);
-
-      SVN_ERR(svn_sqlite__step(&have_row, stmt));
-    }
-
-  return svn_sqlite__reset(stmt);
-}
-
-
-/* Set *CHILDREN to a new array of the (const char *) basenames of the
-   immediate children, whatever their status, of the working node at
-   LOCAL_RELPATH. */
-static svn_error_t *
-gather_children2(const apr_array_header_t **children,
-                 svn_wc__db_wcroot_t *wcroot,
-                 const char *local_relpath,
-                 apr_pool_t *result_pool,
-                 apr_pool_t *scratch_pool)
-{
-  apr_hash_t *names_hash = apr_hash_make(scratch_pool);
-  apr_array_header_t *names_array;
-
-  /* All of the names get allocated in RESULT_POOL.  It
-     appears to be faster to use the hash to remove duplicates than to
-     use DISTINCT in the SQL query. */
-  SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_WORKING_CHILDREN,
-                               wcroot->sdb, wcroot->wc_id,
-                               local_relpath, result_pool));
-
-  SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool));
-  *children = names_array;
-  return SVN_NO_ERROR;
-}
-
 /* Return in *CHILDREN all of the children of the directory LOCAL_RELPATH,
    of any status, in all op-depths in the NODES table. */
 static svn_error_t *
 gather_children(const apr_array_header_t **children,
                 svn_wc__db_wcroot_t *wcroot,
-                const char *local_relpath,
+                const char *parent_relpath,
+                int stmt_idx,
+                int op_depth,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
 {
-  apr_hash_t *names_hash = apr_hash_make(scratch_pool);
-  apr_array_header_t *names_array;
-
-  /* All of the names get allocated in RESULT_POOL.  It
-     appears to be faster to use the hash to remove duplicates than to
-     use DISTINCT in the SQL query. */
-  SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_NODE_CHILDREN,
-                               wcroot->sdb, wcroot->wc_id,
-                               local_relpath, result_pool));
-
-  SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool));
-  *children = names_array;
-  return SVN_NO_ERROR;
-}
-
-
-/* Set *CHILDREN to a new array of (const char *) names of the children of
-   the repository directory corresponding to WCROOT:LOCAL_RELPATH:OP_DEPTH -
-   that is, only the children that are at the same op-depth as their parent. */
-static svn_error_t *
-gather_repo_children(const apr_array_header_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)
-{
-  apr_array_header_t *result
-    = apr_array_make(result_pool, 0, sizeof(const char *));
+  apr_array_header_t *result;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
 
-  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));
+  result = apr_array_make(result_pool, 16, sizeof(const char*));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, stmt_idx));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
+  if (op_depth >= 0)
+    SVN_ERR(svn_sqlite__bind_int(stmt, 3, op_depth));
+
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   while (have_row)
     {
       const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+      const char *name = svn_relpath_basename(child_relpath, result_pool);
 
-      /* Allocate the name in RESULT_POOL so we won't have to copy it. */
-      APR_ARRAY_PUSH(result, const char *)
-        = svn_relpath_basename(child_relpath, result_pool);
+      APR_ARRAY_PUSH(result, const char *) = name;
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
-  SVN_ERR(svn_sqlite__reset(stmt));
 
+  SVN_ERR(svn_sqlite__reset(stmt));
   *children = result;
   return SVN_NO_ERROR;
 }
@@ -1577,7 +1481,7 @@ svn_wc__db_init(svn_wc__db_t *db,
 
   /* ### REPOS_ROOT_URL and REPOS_UUID may be NULL. ... more doc: tbd  */
 
-  SVN_ERR(svn_config_get_bool((svn_config_t *)db->config, &sqlite_exclusive,
+  SVN_ERR(svn_config_get_bool(db->config, &sqlite_exclusive,
                               SVN_CONFIG_SECTION_WORKING_COPY,
                               SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE,
                               FALSE));
@@ -2203,9 +2107,9 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
                const char *local_relpath,
                svn_wc__db_t *db, /* For checking conflicts */
                svn_boolean_t keep_as_working,
-               svn_boolean_t queue_deletes,
-               svn_boolean_t remove_locks,
-               svn_revnum_t not_present_revision,
+               svn_boolean_t mark_not_present,
+               svn_boolean_t mark_excluded,
+               svn_revnum_t marker_revision,
                svn_skel_t *conflict,
                svn_skel_t *work_items,
                apr_pool_t *scratch_pool)
@@ -2213,66 +2117,80 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   svn_wc__db_status_t status;
+  svn_revnum_t revision;
   apr_int64_t repos_id;
   const char *repos_relpath;
   svn_node_kind_t kind;
   svn_boolean_t keep_working;
+  int op_depth;
+  svn_node_kind_t wrk_kind;
+  svn_boolean_t no_delete_wc = FALSE;
 
-  SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, NULL,
+  SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, &revision,
                                             &repos_relpath, &repos_id,
                                             NULL, NULL, NULL, NULL, NULL,
                                             NULL, NULL, NULL, NULL, NULL,
                                             wcroot, local_relpath,
                                             scratch_pool, scratch_pool));
 
-  if (remove_locks)
-    {
-      svn_sqlite__stmt_t *lock_stmt;
+  /* Check if there is already a working node */
+  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(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb,
-                                        STMT_DELETE_LOCK_RECURSIVELY));
-      SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath));
-      SVN_ERR(svn_sqlite__step_done(lock_stmt));
-    }
+  if (!have_row)
+    return svn_error_trace(svn_sqlite__reset(stmt)); /* No BASE */
+
+  op_depth = svn_sqlite__column_int(stmt, 0);
+  wrk_kind = svn_sqlite__column_token(stmt, 4, kind_map);
 
-  if (status == svn_wc__db_status_normal
-      && keep_as_working)
+  if (op_depth > 0
+      && op_depth == relpath_depth(local_relpath))
     {
-      SVN_ERR(svn_wc__db_op_make_copy(db,
-                                      svn_dirent_join(wcroot->abspath,
-                                                      local_relpath,
-                                                      scratch_pool),
-                                      NULL, NULL,
-                                      scratch_pool));
-      keep_working = TRUE;
+      svn_wc__db_status_t presence;
+      presence = svn_sqlite__column_token(stmt, 3, presence_map);
+
+      if (presence == svn_wc__db_status_base_deleted)
+        {
+          keep_working = FALSE;
+          no_delete_wc = TRUE;
+        }
+      else
+        {
+          keep_working = TRUE;
+        }
     }
   else
+    keep_working = FALSE;
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  if (keep_as_working && op_depth == 0)
     {
-      /* Check if there is already a working node */
-      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(&keep_working, stmt));
-      SVN_ERR(svn_sqlite__reset(stmt));
+      if (status == svn_wc__db_status_normal
+          || status == svn_wc__db_status_incomplete)
+        {
+          SVN_ERR(svn_wc__db_op_make_copy_internal(wcroot, local_relpath, TRUE,
+                                                   NULL, NULL,
+                                                   scratch_pool));
+        }
+      keep_working = TRUE;
     }
 
   /* Step 1: Create workqueue operations to remove files and dirs in the
      local-wc */
-  if (!keep_working
-      && queue_deletes
-      && (status == svn_wc__db_status_normal
-          || status == svn_wc__db_status_incomplete))
+  if (!keep_working && !no_delete_wc)
     {
       svn_skel_t *work_item;
       const char *local_abspath;
 
       local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
                                       scratch_pool);
-      if (kind == svn_node_dir)
+      if (wrk_kind == svn_node_dir)
         {
           apr_pool_t *iterpool;
           SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                            STMT_SELECT_BASE_PRESENT));
+                                            STMT_SELECT_WORKING_PRESENT));
           SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
 
           iterpool = svn_pool_create(scratch_pool);
@@ -2351,27 +2269,12 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
            ACTUAL_NODE records */
 
   /* Step 3: Delete WORKING nodes */
-  if (conflict)
+  if (!keep_working)
     {
       apr_pool_t *iterpool;
 
-      /*
-       * When deleting a conflicted node, moves of any moved-outside children
-       * of the node must be broken. Else, the destination will still be marked
-       * moved-here after the move source disappears from the working copy.
-       *
-       * ### FIXME: It would be nicer to have the conflict resolver
-       * break the move instead. It might also be a good idea to
-       * flag a tree conflict on each moved-away child. But doing so
-       * might introduce actual-only nodes without direct parents,
-       * and we're not yet sure if other existing code is prepared
-       * to handle such nodes. To be revisited post-1.8.
-       *
-       * ### In case of a conflict we are most likely creating WORKING nodes
-       *     describing a copy of what was in BASE. The move information
-       *     should be updated to describe a move from the WORKING layer.
-       *     When stored that way the resolver of the tree conflict still has
-       *     the knowledge of what was moved.
+      /* When deleting everything in working we should break moves from
+         here and to here.
        */
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                         STMT_SELECT_MOVED_OUTSIDE));
@@ -2395,10 +2298,51 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
       svn_pool_destroy(iterpool);
       SVN_ERR(svn_sqlite__reset(stmt));
     }
-  if (keep_working)
+  else
     {
+      /* We are keeping things that are in WORKING, but we should still
+         break moves of things in BASE. (Mixed revisions make it
+         impossible to guarantee that we can keep everything moved) */
+
+      apr_pool_t *iterpool;
+
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_WORKING_BASE_DELETE));
+                                        STMT_SELECT_MOVED_DESCENDANTS_SRC));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                                local_relpath, 0));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+      iterpool = svn_pool_create(scratch_pool);
+      while (have_row)
+        {
+          int delete_op_depth = svn_sqlite__column_int(stmt, 0);
+          const char *src_relpath;
+          const char *dst_relpath;
+          svn_error_t *err;
+
+          svn_pool_clear(iterpool);
+
+          src_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
+          dst_relpath = svn_sqlite__column_text(stmt, 4, iterpool);
+
+          err = svn_wc__db_op_break_move_internal(wcroot, src_relpath,
+                                                  delete_op_depth,
+                                                  dst_relpath,
+                                                  NULL,
+                                                  iterpool);
+
+          if (err)
+            return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+
+          SVN_ERR(svn_sqlite__step(&have_row, stmt));
+        }
+      svn_pool_destroy(iterpool);
+      SVN_ERR(svn_sqlite__reset(stmt));
+    }
+  if (keep_working)
+    {
+      SVN_ERR(svn_sqlite__get_statement(
+                    &stmt, wcroot->sdb,
+                    STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE));
       SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
@@ -2424,25 +2368,19 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
 
   SVN_ERR(db_retract_parent_delete(wcroot, local_relpath, 0, scratch_pool));
 
-  /* Step 6: Delete actual node if we don't keep working */
-  if (! keep_working)
-    {
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_ACTUAL_NODE));
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-      SVN_ERR(svn_sqlite__step_done(stmt));
-    }
-
-  if (SVN_IS_VALID_REVNUM(not_present_revision))
+  if (mark_not_present || mark_excluded)
     {
       struct insert_base_baton_t ibb;
       blank_ibb(&ibb);
 
       ibb.repos_id = repos_id;
-      ibb.status = svn_wc__db_status_not_present;
+      ibb.status = mark_excluded ? svn_wc__db_status_excluded
+                                 : svn_wc__db_status_not_present;
       ibb.kind = kind;
       ibb.repos_relpath = repos_relpath;
-      ibb.revision = not_present_revision;
+      ibb.revision = SVN_IS_VALID_REVNUM(marker_revision)
+                        ? marker_revision
+                        : revision;
 
       /* Depending upon KIND, any of these might get used. */
       ibb.children = NULL;
@@ -2466,9 +2404,9 @@ svn_error_t *
 svn_wc__db_base_remove(svn_wc__db_t *db,
                        const char *local_abspath,
                        svn_boolean_t keep_as_working,
-                       svn_boolean_t queue_deletes,
-                       svn_boolean_t remove_locks,
-                       svn_revnum_t not_present_revision,
+                       svn_boolean_t mark_not_present,
+                       svn_boolean_t mark_excluded,
+                       svn_revnum_t marker_revision,
                        svn_skel_t *conflict,
                        svn_skel_t *work_items,
                        apr_pool_t *scratch_pool)
@@ -2483,8 +2421,9 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
   VERIFY_USABLE_WCROOT(wcroot);
 
   SVN_WC__DB_WITH_TXN(db_base_remove(wcroot, local_relpath,
-                                     db, keep_as_working, queue_deletes,
-                                     remove_locks, not_present_revision,
+                                     db, keep_as_working,
+                                     mark_not_present, mark_excluded,
+                                     marker_revision,
                                      conflict, work_items, scratch_pool),
                       wcroot);
 
@@ -2835,8 +2774,10 @@ svn_wc__db_base_get_children(const apr_a
                                              scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  return gather_repo_children(children, wcroot, local_relpath, 0,
-                              result_pool, scratch_pool);
+  return svn_error_trace(
+              gather_children(children, wcroot, local_relpath,
+                              STMT_SELECT_OP_DEPTH_CHILDREN, 0,
+                              result_pool, scratch_pool));
 }
 
 
@@ -2846,12 +2787,20 @@ svn_wc__db_base_set_dav_cache(svn_wc__db
                               const apr_hash_t *props,
                               apr_pool_t *scratch_pool)
 {
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
   svn_sqlite__stmt_t *stmt;
   int affected_rows;
 
-  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
-                                 STMT_UPDATE_BASE_NODE_DAV_CACHE,
-                                 scratch_pool));
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  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_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_UPDATE_BASE_NODE_DAV_CACHE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
 
   SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
@@ -2873,11 +2822,20 @@ svn_wc__db_base_get_dav_cache(apr_hash_t
                               apr_pool_t *result_pool,
                               apr_pool_t *scratch_pool)
 {
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
 
-  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
-                                 STMT_SELECT_BASE_DAV_CACHE, scratch_pool));
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  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_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_BASE_DAV_CACHE));
+
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   if (!have_row)
     return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
@@ -4030,9 +3988,7 @@ scan_deletion_txn(const char **base_del_
   scan = (moved_to_op_root_relpath || moved_to_relpath);
 
   SVN_ERR(svn_sqlite__get_statement(
-                    &stmt, wcroot->sdb,
-                    scan ? STMT_SELECT_DELETION_INFO_SCAN
-                         : STMT_SELECT_DELETION_INFO));
+                    &stmt, wcroot->sdb, STMT_SELECT_DELETION_INFO));
 
   SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
@@ -4606,8 +4562,9 @@ db_op_copy(svn_wc__db_wcroot_t *src_wcro
       int src_op_depth;
 
       SVN_ERR(op_depth_of(&src_op_depth, src_wcroot, src_relpath));
-      SVN_ERR(gather_repo_children(&children, src_wcroot, src_relpath,
-                                   src_op_depth, scratch_pool, scratch_pool));
+      SVN_ERR(gather_children(&children, src_wcroot, src_relpath,
+                              STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth,
+                              scratch_pool, scratch_pool));
     }
   else
     children = NULL;
@@ -4831,6 +4788,72 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
   return SVN_NO_ERROR;
 }
 
+/* Remove unneeded actual nodes for svn_wc__db_op_copy_layer_internal */
+static svn_error_t *
+clear_or_remove_actual(svn_wc__db_wcroot_t *wcroot,
+                       const char *local_relpath,
+                       int op_depth,
+                       apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row, shadowed;
+  svn_boolean_t keep_conflict = FALSE;
+
+  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));
+
+  if (have_row)
+    {
+      svn_wc__db_status_t presence;
+
+      shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth);
+      presence = svn_sqlite__column_token(stmt, 3, presence_map);
+
+      if (shadowed && presence == svn_wc__db_status_base_deleted)
+        {
+          keep_conflict = TRUE;
+          SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+          if (have_row)
+            shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth);
+          else
+            shadowed = FALSE;
+        }
+    }
+  else
+    shadowed = FALSE;
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+  if (shadowed)
+    return SVN_NO_ERROR;
+
+  if (keep_conflict)
+    {
+      /* We don't want to accidentally remove delete-delete conflicts */
+      SVN_ERR(svn_sqlite__get_statement(
+                          &stmt, wcroot->sdb,
+                          STMT_CLEAR_ACTUAL_NODE_LEAVING_CONFLICT));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_DELETE_ACTUAL_EMPTY));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+    }
+  else
+    {
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_DELETE_ACTUAL_NODE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_wc__db_op_copy_layer_internal(svn_wc__db_wcroot_t *wcroot,
                                   const char *src_op_relpath,
@@ -4962,6 +4985,12 @@ svn_wc__db_op_copy_layer_internal(svn_wc
         err = svn_sqlite__step_done(stmt2);
 
       /* stmt2 is reset (never modified or by step_done) */
+      if (err)
+        break;
+
+      /* Delete ACTUAL information about this node that we just deleted */
+      err = clear_or_remove_actual(wcroot, dst_relpath, dst_op_depth,
+                                   scratch_pool);
 
       if (err)
         break;
@@ -4979,8 +5008,6 @@ svn_wc__db_op_copy_layer_internal(svn_wc
 
   SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
 
-  /* ### TODO: Did we handle ACTUAL as intended? */
-
   SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
 
   if (conflict)
@@ -5397,8 +5424,9 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
       return SVN_NO_ERROR;
     }
 
-  SVN_ERR(gather_repo_children(&children, src_wcroot, src_relpath,
-                               src_op_depth, scratch_pool, iterpool));
+  SVN_ERR(gather_children(&children, src_wcroot, src_relpath,
+                          STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth,
+                          scratch_pool, iterpool));
 
   for (i = 0; i < children->nelts; i++)
     {
@@ -5585,8 +5613,8 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
                        const char *original_uuid,
                        svn_revnum_t original_revision,
                        const apr_array_header_t *children,
-                       svn_boolean_t is_move,
                        svn_depth_t depth,
+                       svn_boolean_t is_move,
                        const svn_skel_t *conflict,
                        const svn_skel_t *work_items,
                        apr_pool_t *scratch_pool)
@@ -5613,11 +5641,6 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
   iwb.presence = svn_wc__db_status_normal;
   iwb.kind = svn_node_dir;
 
-  iwb.props = props;
-  iwb.changed_rev = changed_rev;
-  iwb.changed_date = changed_date;
-  iwb.changed_author = changed_author;
-
   if (original_root_url != NULL)
     {
       SVN_ERR(create_repos_id(&iwb.original_repos_id,
@@ -5625,6 +5648,11 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
                               wcroot->sdb, scratch_pool));
       iwb.original_repos_relpath = original_repos_relpath;
       iwb.original_revnum = original_revision;
+
+      iwb.props = props;
+      iwb.changed_rev = changed_rev;
+      iwb.changed_date = changed_date;
+      iwb.changed_author = changed_author;
     }
 
   /* ### Should we do this inside the transaction? */
@@ -5693,11 +5721,6 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db
   iwb.presence = svn_wc__db_status_normal;
   iwb.kind = svn_node_file;
 
-  iwb.props = props;
-  iwb.changed_rev = changed_rev;
-  iwb.changed_date = changed_date;
-  iwb.changed_author = changed_author;
-
   if (original_root_url != NULL)
     {
       SVN_ERR(create_repos_id(&iwb.original_repos_id,
@@ -5705,6 +5728,11 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db
                               wcroot->sdb, scratch_pool));
       iwb.original_repos_relpath = original_repos_relpath;
       iwb.original_revnum = original_revision;
+
+      iwb.props = props;
+      iwb.changed_rev = changed_rev;
+      iwb.changed_date = changed_date;
+      iwb.changed_author = changed_author;
     }
 
   /* ### Should we do this inside the transaction? */
@@ -5747,6 +5775,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t
                            const char *original_uuid,
                            svn_revnum_t original_revision,
                            const char *target,
+                           svn_boolean_t is_move,
                            const svn_skel_t *conflict,
                            const svn_skel_t *work_items,
                            apr_pool_t *scratch_pool)
@@ -5771,11 +5800,6 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t
   iwb.presence = svn_wc__db_status_normal;
   iwb.kind = svn_node_symlink;
 
-  iwb.props = props;
-  iwb.changed_rev = changed_rev;
-  iwb.changed_date = changed_date;
-  iwb.changed_author = changed_author;
-  iwb.moved_here = FALSE;
 
   if (original_root_url != NULL)
     {
@@ -5784,6 +5808,11 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t
                               wcroot->sdb, scratch_pool));
       iwb.original_repos_relpath = original_repos_relpath;
       iwb.original_revnum = original_revision;
+
+      iwb.props = props;
+      iwb.changed_rev = changed_rev;
+      iwb.changed_date = changed_date;
+      iwb.changed_author = changed_author;
     }
 
   /* ### Should we do this inside the transaction? */
@@ -5793,6 +5822,8 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t
                             wcroot, local_relpath, scratch_pool));
 
   iwb.target = target;
+  iwb.moved_here = is_move && (parent_op_depth == 0 ||
+                               iwb.op_depth == parent_op_depth);
 
   iwb.work_items = work_items;
   iwb.conflict = conflict;
@@ -6002,27 +6033,39 @@ svn_wc__db_global_record_fileinfo(svn_wc
  * 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,
+set_actual_props(svn_wc__db_wcroot_t *wcroot,
                  const char *local_relpath,
                  apr_hash_t *props,
-                 svn_sqlite__db_t *db,
                  apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   int affected_rows;
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_UPDATE_ACTUAL_PROPS));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_UPDATE_ACTUAL_PROPS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
   SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
   if (affected_rows == 1 || !props)
-    return SVN_NO_ERROR; /* We are done */
+    {
+      /* Perhaps the entire ACTUAL record is unneeded now? */
+      if (!props && affected_rows)
+        {
+          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                            STMT_DELETE_ACTUAL_EMPTY));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+        }
+
+      return SVN_NO_ERROR; /* We are done */
+    }
 
   /* We have to insert a row in ACTUAL */
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_ACTUAL_PROPS));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_INSERT_ACTUAL_PROPS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
   if (*local_relpath != '\0')
     SVN_ERR(svn_sqlite__bind_text(stmt, 3,
                                   svn_relpath_dirname(local_relpath,
@@ -6038,8 +6081,7 @@ svn_wc__db_op_set_props_internal(svn_wc_
                                  svn_boolean_t clear_recorded_info,
                                  apr_pool_t *scratch_pool)
 {
-  SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath,
-                           props, wcroot->sdb, scratch_pool));
+  SVN_ERR(set_actual_props(wcroot, local_relpath, props, scratch_pool));
 
   if (clear_recorded_info)
     {
@@ -6318,7 +6360,7 @@ set_changelist_txn(void *baton,
   if (scb->new_changelist)
     {
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_INSERT_ACTUAL_EMPTIES));
+                                        STMT_INSERT_ACTUAL_EMPTIES_FILES));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
 
@@ -7367,9 +7409,6 @@ remove_node_txn(svn_boolean_t *left_chan
                 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_node_kind_t not_present_kind,
                 const svn_skel_t *conflict,
                 const svn_skel_t *work_items,
                 svn_cancel_func_t cancel_func,
@@ -7378,9 +7417,6 @@ remove_node_txn(svn_boolean_t *left_chan
 {
   svn_sqlite__stmt_t *stmt;
 
-  apr_int64_t repos_id;
-  const char *repos_relpath;
-
   /* Note that unlike many similar functions it is a valid scenario for this
      function to be called on a wcroot! */
 
@@ -7390,15 +7426,6 @@ remove_node_txn(svn_boolean_t *left_chan
   if (left_changes)
     *left_changes = FALSE;
 
-  /* Need info for not_present node? */
-  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,
-                                              wcroot, local_relpath,
-                                              scratch_pool, scratch_pool));
-
   if (destroy_wc
       && (!destroy_changes || *local_relpath == '\0'))
     {
@@ -7595,26 +7622,6 @@ remove_node_txn(svn_boolean_t *left_chan
                                          local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
-  /* Should we leave a not-present node? */
-  if (SVN_IS_VALID_REVNUM(not_present_rev))
-    {
-      insert_base_baton_t ibb;
-      blank_ibb(&ibb);
-
-      ibb.repos_id = repos_id;
-
-      SVN_ERR_ASSERT(not_present_status == svn_wc__db_status_not_present
-                     || not_present_status == svn_wc__db_status_excluded);
-
-      ibb.status = not_present_status;
-      ibb.kind = not_present_kind;
-
-      ibb.repos_relpath = repos_relpath;
-      ibb.revision = not_present_rev;
-
-      SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, 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,
@@ -7629,9 +7636,6 @@ svn_wc__db_op_remove_node(svn_boolean_t
                           const char *local_abspath,
                           svn_boolean_t destroy_wc,
                           svn_boolean_t destroy_changes,
-                          svn_revnum_t not_present_revision,
-                          svn_wc__db_status_t not_present_status,
-                          svn_node_kind_t not_present_kind,
                           const svn_skel_t *conflict,
                           const svn_skel_t *work_items,
                           svn_cancel_func_t cancel_func,
@@ -7650,8 +7654,7 @@ svn_wc__db_op_remove_node(svn_boolean_t
   SVN_WC__DB_WITH_TXN(remove_node_txn(left_changes,
                                       wcroot, local_relpath, db,
                                       destroy_wc, destroy_changes,
-                                      not_present_revision, not_present_status,
-                                      not_present_kind, conflict, work_items,
+                                      conflict, work_items,
                                       cancel_func, cancel_baton, scratch_pool),
                       wcroot);
 
@@ -9913,35 +9916,34 @@ svn_wc__db_read_node_install_info(const
 
 
 
-/* The body of svn_wc__db_read_url().
+/* The body of svn_wc__db_read_repos_info().
  */
 static svn_error_t *
-read_url_txn(const char **url,
-             svn_wc__db_wcroot_t *wcroot,
-             const char *local_relpath,
-             apr_pool_t *result_pool,
-             apr_pool_t *scratch_pool)
+db_read_repos_info(svn_revnum_t *revision,
+                   const char **repos_relpath,
+                   apr_int64_t *repos_id,
+                   svn_wc__db_wcroot_t *wcroot,
+                   const char *local_relpath,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
 {
   svn_wc__db_status_t status;
-  const char *repos_relpath;
-  const char *repos_root_url;
-  apr_int64_t repos_id;
-  svn_boolean_t have_base;
 
-  SVN_ERR(read_info(&status, NULL, NULL, &repos_relpath, &repos_id, NULL,
+  SVN_ERR(read_info(&status, NULL, revision, repos_relpath, repos_id, NULL,
                     NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                     NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                    &have_base, NULL, NULL,
-                    wcroot, local_relpath, scratch_pool, scratch_pool));
+                    NULL, NULL, NULL,
+                    wcroot, local_relpath, result_pool, scratch_pool));
 
-  if (repos_relpath == NULL)
+  if ((repos_relpath && !*repos_relpath)
+      || (repos_id && *repos_id == INVALID_REPOS_ID))
     {
       if (status == svn_wc__db_status_added)
         {
-          SVN_ERR(scan_addition(NULL, NULL, &repos_relpath, &repos_id, NULL,
+          SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL,
                                 NULL, NULL, NULL, NULL, NULL,
                                 wcroot, local_relpath,
-                                scratch_pool, scratch_pool));
+                                result_pool, scratch_pool));
         }
       else if (status == svn_wc__db_status_deleted)
         {
@@ -9955,26 +9957,7 @@ read_url_txn(const char **url,
                                     scratch_pool,
                                     scratch_pool));
 
-          if (base_del_relpath)
-            {
-              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,
-                                                        wcroot,
-                                                        base_del_relpath,
-                                                        scratch_pool,
-                                                        scratch_pool));
-
-              repos_relpath = svn_relpath_join(
-                                    repos_relpath,
-                                    svn_dirent_skip_ancestor(base_del_relpath,
-                                                             local_relpath),
-                                    scratch_pool);
-            }
-          else
+          if (work_del_relpath)
             {
               /* The parent of the WORKING delete, must be an addition */
               const char *work_relpath = NULL;
@@ -9987,34 +9970,57 @@ read_url_txn(const char **url,
               work_relpath = svn_relpath_dirname(work_del_relpath,
                                                  scratch_pool);
 
-              SVN_ERR(scan_addition(NULL, NULL, &repos_relpath, &repos_id,
+              SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id,
                                     NULL, NULL, NULL, NULL, NULL, NULL,
                                     wcroot, work_relpath,
                                     scratch_pool, scratch_pool));
 
-              repos_relpath = svn_relpath_join(
-                                    repos_relpath,
+              if (repos_relpath)
+                *repos_relpath = svn_relpath_join(
+                                    *repos_relpath,
                                     svn_dirent_skip_ancestor(work_relpath,
                                                              local_relpath),
-                                    scratch_pool);
+                                    result_pool);
+            }
+          else
+            {
+              SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, revision,
+                                                        repos_relpath,
+                                                        repos_id,
+                                                        NULL, NULL, NULL,
+                                                        NULL, NULL, NULL,
+                                                        NULL, NULL, NULL, NULL,
+                                                        wcroot,
+                                                        base_del_relpath,
+                                                        scratch_pool,
+                                                        scratch_pool));
+
+              if (repos_relpath)
+                *repos_relpath = svn_relpath_join(
+                                    *repos_relpath,
+                                    svn_dirent_skip_ancestor(base_del_relpath,
+                                                             local_relpath),
+                                    result_pool);
             }
         }
       else if (status == svn_wc__db_status_excluded)
         {
           const char *parent_relpath;
           const char *name;
-          const char *url2;
 
-          /* Set 'url' to the *full URL* of the parent WC dir,
-           * and 'name' to the *single path component* that is the
-           * basename of this WC directory, so that joining them will result
-           * in the correct full URL. */
+          /* A BASE excluded would have had repository information, so
+             we have a working exclude, which must be below an addition */
+
           svn_relpath_split(&parent_relpath, &name, local_relpath,
                             scratch_pool);
-          SVN_ERR(read_url_txn(&url2, wcroot, parent_relpath,
-                               scratch_pool, scratch_pool));
+          SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL,
+                                NULL, NULL, NULL, NULL, NULL,
+                                wcroot, parent_relpath,
+                                scratch_pool, scratch_pool));
 
-          *url = svn_path_url_add_component2(url2, name, result_pool);
+          if (repos_relpath)
+            *repos_relpath = svn_relpath_join(*repos_relpath, name,
+                                              result_pool);
 
           return SVN_NO_ERROR;
         }
@@ -10026,26 +10032,23 @@ read_url_txn(const char **url,
         }
     }
 
-  SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, NULL, wcroot,
-                                      repos_id, scratch_pool));
-
-  SVN_ERR_ASSERT(repos_root_url != NULL && repos_relpath != NULL);
-  *url = svn_path_url_add_component2(repos_root_url, repos_relpath,
-                                     result_pool);
-
   return SVN_NO_ERROR;
 }
 
 
 svn_error_t *
-svn_wc__db_read_url(const char **url,
-                    svn_wc__db_t *db,
-                    const char *local_abspath,
-                    apr_pool_t *result_pool,
-                    apr_pool_t *scratch_pool)
+svn_wc__db_read_repos_info(svn_revnum_t *revision,
+                           const char **repos_relpath,
+                           const char **repos_root_url,
+                           const char **repos_uuid,
+                           svn_wc__db_t *db,
+                           const char *local_abspath,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
 {
   svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
+  apr_int64_t repos_id = INVALID_REPOS_ID;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -10054,9 +10057,17 @@ svn_wc__db_read_url(const char **url,
                                                 scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_WC__DB_WITH_TXN(read_url_txn(url, wcroot, local_relpath,
-                                   result_pool, scratch_pool),
-                      wcroot);
+  SVN_WC__DB_WITH_TXN4(db_read_repos_info(revision, repos_relpath,
+                                          (repos_root_url || repos_uuid)
+                                            ? &repos_id : NULL,
+                                          wcroot, local_relpath,
+                                          result_pool, scratch_pool),
+                       svn_wc__db_fetch_repos_info(repos_root_url,
+                                                   repos_uuid,
+                                                   wcroot, repos_id,
+                                                   result_pool),
+                       SVN_NO_ERROR, SVN_NO_ERROR,
+                       wcroot);
 
   return SVN_NO_ERROR;
 }
@@ -10898,8 +10909,34 @@ svn_wc__db_read_children_of_working_node
                                              scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  return gather_children2(children, wcroot, local_relpath,
-                          result_pool, scratch_pool);
+  return svn_error_trace(
+          gather_children(children, wcroot, local_relpath,
+                          STMT_SELECT_WORKING_CHILDREN, -1,
+                          result_pool, scratch_pool));
+}
+
+svn_error_t *
+svn_wc__db_base_read_not_present_children(
+                                const apr_array_header_t **children,
+                                svn_wc__db_t *db,
+                                const char *local_abspath,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
+  svn_wc__db_wcroot_t *wcroot;
+  const char *local_relpath;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+                                             local_abspath,
+                                             scratch_pool, scratch_pool));
+  VERIFY_USABLE_WCROOT(wcroot);
+
+  return svn_error_trace(
+          gather_children(children, wcroot, local_relpath,
+                          STMT_SELECT_BASE_NOT_PRESENT_CHILDREN, -1,
+                          result_pool, scratch_pool));
 }
 
 /* Helper for svn_wc__db_node_check_replace().
@@ -11086,6 +11123,7 @@ svn_wc__db_read_children(const apr_array
   VERIFY_USABLE_WCROOT(wcroot);
 
   return gather_children(children, wcroot, local_relpath,
+                         STMT_SELECT_NODE_CHILDREN, -1,
                          result_pool, scratch_pool);
 }
 
@@ -11291,35 +11329,18 @@ determine_repos_info(apr_int64_t *repos_
   return SVN_NO_ERROR;
 }
 
-/* Helper for svn_wc__db_global_commit()
-
-   Makes local_relpath and all its descendants at the same op-depth represent
-   the copy origin repos_id:repos_relpath@revision.
-
-   This code is only valid to fix-up a move from an old location, to a new
-   location during a commit.
-
-   Assumptions:
-     * local_relpath is not the working copy root (can't be moved)
-     * repos_relpath is not the repository root (can't be moved)
-   */
 static svn_error_t *
-moved_descendant_commit(svn_wc__db_wcroot_t *wcroot,
+moved_descendant_collect(apr_hash_t **map,
+                        svn_wc__db_wcroot_t *wcroot,
                         const char *local_relpath,
                         int op_depth,
-                        apr_int64_t repos_id,
-                        const char *repos_relpath,
-                        svn_revnum_t revision,
+                        apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool)
 {
-  apr_hash_t *children;
-  apr_pool_t *iterpool;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
-  apr_hash_index_t *hi;
 
-  SVN_ERR_ASSERT(*local_relpath != '\0'
-                 && *repos_relpath != '\0');
+  *map = NULL;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_MOVED_DESCENDANTS_SRC));
@@ -11331,21 +11352,56 @@ moved_descendant_commit(svn_wc__db_wcroo
   if (! have_row)
     return svn_error_trace(svn_sqlite__reset(stmt));
 
-  children = apr_hash_make(scratch_pool);
-
-  /* First, obtain all moved descendants */
-  /* To keep error handling simple, first cache them in a hashtable */
+  /* Find all moved descendants. Key them on target, because that is
+     always unique */
   while (have_row)
     {
-      const char *src_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool);
-      const char *to_relpath = svn_sqlite__column_text(stmt, 4, scratch_pool);
+      const char *src_relpath = svn_sqlite__column_text(stmt, 1, result_pool);
+      const char *to_relpath = svn_sqlite__column_text(stmt, 4, result_pool);
 
-      svn_hash_sets(children, src_relpath, to_relpath);
+      if (!*map)
+        *map = apr_hash_make(result_pool);
+
+      svn_hash_sets(*map, to_relpath, src_relpath);
 
       SVN_ERR(svn_sqlite__step(&have_row, stmt));
     }
   SVN_ERR(svn_sqlite__reset(stmt));
 
+  return SVN_NO_ERROR;
+}
+
+/* Helper for svn_wc__db_global_commit()
+
+   Makes local_relpath and all its descendants at the same op-depth represent
+   the copy origin repos_id:repos_relpath@revision.
+
+   This code is only valid to fix-up a move from an old location, to a new
+   location during a commit.
+
+   Assumptions:
+     * local_relpath is not the working copy root (can't be moved)
+     * repos_relpath is not the repository root (can't be moved)
+ */
+static svn_error_t *
+moved_descendant_commit(svn_wc__db_wcroot_t *wcroot,
+                        const char *local_relpath,
+                        apr_int64_t repos_id,
+                        const char *repos_relpath,
+                        svn_revnum_t revision,
+                        apr_hash_t *children,
+                        apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool;
+  svn_sqlite__stmt_t *stmt;
+  apr_hash_index_t *hi;
+
+  SVN_ERR_ASSERT(*local_relpath != '\0'
+                 && *repos_relpath != '\0');
+
+  if (!children)
+    return SVN_NO_ERROR;
+
   /* Then update them */
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_COMMIT_UPDATE_ORIGIN));
@@ -11353,11 +11409,12 @@ moved_descendant_commit(svn_wc__db_wcroo
   iterpool = svn_pool_create(scratch_pool);
   for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi))
     {
-      const char *src_relpath = apr_hash_this_key(hi);
-      const char *to_relpath = apr_hash_this_val(hi);
+      const char *src_relpath = apr_hash_this_val(hi);
+      const char *to_relpath = apr_hash_this_key(hi);
       const char *new_repos_relpath;
       int to_op_depth = relpath_depth(to_relpath);
       int affected;
+      apr_hash_t *map;
 
       svn_pool_clear(iterpool);
 
@@ -11384,9 +11441,11 @@ moved_descendant_commit(svn_wc__db_wcroo
       SVN_ERR_ASSERT(affected >= 1); /* If this fails there is no move dest */
 #endif
 
-      SVN_ERR(moved_descendant_commit(wcroot, to_relpath, to_op_depth,
+      SVN_ERR(moved_descendant_collect(&map, wcroot, to_relpath, to_op_depth,
+                                       iterpool, iterpool));
+      SVN_ERR(moved_descendant_commit(wcroot, to_relpath,
                                       repos_id, new_repos_relpath, revision,
-                                      iterpool));
+                                      map, iterpool));
     }
 
   svn_pool_destroy(iterpool);
@@ -11445,7 +11504,6 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
             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,
             svn_boolean_t keep_changelist,
             svn_boolean_t no_unlock,
@@ -11467,6 +11525,7 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
   const char *repos_relpath;
   int op_depth;
   svn_wc__db_status_t old_presence;
+  svn_boolean_t moved_here;
 
     /* If we are adding a file or directory, then we need to get
      repository information from the parent node since "this node" does
@@ -11496,6 +11555,7 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
 
   /* Figure out the new node's kind. It will be whatever is in WORKING_NODE,
      or there will be a BASE_NODE that has it.  */
+  old_presence = svn_sqlite__column_token(stmt_info, 3, presence_map);
   new_kind = svn_sqlite__column_token(stmt_info, 4, kind_map);
 
   /* What will the new depth be?  */
@@ -11514,26 +11574,35 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
                             svn_sqlite__column_text(stmt_info, 2, NULL)) == 0);
     }
 
-  /* Find the appropriate new properties -- ACTUAL overrides any properties
-     in WORKING that arrived as part of a copy/move.
+  if (old_presence != svn_wc__db_status_base_deleted)
+    {
+      /* Find the appropriate new properties -- ACTUAL overrides any properties
+         in WORKING that arrived as part of a copy/move.
 
-     Note: we'll keep them as a big blob of data, rather than
-     deserialize/serialize them.  */
-  if (have_act)
-    prop_blob.data = svn_sqlite__column_blob(stmt_act, 1, &prop_blob.len,
-                                             scratch_pool);
-  if (prop_blob.data == NULL)
-    prop_blob.data = svn_sqlite__column_blob(stmt_info, 14, &prop_blob.len,
-                                             scratch_pool);
-
-  inherited_prop_blob.data = svn_sqlite__column_blob(stmt_info, 16,
-                                                     &inherited_prop_blob.len,
-                                                     scratch_pool);
+         Note: we'll keep them as a big blob of data, rather than
+         deserialize/serialize them.  */
+      if (have_act)
+        prop_blob.data = svn_sqlite__column_blob(stmt_act, 1, &prop_blob.len,
+                                                 scratch_pool);
+      if (prop_blob.data == NULL)
+        prop_blob.data = svn_sqlite__column_blob(stmt_info, 14, &prop_blob.len,
+                                                 scratch_pool);
 
-  if (keep_changelist && have_act)
-    changelist = svn_sqlite__column_text(stmt_act, 0, scratch_pool);
+      inherited_prop_blob.data = svn_sqlite__column_blob(
+                                            stmt_info, 16,
+                                            &inherited_prop_blob.len,
+                                            scratch_pool);
 
-  old_presence = svn_sqlite__column_token(stmt_info, 3, presence_map);
+      if (keep_changelist && have_act)
+        changelist = svn_sqlite__column_text(stmt_act, 0, scratch_pool);
+
+      moved_here = svn_sqlite__column_int(stmt_info, 15);
+    }
+  else
+    {
+      moved_here = FALSE;
+      changelist = NULL;
+    }
 
   /* ### other stuff?  */
 
@@ -11544,6 +11613,24 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
     {
       int affected_rows;
 
+      SVN_ERR_ASSERT(op_depth == relpath_depth(local_relpath));
+
+      /* First clear the moves that we are going to delete in a bit */
+      {
+        apr_hash_t *old_moves;
+        apr_hash_index_t *hi;
+        SVN_ERR(moved_descendant_collect(&old_moves, wcroot, local_relpath, 0,
+                                         scratch_pool, scratch_pool));
+
+        if (old_moves)
+          for (hi = apr_hash_first(scratch_pool, old_moves);
+                hi; hi = apr_hash_next(hi))
+            {
+              SVN_ERR(clear_moved_here(wcroot, apr_hash_this_key(hi),
+                                        scratch_pool));
+            }
+      }
+
       /* This removes all layers of this node and at the same time determines
          if we need to remove shadowed layers below our descendants. */
 
@@ -11576,26 +11663,40 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
          be integrated, they really affect a different op-depth and
          completely different nodes (via a different recursion pattern). */
 
-      /* Collapse descendants of the current op_depth in layer 0 */
-      SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth,
-                                repos_id, repos_relpath, new_revision,
-                                scratch_pool));
+      if (old_presence != svn_wc__db_status_base_deleted)
+        {
+          /* Collapse descendants of the current op_depth to layer 0,
+             this includes moved-from/to clearing */
+          SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth,
+                                    repos_id, repos_relpath, new_revision,
+                                    scratch_pool));
+        }
 
-      /* And make the recorded local moves represent moves of the node we just
-         committed. */
-      SVN_ERR(moved_descendant_commit(wcroot, local_relpath, 0,
+      if (old_presence != svn_wc__db_status_base_deleted)
+        {
+          apr_hash_t *moves = NULL;
+
+          SVN_ERR(moved_descendant_collect(&moves, wcroot, local_relpath, 0,
+                                           scratch_pool, scratch_pool));
+
+          /* And make the recorded local moves represent moves of the node we
+             just committed. */
+          SVN_ERR(moved_descendant_commit(wcroot, local_relpath,
                                       repos_id, repos_relpath, new_revision,
-                                      scratch_pool));
+                                      moves, scratch_pool));
+        }
 
-      /* This node is no longer modified, so no node was moved here */
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_CLEAR_MOVED_TO_FROM_DEST));
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
-                                            local_relpath));
+      if (moved_here)
+        {
+          /* This node is no longer modified, so no node was moved here */
+          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                            STMT_CLEAR_MOVED_TO_FROM_DEST));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
+                                                local_relpath));
 
-      SVN_ERR(svn_sqlite__step_done(stmt));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+        }
     }
-
   /* Update or add the BASE_NODE row with all the new information.  */
 
   if (*local_relpath == '\0')
@@ -11604,38 +11705,56 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
     parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
 
   /* Preserve any incomplete status */
-  new_presence = (old_presence == svn_wc__db_status_incomplete
-                  ? svn_wc__db_status_incomplete
-                  : svn_wc__db_status_normal);
+  if (old_presence != svn_wc__db_status_base_deleted)
+    {
+      new_presence = (old_presence == svn_wc__db_status_incomplete
+                      ? svn_wc__db_status_incomplete
+                      : svn_wc__db_status_normal);
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_APPLY_CHANGES_TO_BASE_NODE));
-  /* symlink_target not yet used */
-  SVN_ERR(svn_sqlite__bindf(stmt, "issisrtstrisnbn",
-                            wcroot->wc_id, local_relpath,
-                            parent_relpath,
-                            repos_id,
-                            repos_relpath,
-                            new_revision,
-                            presence_map, new_presence,
-                            new_depth_str,
-                            kind_map, new_kind,
-                            changed_rev,
-                            changed_date,
-                            changed_author,
-                            prop_blob.data, prop_blob.len));
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_APPLY_CHANGES_TO_BASE_NODE));
+      /* symlink_target not yet used */
+      SVN_ERR(svn_sqlite__bindf(stmt, "issisrtstrisnbn",
+                                wcroot->wc_id, local_relpath,
+                                parent_relpath,
+                                repos_id,
+                                repos_relpath,
+                                new_revision,
+                                presence_map, new_presence,
+                                new_depth_str,
+                                kind_map, new_kind,
+                                changed_rev,
+                                changed_date,
+                                changed_author,
+                                prop_blob.data, prop_blob.len));
 
-  SVN_ERR(svn_sqlite__bind_checksum(stmt, 13, new_checksum,
-                                    scratch_pool));
-  SVN_ERR(svn_sqlite__bind_properties(stmt, 15, new_dav_cache,
-                                      scratch_pool));
-  if (inherited_prop_blob.data != NULL)
-    {
-      SVN_ERR(svn_sqlite__bind_blob(stmt, 17, inherited_prop_blob.data,
-                                    inherited_prop_blob.len));
+      SVN_ERR(svn_sqlite__bind_checksum(stmt, 13, new_checksum,
+                                        scratch_pool));
+      SVN_ERR(svn_sqlite__bind_properties(stmt, 15, new_dav_cache,
+                                          scratch_pool));
+      if (inherited_prop_blob.data != NULL)
+        {
+          SVN_ERR(svn_sqlite__bind_blob(stmt, 17, inherited_prop_blob.data,
+                                        inherited_prop_blob.len));
+        }
+
+      SVN_ERR(svn_sqlite__step_done(stmt));
     }
+  else
+    {
+      struct insert_base_baton_t ibb;
+      blank_ibb(&ibb);
 
-  SVN_ERR(svn_sqlite__step_done(stmt));
+      ibb.repos_id = repos_id;
+      ibb.status = svn_wc__db_status_not_present;
+      ibb.kind = new_kind;
+      ibb.repos_relpath = repos_relpath;
+      ibb.revision = new_revision;
+
+      SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
+
+      keep_changelist = FALSE; /* Nothing there */
+    }
 
   if (have_act)
     {
@@ -11663,23 +11782,21 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
         }
     }
 
-  if (new_kind == svn_node_dir)
-    {
-      /* When committing a directory, we should have its new children.  */
-      /* ### one day. just not today.  */
-#if 0
-      SVN_ERR_ASSERT(new_children != NULL);
-#endif
-
-      /* ### process the children  */
-    }
-
   if (!no_unlock)
     {
       svn_sqlite__stmt_t *lock_stmt;
+      svn_boolean_t op_root = (op_depth > 0
+                               && (relpath_depth(local_relpath) == op_depth));
 
+      /* If we are committing an add of a delete, we can assume we own
+         all locks at or below REPOS_RELPATH (or the server would have
+         denied the commit). As we must have passed these to the server
+         we can now safely remove them.
+       */
       SVN_ERR(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb,
-                                        STMT_DELETE_LOCK_RECURSIVELY));
+                                        op_root
+                                          ? STMT_DELETE_LOCK_RECURSIVELY
+                                          : STMT_DELETE_LOCK));
       SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath));
       SVN_ERR(svn_sqlite__step_done(lock_stmt));
     }
@@ -11699,7 +11816,6 @@ svn_wc__db_global_commit(svn_wc__db_t *d
                          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,
                          svn_boolean_t keep_changelist,
                          svn_boolean_t no_unlock,
@@ -11711,7 +11827,6 @@ svn_wc__db_global_commit(svn_wc__db_t *d
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
   SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_revision));
-  SVN_ERR_ASSERT(new_checksum == NULL || new_children == NULL);
 
   SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
                               local_abspath, scratch_pool, scratch_pool));
@@ -11720,7 +11835,7 @@ svn_wc__db_global_commit(svn_wc__db_t *d
   SVN_WC__DB_WITH_TXN(
     commit_node(wcroot, local_relpath,
                 new_revision, changed_revision, changed_date, changed_author,
-                new_checksum, new_children, new_dav_cache, keep_changelist,
+                new_checksum, new_dav_cache, keep_changelist,
                 no_unlock, work_items, scratch_pool),
     wcroot);
 
@@ -11967,11 +12082,11 @@ bump_node_revision(svn_wc__db_wcroot_t *
           || (child_info->status == svn_wc__db_status_server_excluded &&
               child_info->revnum != new_rev))
         {
-          SVN_ERR(db_base_remove(wcroot,
-                                 child_local_relpath,
-                                 db, FALSE, FALSE, FALSE,
-                                 SVN_INVALID_REVNUM,
-                                 NULL, NULL, scratch_pool));
+          svn_sqlite__stmt_t *stmt;
+          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_DELETE_BASE_NODE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, 
child_local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
           continue;
         }
 
@@ -13055,191 +13170,6 @@ svn_wc__db_upgrade_begin(svn_sqlite__db_
   return SVN_NO_ERROR;
 }
 
-
-svn_error_t *
-svn_wc__db_upgrade_apply_dav_cache(svn_sqlite__db_t *sdb,
-                                   const char *dir_relpath,
-                                   apr_hash_t *cache_values,
-                                   apr_pool_t *scratch_pool)
-{
-  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  apr_int64_t wc_id;
-  apr_hash_index_t *hi;
-  svn_sqlite__stmt_t *stmt;
-
-  SVN_ERR(svn_wc__db_util_fetch_wc_id(&wc_id, sdb, iterpool));
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                    STMT_UPDATE_BASE_NODE_DAV_CACHE));
-
-  /* Iterate over all the wcprops, writing each one to the wc_db. */
-  for (hi = apr_hash_first(scratch_pool, cache_values);
-       hi;
-       hi = apr_hash_next(hi))
-    {
-      const char *name = apr_hash_this_key(hi);
-      apr_hash_t *props = apr_hash_this_val(hi);
-      const char *local_relpath;
-
-      svn_pool_clear(iterpool);
-
-      local_relpath = svn_relpath_join(dir_relpath, name, iterpool);
-
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
-      SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, iterpool));
-      SVN_ERR(svn_sqlite__step_done(stmt));
-    }
-
-  svn_pool_destroy(iterpool);
-
-  return SVN_NO_ERROR;
-}
-
-
-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,
-                               apr_hash_t *working_props,
-                               int original_format,
-                               apr_int64_t wc_id,
-                               apr_pool_t *scratch_pool)
-{
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  int top_op_depth = -1;
-  int below_op_depth = -1;
-  svn_wc__db_status_t top_presence;
-  svn_wc__db_status_t below_presence;
-  int affected_rows;
-
-  /* ### working_props: use set_props_txn.
-     ### if working_props == NULL, then skip. what if they equal the
-     ### pristine props? we should probably do the compare here.
-     ###
-     ### base props go into WORKING_NODE if avail, otherwise BASE.
-     ###
-     ### revert only goes into BASE. (and WORKING better be there!)
-
-     Prior to 1.4.0 (ORIGINAL_FORMAT < 8), REVERT_PROPS did not exist. If a
-     file was deleted, then a copy (potentially with props) was disallowed
-     and could not replace the deletion. An addition *could* be performed,
-     but that would never bring its own props.
-
-     1.4.0 through 1.4.5 created the concept of REVERT_PROPS, but had a
-     bug in svn_wc_add_repos_file2() whereby a copy-with-props did NOT
-     construct a REVERT_PROPS if the target had no props. Thus, reverting
-     the delete/copy would see no REVERT_PROPS to restore, leaving the
-     props from the copy source intact, and appearing as if they are (now)
-     the base props for the previously-deleted file. (wc corruption)
-
-     1.4.6 ensured that an empty REVERT_PROPS would be established at all
-     times. See issue 2530, and r861670 as starting points.
-
-     We will use ORIGINAL_FORMAT and SVN_WC__NO_REVERT_FILES to determine
-     the handling of our inputs, relative to the state of this node.
-  */
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_NODE_INFO));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  if (have_row)
-    {
-      top_op_depth = svn_sqlite__column_int(stmt, 0);
-      top_presence = svn_sqlite__column_token(stmt, 3, presence_map);
-      SVN_ERR(svn_sqlite__step(&have_row, stmt));
-      if (have_row)
-        {
-          below_op_depth = svn_sqlite__column_int(stmt, 0);
-          below_presence = svn_sqlite__column_token(stmt, 3, presence_map);
-        }
-    }
-  SVN_ERR(svn_sqlite__reset(stmt));
-
-  /* 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
-      && top_op_depth != -1
-      && top_presence == svn_wc__db_status_normal
-      && below_op_depth != -1
-      && below_presence != svn_wc__db_status_not_present)
-    {
-      /* There should be REVERT_PROPS, so it appears that we just ran into
-         the described bug. Sigh.  */
-      return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
-                               _("The properties of '%s' are in an "
-                                 "indeterminate state and cannot be "
-                                 "upgraded. See issue #2530."),
-                               svn_dirent_local_style(
-                                 svn_dirent_join(dir_abspath, local_relpath,
-                                                 scratch_pool), scratch_pool));
-    }
-
-  /* Need at least one row, or two rows if there are revert props */
-  if (top_op_depth == -1
-      || (below_op_depth == -1 && revert_props))
-    return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
-                             _("Insufficient NODES rows for '%s'"),
-                             svn_dirent_local_style(
-                               svn_dirent_join(dir_abspath, local_relpath,
-                                               scratch_pool), scratch_pool));
-
-  /* one row, base props only: upper row gets base props
-     two rows, base props only: lower row gets base props
-     two rows, revert props only: lower row gets revert props
-     two rows, base and revert props: upper row gets base, lower gets revert */
-
-
-  if (revert_props || below_op_depth == -1)
-    {
-      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                        STMT_UPDATE_NODE_PROPS));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isd",
-                                wc_id, local_relpath, top_op_depth));
-      SVN_ERR(svn_sqlite__bind_properties(stmt, 4, base_props, scratch_pool));
-      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
-
-      SVN_ERR_ASSERT(affected_rows == 1);
-    }
-
-  if (below_op_depth != -1)
-    {
-      apr_hash_t *props = revert_props ? revert_props : base_props;
-
-      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                        STMT_UPDATE_NODE_PROPS));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isd",
-                                wc_id, local_relpath, below_op_depth));
-      SVN_ERR(svn_sqlite__bind_properties(stmt, 4, props, scratch_pool));
-      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
-
-      SVN_ERR_ASSERT(affected_rows == 1);
-    }
-
-  /* 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)
-    {
-      SVN_ERR(set_actual_props(wc_id, local_relpath, working_props,
-                               sdb, scratch_pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *
 svn_wc__db_upgrade_insert_external(svn_wc__db_t *db,
                                    const char *local_abspath,
@@ -13315,28 +13245,6 @@ svn_wc__db_upgrade_insert_external(svn_w
 }
 
 svn_error_t *
-svn_wc__db_upgrade_get_repos_id(apr_int64_t *repos_id,
-                                svn_sqlite__db_t *sdb,
-                                const char *repos_root_url,
-                                apr_pool_t *scratch_pool)
-{
-  svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_REPOSITORY));
-  SVN_ERR(svn_sqlite__bindf(stmt, "s", repos_root_url));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-
-  if (!have_row)
-    return svn_error_createf(SVN_ERR_WC_DB_ERROR, svn_sqlite__reset(stmt),
-                             _("Repository '%s' not found in the database"),
-                             repos_root_url);
-
-  *repos_id = svn_sqlite__column_int64(stmt, 0);
-  return svn_error_trace(svn_sqlite__reset(stmt));
-}
-
-svn_error_t *
 svn_wc__db_wq_add_internal(svn_wc__db_wcroot_t *wcroot,
                            const svn_skel_t *work_item,
                            apr_pool_t *scratch_pool)
@@ -13991,6 +13899,7 @@ svn_wc__db_read_kind(svn_node_kind_t *ki
   const char *local_relpath;
   svn_sqlite__stmt_t *stmt_info;
   svn_boolean_t have_info;
+  svn_wc__db_status_t status;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
@@ -14022,12 +13931,27 @@ svn_wc__db_read_kind(svn_node_kind_t *ki
         }
     }
 
+  status = svn_sqlite__column_token(stmt_info, 3, presence_map);
+
+  if (show_deleted && status == svn_wc__db_status_base_deleted)
+    {
+      /* Let's return the kind of what is really deleted insead of what
+         we have cached in the base-deleted record */
+
+      SVN_ERR(svn_sqlite__step(&have_info, stmt_info));
+
+      if (!have_info)
+        {
+          /* No lower layer deleted? Database inconsistency! */
+          *kind = svn_node_none;
+          return svn_error_trace(svn_sqlite__reset(stmt_info));
+        }
+    }
+
   if (!(show_deleted && show_hidden))
     {
       int op_depth = svn_sqlite__column_int(stmt_info, 0);
       svn_boolean_t report_none = FALSE;
-      svn_wc__db_status_t status = svn_sqlite__column_token(stmt_info, 3,
-                                                            presence_map);
 
       if (op_depth > 0)
         SVN_ERR(convert_to_working_status(&status, status));
@@ -14063,38 +13987,6 @@ svn_wc__db_read_kind(svn_node_kind_t *ki
   return svn_error_trace(svn_sqlite__reset(stmt_info));
 }
 
-
-svn_error_t *
-svn_wc__db_node_hidden(svn_boolean_t *hidden,
-                       svn_wc__db_t *db,
-                       const char *local_abspath,
-                       apr_pool_t *scratch_pool)
-{
-  svn_wc__db_wcroot_t *wcroot;
-  const char *local_relpath;
-  svn_wc__db_status_t status;
-
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
-  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(read_info(&status, NULL, NULL, NULL, NULL, NULL,
-                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                    NULL, NULL, NULL,
-                    wcroot, local_relpath,
-                    scratch_pool, scratch_pool));
-
-  *hidden = (status == svn_wc__db_status_server_excluded
-             || status == svn_wc__db_status_not_present
-             || status == svn_wc__db_status_excluded);
-
-  return SVN_NO_ERROR;
-}
-
-
 svn_error_t *
 svn_wc__db_is_wcroot(svn_boolean_t *is_wcroot,
                      svn_wc__db_t *db,
@@ -14876,6 +14768,87 @@ svn_wc__db_temp_op_start_directory_updat
   return SVN_NO_ERROR;
 }
 
+/* Helper for svn_wc__db_op_make_copy_internal */
+static svn_error_t *
+db_move_moved_to(svn_wc__db_wcroot_t *wcroot,
+                 const char *src1_relpath,
+                 int src1_op_depth,
+                 const char *src2_relpath,
+                 int src2_op_depth,
+                 const char *dst_relpath,
+                 apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  int affected_rows;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                     STMT_UPDATE_MOVED_TO_RELPATH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                            src1_relpath, src1_op_depth));
+  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+  if (affected_rows == 1)
+    {
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                     STMT_UPDATE_MOVED_TO_RELPATH));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isds", wcroot->wc_id,
+                                src2_relpath, src2_op_depth,
+                                dst_relpath));
+      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+    }
+  if (affected_rows != 1)
+    return svn_error_create(SVN_ERR_WC_PATH_NOT_FOUND, NULL, NULL);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+db_move_moved_to_down_recursive(svn_wc__db_wcroot_t *wcroot,
+                                const char *local_relpath,
+                                int new_shadow_layer,
+                                apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                        STMT_SELECT_MOVED_DESCENDANTS_SRC));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+                            new_shadow_layer));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  while (have_row)
+    {
+      int del_op_depth;
+      const char *src_relpath;
+      const char *dst_relpath;
+      svn_error_t *err;
+
+      svn_pool_clear(iterpool);
+
+      del_op_depth = svn_sqlite__column_int(stmt, 0);
+      src_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
+      dst_relpath = svn_sqlite__column_text(stmt, 4, iterpool);
+
+      err = svn_error_trace(
+               db_move_moved_to(
+                             wcroot,
+                             src_relpath, del_op_depth,
+                             src_relpath, new_shadow_layer,
+                             dst_relpath, iterpool));
+
+      if (err)
+        return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  return SVN_NO_ERROR;
+}
+
 
 /* The body of svn_wc__db_temp_op_make_copy().  This is
    used by the update editor when deleting a base node tree would be a
@@ -14913,98 +14886,149 @@ svn_wc__db_temp_op_start_directory_updat
 static svn_error_t *
 make_copy_txn(svn_wc__db_wcroot_t *wcroot,
               const char *local_relpath,
-              int op_depth,
+              apr_int64_t last_repos_id,
+              const char *last_repos_relpath,
+              svn_revnum_t last_revision,
+              int last_op_depth,
+              svn_boolean_t shadowed,
+              int root_shadow_depth,
               apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
-  svn_boolean_t add_working_base_deleted = FALSE;
-  svn_boolean_t remove_working = FALSE;
-  const apr_array_header_t *children;
-  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  int i;
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                    STMT_SELECT_LOWEST_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  svn_boolean_t have_row = FALSE;
+  svn_revnum_t revision;
+  apr_int64_t repos_id;
+  const char *repos_relpath;
+  svn_node_kind_t kind;
+  int op_depth = relpath_depth(local_relpath);
 
-  if (have_row)
+  if (last_op_depth != op_depth)
     {
-      svn_wc__db_status_t working_status;
-      int working_op_depth;
-
-      working_status = svn_sqlite__column_token(stmt, 1, presence_map);
-      working_op_depth = svn_sqlite__column_int(stmt, 0);
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_SELECT_DEPTH_NODE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+                                op_depth));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
       SVN_ERR(svn_sqlite__reset(stmt));
+      if (have_row)
+        shadowed = TRUE;
+    }
 
-      SVN_ERR_ASSERT(working_status == svn_wc__db_status_normal
-                     || working_status == svn_wc__db_status_base_deleted
-                     || working_status == svn_wc__db_status_not_present
-                     || working_status == svn_wc__db_status_incomplete);
+  SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &kind, &revision,
+                                            &repos_relpath, &repos_id, NULL,
+                                            NULL, NULL, NULL, NULL, NULL, NULL,
+                                            NULL, NULL, NULL,
+                                            wcroot, local_relpath,
+                                            scratch_pool, scratch_pool));
 
-      /* Only change nodes in the layers where we are creating the copy.
-         Deletes in higher layers will just apply to the copy */
-      if (working_op_depth <= op_depth)
-        {
-          add_working_base_deleted = TRUE;
+  if (last_repos_relpath
+      && repos_id == last_repos_id
+      && revision == last_revision)
+    {
+      const char *name = svn_relpath_skip_ancestor(last_repos_relpath,
+                                                   repos_relpath);
 
-          if (working_status == svn_wc__db_status_base_deleted)
-            remove_working = TRUE;
-        }
+      if (strcmp(name, svn_relpath_basename(local_relpath, NULL)) == 0)
+        op_depth = last_op_depth;
     }
-  else
-    SVN_ERR(svn_sqlite__reset(stmt));
 
-  if (remove_working)
+  /* Can we add a new copy node at the wanted op-depth? */
+  if (!have_row || op_depth == last_op_depth)
     {
-      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__step_done(stmt));
-    }
+      int i;
 
-  if (add_working_base_deleted)
-    {
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_INSERT_DELETE_FROM_BASE));
+      SVN_ERR(svn_sqlite__get_statement(

[... 496 lines stripped ...]

Reply via email to