Author: rhuijben
Date: Wed Feb 18 22:15:50 2015
New Revision: 1660742

URL: http://svn.apache.org/r1660742
Log:
Fix svn_wc__db_op_make_copy_internal()'s handling of mixed revision BASE trees.

This fixes some issues around tree conflict handling, and improves
database consistency.

* build/transform_sql.py
  (process_file): Allow passing columns and binding variables as argument of
    IS_STRICT_DESCENDANT_OF, like the other macros.

* subversion/libsvn_wc/wc-checks.sql
  (STMT_STATIC_VERIFY): Add documentation to the older statements. Extend.

* subversion/libsvn_wc/wc-queries.sql
  (STMT_DELETE_WORKING_BASE_DELETE): Split into non-recursive...
  (STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE): ... and recursive variants.
  (STMT_INSERT_WORKING_NODE_FROM_BASE_COPY): Allow replacing nodes, and
    handle moved_to when doing that.

* subversion/libsvn_wc/wc_db.c
  (db_base_remove): Update caller.
  (make_copy_txn): Add recursion arguments to determine when a new op-depth
    is needed. Simplify code, by moving the initial shadowing to the calling
    function.
  (make_copy_move_moved_to): New function.
  (svn_wc__db_op_make_copy_internal): Update caller. Shadow all nodes with
    base-deleted before calling make_copy_txn. Move moved-to information
    to this layer.

* subversion/tests/cmdline/tree_conflict_tests.py
  (update_delete_mixed_rev): Remove XFail. Tweak status value.

* subversion/tests/libsvn_wc/op-depth-test.c
  (make_copy_mixed): New function. Tests svn_wc__db_op_make_copy_internal.
   make_copy_and_delete_mixed): New functions. Tests svn_wc__db_base_remove
     and shows an existing issue with move handling on base-delete.
  (test_list): Add new items.

Modified:
    subversion/trunk/build/transform_sql.py
    subversion/trunk/subversion/libsvn_wc/wc-checks.sql
    subversion/trunk/subversion/libsvn_wc/wc-queries.sql
    subversion/trunk/subversion/libsvn_wc/wc_db.c
    subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py
    subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c

Modified: subversion/trunk/build/transform_sql.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/build/transform_sql.py?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/build/transform_sql.py (original)
+++ subversion/trunk/build/transform_sql.py Wed Feb 18 22:15:50 2015
@@ -140,7 +140,7 @@ class Processor(object):
 
       # '/'+1 == '0'
       line = re.sub(
-            r'IS_STRICT_DESCENDANT_OF[(]([A-Za-z_.]+), ([?][0-9]+)[)]',
+            r'IS_STRICT_DESCENDANT_OF[(]([?]?[A-Za-z0-9_.]+), 
([?]?[A-Za-z0-9_.]+)[)]',
             r"(((\1) > (CASE (\2) WHEN '' THEN '' ELSE (\2) || '/' END))" +
             r" AND ((\1) < CASE (\2) WHEN '' THEN X'FFFF' ELSE (\2) || '0' 
END))",
             line)

Modified: subversion/trunk/subversion/libsvn_wc/wc-checks.sql
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-checks.sql?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-checks.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-checks.sql Wed Feb 18 22:15:50 2015
@@ -76,6 +76,8 @@ BEGIN
 END;
 
 -- STMT_STATIC_VERIFY
+/* A parent node must exist for every normal node except the root.
+   That node must exist at a lower or equal op-depth */
 SELECT local_relpath, op_depth, 'SV001: No ancestor in NODES'
 FROM nodes n WHERE local_relpath != ''
  AND file_external IS NULL
@@ -86,6 +88,8 @@ FROM nodes n WHERE local_relpath != ''
 
 UNION ALL
 
+/* All ACTUAL nodes must have an equivalent NODE in NODES
+   or be only one level deep (delete-delete tc) */
 SELECT local_relpath, -1, 'SV002: No ancestor in ACTUAL'
 FROM actual_node a WHERE local_relpath != ''
  AND NOT EXISTS(SELECT 1 from nodes i
@@ -96,7 +100,8 @@ FROM actual_node a WHERE local_relpath !
                   AND i.local_relpath=a.local_relpath)
 
 UNION ALL
-
+/* Verify if the ACTUAL data makes sense for the related node.
+   Only conflict data is valid if there is none */
 SELECT a.local_relpath, -1, 'SV003: Bad or Unneeded actual data'
 FROM actual_node a
 LEFT JOIN nodes n on n.wc_id = a.wc_id AND n.local_relpath = a.local_relpath
@@ -111,7 +116,8 @@ WHERE (a.properties IS NOT NULL
                   AND i.local_relpath=a.parent_relpath)
 
 UNION ALL
-
+/* If a node is not present in the working copy (normal, add, copy) it doesn't
+   have revision details stored on this record */
 SELECT local_relpath, op_depth, 'SV004: Unneeded node data'
 FROM nodes
 WHERE presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
@@ -129,7 +135,8 @@ AND (properties IS NOT NULL
      OR inherited_props IS NOT NULL)
 
 UNION ALL
-
+/* base-deleted nodes don't have a repository location. They are just
+   shadowing without a replacement */
 SELECT local_relpath, op_depth, 'SV005: Unneeded base-deleted node data'
 FROM nodes
 WHERE presence IN (MAP_BASE_DELETED)
@@ -138,7 +145,7 @@ AND (repos_id IS NOT NULL
      OR revision IS NOT NULL)
 
 UNION ALL
-
+/* Verify if type specific data is set (or not set for wrong type) */
 SELECT local_relpath, op_depth, 'SV006: Kind specific data invalid on normal'
 FROM nodes
 WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
@@ -157,7 +164,8 @@ AND (kind IS NULL
                                       ELSE symlink_target IS NOT NULL END))
 
 UNION ALL
-
+/* Local-adds are always their own operation (read: they don't have
+   op-depth descendants, nor are op-depth descendants */
 SELECT local_relpath, op_depth, 'SV007: Invalid op-depth for local add'
 FROM nodes
 WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
@@ -165,7 +173,9 @@ WHERE presence IN (MAP_NORMAL, MAP_INCOM
   AND op_depth != relpath_depth(local_relpath)
 
 UNION ALL
-
+/* op-depth descendants are only valid if they have a direct parent
+   node at the same op-depth. Only certain types allow further
+   descendants */
 SELECT local_relpath, op_depth, 'SV008: Node missing ancestor'
 FROM nodes n
 WHERE op_depth < relpath_depth(local_relpath)
@@ -174,11 +184,12 @@ WHERE op_depth < relpath_depth(local_rel
                  WHERE p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath
                    AND p.op_depth=n.op_depth
                    AND (p.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
-                        OR (p.presence = MAP_BASE_DELETED
+                        OR (p.presence IN (MAP_BASE_DELETED, MAP_NOT_PRESENT)
                             AND n.presence = MAP_BASE_DELETED)))
 
-UNION all
-
+UNION ALL
+/* Present op-depth descendants have the repository location implied by their
+   ancestor */
 SELECT n.local_relpath, n.op_depth, 'SV009: Copied descendant mismatch'
 FROM nodes n
 JOIN nodes p
@@ -188,11 +199,65 @@ WHERE n.op_depth > 0 AND n.presence IN (
    AND (n.repos_id != p.repos_id
         OR n.repos_path !=
            RELPATH_SKIP_JOIN(n.parent_relpath, p.repos_path, n.local_relpath)
-        OR n.revision != p.revision)
-
-UNION all
+        OR n.revision != p.revision
+        OR p.kind != MAP_DIR
+        OR n.moved_here != p.moved_here)
 
+UNION ALL
+/* Only certain presence values are valid as op-root.
+   Note that the wc-root always has presence normal or incomplete */
 SELECT n.local_relpath, n.op_depth, 'SV010: Invalid op-root presence'
 FROM nodes n
 WHERE n.op_depth = relpath_depth(local_relpath)
   AND presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE, MAP_BASE_DELETED)
+
+UNION ALL
+/* If a node is shadowed, all its present op-depth descendants
+   must be shadowed at the same op-depth as well */
+SELECT n.local_relpath, n.op_depth, 'SV011: Incomplete shadowing'
+FROM nodes n
+JOIN nodes s ON s.wc_id=n.wc_id AND s.local_relpath=n.local_relpath
+ AND s.op_depth = relpath_depth(s.local_relpath)
+ AND s.op_depth = (SELECT MIN(op_depth) FROM nodes d
+                   WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
+                     AND d.op_depth > n.op_depth)
+WHERE n.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+  AND EXISTS(SELECT 1
+             FROM nodes dn
+             WHERE dn.wc_id=n.wc_id AND dn.op_depth=n.op_depth
+               AND dn.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+               AND IS_STRICT_DESCENDANT_OF(dn.local_relpath, n.local_relpath)
+               AND dn.file_external IS NULL
+               AND NOT EXISTS(SELECT 1
+                              FROM nodes ds
+                              WHERE ds.wc_id=n.wc_id AND ds.op_depth=s.op_depth
+                                AND ds.local_relpath=dn.local_relpath))
+
+UNION ALL
+/* A base-delete is only valid if it directly deletes a present node */
+SELECT s.local_relpath, s.op_depth, 'SV012: Invalid base-delete'
+FROM nodes s
+LEFT JOIN nodes n ON n.wc_id=s.wc_id AND n.local_relpath=s.local_relpath
+ AND n.op_depth = (SELECT MAX(op_depth) FROM nodes d
+                   WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
+                     AND d.op_depth < s.op_depth)
+WHERE s.presence = MAP_BASE_DELETED
+  AND n.presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
+
+UNION ALL
+
+SELECT d.local_relpath, d.op_depth, 'SV013: Moved here without origin'
+FROM nodes d
+WHERE d.op_depth = relpath_depth(d.local_relpath)
+  AND d.moved_here = 1
+  AND NOT EXISTS(SELECT 1 FROM nodes s
+                 WHERE s.wc_id = d.wc_id AND s.moved_to = d.local_relpath)
+
+UNION ALL
+
+SELECT s.local_relpath, s.op_depth, 'SV014: Moved to without target'
+FROM nodes s
+WHERE s.moved_to IS NOT NULL
+  AND NOT EXISTS(SELECT 1 FROM nodes d
+                 WHERE d.wc_id = s.wc_id AND d.local_relpath = s.moved_to
+                   AND d.moved_here =1 AND d.repos_path IS NOT NULL)
\ No newline at end of file

Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Wed Feb 18 22:15:50 
2015
@@ -233,6 +233,16 @@ WHERE wc_id = ?1 AND IS_STRICT_DESCENDAN
 
 -- STMT_DELETE_WORKING_BASE_DELETE
 DELETE FROM nodes
+WHERE wc_id = ?1 AND local_relpath = ?2
+  AND presence = MAP_BASE_DELETED
+  AND op_depth > ?3
+  AND op_depth = (SELECT MIN(op_depth) FROM nodes n
+                    WHERE n.wc_id = ?1
+                      AND n.local_relpath = nodes.local_relpath
+                      AND op_depth > ?3)
+
+-- STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE
+DELETE FROM nodes
 WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
   AND presence = MAP_BASE_DELETED
   AND op_depth > ?3
@@ -1023,15 +1033,17 @@ WHERE wc_id = ?1
 ORDER BY local_relpath
 
 -- STMT_INSERT_WORKING_NODE_FROM_BASE_COPY
-INSERT INTO nodes (
+INSERT OR REPLACE INTO nodes (
     wc_id, local_relpath, op_depth, parent_relpath, repos_id, repos_path,
     revision, presence, depth, kind, changed_revision, changed_date,
     changed_author, checksum, properties, translated_size, last_mod_time,
-    symlink_target )
+    symlink_target, moved_to )
 SELECT wc_id, local_relpath, ?3 /*op_depth*/, parent_relpath, repos_id,
     repos_path, revision, presence, depth, kind, changed_revision,
     changed_date, changed_author, checksum, properties, translated_size,
-    last_mod_time, symlink_target
+    last_mod_time, symlink_target,
+    (SELECT moved_to FROM nodes
+     WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3) moved_to
 FROM nodes
 WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = 0
 

Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Wed Feb 18 22:15:50 2015
@@ -2410,8 +2410,9 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
     }
   if (keep_working)
     {
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_WORKING_BASE_DELETE));
+      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));
     }
@@ -15010,95 +15011,163 @@ 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,
               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);
-
-      /* 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;
+  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));
 
-          if (working_status == svn_wc__db_status_base_deleted)
-            remove_working = 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 (strcmp(name, svn_relpath_basename(local_relpath, NULL)) == 0)
+        op_depth = last_op_depth;
     }
-  else
-    SVN_ERR(svn_sqlite__reset(stmt));
 
-  if (remove_working)
+  /* Insert a not-present node to mark that we don't know what exists
+     here */
+  if (last_op_depth > 0 && last_op_depth != 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));
+      insert_working_baton_t iwb;
+
+      blank_iwb(&iwb);
+      iwb.presence = svn_wc__db_status_not_present;
+      iwb.op_depth = last_op_depth;
+
+      iwb.original_repos_id = repos_id;
+      iwb.original_repos_relpath = repos_relpath;
+      iwb.original_revnum = revision;
+      iwb.kind = kind;
+
+      SVN_ERR(insert_working_node(&iwb, wcroot, local_relpath, scratch_pool));
     }
 
-  if (add_working_base_deleted)
+  /* 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_INSERT_DELETE_FROM_BASE));
+      int i;
+
+      SVN_ERR(svn_sqlite__get_statement(
+                    &stmt, wcroot->sdb,
+                    STMT_INSERT_WORKING_NODE_FROM_BASE_COPY));
       SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
                                 op_depth));
       SVN_ERR(svn_sqlite__step_done(stmt));
+
+      if (shadowed)
+        SVN_ERR(db_extend_parent_delete(wcroot, local_relpath, kind,
+                                        op_depth, scratch_pool));
+
+      if (kind == svn_node_dir)
+        {
+          const apr_array_header_t *children;
+          apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+          SVN_ERR(gather_repo_children(&children, wcroot, local_relpath,
+                                        0, scratch_pool, iterpool));
+
+          for (i = 0; i < children->nelts; i++)
+            {
+              const char *name = APR_ARRAY_IDX(children, i, const char *);
+              const char *copy_relpath;
+
+              svn_pool_clear(iterpool);
+
+              copy_relpath = svn_relpath_join(local_relpath, name, iterpool);
+
+              SVN_ERR(make_copy_txn(wcroot, copy_relpath,
+                                    repos_id, repos_relpath, revision,
+                                    op_depth, shadowed, scratch_pool));
+            }
+          svn_pool_destroy(iterpool);
+        }
     }
   else
     {
+      /* Auch... we can't make a copy of whatever comes deeper, as this
+         op-depth is already filled by something else. Let's hope
+         the user doesn't mind.
+
+         Luckily we know that the moves are already moved to the shadowing
+         layer, so we can just remove dangling base-deletes if there are
+         any.
+       */
+      /* BASE_DELETED may be at op_depth, so let's use last_op_depth! */
+
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                      
STMT_INSERT_WORKING_NODE_FROM_BASE_COPY));
+                    STMT_DELETE_WORKING_BASE_DELETE));
       SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
-                                op_depth));
+                                last_op_depth));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+      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,
+                                last_op_depth));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
 
-  /* Get the BASE children, as WORKING children don't need modifications */
-  SVN_ERR(gather_repo_children(&children, wcroot, local_relpath,
-                               0, scratch_pool, iterpool));
-
-  for (i = 0; i < children->nelts; i++)
-    {
-      const char *name = APR_ARRAY_IDX(children, i, const char *);
-      const char *copy_relpath;
-
-      svn_pool_clear(iterpool);
+  return SVN_NO_ERROR;
+}
 
-      copy_relpath = svn_relpath_join(local_relpath, name, iterpool);
+/* Helper for svn_wc__db_op_make_copy_internal */
+static svn_error_t *
+make_copy_move_moved_to(svn_wc__db_wcroot_t *wcroot,
+                        const char *local_relpath,
+                        int cur_op_depth,
+                        int new_op_depth,
+                        const char *moved_to,
+                        apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
 
-      SVN_ERR(make_copy_txn(wcroot, copy_relpath, op_depth, iterpool));
-    }
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_UPDATE_MOVED_TO_RELPATH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                            local_relpath, cur_op_depth));
+  SVN_ERR(svn_sqlite__step_done(stmt));
 
-  svn_pool_destroy(iterpool);
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_UPDATE_MOVED_TO_RELPATH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isds", wcroot->wc_id,
+                            local_relpath, new_op_depth, moved_to));
+  SVN_ERR(svn_sqlite__step_done(stmt));
 
   return SVN_NO_ERROR;
 }
 
+
 svn_error_t *
 svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot,
                                  const char *local_relpath,
@@ -15140,12 +15209,56 @@ svn_wc__db_op_make_copy_internal(svn_wc_
     }
   else
     {
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+      svn_error_t *err = NULL;
+      int affected_rows;
+
+      op_depth = relpath_depth(local_relpath);
       /* We don't allow copies to contain server-excluded nodes;
          the update editor is going to have to bail out. */
-      SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath, 
scratch_pool));
+      SVN_ERR(catch_copy_of_server_excluded(wcroot, local_relpath, iterpool));
+
+      /* Insert a shadowing layer */
+      SVN_ERR(svn_sqlite__get_statement(
+                        &stmt, wcroot->sdb,
+                        STMT_INSERT_DELETE_FROM_NODE_RECURSIVE));
+
+      /* As we are keeping whatever is below, move the*/
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "isdd",
+                                wcroot->wc_id, local_relpath,
+                                0, op_depth));
+      SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+      SVN_ERR_ASSERT(affected_rows > 0);
+
+      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,
+                                op_depth));
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+      while (have_row && !err)
+        {
+          err = make_copy_move_moved_to(
+                              wcroot,
+                              svn_sqlite__column_text(stmt, 1, iterpool),
+                              svn_sqlite__column_int(stmt, 0),
+                              op_depth,
+                              svn_sqlite__column_text(stmt, 4, iterpool),
+                              iterpool);
+
+          SVN_ERR(svn_sqlite__step(&have_row, stmt));
+        }
+
+      SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+
 
       SVN_ERR(make_copy_txn(wcroot, local_relpath,
-                            relpath_depth(local_relpath), scratch_pool));
+                            INVALID_REPOS_ID, NULL, SVN_INVALID_REVNUM,
+                            relpath_depth(local_relpath), FALSE, 
scratch_pool));
     }
 
   if (conflicts)

Modified: subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/tree_conflict_tests.py Wed Feb 18 
22:15:50 2015
@@ -1449,7 +1449,6 @@ def update_dir_with_not_present(sbox):
   run_and_verify_svn(None, [],
                      'ci', '-m', '', wc_dir)
 
-@XFail()
 def update_delete_mixed_rev(sbox):
   "update that deletes mixed-rev"
 
@@ -1484,6 +1483,10 @@ def update_delete_mixed_rev(sbox):
                         status='A ', copied='+', treeconflict='C', wc_rev='-')
   expected_status.tweak('A/B/F', 'A/B/E', 'A/B/E/beta', 'A/B/lambda',
                         copied='+', wc_rev='-')
+
+  # The entries world doesn't see a changed revision as another add
+  # while the WC-NG world does...
+  expected_status.tweak('A/B/E', status='A ', entry_status='  ')
   run_and_verify_update(wc_dir,
                         expected_output, expected_disk, expected_status,
                         None, None, None, None, None, 1,

Modified: subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c?rev=1660742&r1=1660741&r2=1660742&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c Wed Feb 18 
22:15:50 2015
@@ -10993,6 +10993,334 @@ move_deep_bump(const svn_test_opts_t *op
 
   return SVN_NO_ERROR;
 }
+
+static svn_error_t *
+make_copy_mixed(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_test__sandbox_t b;
+
+  SVN_ERR(svn_test__sandbox_create(&b, "make_copy_mixed", opts, pool));
+
+  SVN_ERR(sbox_wc_mkdir(&b, "A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/D"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/E"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/F"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/H"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/I"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/K"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/L"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/M"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N/O"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N/P"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N/Q"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/R"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/R/S"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/R/S/T"));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_update(&b, "", 1));
+  SVN_ERR(sbox_wc_propset(&b, "k", "r2", ""));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_propset(&b, "k", "r3", ""));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_propset(&b, "k", "r4", ""));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_propset(&b, "k", "r5", ""));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+
+  SVN_ERR(sbox_wc_update(&b, "", 5));
+  SVN_ERR(sbox_wc_update(&b, "A", 4));
+  SVN_ERR(sbox_wc_update(&b, "A/B", 3));
+  SVN_ERR(sbox_wc_update(&b, "A/B/C", 2));
+  SVN_ERR(sbox_wc_update(&b, "A/B/K", 1));
+  SVN_ERR(sbox_wc_update(&b, "A/N/O", 3));
+
+  SVN_ERR(sbox_wc_delete(&b, "A/B/C/F"));
+  SVN_ERR(sbox_wc_delete(&b, "A/B/G/J"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J"));
+
+  SVN_ERR(sbox_wc_update(&b, "A/N/P", 1));
+  SVN_ERR(sbox_wc_update(&b, "A/N/Q", 1));
+  SVN_ERR(sbox_wc_delete(&b, "A/N/P"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N/P"));
+  SVN_ERR(sbox_wc_move(&b, "A/N/Q", "Q"));
+  SVN_ERR(sbox_wc_move(&b, "A/B/G/H", "H"));
+
+  /* And something that can't be represented */
+  SVN_ERR(sbox_wc_update(&b, "A/B/C/E", 1));
+  SVN_ERR(sbox_wc_move(&b, "A/B/C/E", "E"));
+
+  {
+    nodes_row_t nodes[] = {
+      {0, "",             "normal",       5, "", NOT_MOVED, "k"},
+      {0, "A",            "normal",       4, "A"},
+      {0, "A/B",          "normal",       3, "A/B"},
+      {0, "A/B/C",        "normal",       2, "A/B/C"},
+      {0, "A/B/C/D",      "normal",       2, "A/B/C/D"},
+      {0, "A/B/C/E",      "normal",       1, "A/B/C/E"},
+      {0, "A/B/C/F",      "normal",       2, "A/B/C/F"},
+      {0, "A/B/G",        "normal",       3, "A/B/G"},
+      {0, "A/B/G/H",      "normal",       3, "A/B/G/H"},
+      {0, "A/B/G/I",      "normal",       3, "A/B/G/I"},
+      {0, "A/B/G/J",      "normal",       3, "A/B/G/J"},
+      {0, "A/B/K",        "normal",       1, "A/B/K"},
+      {0, "A/B/K/L",      "normal",       1, "A/B/K/L"},
+      {0, "A/B/K/M",      "normal",       1, "A/B/K/M"},
+      {0, "A/N",          "normal",       4, "A/N"},
+      {0, "A/N/O",        "normal",       3, "A/N/O"},
+      {0, "A/N/P",        "normal",       1, "A/N/P"},
+      {0, "A/N/Q",        "normal",       1, "A/N/Q"},
+      {0, "A/R",          "normal",       4, "A/R"},
+      {0, "A/R/S",        "normal",       4, "A/R/S"},
+      {0, "A/R/S/T",      "normal",       4, "A/R/S/T"},
+      {1, "E",            "normal",       1, "A/B/C/E", MOVED_HERE},
+      {1, "H",            "normal",       3, "A/B/G/H", MOVED_HERE},
+      {1, "Q",            "normal",       1, "A/N/Q", MOVED_HERE},
+      {3, "A/N/P",        "normal",       NO_COPY_FROM},
+      {3, "A/N/Q",        "base-deleted", NO_COPY_FROM, "Q"},
+      {4, "A/B/C/E",      "base-deleted", NO_COPY_FROM, "E"},
+      {4, "A/B/C/F",      "base-deleted", NO_COPY_FROM},
+      {4, "A/B/G/H",      "base-deleted", NO_COPY_FROM, "H"},
+      {4, "A/B/G/J",      "normal",       NO_COPY_FROM},
+
+      {0}
+    };
+
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  SVN_ERR(svn_wc__db_op_make_copy(b.wc_ctx->db, sbox_wc_path(&b, "A"),
+                                  NULL, NULL, pool));
+
+  {
+    nodes_row_t nodes[] = {
+      {0, "",             "normal",       5, "", NOT_MOVED, "k"},
+      {0, "A",            "normal",       4, "A"},
+      {0, "A/B",          "normal",       3, "A/B"},
+      {0, "A/B/C",        "normal",       2, "A/B/C"},
+      {0, "A/B/C/D",      "normal",       2, "A/B/C/D"},
+      {0, "A/B/C/E",      "normal",       1, "A/B/C/E"},
+      {0, "A/B/C/F",      "normal",       2, "A/B/C/F"},
+      {0, "A/B/G",        "normal",       3, "A/B/G"},
+      {0, "A/B/G/H",      "normal",       3, "A/B/G/H"},
+      {0, "A/B/G/I",      "normal",       3, "A/B/G/I"},
+      {0, "A/B/G/J",      "normal",       3, "A/B/G/J"},
+      {0, "A/B/K",        "normal",       1, "A/B/K"},
+      {0, "A/B/K/L",      "normal",       1, "A/B/K/L"},
+      {0, "A/B/K/M",      "normal",       1, "A/B/K/M"},
+      {0, "A/N",          "normal",       4, "A/N"},
+      {0, "A/N/O",        "normal",       3, "A/N/O"},
+      {0, "A/N/P",        "normal",       1, "A/N/P"},
+      {0, "A/N/Q",        "normal",       1, "A/N/Q"},
+      {0, "A/R",          "normal",       4, "A/R"},
+      {0, "A/R/S",        "normal",       4, "A/R/S"},
+      {0, "A/R/S/T",      "normal",       4, "A/R/S/T"},
+      {1, "A",            "normal",       4, "A"},
+      {1, "A/B",          "not-present",  3, "A/B"},
+      {1, "A/B/C",        "base-deleted", NO_COPY_FROM},
+      {1, "A/B/C/D",      "base-deleted", NO_COPY_FROM},
+      {1, "A/B/C/E",      "base-deleted", NO_COPY_FROM, "E"},
+      {1, "A/B/C/F",      "base-deleted", NO_COPY_FROM},
+      {1, "A/B/G",        "base-deleted", NO_COPY_FROM},
+      {1, "A/B/G/H",      "base-deleted", NO_COPY_FROM, "H"},
+      {1, "A/B/G/I",      "base-deleted", NO_COPY_FROM},
+      {1, "A/B/G/J",      "base-deleted", NO_COPY_FROM},
+      {1, "A/B/K",        "base-deleted", NO_COPY_FROM},
+      {1, "A/B/K/L",      "base-deleted", NO_COPY_FROM},
+      {1, "A/B/K/M",      "base-deleted", NO_COPY_FROM},
+      {1, "A/N",          "normal",       4, "A/N"},
+      {1, "A/N/O",        "not-present",  3, "A/N/O"},
+      {1, "A/N/P",        "not-present",  1, "A/N/P"},
+      {1, "A/N/Q",        "not-present",  1, "A/N/Q", FALSE, "Q"},
+      {1, "A/R",          "normal",       4, "A/R"},
+      {1, "A/R/S",        "normal",       4, "A/R/S"},
+      {1, "A/R/S/T",      "normal",       4, "A/R/S/T"},
+      {1, "E",            "normal",       1, "A/B/C/E", MOVED_HERE},
+      {1, "H",            "normal",       3, "A/B/G/H", MOVED_HERE},
+      {1, "Q",            "normal",       1, "A/N/Q", MOVED_HERE},
+      {2, "A/B",          "normal",       3, "A/B"},
+      {2, "A/B/C",        "not-present",  2, "A/B/C"},
+      {2, "A/B/G",        "normal",       3, "A/B/G"},
+      {2, "A/B/G/H",      "normal",       3, "A/B/G/H"},
+      {2, "A/B/G/I",      "normal",       3, "A/B/G/I"},
+      {2, "A/B/G/J",      "normal",       3, "A/B/G/J"},
+      {2, "A/B/K",        "not-present",  1, "A/B/K"},
+      {3, "A/B/C",        "normal",       2, "A/B/C"},
+      {3, "A/B/C/D",      "normal",       2, "A/B/C/D"},
+      {3, "A/B/C/E",      "not-present",  1, "A/B/C/E"},
+      {3, "A/B/C/F",      "normal",       2, "A/B/C/F"},
+      {3, "A/B/K",        "normal",       1, "A/B/K"},
+      {3, "A/B/K/L",      "normal",       1, "A/B/K/L"},
+      {3, "A/B/K/M",      "normal",       1, "A/B/K/M"},
+      {3, "A/N/O",        "normal",       3, "A/N/O"},
+      {3, "A/N/P",        "normal",       NO_COPY_FROM},
+      {4, "A/B/C/F",      "base-deleted", NO_COPY_FROM},
+      {4, "A/B/G/H",      "base-deleted", NO_COPY_FROM},
+      {4, "A/B/G/J",      "normal",       NO_COPY_FROM},
+
+      {0}
+    };
+
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+make_copy_and_delete_mixed(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_test__sandbox_t b;
+
+  SVN_ERR(svn_test__sandbox_create(&b, "make_copy_and_del_mixed", opts, pool));
+
+  SVN_ERR(sbox_wc_mkdir(&b, "A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/D"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/E"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C/F"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/H"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/I"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/K"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/L"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/K/M"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N/O"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N/P"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N/Q"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/R"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/R/S"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/R/S/T"));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_update(&b, "", 1));
+  SVN_ERR(sbox_wc_propset(&b, "k", "r2", ""));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_propset(&b, "k", "r3", ""));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_propset(&b, "k", "r4", ""));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_propset(&b, "k", "r5", ""));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+
+  SVN_ERR(sbox_wc_update(&b, "", 5));
+  SVN_ERR(sbox_wc_update(&b, "A", 4));
+  SVN_ERR(sbox_wc_update(&b, "A/B", 3));
+  SVN_ERR(sbox_wc_update(&b, "A/B/C", 2));
+  SVN_ERR(sbox_wc_update(&b, "A/B/K", 1));
+  SVN_ERR(sbox_wc_update(&b, "A/N/O", 3));
+
+  SVN_ERR(sbox_wc_delete(&b, "A/B/C/F"));
+  SVN_ERR(sbox_wc_delete(&b, "A/B/G/J"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/G/J"));
+
+  SVN_ERR(sbox_wc_update(&b, "A/N/P", 1));
+  SVN_ERR(sbox_wc_update(&b, "A/N/Q", 1));
+  SVN_ERR(sbox_wc_delete(&b, "A/N/P"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/N/P"));
+  SVN_ERR(sbox_wc_move(&b, "A/N/Q", "Q"));
+  SVN_ERR(sbox_wc_move(&b, "A/B/G/H", "H"));
+
+  /* And something that can't be represented */
+  SVN_ERR(sbox_wc_update(&b, "A/B/C/E", 1));
+  SVN_ERR(sbox_wc_move(&b, "A/B/C/E", "E"));
+
+  {
+    nodes_row_t nodes[] = {
+      {0, "",             "normal",       5, "", NOT_MOVED, "k"},
+      {0, "A",            "normal",       4, "A"},
+      {0, "A/B",          "normal",       3, "A/B"},
+      {0, "A/B/C",        "normal",       2, "A/B/C"},
+      {0, "A/B/C/D",      "normal",       2, "A/B/C/D"},
+      {0, "A/B/C/E",      "normal",       1, "A/B/C/E"},
+      {0, "A/B/C/F",      "normal",       2, "A/B/C/F"},
+      {0, "A/B/G",        "normal",       3, "A/B/G"},
+      {0, "A/B/G/H",      "normal",       3, "A/B/G/H"},
+      {0, "A/B/G/I",      "normal",       3, "A/B/G/I"},
+      {0, "A/B/G/J",      "normal",       3, "A/B/G/J"},
+      {0, "A/B/K",        "normal",       1, "A/B/K"},
+      {0, "A/B/K/L",      "normal",       1, "A/B/K/L"},
+      {0, "A/B/K/M",      "normal",       1, "A/B/K/M"},
+      {0, "A/N",          "normal",       4, "A/N"},
+      {0, "A/N/O",        "normal",       3, "A/N/O"},
+      {0, "A/N/P",        "normal",       1, "A/N/P"},
+      {0, "A/N/Q",        "normal",       1, "A/N/Q"},
+      {0, "A/R",          "normal",       4, "A/R"},
+      {0, "A/R/S",        "normal",       4, "A/R/S"},
+      {0, "A/R/S/T",      "normal",       4, "A/R/S/T"},
+      {1, "E",            "normal",       1, "A/B/C/E", MOVED_HERE},
+      {1, "H",            "normal",       3, "A/B/G/H", MOVED_HERE},
+      {1, "Q",            "normal",       1, "A/N/Q", MOVED_HERE},
+      {3, "A/N/P",        "normal",       NO_COPY_FROM},
+      {3, "A/N/Q",        "base-deleted", NO_COPY_FROM, "Q"},
+      {4, "A/B/C/E",      "base-deleted", NO_COPY_FROM, "E"},
+      {4, "A/B/C/F",      "base-deleted", NO_COPY_FROM},
+      {4, "A/B/G/H",      "base-deleted", NO_COPY_FROM, "H"},
+      {4, "A/B/G/J",      "normal",       NO_COPY_FROM},
+
+      {0}
+    };
+
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  SVN_ERR(svn_wc__db_base_remove(b.wc_ctx->db, sbox_wc_path(&b, "A"),
+                                 TRUE, FALSE, FALSE, 99,
+                                 NULL, NULL, pool));
+
+  {
+    nodes_row_t nodes[] = {
+      {0, "",             "normal",       5, "", NOT_MOVED, "k"},
+      {0, "A",            "not-present",  99, "A"},
+      {1, "A",            "normal",       4, "A"},
+      {1, "A/B",          "not-present",  3, "A/B"},
+      {1, "A/N",          "normal",       4, "A/N"},
+      {1, "A/N/O",        "not-present",  3, "A/N/O"},
+      {1, "A/N/P",        "not-present",  1, "A/N/P"},
+      {1, "A/N/Q",        "not-present",  1, "A/N/Q", FALSE},
+      {1, "A/R",          "normal",       4, "A/R"},
+      {1, "A/R/S",        "normal",       4, "A/R/S"},
+      {1, "A/R/S/T",      "normal",       4, "A/R/S/T"},
+      {1, "E",            "normal",       1, "A/B/C/E"},
+      {1, "H",            "normal",       3, "A/B/G/H", MOVED_HERE},
+      {1, "Q",            "normal",       1, "A/N/Q"},
+      {2, "A/B",          "normal",       3, "A/B"},
+      {2, "A/B/C",        "not-present",  2, "A/B/C"},
+      {2, "A/B/G",        "normal",       3, "A/B/G"},
+      {2, "A/B/G/H",      "normal",       3, "A/B/G/H"},
+      {2, "A/B/G/I",      "normal",       3, "A/B/G/I"},
+      {2, "A/B/G/J",      "normal",       3, "A/B/G/J"},
+      {3, "A/B/C",        "normal",       2, "A/B/C"},
+      {3, "A/B/C/D",      "normal",       2, "A/B/C/D"},
+      {3, "A/B/C/E",      "not-present",  1, "A/B/C/E"},
+      {3, "A/B/C/F",      "normal",       2, "A/B/C/F"},
+      {2, "A/B/K",        "not-present",  1, "A/B/K"},
+      {3, "A/B/K",        "normal",       1, "A/B/K"},
+      {3, "A/B/K/L",      "normal",       1, "A/B/K/L"},
+      {3, "A/B/K/M",      "normal",       1, "A/B/K/M"},
+      {3, "A/N/O",        "normal",       3, "A/N/O"},
+      {3, "A/N/P",        "normal",       NO_COPY_FROM},
+      {4, "A/B/C/F",      "base-deleted", NO_COPY_FROM},
+      {4, "A/B/G/H",      "base-deleted", NO_COPY_FROM},
+      {4, "A/B/G/J",      "normal",       NO_COPY_FROM},
+
+      {0}
+    };
+
+    /* This currently fails because Q and E are still marked as moved,
+       while there is nothing to be moved. */
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  return SVN_NO_ERROR;
+}
+
 /* ---------------------------------------------------------------------- */
 /* The list of test functions */
 
@@ -11202,6 +11530,10 @@ static struct svn_test_descriptor_t test
                        "move edit obstruction"),
     SVN_TEST_OPTS_PASS(move_deep_bump,
                        "move deep bump"),
+    SVN_TEST_OPTS_PASS(make_copy_mixed,
+                       "make a copy of a mixed revision tree"),
+    SVN_TEST_OPTS_XFAIL(make_copy_and_delete_mixed,
+                       "make a copy of a mixed revision tree and del"),
     SVN_TEST_NULL
   };
 


Reply via email to