Modified: subversion/branches/pin-externals/subversion/libsvn_wc/wc-queries.sql URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc-queries.sql?rev=1658128&r1=1658127&r2=1658128&view=diff ============================================================================== --- subversion/branches/pin-externals/subversion/libsvn_wc/wc-queries.sql (original) +++ subversion/branches/pin-externals/subversion/libsvn_wc/wc-queries.sql Sun Feb 8 03:10:25 2015 @@ -257,30 +257,35 @@ WHERE wc_id = ?1 AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) AND op_depth = ?3 --- STMT_DELETE_WORKING_OP_DEPTH_ABOVE -DELETE FROM nodes -WHERE wc_id = ?1 - AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) - AND op_depth > ?3 - --- STMT_SELECT_LOCAL_RELPATH_OP_DEPTH -SELECT local_relpath, kind -FROM nodes -WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 +/* Full layer replacement check code for handling moves +The op_root must exist (or there is no layer to replace) and an op-root + always has presence 'normal' */ +-- STMT_SELECT_LAYER_FOR_REPLACE +SELECT s.local_relpath, s.kind, + RELPATH_SKIP_JOIN(?2, ?4, s.local_relpath) drp, 'normal', 0 +FROM nodes s +WHERE s.wc_id = ?1 AND s.local_relpath = ?2 AND s.op_depth = ?3 UNION ALL -SELECT local_relpath, kind -FROM nodes -WHERE wc_id = ?1 - AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2) - AND op_depth = ?3 -ORDER BY local_relpath +SELECT s.local_relpath, s.kind, + RELPATH_SKIP_JOIN(?2, ?4, s.local_relpath) drp, d.presence, + EXISTS(SELECT * FROM nodes sh + WHERE sh.wc_id = ?1 AND sh.op_depth > ?5 + AND sh.local_relpath = d.local_relpath) shadowed +FROM nodes s +LEFT OUTER JOIN nodes d ON d.wc_id= ?1 AND d.op_depth = ?5 + AND d.local_relpath = drp +WHERE s.wc_id = ?1 + AND IS_STRICT_DESCENDANT_OF(s.local_relpath, ?2) + AND s.op_depth = ?3 +ORDER BY s.local_relpath --- STMT_SELECT_CHILDREN_OP_DEPTH +-- STMT_SELECT_DESCENDANTS_OP_DEPTH_RV SELECT local_relpath, kind FROM nodes WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2) AND op_depth = ?3 + AND presence in (MAP_NORMAL, MAP_INCOMPLETE) ORDER BY local_relpath DESC -- STMT_COPY_NODE_MOVE @@ -302,6 +307,24 @@ SELECT FROM nodes WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 +-- STMT_SELECT_NO_LONGER_MOVED_RV +SELECT d.local_relpath, RELPATH_SKIP_JOIN(?2, ?4, d.local_relpath) srp, + b.presence, b.op_depth +FROM nodes d +LEFT OUTER JOIN nodes b ON b.wc_id = ?1 AND b.local_relpath = d.local_relpath + AND b.op_depth = (SELECT MAX(x.op_depth) FROM nodes x + WHERE x.wc_id = ?1 + AND x.local_relpath = b.local_relpath + AND x.op_depth < ?3) +WHERE d.wc_id = ?1 + AND IS_STRICT_DESCENDANT_OF(d.local_relpath, ?2) + AND d.op_depth = ?3 + AND NOT EXISTS(SELECT * FROM nodes s + WHERE s.wc_id = ?1 + AND s.local_relpath = srp + AND s.op_depth = ?5) +ORDER BY d.local_relpath DESC + -- STMT_SELECT_OP_DEPTH_CHILDREN SELECT local_relpath, kind FROM nodes WHERE wc_id = ?1 @@ -452,16 +475,12 @@ WHERE wc_id = ?1 AND local_relpath = ?2 ORDER BY op_depth DESC -- STMT_SELECT_OP_DEPTH_MOVED_TO -SELECT n.op_depth, n.moved_to, p.repos_path, p.revision -FROM nodes p -LEFT JOIN nodes n - ON p.wc_id=n.wc_id AND p.local_relpath = n.local_relpath - AND n.op_depth = (SELECT MIN(d.op_depth) - FROM nodes d - WHERE d.wc_id = ?1 - AND d.local_relpath = n.local_relpath - AND d.op_depth > ?3) -WHERE p.wc_id = ?1 AND p.local_relpath = ?2 AND p.op_depth = ?3 +SELECT op_depth, moved_to +FROM nodes +WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3 + AND EXISTS(SELECT * from nodes + WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3) +ORDER BY op_depth ASC LIMIT 1 -- STMT_SELECT_MOVED_TO @@ -949,17 +968,6 @@ INSERT INTO nodes ( parent_relpath, presence, kind) VALUES(?1, ?2, ?3, ?4, MAP_BASE_DELETED, ?5) --- STMT_DELETE_NO_LOWER_LAYER -DELETE FROM nodes - WHERE wc_id = ?1 - AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) - AND op_depth = ?3 - AND NOT EXISTS (SELECT 1 FROM nodes n - WHERE n.wc_id = ?1 - AND n.local_relpath = nodes.local_relpath - AND n.op_depth = ?4 - AND n.presence IN (MAP_NORMAL, MAP_INCOMPLETE)) - -- STMT_REPLACE_WITH_BASE_DELETED INSERT OR REPLACE INTO nodes (wc_id, local_relpath, op_depth, parent_relpath, kind, moved_to, presence) @@ -967,7 +975,7 @@ SELECT wc_id, local_relpath, op_depth, p kind, moved_to, MAP_BASE_DELETED FROM nodes WHERE wc_id = ?1 - AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) + AND local_relpath = ?2 AND op_depth = ?3 /* If this query is updated, STMT_INSERT_DELETE_LIST should too. @@ -1018,11 +1026,30 @@ WHERE wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2) AND op_depth = ?3 --- STMT_UPDATE_OP_DEPTH_RECURSIVE -UPDATE nodes SET op_depth = ?4, moved_here = NULL -WHERE wc_id = ?1 - AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)) - AND op_depth = ?3 +/* Duplicated SELECT body to avoid creating temporary table */ +-- STMT_COPY_OP_DEPTH_RECURSIVE +INSERT 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, moved_here, moved_to ) +SELECT + wc_id, local_relpath, ?4, 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, NULL, NULL +FROM nodes +WHERE wc_id = ?1 AND op_depth = ?3 AND local_relpath = ?2 +UNION ALL +SELECT + wc_id, local_relpath, ?4, 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, NULL, NULL +FROM nodes +WHERE wc_id = ?1 AND op_depth = ?3 + AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2) +ORDER BY local_relpath -- STMT_DOES_NODE_EXIST SELECT 1 FROM nodes WHERE wc_id = ?1 AND local_relpath = ?2 @@ -1592,16 +1619,29 @@ UPDATE nodes SET moved_to = NULL AND IS_STRICT_DESCENDANT_OF(moved_to, ?2) -- STMT_SELECT_MOVED_PAIR3 -SELECT local_relpath, moved_to, op_depth, kind FROM nodes -WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3 - AND moved_to IS NOT NULL +SELECT n.local_relpath, d.moved_to, d.op_depth, n.kind +FROM nodes n +JOIN nodes d ON d.wc_id = ?1 AND d.local_relpath = n.local_relpath + AND d.op_depth = (SELECT MIN(dd.op_depth) + FROM nodes dd + WHERE dd.wc_id = ?1 + AND dd.local_relpath = d.local_relpath + AND dd.op_depth > ?3) +WHERE n.wc_id = ?1 AND n.local_relpath = ?2 AND n.op_depth = ?3 + AND d.moved_to IS NOT NULL UNION ALL -SELECT local_relpath, moved_to, op_depth, kind FROM nodes -WHERE wc_id = ?1 - AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2) - AND op_depth > ?3 - AND moved_to IS NOT NULL -ORDER BY local_relpath, op_depth +SELECT n.local_relpath, d.moved_to, d.op_depth, n.kind +FROM nodes n +JOIN nodes d ON d.wc_id = ?1 AND d.local_relpath = n.local_relpath + AND d.op_depth = (SELECT MIN(dd.op_depth) + FROM nodes dd + WHERE dd.wc_id = ?1 + AND dd.local_relpath = d.local_relpath + AND dd.op_depth > ?3) +WHERE n.wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(n.local_relpath, ?2) + AND n.op_depth = ?3 + AND d.moved_to IS NOT NULL +ORDER BY n.local_relpath -- STMT_SELECT_MOVED_OUTSIDE SELECT local_relpath, moved_to, op_depth FROM nodes @@ -1613,16 +1653,12 @@ WHERE wc_id = ?1 -- STMT_SELECT_OP_DEPTH_MOVED_PAIR SELECT n.local_relpath, p.kind, n.moved_to, p.repos_path -FROM nodes AS n -JOIN (SELECT local_relpath, kind, repos_path - FROM nodes AS o - WHERE o.wc_id = ?1 - AND o.op_depth=(SELECT MAX(d.op_depth) - FROM nodes AS d - WHERE d.wc_id = ?1 - AND d.local_relpath = o.local_relpath - AND d.op_depth < ?3)) AS p - ON n.local_relpath = p.local_relpath +FROM nodes n +JOIN nodes p ON p.wc_id = ?1 AND p.local_relpath = ?2 + AND p.op_depth=(SELECT MAX(d.op_depth) + FROM nodes d + WHERE d.wc_id = ?1 AND d.local_relpath = ?2 + AND d.op_depth < ?3) WHERE n.wc_id = ?1 AND IS_STRICT_DESCENDANT_OF(n.local_relpath, ?2) AND n.op_depth = ?3
Modified: subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c?rev=1658128&r1=1658127&r2=1658128&view=diff ============================================================================== --- subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c (original) +++ subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.c Sun Feb 8 03:10:25 2015 @@ -569,12 +569,54 @@ blank_ibb(insert_base_baton_t *pibb) } -svn_error_t * -svn_wc__db_extend_parent_delete(svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - svn_node_kind_t kind, - int op_depth, - apr_pool_t *scratch_pool) +/* Extend any delete of the parent of LOCAL_RELPATH to LOCAL_RELPATH. + + ### What about KIND and OP_DEPTH? KIND ought to be redundant; I'm + discussing on dev@ whether we can let that be null for presence + == base-deleted. OP_DEPTH is the op-depth of what, and why? + It is used to select the lowest working node higher than OP_DEPTH, + so, in terms of the API, OP_DEPTH means ...? + + Given a wc: + + 0 1 2 3 4 + normal + A normal + A/B normal normal + A/B/C not-pres normal + A/B/C/D normal + + That is checkout, delete A/B, copy a replacement A/B, delete copied + child A/B/C, add replacement A/B/C, add A/B/C/D. + + Now an update that adds base nodes for A/B/C, A/B/C/D and A/B/C/D/E + must extend the A/B deletion: + + 0 1 2 3 4 + normal + A normal + A/B normal normal + A/B/C normal not-pres normal + A/B/C/D normal base-del normal + A/B/C/D/E normal base-del + + When adding a node if the parent has a higher working node then the + parent node is deleted (or replaced) and the delete must be extended + to cover new node. + + In the example above A/B/C/D and A/B/C/D/E are the nodes that get + the extended delete, A/B/C is already deleted. + + If ADDED_DELETE is not NULL, set *ADDED_DELETE to TRUE if a new delete + was recorded, otherwise to FALSE. + */ +static svn_error_t * +db_extend_parent_delete(svn_boolean_t *added_delete, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + svn_node_kind_t kind, + int op_depth, + apr_pool_t *scratch_pool) { svn_boolean_t have_row; svn_sqlite__stmt_t *stmt; @@ -583,6 +625,9 @@ svn_wc__db_extend_parent_delete(svn_wc__ SVN_ERR_ASSERT(local_relpath[0]); + if (added_delete) + *added_delete = FALSE; + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_LOWEST_WORKING_NODE)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, parent_relpath, @@ -609,6 +654,9 @@ svn_wc__db_extend_parent_delete(svn_wc__ local_relpath, parent_op_depth, parent_relpath, kind_map, kind)); SVN_ERR(svn_sqlite__update(NULL, stmt)); + + if (added_delete) + *added_delete = TRUE; } } @@ -616,7 +664,7 @@ svn_wc__db_extend_parent_delete(svn_wc__ } -/* This is the reverse of svn_wc__db_extend_parent_delete. +/* This is the reverse of db_extend_parent_delete. When removing a node if the parent has a higher working node then the parent node and this node are both deleted or replaced and any @@ -626,11 +674,11 @@ svn_wc__db_extend_parent_delete(svn_wc__ only uses this function within an sqlite transaction if atomic behavior is needed. */ -svn_error_t * -svn_wc__db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - int op_depth, - apr_pool_t *scratch_pool) +static svn_error_t * +db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + int op_depth, + apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; @@ -833,16 +881,17 @@ insert_base_node(const insert_base_baton || (pibb->status == svn_wc__db_status_incomplete)) && ! pibb->file_external) { - SVN_ERR(svn_wc__db_extend_parent_delete(wcroot, local_relpath, - pibb->kind, 0, - scratch_pool)); + SVN_ERR(db_extend_parent_delete(NULL, + wcroot, local_relpath, + pibb->kind, 0, + scratch_pool)); } else if (pibb->status == svn_wc__db_status_not_present || pibb->status == svn_wc__db_status_server_excluded || pibb->status == svn_wc__db_status_excluded) { - SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, 0, - scratch_pool)); + SVN_ERR(db_retract_parent_delete(wcroot, local_relpath, 0, + scratch_pool)); } } @@ -2387,8 +2436,7 @@ db_base_remove(svn_wc__db_wcroot_t *wcro SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); SVN_ERR(svn_sqlite__step_done(stmt)); - SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, 0, - scratch_pool)); + 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) @@ -4797,6 +4845,187 @@ svn_wc__db_op_copy(svn_wc__db_t *db, 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, + int src_op_depth, + const char *dst_op_relpath, + svn_skel_t *conflict, + svn_skel_t *work_items, + apr_pool_t *scratch_pool) +{ + svn_sqlite__stmt_t *stmt, *stmt2; + svn_boolean_t have_row; + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + int dst_op_depth = relpath_depth(dst_op_relpath); + svn_boolean_t locked; + svn_error_t *err = NULL; + + SVN_ERR(svn_wc__db_wclock_owns_lock_internal(&locked, wcroot, dst_op_relpath, + FALSE, scratch_pool)); + + if (!locked) + return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL, + _("No write-lock in '%s'"), + path_for_error_message(wcroot, dst_op_relpath, + scratch_pool)); + + SVN_ERR(svn_sqlite__get_statement(&stmt2, wcroot->sdb, + STMT_COPY_NODE_MOVE)); + + /* Replace entire subtree at one op-depth. */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_LAYER_FOR_REPLACE)); + SVN_ERR(svn_sqlite__bindf(stmt, "isdsd", wcroot->wc_id, + src_op_relpath, src_op_depth, + dst_op_relpath, dst_op_depth)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + while (have_row) + { + const char *src_relpath; + const char *dst_relpath; + svn_boolean_t exists; + + svn_pool_clear(iterpool); + + src_relpath = svn_sqlite__column_text(stmt, 0, iterpool); + dst_relpath = svn_sqlite__column_text(stmt, 2, iterpool); + + exists = !svn_sqlite__column_is_null(stmt, 3); + + err = svn_sqlite__bindf(stmt2, "isdsds", wcroot->wc_id, + src_relpath, src_op_depth, + dst_relpath, dst_op_depth, + svn_relpath_dirname(dst_relpath, iterpool)); + if (!err) + err = svn_sqlite__step_done(stmt2); + + /* stmt2 is reset (never modified or by step_done) */ + + if (err) + break; + + if (strlen(dst_relpath) > strlen(dst_op_relpath)) + { + svn_boolean_t added_delete = FALSE; + svn_node_kind_t kind = svn_sqlite__column_token(stmt, 1, kind_map); + + /* The op root can't be shadowed, so extension of a parent delete + is only needed when the parent can be deleted */ + if (relpath_depth(dst_relpath) > (dst_op_depth+1)) + { + err = db_extend_parent_delete(&added_delete, wcroot, dst_relpath, + kind, dst_op_depth, iterpool); + + if (err) + break; + } + + if (exists) + { + svn_wc__db_status_t presence; + + presence = svn_sqlite__column_token(stmt, 3, presence_map); + + if (presence == svn_wc__db_status_not_present) + exists = FALSE; + } + + /* ### Fails in a few tests... Needs further research */ + /*SVN_ERR_ASSERT(!(exists && added_delete));*/ + + if (!exists) + { + svn_boolean_t shadowed; + + shadowed = svn_sqlite__column_int(stmt, 4); + + /*if (!shadowed && !added_delete) + { + err = svn_error_createf( + SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, + _("Node '%s' was unexpectedly added unshadowed"), + path_for_error_message(wcroot, dst_relpath, + iterpool)); + break; + }*/ + } + } + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + + SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt))); + + /* And now remove the records that are no longer needed */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_NO_LONGER_MOVED_RV)); + SVN_ERR(svn_sqlite__bindf(stmt, "isdsd", wcroot->wc_id, + dst_op_relpath, dst_op_depth, + src_op_relpath, src_op_depth)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + while (have_row) + { + const char *dst_relpath; + svn_wc__db_status_t shadowed_presence; + + svn_pool_clear(iterpool); + + dst_relpath = svn_sqlite__column_text(stmt, 0, iterpool); + + if (!svn_sqlite__column_is_null(stmt, 2)) + shadowed_presence = svn_sqlite__column_token(stmt, 2, presence_map); + else + shadowed_presence = svn_wc__db_status_not_present; + + if (shadowed_presence != svn_wc__db_status_normal + && shadowed_presence != svn_wc__db_status_incomplete) + { + err = svn_sqlite__get_statement(&stmt2, wcroot->sdb, + STMT_DELETE_NODE); + } + else + { + err =svn_sqlite__get_statement(&stmt2, wcroot->sdb, + STMT_REPLACE_WITH_BASE_DELETED); + } + + if (!err) + err = svn_sqlite__bindf(stmt2, "isd", wcroot->wc_id, dst_relpath, + dst_op_depth); + + if (!err) + err = svn_sqlite__step_done(stmt2); + + /* stmt2 is reset (never modified or by step_done) */ + + if (err) + break; + + /* Retract base-delete for the node itself */ + err = db_retract_parent_delete(wcroot, dst_relpath, dst_op_depth, + scratch_pool); + + if (err) + break; + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + svn_pool_destroy(iterpool); + + 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) + SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, dst_op_relpath /* ## */, + conflict, scratch_pool)); + + return SVN_NO_ERROR; +} + /* The txn body of svn_wc__db_op_handle_move_back */ static svn_error_t * handle_move_back(svn_boolean_t *moved_back, @@ -12518,7 +12747,7 @@ svn_wc__db_scan_moved(const char **moved return SVN_NO_ERROR; } -/* ### +/* ### Recursive helper for svn_wc__db_follow_moved_to() */ static svn_error_t * follow_moved_to(svn_wc__db_wcroot_t *wcroot, @@ -12530,11 +12759,13 @@ follow_moved_to(svn_wc__db_wcroot_t *wcr { svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - int working_op_depth; + int shadowing_op_depth; const char *ancestor_relpath; const char *node_moved_to = NULL; int i; + /* Obtain the depth of the node directly shadowing local_relpath + as it exists at OP_DEPTH, and perhaps moved to info */ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_OP_DEPTH_MOVED_TO)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, @@ -12542,7 +12773,7 @@ follow_moved_to(svn_wc__db_wcroot_t *wcr SVN_ERR(svn_sqlite__step(&have_row, stmt)); if (have_row) { - working_op_depth = svn_sqlite__column_int(stmt, 0); + shadowing_op_depth = svn_sqlite__column_int(stmt, 0); node_moved_to = svn_sqlite__column_text(stmt, 1, result_pool); if (node_moved_to) @@ -12550,7 +12781,7 @@ follow_moved_to(svn_wc__db_wcroot_t *wcr struct svn_wc__db_moved_to_t *moved_to; moved_to = apr_palloc(result_pool, sizeof(*moved_to)); - moved_to->op_depth = working_op_depth; + moved_to->op_depth = shadowing_op_depth; moved_to->local_relpath = node_moved_to; APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to; } @@ -12559,16 +12790,18 @@ follow_moved_to(svn_wc__db_wcroot_t *wcr SVN_ERR(svn_sqlite__reset(stmt)); if (!have_row) - return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL, - _("The node '%s' was not found."), - path_for_error_message(wcroot, local_relpath, - scratch_pool)); + { + /* Node is not shadowed, so not moved */ + return SVN_NO_ERROR; + } else if (node_moved_to) - return SVN_NO_ERROR; - + { + /* Moved directly, so we have the final location */ + return SVN_NO_ERROR; + } /* Need to handle being moved via an ancestor. */ ancestor_relpath = local_relpath; - for (i = relpath_depth(local_relpath); i > working_op_depth; --i) + for (i = relpath_depth(local_relpath); i > shadowing_op_depth; --i) { const char *ancestor_moved_to; @@ -12577,7 +12810,7 @@ follow_moved_to(svn_wc__db_wcroot_t *wcr SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_TO)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, ancestor_relpath, - working_op_depth)); + shadowing_op_depth)); SVN_ERR(svn_sqlite__step_row(stmt)); ancestor_moved_to = svn_sqlite__column_text(stmt, 0, scratch_pool); @@ -12593,7 +12826,7 @@ follow_moved_to(svn_wc__db_wcroot_t *wcr result_pool); moved_to = apr_palloc(result_pool, sizeof(*moved_to)); - moved_to->op_depth = working_op_depth; + moved_to->op_depth = shadowing_op_depth; moved_to->local_relpath = node_moved_to; APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to; @@ -14621,8 +14854,6 @@ static svn_error_t * make_copy_txn(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, int op_depth, - const svn_skel_t *conflicts, - const svn_skel_t *work_items, apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; @@ -14703,21 +14934,68 @@ make_copy_txn(svn_wc__db_wcroot_t *wcroo copy_relpath = svn_relpath_join(local_relpath, name, iterpool); - SVN_ERR(make_copy_txn(wcroot, copy_relpath, op_depth, NULL, NULL, - iterpool)); + SVN_ERR(make_copy_txn(wcroot, copy_relpath, op_depth, iterpool)); } - SVN_ERR(flush_entries(wcroot, svn_dirent_join(wcroot->abspath, local_relpath, - iterpool), - svn_depth_empty, iterpool)); + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + const svn_skel_t *conflicts, + const svn_skel_t *work_items, + apr_pool_t *scratch_pool) +{ + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row; + int op_depth = -1; + + /* The update editor is supposed to call this function when there is + no working node for LOCAL_ABSPATH. */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_WORKING_NODE)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + if (have_row) + op_depth = svn_sqlite__column_int(stmt, 0); + SVN_ERR(svn_sqlite__reset(stmt)); + + if (have_row) + { + if (op_depth == relpath_depth(local_relpath)) + return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, + _("Modification of '%s' already exists"), + path_for_error_message(wcroot, + local_relpath, + scratch_pool)); + + /* We have a working layer, but not one at the op-depth of local-relpath, + so we can create a copy by just copying the lower layer */ + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_COPY_OP_DEPTH_RECURSIVE)); + SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id, local_relpath, + op_depth, relpath_depth(local_relpath))); + SVN_ERR(svn_sqlite__step_done(stmt)); + } + else + { + /* 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(make_copy_txn(wcroot, local_relpath, + relpath_depth(local_relpath), scratch_pool)); + } if (conflicts) SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath, - conflicts, iterpool)); + conflicts, scratch_pool)); - SVN_ERR(add_work_items(wcroot->sdb, work_items, iterpool)); - - svn_pool_destroy(iterpool); + SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool)); return SVN_NO_ERROR; } @@ -14732,8 +15010,6 @@ svn_wc__db_op_make_copy(svn_wc__db_t *db { svn_wc__db_wcroot_t *wcroot; const char *local_relpath; - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); @@ -14741,30 +15017,14 @@ svn_wc__db_op_make_copy(svn_wc__db_t *db local_abspath, scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - /* The update editor is supposed to call this function when there is - no working node for LOCAL_ABSPATH. */ - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_SELECT_WORKING_NODE)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - SVN_ERR(svn_sqlite__reset(stmt)); - if (have_row) - return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, - _("Modification of '%s' already exists"), - path_for_error_message(wcroot, - local_relpath, - scratch_pool)); - - /* 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_WC__DB_WITH_TXN( - make_copy_txn(wcroot, local_relpath, - relpath_depth(local_relpath), conflicts, work_items, - scratch_pool), + svn_wc__db_op_make_copy_internal(wcroot, local_relpath, conflicts, work_items, + scratch_pool), wcroot); + SVN_ERR(flush_entries(wcroot, local_abspath, + svn_depth_infinity, scratch_pool)); + return SVN_NO_ERROR; } Modified: subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.h URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.h?rev=1658128&r1=1658127&r2=1658128&view=diff ============================================================================== --- subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.h (original) +++ subversion/branches/pin-externals/subversion/libsvn_wc/wc_db.h Sun Feb 8 03:10:25 2015 @@ -3246,9 +3246,21 @@ svn_wc__db_temp_op_end_directory_update( apr_pool_t *scratch_pool); -/* Copy the base tree at LOCAL_ABSPATH into the working tree as copy, - leaving any subtree additions and copies as-is. This allows the - base node tree to be removed. */ +/* When local_abspath has no WORKING layer, copy the base tree at + LOCAL_ABSPATH into the working tree as copy, leaving any subtree + additions and copies as-is. This may introduce multiple layers if + the tree is mixed revision. + + When local_abspath has a WORKING node, but is not an op-root, copy + all descendants at the same op-depth to the op-depth of local_abspath, + thereby turning this node in a copy of what was already there. + + Fails with a SVN_ERR_WC_PATH_UNEXPECTED_STATUS error if LOCAL_RELPATH + is already an op-root (as in that case it can't be copied as that + would overwrite what is already there). + + After this operation the copied layer (E.g. BASE) can be removed, without + the WORKING nodes chaning. Typical usecase: tree conflict handling */ svn_error_t * svn_wc__db_op_make_copy(svn_wc__db_t *db, const char *local_abspath, Modified: subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_private.h URL: http://svn.apache.org/viewvc/subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_private.h?rev=1658128&r1=1658127&r2=1658128&view=diff ============================================================================== --- subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_private.h (original) +++ subversion/branches/pin-externals/subversion/libsvn_wc/wc_db_private.h Sun Feb 8 03:10:25 2015 @@ -394,58 +394,27 @@ svn_wc__db_get_children_op_depth(apr_has apr_pool_t *result_pool, apr_pool_t *scratch_pool); - -/* Extend any delete of the parent of LOCAL_RELPATH to LOCAL_RELPATH. - - ### What about KIND and OP_DEPTH? KIND ought to be redundant; I'm - discussing on dev@ whether we can let that be null for presence - == base-deleted. OP_DEPTH is the op-depth of what, and why? - It is used to select the lowest working node higher than OP_DEPTH, - so, in terms of the API, OP_DEPTH means ...? - - Given a wc: - - 0 1 2 3 4 - normal - A normal - A/B normal normal - A/B/C not-pres normal - A/B/C/D normal - - That is checkout, delete A/B, copy a replacement A/B, delete copied - child A/B/C, add replacement A/B/C, add A/B/C/D. - - Now an update that adds base nodes for A/B/C, A/B/C/D and A/B/C/D/E - must extend the A/B deletion: - - 0 1 2 3 4 - normal - A normal - A/B normal normal - A/B/C normal not-pres normal - A/B/C/D normal base-del normal - A/B/C/D/E normal base-del - - When adding a node if the parent has a higher working node then the - parent node is deleted (or replaced) and the delete must be extended - to cover new node. - - In the example above A/B/C/D and A/B/C/D/E are the nodes that get - the extended delete, A/B/C is already deleted. - */ +/* Update the single op-depth layer in the move destination subtree + rooted at DST_RELPATH to make it match the move source subtree + rooted at SRC_RELPATH. */ svn_error_t * -svn_wc__db_extend_parent_delete(svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - svn_node_kind_t kind, - int op_depth, - apr_pool_t *scratch_pool); +svn_wc__db_op_copy_layer_internal(svn_wc__db_wcroot_t *wcroot, + const char *src_op_relpath, + int src_op_depth, + const char *dst_op_relpath, + svn_skel_t *conflict, + svn_skel_t *work_items, + apr_pool_t *scratch_pool); +/* Like svn_wc__db_op_make_copy but with wcroot, local_relpath */ svn_error_t * -svn_wc__db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot, +svn_wc__db_op_make_copy_internal(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, - int op_depth, + const svn_skel_t *conflicts, + const svn_skel_t *work_items, apr_pool_t *scratch_pool); + /* Extract the moved-to information for LOCAL_RELPATH at OP-DEPTH by examining the lowest working node above OP_DEPTH. The output paths are NULL if there is no move, otherwise:
