summaryrefslogtreecommitdiff
path: root/subversion/libsvn_wc
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_wc')
-rw-r--r--subversion/libsvn_wc/adm_ops.c3
-rw-r--r--subversion/libsvn_wc/cleanup.c79
-rw-r--r--subversion/libsvn_wc/conflicts.c29
-rw-r--r--subversion/libsvn_wc/copy.c28
-rw-r--r--subversion/libsvn_wc/diff.h35
-rw-r--r--subversion/libsvn_wc/diff_editor.c493
-rw-r--r--subversion/libsvn_wc/diff_local.c27
-rw-r--r--subversion/libsvn_wc/entries.c5
-rw-r--r--subversion/libsvn_wc/externals.c36
-rw-r--r--subversion/libsvn_wc/update_editor.c20
-rw-r--r--subversion/libsvn_wc/wc-checks.h2
-rw-r--r--subversion/libsvn_wc/wc-metadata.h22
-rw-r--r--subversion/libsvn_wc/wc-metadata.sql21
-rw-r--r--subversion/libsvn_wc/wc-queries.h191
-rw-r--r--subversion/libsvn_wc/wc-queries.sql4
-rw-r--r--subversion/libsvn_wc/wc.h4
-rw-r--r--subversion/libsvn_wc/wc_db.c205
-rw-r--r--subversion/libsvn_wc/wc_db.h3
-rw-r--r--subversion/libsvn_wc/wc_db_private.h12
-rw-r--r--subversion/libsvn_wc/wc_db_wcroot.c57
20 files changed, 893 insertions, 383 deletions
diff --git a/subversion/libsvn_wc/adm_ops.c b/subversion/libsvn_wc/adm_ops.c
index e1e7fe4b9104..a0f806140937 100644
--- a/subversion/libsvn_wc/adm_ops.c
+++ b/subversion/libsvn_wc/adm_ops.c
@@ -965,7 +965,8 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
repos_relpath,
repos_root_url, repos_uuid,
copyfrom_rev,
- NULL /* children */, FALSE, depth,
+ NULL /* children */, depth,
+ FALSE /* is_move */,
NULL /* conflicts */,
NULL /* work items */,
scratch_pool));
diff --git a/subversion/libsvn_wc/cleanup.c b/subversion/libsvn_wc/cleanup.c
index 8ffb87e0fe1c..afe73718d0c7 100644
--- a/subversion/libsvn_wc/cleanup.c
+++ b/subversion/libsvn_wc/cleanup.c
@@ -67,69 +67,13 @@ can_be_cleaned(int *wc_format,
return SVN_NO_ERROR;
}
-/* Do a modifed check for LOCAL_ABSPATH, and all working children, to force
- timestamp repair. */
+/* Dummy svn_wc_status_func4_t implementation */
static svn_error_t *
-repair_timestamps(svn_wc__db_t *db,
- const char *local_abspath,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *scratch_pool)
+status_dummy_callback(void *baton,
+ const char *local_abspath,
+ const svn_wc_status3_t *status,
+ apr_pool_t *scratch_pool)
{
- svn_node_kind_t kind;
- svn_wc__db_status_t status;
-
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
-
- SVN_ERR(svn_wc__db_read_info(&status, &kind,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL,
- db, local_abspath, scratch_pool, scratch_pool));
-
- if (status == svn_wc__db_status_server_excluded
- || status == svn_wc__db_status_deleted
- || status == svn_wc__db_status_excluded
- || status == svn_wc__db_status_not_present)
- return SVN_NO_ERROR;
-
- if (kind == svn_node_file
- || kind == svn_node_symlink)
- {
- svn_boolean_t modified;
- SVN_ERR(svn_wc__internal_file_modified_p(&modified,
- db, local_abspath, FALSE,
- scratch_pool));
- }
- else if (kind == svn_node_dir)
- {
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- const apr_array_header_t *children;
- int i;
-
- SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
- local_abspath,
- scratch_pool,
- iterpool));
- for (i = 0; i < children->nelts; ++i)
- {
- const char *child_abspath;
-
- svn_pool_clear(iterpool);
-
- child_abspath = svn_dirent_join(local_abspath,
- APR_ARRAY_IDX(children, i,
- const char *),
- iterpool);
-
- SVN_ERR(repair_timestamps(db, child_abspath,
- cancel_func, cancel_baton, iterpool));
- }
- svn_pool_destroy(iterpool);
- }
-
return SVN_NO_ERROR;
}
@@ -184,8 +128,17 @@ cleanup_internal(svn_wc__db_t *db,
SVN_ERR(svn_wc__db_pristine_cleanup(db, dir_abspath, scratch_pool));
}
- SVN_ERR(repair_timestamps(db, dir_abspath, cancel_func, cancel_baton,
- scratch_pool));
+ /* Instead of implementing a separate repair step here, use the standard
+ status walker's optimized implementation, which performs repairs when
+ there is a lock. */
+ SVN_ERR(svn_wc__internal_walk_status(db, dir_abspath, svn_depth_infinity,
+ FALSE /* get_all */,
+ FALSE /* no_ignore */,
+ FALSE /* ignore_text_mods */,
+ NULL /* ignore patterns */,
+ status_dummy_callback, NULL,
+ cancel_func, cancel_baton,
+ scratch_pool));
/* All done, toss the lock */
SVN_ERR(svn_wc__db_wclock_release(db, dir_abspath, scratch_pool));
diff --git a/subversion/libsvn_wc/conflicts.c b/subversion/libsvn_wc/conflicts.c
index 7a491883b6cc..8bd54105a500 100644
--- a/subversion/libsvn_wc/conflicts.c
+++ b/subversion/libsvn_wc/conflicts.c
@@ -1642,7 +1642,13 @@ eval_text_conflict_func_result(svn_skel_t **work_items,
}
}
- SVN_ERR_ASSERT(install_from_abspath != NULL);
+ if (install_from_abspath == NULL)
+ return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+ _("Conflict on '%s' could not be resolved "
+ "because the chosen version of the file "
+ "is not available."),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
{
svn_skel_t *work_item;
@@ -1761,6 +1767,7 @@ resolve_text_conflict(svn_skel_t **work_items,
svn_skel_t *work_item;
svn_wc_conflict_description2_t *cdesc;
apr_hash_t *props;
+ const char *mime_type;
*work_items = NULL;
*was_resolved = FALSE;
@@ -1773,8 +1780,9 @@ resolve_text_conflict(svn_skel_t **work_items,
cdesc = svn_wc_conflict_description_create_text2(local_abspath,
scratch_pool);
- cdesc->is_binary = FALSE;
- cdesc->mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
+ mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
+ cdesc->is_binary = mime_type ? svn_mime_type_is_binary(mime_type) : FALSE;
+ cdesc->mime_type = mime_type;
cdesc->base_abspath = left_abspath;
cdesc->their_abspath = right_abspath;
cdesc->my_abspath = detranslated_target;
@@ -2262,6 +2270,8 @@ svn_wc__read_conflicts(const apr_array_header_t **conflicts,
if (text_conflicted)
{
+ apr_hash_t *props;
+ const char *mime_type;
svn_wc_conflict_description2_t *desc;
desc = svn_wc_conflict_description_create_text2(local_abspath,
result_pool);
@@ -2270,6 +2280,12 @@ svn_wc__read_conflicts(const apr_array_header_t **conflicts,
desc->src_left_version = left_version;
desc->src_right_version = right_version;
+ SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
+ scratch_pool, scratch_pool));
+ mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
+ desc->is_binary = mime_type ? svn_mime_type_is_binary(mime_type) : FALSE;
+ desc->mime_type = mime_type;
+
SVN_ERR(svn_wc__conflict_read_text_conflict(&desc->my_abspath,
&desc->base_abspath,
&desc->their_abspath,
@@ -2913,6 +2929,13 @@ conflict_status_walker(void *baton,
cd = APR_ARRAY_IDX(conflicts, i, const svn_wc_conflict_description2_t *);
+ if ((cd->kind == svn_wc_conflict_kind_property && !cswb->resolve_prop)
+ || (cd->kind == svn_wc_conflict_kind_text && !cswb->resolve_text)
+ || (cd->kind == svn_wc_conflict_kind_tree && !cswb->resolve_tree))
+ {
+ continue; /* Easy out. Don't call resolver func and ignore result */
+ }
+
svn_pool_clear(iterpool);
if (my_choice == svn_wc_conflict_choose_unspecified)
diff --git a/subversion/libsvn_wc/copy.c b/subversion/libsvn_wc/copy.c
index 1b82c2d8fdc9..1e7d7cf08b76 100644
--- a/subversion/libsvn_wc/copy.c
+++ b/subversion/libsvn_wc/copy.c
@@ -891,18 +891,18 @@ remove_node_conflict_markers(svn_wc__db_t *db,
{
const char *marker_abspath;
const char *child_relpath;
- const char *child_abpath;
+ const char *child_abspath;
marker_abspath = APR_ARRAY_IDX(markers, i, const char *);
- child_relpath = svn_dirent_is_child(src_dir, marker_abspath, NULL);
+ child_relpath = svn_dirent_skip_ancestor(src_dir, marker_abspath);
if (child_relpath)
{
- child_abpath = svn_dirent_join(dst_dir, child_relpath,
- scratch_pool);
+ child_abspath = svn_dirent_join(dst_dir, child_relpath,
+ scratch_pool);
- SVN_ERR(svn_io_remove_file2(child_abpath, TRUE, scratch_pool));
+ SVN_ERR(svn_io_remove_file2(child_abspath, TRUE, scratch_pool));
}
}
}
@@ -922,7 +922,7 @@ remove_node_conflict_markers(svn_wc__db_t *db,
static svn_error_t *
remove_all_conflict_markers(svn_wc__db_t *db,
const char *src_dir_abspath,
- const char *wc_dir_abspath,
+ const char *dst_dir_abspath,
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@@ -951,7 +951,7 @@ remove_all_conflict_markers(svn_wc__db_t *db,
SVN_ERR(remove_node_conflict_markers(
db,
svn_dirent_join(src_dir_abspath, name, iterpool),
- svn_dirent_join(wc_dir_abspath, name, iterpool),
+ svn_dirent_join(dst_dir_abspath, name, iterpool),
iterpool));
}
if (info->kind == svn_node_dir)
@@ -960,7 +960,7 @@ remove_all_conflict_markers(svn_wc__db_t *db,
SVN_ERR(remove_all_conflict_markers(
db,
svn_dirent_join(src_dir_abspath, name, iterpool),
- svn_dirent_join(wc_dir_abspath, name, iterpool),
+ svn_dirent_join(dst_dir_abspath, name, iterpool),
iterpool));
}
}
@@ -1033,8 +1033,16 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
scratch_pool));
if (conflicted)
- SVN_ERR(remove_node_conflict_markers(db, src_abspath, dst_abspath,
- scratch_pool));
+ {
+ /* When we moved a directory, we moved the conflict markers
+ with the target... if we moved a file we only moved the
+ file itself and the markers are still in the old location */
+ SVN_ERR(remove_node_conflict_markers(db, src_abspath,
+ (kind == svn_node_dir)
+ ? dst_abspath
+ : src_abspath,
+ scratch_pool));
+ }
SVN_ERR(svn_wc__db_op_delete(db, src_abspath,
move_degraded_to_copy ? NULL : dst_abspath,
diff --git a/subversion/libsvn_wc/diff.h b/subversion/libsvn_wc/diff.h
index ebaf5a8825ca..3ddada67d5d4 100644
--- a/subversion/libsvn_wc/diff.h
+++ b/subversion/libsvn_wc/diff.h
@@ -47,9 +47,6 @@ extern "C" {
svn_wc__db_status_added. When DIFF_PRISTINE is TRUE, report the pristine
version of LOCAL_ABSPATH as ADDED. In this case an
svn_wc__db_status_deleted may shadow an added or deleted node.
-
- If CHANGELIST_HASH is not NULL and LOCAL_ABSPATH's changelist is not
- in the changelist, don't report the node.
*/
svn_error_t *
svn_wc__diff_local_only_file(svn_wc__db_t *db,
@@ -57,7 +54,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
const char *relpath,
const svn_diff_tree_processor_t *processor,
void *processor_parent_baton,
- apr_hash_t *changelist_hash,
svn_boolean_t diff_pristine,
svn_cancel_func_t cancel_func,
void *cancel_baton,
@@ -73,9 +69,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
svn_wc__db_status_added. When DIFF_PRISTINE is TRUE, report the pristine
version of LOCAL_ABSPATH as ADDED. In this case an
svn_wc__db_status_deleted may shadow an added or deleted node.
-
- If CHANGELIST_HASH is not NULL and LOCAL_ABSPATH's changelist is not
- in the changelist, don't report the node.
*/
svn_error_t *
svn_wc__diff_local_only_dir(svn_wc__db_t *db,
@@ -84,7 +77,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
svn_depth_t depth,
const svn_diff_tree_processor_t *processor,
void *processor_parent_baton,
- apr_hash_t *changelist_hash,
svn_boolean_t diff_pristine,
svn_cancel_func_t cancel_func,
void *cancel_baton,
@@ -132,7 +124,6 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
const char *local_abspath,
const char *relpath,
svn_revnum_t revision,
- apr_hash_t *changelist_hash,
const svn_diff_tree_processor_t *processor,
void *processor_dir_baton,
svn_boolean_t diff_pristine,
@@ -140,6 +131,32 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
void *cancel_baton,
apr_pool_t *scratch_pool);
+/* Return a tree processor filter that filters by changelist membership.
+ *
+ * This filter only passes on the changes for a file if the file's path
+ * (in the WC) is assigned to one of the changelists in @a changelist_hash.
+ * It also passes on the opening and closing of each directory that contains
+ * such a change, and possibly also of other directories, but not addition
+ * or deletion or changes to a directory.
+ *
+ * If @a changelist_hash is null then no filtering is performed and the
+ * returned diff processor is driven exactly like the input @a processor.
+ *
+ * @a wc_ctx is the WC context and @a root_local_abspath is the WC path of
+ * the root of the diff (for which relpath = "" in the diff processor).
+ *
+ * Allocate the returned diff processor in @a result_pool, or if no
+ * filtering is required then the input pointer @a processor itself may be
+ * returned.
+ */
+const svn_diff_tree_processor_t *
+svn_wc__changelist_filter_tree_processor_create(
+ const svn_diff_tree_processor_t *processor,
+ svn_wc_context_t *wc_ctx,
+ const char *root_local_abspath,
+ apr_hash_t *changelist_hash,
+ apr_pool_t *result_pool);
+
#ifdef __cplusplus
}
diff --git a/subversion/libsvn_wc/diff_editor.c b/subversion/libsvn_wc/diff_editor.c
index b4268843893b..c9078ed7de23 100644
--- a/subversion/libsvn_wc/diff_editor.c
+++ b/subversion/libsvn_wc/diff_editor.c
@@ -114,9 +114,6 @@ struct edit_baton_t
/* Possibly diff repos against text-bases instead of working files. */
svn_boolean_t diff_pristine;
- /* Hash whose keys are const char * changelist names. */
- apr_hash_t *changelist_hash;
-
/* Cancel function/baton */
svn_cancel_func_t cancel_func;
void *cancel_baton;
@@ -238,43 +235,26 @@ struct file_baton_t
* calculating diffs. USE_TEXT_BASE defines whether to compare
* against working files or text-bases. REVERSE_ORDER defines which
* direction to perform the diff.
- *
- * CHANGELIST_FILTER is a list of const char * changelist names, used to
- * filter diff output responses to only those items in one of the
- * specified changelists, empty (or NULL altogether) if no changelist
- * filtering is requested.
*/
static svn_error_t *
make_edit_baton(struct edit_baton_t **edit_baton,
svn_wc__db_t *db,
const char *anchor_abspath,
const char *target,
- const svn_wc_diff_callbacks4_t *callbacks,
- void *callback_baton,
+ const svn_diff_tree_processor_t *processor,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
svn_boolean_t show_copies_as_adds,
svn_boolean_t use_text_base,
svn_boolean_t reverse_order,
- const apr_array_header_t *changelist_filter,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *pool)
{
- apr_hash_t *changelist_hash = NULL;
struct edit_baton_t *eb;
- const svn_diff_tree_processor_t *processor;
SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath));
- if (changelist_filter && changelist_filter->nelts)
- SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
- pool));
-
- SVN_ERR(svn_wc__wrap_diff_callbacks(&processor,
- callbacks, callback_baton, TRUE,
- pool, pool));
-
if (reverse_order)
processor = svn_diff__tree_processor_reverse_create(processor, NULL, pool);
@@ -295,7 +275,6 @@ make_edit_baton(struct edit_baton_t **edit_baton,
eb->ignore_ancestry = ignore_ancestry;
eb->local_before_remote = reverse_order;
eb->diff_pristine = use_text_base;
- eb->changelist_hash = changelist_hash;
eb->cancel_func = cancel_func;
eb->cancel_baton = cancel_baton;
eb->pool = pool;
@@ -409,7 +388,6 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
const char *local_abspath,
const char *relpath,
svn_revnum_t revision,
- apr_hash_t *changelist_hash,
const svn_diff_tree_processor_t *processor,
void *processor_dir_baton,
svn_boolean_t diff_pristine,
@@ -436,12 +414,11 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
apr_hash_t *base_props;
apr_hash_t *local_props;
apr_array_header_t *prop_changes;
- const char *changelist;
SVN_ERR(svn_wc__db_read_info(&status, NULL, &db_revision, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, &working_checksum, NULL,
NULL, NULL, NULL, NULL, NULL, &recorded_size,
- &recorded_time, &changelist, NULL, NULL,
+ &recorded_time, NULL, NULL, NULL,
&had_props, &props_mod, NULL, NULL, NULL,
db, local_abspath, scratch_pool, scratch_pool));
checksum = working_checksum;
@@ -450,12 +427,6 @@ svn_wc__diff_base_working_diff(svn_wc__db_t *db,
|| status == svn_wc__db_status_added
|| (status == svn_wc__db_status_deleted && diff_pristine));
- /* If the item is not a member of a specified changelist (and there are
- some specified changelists), skip it. */
- if (changelist_hash && !svn_hash_gets(changelist_hash, changelist))
- return SVN_NO_ERROR;
-
-
if (status != svn_wc__db_status_normal)
{
SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &db_revision,
@@ -780,7 +751,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
child_relpath,
eb->processor, dir_baton,
- eb->changelist_hash,
eb->diff_pristine,
eb->cancel_func,
eb->cancel_baton,
@@ -790,7 +760,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
child_relpath,
depth_below_here,
eb->processor, dir_baton,
- eb->changelist_hash,
eb->diff_pristine,
eb->cancel_func,
eb->cancel_baton,
@@ -826,7 +795,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
db, child_abspath,
child_relpath,
eb->revnum,
- eb->changelist_hash,
eb->processor, dir_baton,
eb->diff_pristine,
eb->cancel_func,
@@ -849,7 +817,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
child_relpath,
eb->processor, dir_baton,
- eb->changelist_hash,
eb->diff_pristine,
eb->cancel_func,
eb->cancel_baton,
@@ -858,7 +825,6 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
child_relpath, depth_below_here,
eb->processor, dir_baton,
- eb->changelist_hash,
eb->diff_pristine,
eb->cancel_func,
eb->cancel_baton,
@@ -870,13 +836,9 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
if (compared)
return SVN_NO_ERROR;
- /* Check for local property mods on this directory, if we haven't
- already reported them and we aren't changelist-filted.
- ### it should be noted that we do not currently allow directories
- ### to be part of changelists, so if a changelist is provided, the
- ### changelist check will always fail. */
+ /* Check for local property mods on this directory, if we haven't
+ already reported them. */
if (! skip
- && ! eb->changelist_hash
&& ! in_anchor_not_target
&& props_mod)
{
@@ -919,7 +881,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
const char *relpath,
const svn_diff_tree_processor_t *processor,
void *processor_parent_baton,
- apr_hash_t *changelist_hash,
svn_boolean_t diff_pristine,
svn_cancel_func_t cancel_func,
void *cancel_baton,
@@ -932,7 +893,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
const svn_checksum_t *checksum;
const char *original_repos_relpath;
svn_revnum_t original_revision;
- const char *changelist;
svn_boolean_t had_props;
svn_boolean_t props_mod;
apr_hash_t *pristine_props;
@@ -948,7 +908,7 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
NULL, NULL, NULL, NULL, &checksum, NULL,
&original_repos_relpath, NULL, NULL,
&original_revision, NULL, NULL, NULL,
- &changelist, NULL, NULL, &had_props,
+ NULL, NULL, NULL, &had_props,
&props_mod, NULL, NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool));
@@ -959,10 +919,6 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
|| (status == svn_wc__db_status_deleted && diff_pristine)));
- if (changelist && changelist_hash
- && !svn_hash_gets(changelist_hash, changelist))
- return SVN_NO_ERROR;
-
if (status == svn_wc__db_status_deleted)
{
assert(diff_pristine);
@@ -1065,12 +1021,19 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
svn_depth_t depth,
const svn_diff_tree_processor_t *processor,
void *processor_parent_baton,
- apr_hash_t *changelist_hash,
svn_boolean_t diff_pristine,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
+ svn_wc__db_status_t status;
+ svn_node_kind_t kind;
+ svn_boolean_t had_props;
+ svn_boolean_t props_mod;
+ const char *original_repos_relpath;
+ svn_revnum_t original_revision;
+ svn_diff_source_t *copyfrom_src = NULL;
+ apr_hash_t *pristine_props;
const apr_array_header_t *children;
int i;
apr_pool_t *iterpool;
@@ -1083,6 +1046,47 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
apr_hash_t *nodes;
apr_hash_t *conflicts;
+ SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ &original_repos_relpath, NULL, NULL,
+ &original_revision, NULL, NULL, NULL,
+ NULL, NULL, NULL, &had_props,
+ &props_mod, NULL, NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+ if (original_repos_relpath)
+ {
+ copyfrom_src = svn_diff__source_create(original_revision, scratch_pool);
+ copyfrom_src->repos_relpath = original_repos_relpath;
+ }
+
+ /* svn_wc__db_status_incomplete should never happen, as the result won't be
+ stable or guaranteed related to what is in the repository for this
+ revision, but without this it would be hard to diagnose that status... */
+ assert(kind == svn_node_dir
+ && (status == svn_wc__db_status_normal
+ || status == svn_wc__db_status_incomplete
+ || status == svn_wc__db_status_added
+ || (status == svn_wc__db_status_deleted && diff_pristine)));
+
+ if (status == svn_wc__db_status_deleted)
+ {
+ assert(diff_pristine);
+
+ SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, &had_props,
+ &pristine_props,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+ props_mod = FALSE;
+ }
+ else if (!had_props)
+ pristine_props = apr_hash_make(scratch_pool);
+ else
+ SVN_ERR(svn_wc__db_read_pristine_props(&pristine_props,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
/* Report the addition of the directory's contents. */
iterpool = svn_pool_create(scratch_pool);
@@ -1090,10 +1094,11 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
relpath,
NULL,
right_src,
- NULL /* copyfrom_src */,
+ copyfrom_src,
processor_parent_baton,
processor,
scratch_pool, iterpool));
+ /* ### skip_children is not used */
SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, db, local_abspath,
scratch_pool, iterpool));
@@ -1138,7 +1143,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
child_relpath,
processor, pdb,
- changelist_hash,
diff_pristine,
cancel_func, cancel_baton,
scratch_pool));
@@ -1150,7 +1154,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
child_relpath, depth_below_here,
processor, pdb,
- changelist_hash,
diff_pristine,
cancel_func, cancel_baton,
iterpool));
@@ -1165,17 +1168,19 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
if (!skip)
{
apr_hash_t *right_props;
- if (diff_pristine)
- SVN_ERR(svn_wc__db_read_pristine_props(&right_props, db, local_abspath,
- scratch_pool, scratch_pool));
+
+ if (props_mod && !diff_pristine)
+ SVN_ERR(svn_wc__db_read_props(&right_props, db, local_abspath,
+ scratch_pool, scratch_pool));
else
- SVN_ERR(svn_wc__get_actual_props(&right_props, db, local_abspath,
- scratch_pool, scratch_pool));
+ right_props = svn_prop_hash_dup(pristine_props, scratch_pool);
SVN_ERR(processor->dir_added(relpath,
- NULL /* copyfrom_src */,
+ copyfrom_src,
right_src,
- NULL,
+ copyfrom_src
+ ? pristine_props
+ : NULL,
right_props,
pdb,
processor,
@@ -1246,7 +1251,6 @@ handle_local_only(struct dir_baton_t *pb,
svn_relpath_join(pb->relpath, name, scratch_pool),
repos_delete ? svn_depth_infinity : depth,
eb->processor, pb->pdb,
- eb->changelist_hash,
eb->diff_pristine,
eb->cancel_func, eb->cancel_baton,
scratch_pool));
@@ -1257,7 +1261,6 @@ handle_local_only(struct dir_baton_t *pb,
svn_dirent_join(pb->local_abspath, name, scratch_pool),
svn_relpath_join(pb->relpath, name, scratch_pool),
eb->processor, pb->pdb,
- eb->changelist_hash,
eb->diff_pristine,
eb->cancel_func, eb->cancel_baton,
scratch_pool));
@@ -2032,7 +2035,14 @@ close_file(void *file_baton,
const char *repos_file;
apr_hash_t *repos_props;
- if (!fb->skip && expected_md5_digest != NULL)
+ if (fb->skip)
+ {
+ svn_pool_destroy(fb->pool); /* destroys scratch_pool and fb */
+ SVN_ERR(maybe_done(pb));
+ return SVN_NO_ERROR;
+ }
+
+ if (expected_md5_digest != NULL)
{
svn_checksum_t *expected_checksum;
const svn_checksum_t *result_checksum;
@@ -2087,11 +2097,7 @@ close_file(void *file_baton,
}
}
- if (fb->skip)
- {
- /* Diff processor requested skipping information */
- }
- else if (fb->repos_only)
+ if (fb->repos_only)
{
SVN_ERR(eb->processor->file_deleted(fb->relpath,
fb->left_src,
@@ -2271,6 +2277,7 @@ svn_wc__get_diff_editor(const svn_delta_editor_t **editor,
struct svn_wc__shim_fetch_baton_t *sfb;
svn_delta_shim_callbacks_t *shim_callbacks =
svn_delta_shim_callbacks_default(result_pool);
+ const svn_diff_tree_processor_t *diff_processor;
SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath));
@@ -2278,12 +2285,28 @@ svn_wc__get_diff_editor(const svn_delta_editor_t **editor,
if (use_git_diff_format)
show_copies_as_adds = TRUE;
+ SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor,
+ callbacks, callback_baton, TRUE,
+ result_pool, scratch_pool));
+
+ /* Apply changelist filtering to the output */
+ if (changelist_filter && changelist_filter->nelts)
+ {
+ apr_hash_t *changelist_hash;
+
+ SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
+ result_pool));
+ diff_processor = svn_wc__changelist_filter_tree_processor_create(
+ diff_processor, wc_ctx, anchor_abspath,
+ changelist_hash, result_pool);
+ }
+
SVN_ERR(make_edit_baton(&eb,
wc_ctx->db,
anchor_abspath, target,
- callbacks, callback_baton,
+ diff_processor,
depth, ignore_ancestry, show_copies_as_adds,
- use_text_base, reverse_order, changelist_filter,
+ use_text_base, reverse_order,
cancel_func, cancel_baton,
result_pool));
@@ -2390,8 +2413,8 @@ wrap_dir_opened(void **new_dir_baton,
wc_diff_wrap_baton_t *wb = processor->baton;
svn_boolean_t tree_conflicted = FALSE;
- assert(left_source || right_source);
- assert(!copyfrom_source || !right_source);
+ assert(left_source || right_source); /* Must exist at one point. */
+ assert(!left_source || !copyfrom_source); /* Either existed or added. */
/* Maybe store state and tree_conflicted in baton? */
if (left_source != NULL)
@@ -2749,3 +2772,329 @@ svn_wc__wrap_diff_callbacks(const svn_diff_tree_processor_t **diff_processor,
*diff_processor = processor;
return SVN_NO_ERROR;
}
+
+/* =====================================================================
+ * A tree processor filter that filters by changelist membership
+ * =====================================================================
+ *
+ * The current implementation queries the WC for the changelist of each
+ * file as it comes through, and sets the 'skip' flag for a non-matching
+ * file.
+ *
+ * (It doesn't set the 'skip' flag for a directory, as we need to receive
+ * the changed/added/deleted/closed call to know when it is closed, in
+ * order to preserve the strict open-close semantics for the wrapped tree
+ * processor.)
+ *
+ * It passes on the opening and closing of every directory, even if there
+ * are no file changes to be passed on inside that directory.
+ */
+
+typedef struct filter_tree_baton_t
+{
+ const svn_diff_tree_processor_t *processor;
+ svn_wc_context_t *wc_ctx;
+ /* WC path of the root of the diff (where relpath = "") */
+ const char *root_local_abspath;
+ /* Hash whose keys are const char * changelist names. */
+ apr_hash_t *changelist_hash;
+} filter_tree_baton_t;
+
+static svn_error_t *
+filter_dir_opened(void **new_dir_baton,
+ svn_boolean_t *skip,
+ svn_boolean_t *skip_children,
+ const char *relpath,
+ const svn_diff_source_t *left_source,
+ const svn_diff_source_t *right_source,
+ const svn_diff_source_t *copyfrom_source,
+ void *parent_dir_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->dir_opened(new_dir_baton, skip, skip_children,
+ relpath,
+ left_source, right_source,
+ copyfrom_source,
+ parent_dir_baton,
+ fb->processor,
+ result_pool, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_dir_added(const char *relpath,
+ const svn_diff_source_t *copyfrom_source,
+ const svn_diff_source_t *right_source,
+ /*const*/ apr_hash_t *copyfrom_props,
+ /*const*/ apr_hash_t *right_props,
+ void *dir_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->dir_closed(relpath,
+ NULL,
+ right_source,
+ dir_baton,
+ fb->processor,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_dir_deleted(const char *relpath,
+ const svn_diff_source_t *left_source,
+ /*const*/ apr_hash_t *left_props,
+ void *dir_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->dir_closed(relpath,
+ left_source,
+ NULL,
+ dir_baton,
+ fb->processor,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_dir_changed(const char *relpath,
+ const svn_diff_source_t *left_source,
+ const svn_diff_source_t *right_source,
+ /*const*/ apr_hash_t *left_props,
+ /*const*/ apr_hash_t *right_props,
+ const apr_array_header_t *prop_changes,
+ void *dir_baton,
+ const struct svn_diff_tree_processor_t *processor,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->dir_closed(relpath,
+ left_source,
+ right_source,
+ dir_baton,
+ fb->processor,
+ scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_dir_closed(const char *relpath,
+ const svn_diff_source_t *left_source,
+ const svn_diff_source_t *right_source,
+ void *dir_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->dir_closed(relpath,
+ left_source,
+ right_source,
+ dir_baton,
+ fb->processor,
+ scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_opened(void **new_file_baton,
+ svn_boolean_t *skip,
+ const char *relpath,
+ const svn_diff_source_t *left_source,
+ const svn_diff_source_t *right_source,
+ const svn_diff_source_t *copyfrom_source,
+ void *dir_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+ const char *local_abspath
+ = svn_dirent_join(fb->root_local_abspath, relpath, scratch_pool);
+
+ /* Skip if not a member of a given changelist */
+ if (! svn_wc__changelist_match(fb->wc_ctx, local_abspath,
+ fb->changelist_hash, scratch_pool))
+ {
+ *skip = TRUE;
+ return SVN_NO_ERROR;
+ }
+
+ SVN_ERR(fb->processor->file_opened(new_file_baton,
+ skip,
+ relpath,
+ left_source,
+ right_source,
+ copyfrom_source,
+ dir_baton,
+ fb->processor,
+ result_pool,
+ scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_added(const char *relpath,
+ const svn_diff_source_t *copyfrom_source,
+ const svn_diff_source_t *right_source,
+ const char *copyfrom_file,
+ const char *right_file,
+ /*const*/ apr_hash_t *copyfrom_props,
+ /*const*/ apr_hash_t *right_props,
+ void *file_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->file_added(relpath,
+ copyfrom_source,
+ right_source,
+ copyfrom_file,
+ right_file,
+ copyfrom_props,
+ right_props,
+ file_baton,
+ fb->processor,
+ scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_deleted(const char *relpath,
+ const svn_diff_source_t *left_source,
+ const char *left_file,
+ /*const*/ apr_hash_t *left_props,
+ void *file_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->file_deleted(relpath,
+ left_source,
+ left_file,
+ left_props,
+ file_baton,
+ fb->processor,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_changed(const char *relpath,
+ const svn_diff_source_t *left_source,
+ const svn_diff_source_t *right_source,
+ const char *left_file,
+ const char *right_file,
+ /*const*/ apr_hash_t *left_props,
+ /*const*/ apr_hash_t *right_props,
+ svn_boolean_t file_modified,
+ const apr_array_header_t *prop_changes,
+ void *file_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->file_changed(relpath,
+ left_source,
+ right_source,
+ left_file,
+ right_file,
+ left_props,
+ right_props,
+ file_modified,
+ prop_changes,
+ file_baton,
+ fb->processor,
+ scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_file_closed(const char *relpath,
+ const svn_diff_source_t *left_source,
+ const svn_diff_source_t *right_source,
+ void *file_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->file_closed(relpath,
+ left_source,
+ right_source,
+ file_baton,
+ fb->processor,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+filter_node_absent(const char *relpath,
+ void *dir_baton,
+ const svn_diff_tree_processor_t *processor,
+ apr_pool_t *scratch_pool)
+{
+ struct filter_tree_baton_t *fb = processor->baton;
+
+ SVN_ERR(fb->processor->node_absent(relpath,
+ dir_baton,
+ fb->processor,
+ scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+const svn_diff_tree_processor_t *
+svn_wc__changelist_filter_tree_processor_create(
+ const svn_diff_tree_processor_t *processor,
+ svn_wc_context_t *wc_ctx,
+ const char *root_local_abspath,
+ apr_hash_t *changelist_hash,
+ apr_pool_t *result_pool)
+{
+ struct filter_tree_baton_t *fb;
+ svn_diff_tree_processor_t *filter;
+
+ if (! changelist_hash)
+ return processor;
+
+ fb = apr_pcalloc(result_pool, sizeof(*fb));
+ fb->processor = processor;
+ fb->wc_ctx = wc_ctx;
+ fb->root_local_abspath = root_local_abspath;
+ fb->changelist_hash = changelist_hash;
+
+ filter = svn_diff__tree_processor_create(fb, result_pool);
+ filter->dir_opened = filter_dir_opened;
+ filter->dir_added = filter_dir_added;
+ filter->dir_deleted = filter_dir_deleted;
+ filter->dir_changed = filter_dir_changed;
+ filter->dir_closed = filter_dir_closed;
+
+ filter->file_opened = filter_file_opened;
+ filter->file_added = filter_file_added;
+ filter->file_deleted = filter_file_deleted;
+ filter->file_changed = filter_file_changed;
+ filter->file_closed = filter_file_closed;
+
+ filter->node_absent = filter_node_absent;
+
+ return filter;
+}
+
diff --git a/subversion/libsvn_wc/diff_local.c b/subversion/libsvn_wc/diff_local.c
index 04d4c480b751..22b498ffdb29 100644
--- a/subversion/libsvn_wc/diff_local.c
+++ b/subversion/libsvn_wc/diff_local.c
@@ -92,9 +92,6 @@ struct diff_baton
/* Should this diff not compare copied files with their source? */
svn_boolean_t show_copies_as_adds;
- /* Hash whose keys are const char * changelist names. */
- apr_hash_t *changelist_hash;
-
/* Cancel function/baton */
svn_cancel_func_t cancel_func;
void *cancel_baton;
@@ -252,11 +249,6 @@ diff_status_callback(void *baton,
if (eb->cur && eb->cur->skip_children)
return SVN_NO_ERROR;
- if (eb->changelist_hash != NULL
- && (!status->changelist
- || ! svn_hash_gets(eb->changelist_hash, status->changelist)))
- return SVN_NO_ERROR; /* Filtered via changelist */
-
/* This code does about the same thing as the inner body of
walk_local_nodes_diff() in diff_editor.c, except that
it is already filtered by the status walker, doesn't have to
@@ -361,7 +353,6 @@ diff_status_callback(void *baton,
SVN_ERR(svn_wc__diff_base_working_diff(db, child_abspath,
child_relpath,
SVN_INVALID_REVNUM,
- eb->changelist_hash,
eb->processor,
eb->cur
? eb->cur->baton
@@ -405,7 +396,6 @@ diff_status_callback(void *baton,
child_relpath,
eb->processor,
eb->cur ? eb->cur->baton : NULL,
- eb->changelist_hash,
FALSE,
eb->cancel_func,
eb->cancel_baton,
@@ -415,7 +405,6 @@ diff_status_callback(void *baton,
child_relpath, depth_below_here,
eb->processor,
eb->cur ? eb->cur->baton : NULL,
- eb->changelist_hash,
FALSE,
eb->cancel_func,
eb->cancel_baton,
@@ -482,16 +471,24 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx,
processor = svn_diff__tree_processor_copy_as_changed_create(processor,
scratch_pool);
+ /* Apply changelist filtering to the output */
+ if (changelist_filter && changelist_filter->nelts)
+ {
+ apr_hash_t *changelist_hash;
+
+ SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
+ scratch_pool));
+ processor = svn_wc__changelist_filter_tree_processor_create(
+ processor, wc_ctx, local_abspath,
+ changelist_hash, scratch_pool);
+ }
+
eb.db = wc_ctx->db;
eb.processor = processor;
eb.ignore_ancestry = ignore_ancestry;
eb.show_copies_as_adds = show_copies_as_adds;
eb.pool = scratch_pool;
- if (changelist_filter && changelist_filter->nelts)
- SVN_ERR(svn_hash_from_cstring_keys(&eb.changelist_hash, changelist_filter,
- scratch_pool));
-
if (show_copies_as_adds || use_git_diff_format || !ignore_ancestry)
get_all = TRUE; /* We need unmodified descendants of copies */
else
diff --git a/subversion/libsvn_wc/entries.c b/subversion/libsvn_wc/entries.c
index f6a73bf33134..24dae50c0ca8 100644
--- a/subversion/libsvn_wc/entries.c
+++ b/subversion/libsvn_wc/entries.c
@@ -2140,17 +2140,18 @@ write_entry(struct write_baton **entry_node,
below_working_node->presence = svn_wc__db_status_normal;
below_working_node->kind = entry->kind;
below_working_node->repos_id = work->repos_id;
+ below_working_node->revision = work->revision;
/* This is just guessing. If the node below would have been switched
or if it was updated to a different version, the guess would
fail. But we don't have better information pre wc-ng :( */
if (work->repos_relpath)
below_working_node->repos_relpath
- = svn_relpath_join(work->repos_relpath, entry->name,
+ = svn_relpath_join(work->repos_relpath,
+ svn_relpath_basename(local_relpath, NULL),
result_pool);
else
below_working_node->repos_relpath = NULL;
- below_working_node->revision = parent_node->work->revision;
/* The revert_base checksum isn't available in the entry structure,
so the caller provides it. */
diff --git a/subversion/libsvn_wc/externals.c b/subversion/libsvn_wc/externals.c
index 99127304ec4c..98395b87cc12 100644
--- a/subversion/libsvn_wc/externals.c
+++ b/subversion/libsvn_wc/externals.c
@@ -405,9 +405,10 @@ struct edit_baton
const apr_array_header_t *ext_patterns;
const char *diff3cmd;
- const char *url;
const char *repos_root_url;
const char *repos_uuid;
+ const char *old_repos_relpath;
+ const char *new_repos_relpath;
const char *record_ancestor_abspath;
const char *recorded_repos_relpath;
@@ -517,7 +518,8 @@ open_file(const char *path,
*file_baton = eb;
SVN_ERR(svn_wc__db_base_get_info(NULL, &kind, &eb->original_revision,
- NULL, NULL, NULL, &eb->changed_rev,
+ &eb->old_repos_relpath, NULL, NULL,
+ &eb->changed_rev,
&eb->changed_date, &eb->changed_author,
NULL, &eb->original_checksum, NULL, NULL,
&eb->had_props, NULL, NULL,
@@ -677,8 +679,6 @@ close_file(void *file_baton,
const svn_checksum_t *original_checksum = NULL;
svn_boolean_t added = !SVN_IS_VALID_REVNUM(eb->original_revision);
- const char *repos_relpath = svn_uri_skip_ancestor(eb->repos_root_url,
- eb->url, pool);
if (! added)
{
@@ -853,14 +853,14 @@ close_file(void *file_baton,
svn_wc_conflict_version_create2(
eb->repos_root_url,
eb->repos_uuid,
- repos_relpath,
+ eb->old_repos_relpath,
eb->original_revision,
svn_node_file,
pool),
svn_wc_conflict_version_create2(
eb->repos_root_url,
eb->repos_uuid,
- repos_relpath,
+ eb->new_repos_relpath,
*eb->target_revision,
svn_node_file,
pool),
@@ -878,7 +878,7 @@ close_file(void *file_baton,
eb->db,
eb->local_abspath,
eb->wri_abspath,
- repos_relpath,
+ eb->new_repos_relpath,
eb->repos_root_url,
eb->repos_uuid,
*eb->target_revision,
@@ -945,10 +945,15 @@ close_edit(void *edit_baton,
{
struct edit_baton *eb = edit_baton;
- if (!eb->file_closed
- || eb->iprops)
+ if (!eb->file_closed)
{
apr_hash_t *wcroot_iprops = NULL;
+ /* The file wasn't updated, but its url or revision might have...
+ e.g. switch between branches for relative externals.
+
+ Just bump the information as that is just as expensive as
+ investigating when we should and shouldn't update it...
+ and avoid hard to debug edge cases */
if (eb->iprops)
{
@@ -956,13 +961,15 @@ close_edit(void *edit_baton,
svn_hash_sets(wcroot_iprops, eb->local_abspath, eb->iprops);
}
- /* The node wasn't updated, so we just have to bump its revision */
SVN_ERR(svn_wc__db_op_bump_revisions_post_update(eb->db,
eb->local_abspath,
svn_depth_infinity,
- NULL, NULL, NULL,
+ eb->new_repos_relpath,
+ eb->repos_root_url,
+ eb->repos_uuid,
*eb->target_revision,
- apr_hash_make(pool),
+ apr_hash_make(pool)
+ /* exclude_relpaths */,
wcroot_iprops,
eb->notify_func,
eb->notify_baton,
@@ -1014,9 +1021,12 @@ svn_wc__get_file_external_editor(const svn_delta_editor_t **editor,
eb->name = svn_dirent_basename(eb->local_abspath, NULL);
eb->target_revision = target_revision;
- eb->url = apr_pstrdup(edit_pool, url);
eb->repos_root_url = apr_pstrdup(edit_pool, repos_root_url);
eb->repos_uuid = apr_pstrdup(edit_pool, repos_uuid);
+ eb->new_repos_relpath = svn_uri_skip_ancestor(eb->repos_root_url, url, edit_pool);
+ eb->old_repos_relpath = eb->new_repos_relpath;
+
+ eb->original_revision = SVN_INVALID_REVNUM;
eb->iprops = iprops;
diff --git a/subversion/libsvn_wc/update_editor.c b/subversion/libsvn_wc/update_editor.c
index e02dc301637a..fd3e9ca92eb1 100644
--- a/subversion/libsvn_wc/update_editor.c
+++ b/subversion/libsvn_wc/update_editor.c
@@ -2125,13 +2125,12 @@ add_directory(const char *path,
if (tree_conflict)
{
svn_wc_conflict_reason_t reason;
+ const char *move_src_op_root_abspath;
/* So this deletion wasn't just a deletion, it is actually a
replacement. Let's install a better tree conflict. */
- /* ### Should store the conflict in DB to allow reinstalling
- ### with theoretically more data in close_directory() */
-
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL,
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL,
+ &move_src_op_root_abspath,
eb->db,
db->local_abspath,
tree_conflict,
@@ -2143,7 +2142,7 @@ add_directory(const char *path,
tree_conflict,
eb->db, db->local_abspath,
reason, svn_wc_conflict_action_replace,
- NULL,
+ move_src_op_root_abspath,
db->pool, db->pool));
/* And now stop checking for conflicts here and just perform
@@ -3266,13 +3265,12 @@ add_file(const char *path,
if (tree_conflict)
{
svn_wc_conflict_reason_t reason;
+ const char *move_src_op_root_abspath;
/* So this deletion wasn't just a deletion, it is actually a
replacement. Let's install a better tree conflict. */
- /* ### Should store the conflict in DB to allow reinstalling
- ### with theoretically more data in close_directory() */
-
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL,
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL,
+ &move_src_op_root_abspath,
eb->db,
fb->local_abspath,
tree_conflict,
@@ -3284,7 +3282,7 @@ add_file(const char *path,
tree_conflict,
eb->db, fb->local_abspath,
reason, svn_wc_conflict_action_replace,
- NULL,
+ move_src_op_root_abspath,
fb->pool, fb->pool));
/* And now stop checking for conflicts here and just perform
@@ -5553,8 +5551,8 @@ svn_wc__complete_directory_add(svn_wc_context_t *wc_ctx,
original_repos_relpath, original_root_url,
original_uuid, original_revision,
NULL /* children */,
- FALSE /* is_move */,
svn_depth_infinity,
+ FALSE /* is_move */,
NULL /* conflict */,
NULL /* work_items */,
scratch_pool));
diff --git a/subversion/libsvn_wc/wc-checks.h b/subversion/libsvn_wc/wc-checks.h
index 43a006645426..ebc73ed03472 100644
--- a/subversion/libsvn_wc/wc-checks.h
+++ b/subversion/libsvn_wc/wc-checks.h
@@ -1,4 +1,4 @@
-/* This file is automatically generated from wc-checks.sql and .dist_sandbox/subversion-1.8.10/subversion/libsvn_wc/token-map.h.
+/* This file is automatically generated from wc-checks.sql and .dist_sandbox/subversion-1.8.14/subversion/libsvn_wc/token-map.h.
* Do not edit this file -- edit the source and rerun gen-make.py */
#define STMT_VERIFICATION_TRIGGERS 0
diff --git a/subversion/libsvn_wc/wc-metadata.h b/subversion/libsvn_wc/wc-metadata.h
index b24f24ff3fbc..83854d779d01 100644
--- a/subversion/libsvn_wc/wc-metadata.h
+++ b/subversion/libsvn_wc/wc-metadata.h
@@ -1,4 +1,4 @@
-/* This file is automatically generated from wc-metadata.sql and .dist_sandbox/subversion-1.8.10/subversion/libsvn_wc/token-map.h.
+/* This file is automatically generated from wc-metadata.sql and .dist_sandbox/subversion-1.8.14/subversion/libsvn_wc/token-map.h.
* Do not edit this file -- edit the source and rerun gen-make.py */
#define STMT_CREATE_SCHEMA 0
@@ -164,21 +164,25 @@
#define STMT_4 \
"ANALYZE sqlite_master; " \
"DELETE FROM sqlite_stat1 " \
- "WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK', 'EXTERNALS'); " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('NODES', 'sqlite_autoindex_NODES_1', '8000 8000 2 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('NODES', 'I_NODES_PARENT', '8000 8000 10 2 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('NODES', 'I_NODES_MOVED', '8000 8000 1 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('ACTUAL_NODE', 'sqlite_autoindex_ACTUAL_NODE_1', '8000 8000 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('ACTUAL_NODE', 'I_ACTUAL_PARENT', '8000 8000 10 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('LOCK', 'sqlite_autoindex_LOCK_1', '100 100 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('WC_LOCK', 'sqlite_autoindex_WC_LOCK_1', '100 100 1'); " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ " ('EXTERNALS','sqlite_autoindex_EXTERNALS_1', '100 100 1'); " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ " ('EXTERNALS','I_EXTERNALS_DEFINED', '100 100 3 1'); " \
"ANALYZE sqlite_master; " \
""
diff --git a/subversion/libsvn_wc/wc-metadata.sql b/subversion/libsvn_wc/wc-metadata.sql
index e4b226e09ea5..2a2358d7d635 100644
--- a/subversion/libsvn_wc/wc-metadata.sql
+++ b/subversion/libsvn_wc/wc-metadata.sql
@@ -598,27 +598,32 @@ CREATE UNIQUE INDEX I_EXTERNALS_DEFINED ON EXTERNALS (wc_id,
ANALYZE sqlite_master; /* Creates empty sqlite_stat1 if necessary */
DELETE FROM sqlite_stat1
-WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK');
+WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK', 'EXTERNALS');
-INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
('NODES', 'sqlite_autoindex_NODES_1', '8000 8000 2 1');
-INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
('NODES', 'I_NODES_PARENT', '8000 8000 10 2 1');
/* Tell a lie: We ignore that 99.9% of all moved_to values are NULL */
-INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
('NODES', 'I_NODES_MOVED', '8000 8000 1 1');
-INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
('ACTUAL_NODE', 'sqlite_autoindex_ACTUAL_NODE_1', '8000 8000 1');
-INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
('ACTUAL_NODE', 'I_ACTUAL_PARENT', '8000 8000 10 1');
-INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
('LOCK', 'sqlite_autoindex_LOCK_1', '100 100 1');
-INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES
+INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
('WC_LOCK', 'sqlite_autoindex_WC_LOCK_1', '100 100 1');
+INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
+ ('EXTERNALS','sqlite_autoindex_EXTERNALS_1', '100 100 1');
+INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES
+ ('EXTERNALS','I_EXTERNALS_DEFINED', '100 100 3 1');
+
/* sqlite_autoindex_WORK_QUEUE_1 doesn't exist because WORK_QUEUE is
a INTEGER PRIMARY KEY AUTOINCREMENT table */
diff --git a/subversion/libsvn_wc/wc-queries.h b/subversion/libsvn_wc/wc-queries.h
index 2508bcf256e2..50a1d9770dbf 100644
--- a/subversion/libsvn_wc/wc-queries.h
+++ b/subversion/libsvn_wc/wc-queries.h
@@ -1,4 +1,4 @@
-/* This file is automatically generated from wc-queries.sql and .dist_sandbox/subversion-1.8.10/subversion/libsvn_wc/token-map.h.
+/* This file is automatically generated from wc-queries.sql and .dist_sandbox/subversion-1.8.14/subversion/libsvn_wc/token-map.h.
* Do not edit this file -- edit the source and rerun gen-make.py */
#define STMT_SELECT_NODE_INFO 0
@@ -2172,9 +2172,16 @@
" AND (inherited_props not null) " \
""
-#define STMT_CREATE_SCHEMA 207
-#define STMT_207_INFO {"STMT_CREATE_SCHEMA", NULL}
+#define STMT_HAVE_STAT1_TABLE 207
+#define STMT_207_INFO {"STMT_HAVE_STAT1_TABLE", NULL}
#define STMT_207 \
+ "SELECT 1 FROM sqlite_master WHERE name='sqlite_stat1' AND type='table' " \
+ "LIMIT 1 " \
+ ""
+
+#define STMT_CREATE_SCHEMA 208
+#define STMT_208_INFO {"STMT_CREATE_SCHEMA", NULL}
+#define STMT_208 \
"CREATE TABLE REPOSITORY ( " \
" id INTEGER PRIMARY KEY AUTOINCREMENT, " \
" root TEXT UNIQUE NOT NULL, " \
@@ -2239,9 +2246,9 @@
"; " \
""
-#define STMT_CREATE_NODES 208
-#define STMT_208_INFO {"STMT_CREATE_NODES", NULL}
-#define STMT_208 \
+#define STMT_CREATE_NODES 209
+#define STMT_209_INFO {"STMT_CREATE_NODES", NULL}
+#define STMT_209 \
"CREATE TABLE NODES ( " \
" wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " \
" local_relpath TEXT NOT NULL, " \
@@ -2281,9 +2288,9 @@
" WHERE op_depth = 0; " \
""
-#define STMT_CREATE_NODES_TRIGGERS 209
-#define STMT_209_INFO {"STMT_CREATE_NODES_TRIGGERS", NULL}
-#define STMT_209 \
+#define STMT_CREATE_NODES_TRIGGERS 210
+#define STMT_210_INFO {"STMT_CREATE_NODES_TRIGGERS", NULL}
+#define STMT_210 \
"CREATE TRIGGER nodes_insert_trigger " \
"AFTER INSERT ON nodes " \
"WHEN NEW.checksum IS NOT NULL " \
@@ -2309,9 +2316,9 @@
"END; " \
""
-#define STMT_CREATE_EXTERNALS 210
-#define STMT_210_INFO {"STMT_CREATE_EXTERNALS", NULL}
-#define STMT_210 \
+#define STMT_CREATE_EXTERNALS 211
+#define STMT_211_INFO {"STMT_CREATE_EXTERNALS", NULL}
+#define STMT_211 \
"CREATE TABLE EXTERNALS ( " \
" wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " \
" local_relpath TEXT NOT NULL, " \
@@ -2330,32 +2337,36 @@
" local_relpath); " \
""
-#define STMT_INSTALL_SCHEMA_STATISTICS 211
-#define STMT_211_INFO {"STMT_INSTALL_SCHEMA_STATISTICS", NULL}
-#define STMT_211 \
+#define STMT_INSTALL_SCHEMA_STATISTICS 212
+#define STMT_212_INFO {"STMT_INSTALL_SCHEMA_STATISTICS", NULL}
+#define STMT_212 \
"ANALYZE sqlite_master; " \
"DELETE FROM sqlite_stat1 " \
- "WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK', 'EXTERNALS'); " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('NODES', 'sqlite_autoindex_NODES_1', '8000 8000 2 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('NODES', 'I_NODES_PARENT', '8000 8000 10 2 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('NODES', 'I_NODES_MOVED', '8000 8000 1 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('ACTUAL_NODE', 'sqlite_autoindex_ACTUAL_NODE_1', '8000 8000 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('ACTUAL_NODE', 'I_ACTUAL_PARENT', '8000 8000 10 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('LOCK', 'sqlite_autoindex_LOCK_1', '100 100 1'); " \
- "INSERT OR REPLACE INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
" ('WC_LOCK', 'sqlite_autoindex_WC_LOCK_1', '100 100 1'); " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ " ('EXTERNALS','sqlite_autoindex_EXTERNALS_1', '100 100 1'); " \
+ "INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES " \
+ " ('EXTERNALS','I_EXTERNALS_DEFINED', '100 100 3 1'); " \
"ANALYZE sqlite_master; " \
""
-#define STMT_UPGRADE_TO_20 212
-#define STMT_212_INFO {"STMT_UPGRADE_TO_20", NULL}
-#define STMT_212 \
+#define STMT_UPGRADE_TO_20 213
+#define STMT_213_INFO {"STMT_UPGRADE_TO_20", NULL}
+#define STMT_213 \
"UPDATE BASE_NODE SET checksum = (SELECT checksum FROM pristine " \
" WHERE md5_checksum = BASE_NODE.checksum) " \
"WHERE EXISTS (SELECT 1 FROM pristine WHERE md5_checksum = BASE_NODE.checksum); " \
@@ -2396,59 +2407,59 @@
"PRAGMA user_version = 20; " \
""
-#define STMT_UPGRADE_TO_21 213
-#define STMT_213_INFO {"STMT_UPGRADE_TO_21", NULL}
-#define STMT_213 \
+#define STMT_UPGRADE_TO_21 214
+#define STMT_214_INFO {"STMT_UPGRADE_TO_21", NULL}
+#define STMT_214 \
"PRAGMA user_version = 21; " \
""
-#define STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT 214
-#define STMT_214_INFO {"STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT", NULL}
-#define STMT_214 \
+#define STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT 215
+#define STMT_215_INFO {"STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT", NULL}
+#define STMT_215 \
"SELECT wc_id, local_relpath, tree_conflict_data " \
"FROM actual_node " \
"WHERE tree_conflict_data IS NOT NULL " \
""
-#define STMT_UPGRADE_21_ERASE_OLD_CONFLICTS 215
-#define STMT_215_INFO {"STMT_UPGRADE_21_ERASE_OLD_CONFLICTS", NULL}
-#define STMT_215 \
+#define STMT_UPGRADE_21_ERASE_OLD_CONFLICTS 216
+#define STMT_216_INFO {"STMT_UPGRADE_21_ERASE_OLD_CONFLICTS", NULL}
+#define STMT_216 \
"UPDATE actual_node SET tree_conflict_data = NULL " \
""
-#define STMT_UPGRADE_TO_22 216
-#define STMT_216_INFO {"STMT_UPGRADE_TO_22", NULL}
-#define STMT_216 \
+#define STMT_UPGRADE_TO_22 217
+#define STMT_217_INFO {"STMT_UPGRADE_TO_22", NULL}
+#define STMT_217 \
"UPDATE actual_node SET tree_conflict_data = conflict_data; " \
"UPDATE actual_node SET conflict_data = NULL; " \
"PRAGMA user_version = 22; " \
""
-#define STMT_UPGRADE_TO_23 217
-#define STMT_217_INFO {"STMT_UPGRADE_TO_23", NULL}
-#define STMT_217 \
+#define STMT_UPGRADE_TO_23 218
+#define STMT_218_INFO {"STMT_UPGRADE_TO_23", NULL}
+#define STMT_218 \
"PRAGMA user_version = 23; " \
""
-#define STMT_UPGRADE_23_HAS_WORKING_NODES 218
-#define STMT_218_INFO {"STMT_UPGRADE_23_HAS_WORKING_NODES", NULL}
-#define STMT_218 \
+#define STMT_UPGRADE_23_HAS_WORKING_NODES 219
+#define STMT_219_INFO {"STMT_UPGRADE_23_HAS_WORKING_NODES", NULL}
+#define STMT_219 \
"SELECT 1 FROM nodes WHERE op_depth > 0 " \
"LIMIT 1 " \
""
-#define STMT_UPGRADE_TO_24 219
-#define STMT_219_INFO {"STMT_UPGRADE_TO_24", NULL}
-#define STMT_219 \
+#define STMT_UPGRADE_TO_24 220
+#define STMT_220_INFO {"STMT_UPGRADE_TO_24", NULL}
+#define STMT_220 \
"UPDATE pristine SET refcount = " \
" (SELECT COUNT(*) FROM nodes " \
" WHERE checksum = pristine.checksum ); " \
"PRAGMA user_version = 24; " \
""
-#define STMT_UPGRADE_TO_25 220
-#define STMT_220_INFO {"STMT_UPGRADE_TO_25", NULL}
-#define STMT_220 \
+#define STMT_UPGRADE_TO_25 221
+#define STMT_221_INFO {"STMT_UPGRADE_TO_25", NULL}
+#define STMT_221 \
"DROP VIEW IF EXISTS NODES_CURRENT; " \
"CREATE VIEW NODES_CURRENT AS " \
" SELECT * FROM nodes " \
@@ -2460,9 +2471,9 @@
"PRAGMA user_version = 25; " \
""
-#define STMT_UPGRADE_TO_26 221
-#define STMT_221_INFO {"STMT_UPGRADE_TO_26", NULL}
-#define STMT_221 \
+#define STMT_UPGRADE_TO_26 222
+#define STMT_222_INFO {"STMT_UPGRADE_TO_26", NULL}
+#define STMT_222 \
"DROP VIEW IF EXISTS NODES_BASE; " \
"CREATE VIEW NODES_BASE AS " \
" SELECT * FROM nodes " \
@@ -2470,15 +2481,15 @@
"PRAGMA user_version = 26; " \
""
-#define STMT_UPGRADE_TO_27 222
-#define STMT_222_INFO {"STMT_UPGRADE_TO_27", NULL}
-#define STMT_222 \
+#define STMT_UPGRADE_TO_27 223
+#define STMT_223_INFO {"STMT_UPGRADE_TO_27", NULL}
+#define STMT_223 \
"PRAGMA user_version = 27; " \
""
-#define STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS 223
-#define STMT_223_INFO {"STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS", NULL}
-#define STMT_223 \
+#define STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS 224
+#define STMT_224_INFO {"STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS", NULL}
+#define STMT_224 \
"SELECT 1 FROM actual_node " \
"WHERE NOT ((prop_reject IS NULL) AND (conflict_old IS NULL) " \
" AND (conflict_new IS NULL) AND (conflict_working IS NULL) " \
@@ -2486,18 +2497,18 @@
"LIMIT 1 " \
""
-#define STMT_UPGRADE_TO_28 224
-#define STMT_224_INFO {"STMT_UPGRADE_TO_28", NULL}
-#define STMT_224 \
+#define STMT_UPGRADE_TO_28 225
+#define STMT_225_INFO {"STMT_UPGRADE_TO_28", NULL}
+#define STMT_225 \
"UPDATE NODES SET checksum = (SELECT checksum FROM pristine " \
" WHERE md5_checksum = nodes.checksum) " \
"WHERE EXISTS (SELECT 1 FROM pristine WHERE md5_checksum = nodes.checksum); " \
"PRAGMA user_version = 28; " \
""
-#define STMT_UPGRADE_TO_29 225
-#define STMT_225_INFO {"STMT_UPGRADE_TO_29", NULL}
-#define STMT_225 \
+#define STMT_UPGRADE_TO_29 226
+#define STMT_226_INFO {"STMT_UPGRADE_TO_29", NULL}
+#define STMT_226 \
"DROP TRIGGER IF EXISTS nodes_update_checksum_trigger; " \
"DROP TRIGGER IF EXISTS nodes_insert_trigger; " \
"DROP TRIGGER IF EXISTS nodes_delete_trigger; " \
@@ -2527,9 +2538,9 @@
"PRAGMA user_version = 29; " \
""
-#define STMT_UPGRADE_TO_30 226
-#define STMT_226_INFO {"STMT_UPGRADE_TO_30", NULL}
-#define STMT_226 \
+#define STMT_UPGRADE_TO_30 227
+#define STMT_227_INFO {"STMT_UPGRADE_TO_30", NULL}
+#define STMT_227 \
"CREATE UNIQUE INDEX IF NOT EXISTS I_NODES_MOVED " \
"ON NODES (wc_id, moved_to, op_depth); " \
"CREATE INDEX IF NOT EXISTS I_PRISTINE_MD5 ON PRISTINE (md5_checksum); " \
@@ -2537,9 +2548,9 @@
"UPDATE nodes SET file_external=1 WHERE file_external IS NOT NULL; " \
""
-#define STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE 227
-#define STMT_227_INFO {"STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE", NULL}
-#define STMT_227 \
+#define STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE 228
+#define STMT_228_INFO {"STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE", NULL}
+#define STMT_228 \
"SELECT wc_id, local_relpath, " \
" conflict_old, conflict_working, conflict_new, prop_reject, tree_conflict_data " \
"FROM actual_node " \
@@ -2551,24 +2562,24 @@
"ORDER by wc_id, local_relpath " \
""
-#define STMT_UPGRADE_30_SET_CONFLICT 228
-#define STMT_228_INFO {"STMT_UPGRADE_30_SET_CONFLICT", NULL}
-#define STMT_228 \
+#define STMT_UPGRADE_30_SET_CONFLICT 229
+#define STMT_229_INFO {"STMT_UPGRADE_30_SET_CONFLICT", NULL}
+#define STMT_229 \
"UPDATE actual_node SET conflict_data = ?3, conflict_old = NULL, " \
" conflict_working = NULL, conflict_new = NULL, prop_reject = NULL, " \
" tree_conflict_data = NULL " \
"WHERE wc_id = ?1 and local_relpath = ?2 " \
""
-#define STMT_UPGRADE_TO_31_ALTER_TABLE 229
-#define STMT_229_INFO {"STMT_UPGRADE_TO_31_ALTER_TABLE", NULL}
-#define STMT_229 \
+#define STMT_UPGRADE_TO_31_ALTER_TABLE 230
+#define STMT_230_INFO {"STMT_UPGRADE_TO_31_ALTER_TABLE", NULL}
+#define STMT_230 \
"ALTER TABLE NODES ADD COLUMN inherited_props BLOB; " \
""
-#define STMT_UPGRADE_TO_31_FINALIZE 230
-#define STMT_230_INFO {"STMT_UPGRADE_TO_31_FINALIZE", NULL}
-#define STMT_230 \
+#define STMT_UPGRADE_TO_31_FINALIZE 231
+#define STMT_231_INFO {"STMT_UPGRADE_TO_31_FINALIZE", NULL}
+#define STMT_231 \
"DROP INDEX IF EXISTS I_ACTUAL_CHANGELIST; " \
"DROP INDEX IF EXISTS I_EXTERNALS_PARENT; " \
"DROP INDEX I_NODES_PARENT; " \
@@ -2580,9 +2591,9 @@
"PRAGMA user_version = 31; " \
""
-#define STMT_UPGRADE_31_SELECT_WCROOT_NODES 231
-#define STMT_231_INFO {"STMT_UPGRADE_31_SELECT_WCROOT_NODES", NULL}
-#define STMT_231 \
+#define STMT_UPGRADE_31_SELECT_WCROOT_NODES 232
+#define STMT_232_INFO {"STMT_UPGRADE_31_SELECT_WCROOT_NODES", NULL}
+#define STMT_232 \
"SELECT l.wc_id, l.local_relpath FROM nodes as l " \
"LEFT OUTER JOIN nodes as r " \
"ON l.wc_id = r.wc_id " \
@@ -2594,9 +2605,9 @@
" OR (l.repos_path IS NOT (CASE WHEN (r.local_relpath) = '' THEN (CASE WHEN (r.repos_path) = '' THEN (l.local_relpath) WHEN (l.local_relpath) = '' THEN (r.repos_path) ELSE (r.repos_path) || '/' || (l.local_relpath) END) WHEN (r.repos_path) = '' THEN (CASE WHEN (r.local_relpath) = '' THEN (l.local_relpath) WHEN SUBSTR((l.local_relpath), 1, LENGTH(r.local_relpath)) = (r.local_relpath) THEN CASE WHEN LENGTH(r.local_relpath) = LENGTH(l.local_relpath) THEN '' WHEN SUBSTR((l.local_relpath), LENGTH(r.local_relpath)+1, 1) = '/' THEN SUBSTR((l.local_relpath), LENGTH(r.local_relpath)+2) END END) WHEN SUBSTR((l.local_relpath), 1, LENGTH(r.local_relpath)) = (r.local_relpath) THEN CASE WHEN LENGTH(r.local_relpath) = LENGTH(l.local_relpath) THEN (r.repos_path) WHEN SUBSTR((l.local_relpath), LENGTH(r.local_relpath)+1, 1) = '/' THEN (r.repos_path) || SUBSTR((l.local_relpath), LENGTH(r.local_relpath)+1) END END))) " \
""
-#define STMT_UPGRADE_TO_32 232
-#define STMT_232_INFO {"STMT_UPGRADE_TO_32", NULL}
-#define STMT_232 \
+#define STMT_UPGRADE_TO_32 233
+#define STMT_233_INFO {"STMT_UPGRADE_TO_32", NULL}
+#define STMT_233 \
"DROP INDEX IF EXISTS I_ACTUAL_CHANGELIST; " \
"DROP INDEX IF EXISTS I_EXTERNALS_PARENT; " \
"CREATE INDEX I_EXTERNALS_PARENT ON EXTERNALS (wc_id, parent_relpath); " \
@@ -2649,9 +2660,9 @@
"DROP TABLE ACTUAL_NODE_BACKUP; " \
""
-#define STMT_VERIFICATION_TRIGGERS 233
-#define STMT_233_INFO {"STMT_VERIFICATION_TRIGGERS", NULL}
-#define STMT_233 \
+#define STMT_VERIFICATION_TRIGGERS 234
+#define STMT_234_INFO {"STMT_VERIFICATION_TRIGGERS", NULL}
+#define STMT_234 \
"CREATE TEMPORARY TRIGGER no_repository_updates BEFORE UPDATE ON repository " \
"BEGIN " \
" SELECT RAISE(FAIL, 'Updates to REPOSITORY are not allowed.'); " \
@@ -2926,6 +2937,7 @@
STMT_231, \
STMT_232, \
STMT_233, \
+ STMT_234, \
NULL \
}
@@ -3165,5 +3177,6 @@
STMT_231_INFO, \
STMT_232_INFO, \
STMT_233_INFO, \
+ STMT_234_INFO, \
{NULL, NULL} \
}
diff --git a/subversion/libsvn_wc/wc-queries.sql b/subversion/libsvn_wc/wc-queries.sql
index 0ced98c79c20..7cdb46cc0252 100644
--- a/subversion/libsvn_wc/wc-queries.sql
+++ b/subversion/libsvn_wc/wc-queries.sql
@@ -1716,6 +1716,10 @@ WHERE wc_id = ?1
AND op_depth = 0
AND (inherited_props not null)
+-- STMT_HAVE_STAT1_TABLE
+SELECT 1 FROM sqlite_master WHERE name='sqlite_stat1' AND type='table'
+LIMIT 1
+
/* ------------------------------------------------------------------------- */
/* Grab all the statements related to the schema. */
diff --git a/subversion/libsvn_wc/wc.h b/subversion/libsvn_wc/wc.h
index 70c591ecb5be..d7cf017e3b43 100644
--- a/subversion/libsvn_wc/wc.h
+++ b/subversion/libsvn_wc/wc.h
@@ -190,6 +190,10 @@ extern "C" {
/* A version < this has no work queue (see workqueue.h). */
#define SVN_WC__HAS_WORK_QUEUE 13
+/* While we still have this DB version we should verify if there is
+ sqlite_stat1 table on opening */
+#define SVN_WC__ENSURE_STAT1_TABLE 31
+
/* Return a string indicating the released version (or versions) of
* Subversion that used WC format number WC_FORMAT, or some other
* suitable string if no released version used WC_FORMAT.
diff --git a/subversion/libsvn_wc/wc_db.c b/subversion/libsvn_wc/wc_db.c
index ed59d4cf6456..6c0dd6107408 100644
--- a/subversion/libsvn_wc/wc_db.c
+++ b/subversion/libsvn_wc/wc_db.c
@@ -708,6 +708,7 @@ insert_base_node(const insert_base_baton_t *pibb,
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. */
@@ -738,6 +739,9 @@ insert_base_node(const insert_base_baton_t *pibb,
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 */
@@ -750,15 +754,16 @@ insert_base_node(const insert_base_baton_t *pibb,
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
@@ -783,11 +788,14 @@ insert_base_node(const insert_base_baton_t *pibb,
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,
@@ -992,6 +1000,7 @@ insert_working_node(const insert_working_baton_t *piwb,
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);
@@ -1010,6 +1019,9 @@ insert_working_node(const insert_working_baton_t *piwb,
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 */
@@ -1018,14 +1030,14 @@ insert_working_node(const insert_working_baton_t *piwb,
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));
@@ -1034,7 +1046,7 @@ insert_working_node(const insert_working_baton_t *piwb,
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));
@@ -1051,7 +1063,8 @@ insert_working_node(const insert_working_baton_t *piwb,
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));
@@ -2615,17 +2628,21 @@ svn_wc__db_base_get_info(svn_wc__db_status_t *status,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- SVN_ERR(svn_wc__db_base_get_info_internal(status, kind, revision,
+ SVN_WC__DB_WITH_TXN4(
+ svn_wc__db_base_get_info_internal(status, kind, revision,
repos_relpath, &repos_id,
changed_rev, changed_date,
changed_author, depth,
checksum, target, lock,
had_props, props, update_root,
wcroot, local_relpath,
- result_pool, scratch_pool));
+ result_pool, scratch_pool),
+ svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
+ wcroot->sdb, repos_id, result_pool),
+ SVN_NO_ERROR,
+ SVN_NO_ERROR,
+ wcroot);
SVN_ERR_ASSERT(repos_id != INVALID_REPOS_ID);
- SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
- wcroot->sdb, repos_id, result_pool));
return SVN_NO_ERROR;
}
@@ -5339,8 +5356,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)
@@ -5367,11 +5384,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,
@@ -5379,6 +5391,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? */
@@ -5447,11 +5464,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,
@@ -5459,6 +5471,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? */
@@ -5501,6 +5518,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
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)
@@ -5525,11 +5543,6 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
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)
{
@@ -5538,6 +5551,11 @@ svn_wc__db_op_copy_symlink(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? */
@@ -5547,6 +5565,8 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
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;
@@ -7518,7 +7538,11 @@ delete_update_movedto(svn_wc__db_wcroot_t *wcroot,
op_depth,
new_moved_to_relpath));
SVN_ERR(svn_sqlite__update(&affected, stmt));
- assert(affected == 1);
+#ifdef SVN_DEBUG
+ /* Not fatal in release mode. The move recording is broken,
+ but the rest of the working copy can handle this. */
+ SVN_ERR_ASSERT(affected == 1);
+#endif
return SVN_NO_ERROR;
}
@@ -7908,7 +7932,12 @@ delete_node(void *baton,
child_relpath))
child_op_depth = delete_op_depth;
else
- child_op_depth = relpath_depth(child_relpath);
+ {
+ /* Calculate depth of the shadowing at the new location */
+ child_op_depth = child_op_depth
+ - relpath_depth(local_relpath)
+ + relpath_depth(b->moved_to_relpath);
+ }
fixup = TRUE;
}
@@ -8734,19 +8763,22 @@ svn_wc__db_read_info(svn_wc__db_status_t *status,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- SVN_ERR(read_info(status, kind, revision, repos_relpath, &repos_id,
+ SVN_WC__DB_WITH_TXN4(
+ read_info(status, kind, revision, repos_relpath, &repos_id,
changed_rev, changed_date, changed_author,
depth, checksum, target, original_repos_relpath,
&original_repos_id, original_revision, lock,
recorded_size, recorded_time, changelist, conflicted,
op_root, have_props, props_mod,
have_base, have_more_work, have_work,
- wcroot, local_relpath, result_pool, scratch_pool));
- SVN_ERR(svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
- wcroot->sdb, repos_id, result_pool));
- SVN_ERR(svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
+ wcroot, local_relpath, result_pool, scratch_pool),
+ svn_wc__db_fetch_repos_info(repos_root_url, repos_uuid,
+ wcroot->sdb, repos_id, result_pool),
+ svn_wc__db_fetch_repos_info(original_root_url, original_uuid,
wcroot->sdb, original_repos_id,
- result_pool));
+ result_pool),
+ SVN_NO_ERROR,
+ wcroot);
return SVN_NO_ERROR;
}
@@ -10865,59 +10897,86 @@ svn_wc__db_global_relocate(svn_wc__db_t *db,
}
-/* Set *REPOS_ID and *REPOS_RELPATH to the BASE repository location of
+/* Helper for commit_node()
+ Set *REPOS_ID and *REPOS_RELPATH to the BASE repository location of
(WCROOT, LOCAL_RELPATH), directly if its BASE row exists or implied from
its parent's BASE row if not. In the latter case, error if the parent
BASE row does not exist. */
static svn_error_t *
-determine_repos_info(apr_int64_t *repos_id,
- const char **repos_relpath,
- svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+determine_commit_repos_info(apr_int64_t *repos_id,
+ const char **repos_relpath,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
- const char *repos_parent_relpath;
- const char *local_parent_relpath, *name;
-
- /* ### is it faster to fetch fewer columns? */
+ int op_depth;
/* Prefer the current node's repository information. */
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_BASE_NODE));
+ 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)
+ if (!have_row)
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
+ svn_sqlite__reset(stmt),
+ _("The node '%s' was not found."),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+
+ op_depth = svn_sqlite__column_int(stmt, 0);
+
+ if (op_depth > 0)
{
- SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 0));
- SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 1));
+ svn_wc__db_status_t presence = svn_sqlite__column_token(stmt, 3,
+ presence_map);
+
+ if (presence == svn_wc__db_status_base_deleted)
+ {
+ SVN_ERR(svn_sqlite__step_row(stmt)); /* There must be a row */
+ op_depth = svn_sqlite__column_int(stmt, 0);
+ }
+ else
+ {
+ const char *parent_repos_relpath;
+ const char *parent_relpath;
+ const char *name;
+
+ SVN_ERR(svn_sqlite__reset(stmt));
- *repos_id = svn_sqlite__column_int64(stmt, 0);
- *repos_relpath = svn_sqlite__column_text(stmt, 1, result_pool);
+ /* The repository relative path of an add/copy is based on its
+ ancestor, not on the shadowed base layer.
- return svn_error_trace(svn_sqlite__reset(stmt));
+ As this function is only used from the commit processing we know
+ the parent directory has only a BASE row, so we can just obtain
+ the information directly by recursing (once!) */
+
+ svn_relpath_split(&parent_relpath, &name, local_relpath,
+ scratch_pool);
+
+ SVN_ERR(determine_commit_repos_info(repos_id, &parent_repos_relpath,
+ wcroot, parent_relpath,
+ scratch_pool, scratch_pool));
+
+ *repos_relpath = svn_relpath_join(parent_repos_relpath, name,
+ result_pool);
+ return SVN_NO_ERROR;
+ }
}
- SVN_ERR(svn_sqlite__reset(stmt));
- /* This was a child node within this wcroot. We want to look at the
- BASE node of the directory. */
- svn_relpath_split(&local_parent_relpath, &name, local_relpath, scratch_pool);
+ SVN_ERR_ASSERT(op_depth == 0); /* And that row must be BASE */
- /* The REPOS_ID will be the same (### until we support mixed-repos) */
- SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL,
- &repos_parent_relpath, repos_id,
- NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- wcroot, local_parent_relpath,
- scratch_pool, scratch_pool));
+ SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 1));
+ SVN_ERR_ASSERT(!svn_sqlite__column_is_null(stmt, 2));
- *repos_relpath = svn_relpath_join(repos_parent_relpath, name, result_pool);
+ *repos_id = svn_sqlite__column_int64(stmt, 1);
+ *repos_relpath = svn_sqlite__column_text(stmt, 2, result_pool);
- return SVN_NO_ERROR;
+ return svn_error_trace(svn_sqlite__reset(stmt));
}
/* Helper for svn_wc__db_global_commit()
@@ -11103,9 +11162,9 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
For existing nodes, we should retain the (potentially-switched)
repository information. */
- SVN_ERR(determine_repos_info(&repos_id, &repos_relpath,
- wcroot, local_relpath,
- scratch_pool, scratch_pool));
+ SVN_ERR(determine_commit_repos_info(&repos_id, &repos_relpath,
+ wcroot, local_relpath,
+ scratch_pool, scratch_pool));
/* ### is it better to select only the data needed? */
SVN_ERR(svn_sqlite__get_statement(&stmt_info, wcroot->sdb,
diff --git a/subversion/libsvn_wc/wc_db.h b/subversion/libsvn_wc/wc_db.h
index b0914942416b..0fcce5e0e043 100644
--- a/subversion/libsvn_wc/wc_db.h
+++ b/subversion/libsvn_wc/wc_db.h
@@ -1361,8 +1361,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);
@@ -1403,6 +1403,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t *db,
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);
diff --git a/subversion/libsvn_wc/wc_db_private.h b/subversion/libsvn_wc/wc_db_private.h
index e8f31d132374..a4bf98f67042 100644
--- a/subversion/libsvn_wc/wc_db_private.h
+++ b/subversion/libsvn_wc/wc_db_private.h
@@ -358,6 +358,18 @@ svn_wc__db_with_txn(svn_wc__db_wcroot_t *wcroot,
SVN_SQLITE__WITH_LOCK(expr, (wcroot)->sdb)
+/* Evaluate the expressions EXPR1..EXPR4 within a transaction, returning the
+ * first error if an error occurs.
+ *
+ * Begin a transaction in WCROOT's DB; evaluate the expressions, which would
+ * typically be function calls that do some work in DB; finally commit
+ * the transaction if EXPR evaluated to SVN_NO_ERROR, otherwise roll back
+ * the transaction.
+ */
+#define SVN_WC__DB_WITH_TXN4(expr1, expr2, expr3, expr4, wcroot) \
+ SVN_SQLITE__WITH_LOCK4(expr1, expr2, expr3, expr4, (wcroot)->sdb)
+
+
/* Return CHILDREN mapping const char * names to svn_node_kind_t * for the
children of LOCAL_RELPATH at OP_DEPTH. */
svn_error_t *
diff --git a/subversion/libsvn_wc/wc_db_wcroot.c b/subversion/libsvn_wc/wc_db_wcroot.c
index d801451f613e..a111073b3d18 100644
--- a/subversion/libsvn_wc/wc_db_wcroot.c
+++ b/subversion/libsvn_wc/wc_db_wcroot.c
@@ -262,7 +262,7 @@ svn_wc__db_pdh_create_wcroot(svn_wc__db_wcroot_t **wcroot,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- if (sdb != NULL)
+ if (sdb && format == FORMAT_FROM_SDB)
SVN_ERR(svn_sqlite__read_schema_version(&format, sdb, scratch_pool));
/* If we construct a wcroot, then we better have a format. */
@@ -414,6 +414,56 @@ read_link_target(const char **link_target_abspath,
return SVN_NO_ERROR;
}
+/* Verify if the sqlite_stat1 table exists and if not tries to add
+ this table (but ignores errors on adding the schema) */
+static svn_error_t *
+verify_stats_table(svn_sqlite__db_t *sdb,
+ int format,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ if (format != SVN_WC__ENSURE_STAT1_TABLE)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_HAVE_STAT1_TABLE));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ if (!have_row)
+ {
+ svn_error_clear(
+ svn_wc__db_install_schema_statistics(sdb, scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Sqlite transaction helper for opening the db in
+ svn_wc__db_wcroot_parse_local_abspath() to avoid multiple
+ db operations that each obtain and release a lock */
+static svn_error_t *
+fetch_sdb_info(apr_int64_t *wc_id,
+ int *format,
+ svn_sqlite__db_t *sdb,
+ apr_pool_t *scratch_pool)
+{
+ *wc_id = -1;
+ *format = -1;
+
+ SVN_SQLITE__WITH_LOCK4(
+ svn_wc__db_util_fetch_wc_id(wc_id, sdb, scratch_pool),
+ svn_sqlite__read_schema_version(format, sdb, scratch_pool),
+ verify_stats_table(sdb, *format, scratch_pool),
+ SVN_NO_ERROR,
+ sdb);
+
+ return SVN_NO_ERROR;
+}
+
+
svn_error_t *
svn_wc__db_wcroot_parse_local_abspath(svn_wc__db_wcroot_t **wcroot,
const char **local_relpath,
@@ -654,9 +704,10 @@ try_symlink_as_dir:
/* We finally found the database. Construct a wcroot_t for it. */
apr_int64_t wc_id;
+ int format;
svn_error_t *err;
- err = svn_wc__db_util_fetch_wc_id(&wc_id, sdb, scratch_pool);
+ err = fetch_sdb_info(&wc_id, &format, sdb, scratch_pool);
if (err)
{
if (err->apr_err == SVN_ERR_WC_CORRUPT)
@@ -677,7 +728,7 @@ try_symlink_as_dir:
symlink_wcroot_abspath
? symlink_wcroot_abspath
: local_abspath),
- sdb, wc_id, FORMAT_FROM_SDB,
+ sdb, wc_id, format,
db->verify_format, db->enforce_empty_wq,
db->state_pool, scratch_pool);
if (err && (err->apr_err == SVN_ERR_WC_UNSUPPORTED_FORMAT ||