diff options
Diffstat (limited to 'subversion/libsvn_wc')
-rw-r--r-- | subversion/libsvn_wc/adm_ops.c | 3 | ||||
-rw-r--r-- | subversion/libsvn_wc/cleanup.c | 79 | ||||
-rw-r--r-- | subversion/libsvn_wc/conflicts.c | 29 | ||||
-rw-r--r-- | subversion/libsvn_wc/copy.c | 28 | ||||
-rw-r--r-- | subversion/libsvn_wc/diff.h | 35 | ||||
-rw-r--r-- | subversion/libsvn_wc/diff_editor.c | 493 | ||||
-rw-r--r-- | subversion/libsvn_wc/diff_local.c | 27 | ||||
-rw-r--r-- | subversion/libsvn_wc/entries.c | 5 | ||||
-rw-r--r-- | subversion/libsvn_wc/externals.c | 36 | ||||
-rw-r--r-- | subversion/libsvn_wc/update_editor.c | 20 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc-checks.h | 2 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc-metadata.h | 22 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc-metadata.sql | 21 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc-queries.h | 191 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc-queries.sql | 4 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc.h | 4 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc_db.c | 205 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc_db.h | 3 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc_db_private.h | 12 | ||||
-rw-r--r-- | subversion/libsvn_wc/wc_db_wcroot.c | 57 |
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 || |