diff options
author | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
---|---|---|
committer | Peter Wemm <peter@FreeBSD.org> | 2018-05-08 03:44:38 +0000 |
commit | 3faf8d6bffc5d0fb2525ba37bb504c53366caf9d (patch) | |
tree | 7e47911263e75034b767fe34b2f8d3d17e91f66d /subversion/libsvn_wc | |
parent | a55fb3c0d5eca7d887798125d5b95942b1f01d4b (diff) |
Import Subversion-1.10.0vendor/subversion/subversion-1.10.0
Notes
Notes:
svn path=/vendor/subversion/dist/; revision=333347
svn path=/vendor/subversion/subversion-1.10.0/; revision=333348; tag=vendor/subversion/subversion-1.10.0
Diffstat (limited to 'subversion/libsvn_wc')
29 files changed, 3260 insertions, 1767 deletions
diff --git a/subversion/libsvn_wc/adm_crawler.c b/subversion/libsvn_wc/adm_crawler.c index ebdc75e105f4..864535f6a70b 100644 --- a/subversion/libsvn_wc/adm_crawler.c +++ b/subversion/libsvn_wc/adm_crawler.c @@ -906,6 +906,27 @@ close_handler_copy(void *baton) return svn_stream_close(btn->source); } +/* Implements svn_stream_seek_fn_t */ +static svn_error_t * +seek_handler_copy(void *baton, const svn_stream_mark_t *mark) +{ + struct copying_stream_baton *btn = baton; + + /* Only reset support. */ + if (mark) + { + return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, + NULL, NULL); + } + else + { + SVN_ERR(svn_stream_reset(btn->source)); + SVN_ERR(svn_stream_reset(btn->target)); + } + + return SVN_NO_ERROR; +} + /* Return a stream - allocated in POOL - which reads its input * from SOURCE and, while returning that to the caller, at the @@ -928,6 +949,11 @@ copying_stream(svn_stream_t *source, read_handler_copy); svn_stream_set_close(stream, close_handler_copy); + if (svn_stream_supports_reset(source) && svn_stream_supports_reset(target)) + { + svn_stream_set_seek(stream, seek_handler_copy); + } + return stream; } @@ -995,9 +1021,38 @@ read_and_checksum_pristine_text(svn_stream_t **stream, return SVN_NO_ERROR; } +typedef struct open_txdelta_stream_baton_t +{ + svn_boolean_t need_reset; + svn_stream_t *base_stream; + svn_stream_t *local_stream; +} open_txdelta_stream_baton_t; + +/* Implements svn_txdelta_stream_open_func_t */ +static svn_error_t * +open_txdelta_stream(svn_txdelta_stream_t **txdelta_stream_p, + void *baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + open_txdelta_stream_baton_t *b = baton; + + if (b->need_reset) + { + /* Under rare circumstances, we can be restarted and would need to + * supply the delta stream again. In this case, reset both streams. */ + SVN_ERR(svn_stream_reset(b->base_stream)); + SVN_ERR(svn_stream_reset(b->local_stream)); + } + + svn_txdelta2(txdelta_stream_p, b->base_stream, b->local_stream, + FALSE, result_pool); + b->need_reset = TRUE; + return SVN_NO_ERROR; +} svn_error_t * -svn_wc__internal_transmit_text_deltas(const char **tempfile, +svn_wc__internal_transmit_text_deltas(svn_stream_t *tempstream, const svn_checksum_t **new_text_base_md5_checksum, const svn_checksum_t **new_text_base_sha1_checksum, svn_wc__db_t *db, @@ -1008,8 +1063,6 @@ svn_wc__internal_transmit_text_deltas(const char **tempfile, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - svn_txdelta_window_handler_t handler; - void *wh_baton; const svn_checksum_t *expected_md5_checksum; /* recorded MD5 of BASE_S. */ svn_checksum_t *verify_checksum; /* calc'd MD5 of BASE_STREAM */ svn_checksum_t *local_md5_checksum; /* calc'd MD5 of LOCAL_STREAM */ @@ -1027,22 +1080,13 @@ svn_wc__internal_transmit_text_deltas(const char **tempfile, scratch_pool, scratch_pool)); /* If the caller wants a copy of the working file translated to - * repository-normal form, make the copy by tee-ing the stream and set - * *TEMPFILE to the path to it. This is only needed for the 1.6 API, - * 1.7 doesn't set TEMPFILE. Even when using the 1.6 API this file - * is not used by the functions that would have used it when using - * the 1.6 code. It's possible that 3rd party users (if there are any) - * might expect this file to be a text-base. */ - if (tempfile) + * repository-normal form, make the copy by tee-ing the TEMPSTREAM. + * This is only needed for the 1.6 API. Even when using the 1.6 API + * this temporary file is not used by the functions that would have used + * it when using the 1.6 code. It's possible that 3rd party users (if + * there are any) might expect this file to be a text-base. */ + if (tempstream) { - svn_stream_t *tempstream; - - /* It can't be the same location as in 1.6 because the admin directory - no longer exists. */ - SVN_ERR(svn_stream_open_unique(&tempstream, tempfile, - NULL, svn_io_file_del_none, - result_pool, scratch_pool)); - /* Wrap the translated stream with a new stream that writes the translated contents into the new text base file as we read from it. Note that the new text base file will be closed when the new stream @@ -1088,30 +1132,33 @@ svn_wc__internal_transmit_text_deltas(const char **tempfile, verify_checksum = NULL; } - /* Tell the editor that we're about to apply a textdelta to the - file baton; the editor returns to us a window consumer and baton. */ + /* Arrange the stream to calculate the resulting MD5. */ + local_stream = svn_stream_checksummed2(local_stream, &local_md5_checksum, + NULL, svn_checksum_md5, TRUE, + scratch_pool); + + /* Tell the editor to apply a textdelta stream to the file baton. */ { - /* apply_textdelta() is working against a base with this checksum */ + open_txdelta_stream_baton_t baton = { 0 }; + + /* apply_textdelta_stream() is working against a base with this checksum */ const char *base_digest_hex = NULL; if (expected_md5_checksum) /* ### Why '..._display()'? expected_md5_checksum should never be all- * zero, but if it is, we would want to pass NULL not an all-zero - * digest to apply_textdelta(), wouldn't we? */ + * digest to apply_textdelta_stream(), wouldn't we? */ base_digest_hex = svn_checksum_to_cstring_display(expected_md5_checksum, scratch_pool); - SVN_ERR(editor->apply_textdelta(file_baton, base_digest_hex, scratch_pool, - &handler, &wh_baton)); + baton.need_reset = FALSE; + baton.base_stream = svn_stream_disown(base_stream, scratch_pool); + baton.local_stream = svn_stream_disown(local_stream, scratch_pool); + err = editor->apply_textdelta_stream(editor, file_baton, base_digest_hex, + open_txdelta_stream, &baton, + scratch_pool); } - /* Run diff processing, throwing windows at the handler. */ - err = svn_txdelta_run(base_stream, local_stream, - handler, wh_baton, - svn_checksum_md5, &local_md5_checksum, - NULL, NULL, - scratch_pool, scratch_pool); - /* Close the two streams to force writing the digest */ err2 = svn_stream_close(base_stream); if (err2) @@ -1141,11 +1188,6 @@ svn_wc__internal_transmit_text_deltas(const char **tempfile, investigate. Other commands could be affected, too, such as `svn diff'. */ - if (tempfile) - err = svn_error_compose_create( - err, - svn_io_remove_file2(*tempfile, TRUE, scratch_pool)); - err = svn_error_compose_create( svn_checksum_mismatch_err(expected_md5_checksum, verify_checksum, scratch_pool, diff --git a/subversion/libsvn_wc/conflicts.c b/subversion/libsvn_wc/conflicts.c index f04c6de59481..606710c69f00 100644 --- a/subversion/libsvn_wc/conflicts.c +++ b/subversion/libsvn_wc/conflicts.c @@ -50,6 +50,7 @@ #include "private/svn_wc_private.h" #include "private/svn_skel.h" +#include "private/svn_sorts_private.h" #include "private/svn_string_private.h" #include "svn_private_config.h" @@ -1351,8 +1352,6 @@ generate_propconflict(svn_boolean_t *conflict_remains, } case svn_wc_conflict_choose_merged: { - svn_stringbuf_t *merged_stringbuf; - if (!cdesc->merged_file && (!result->merged_file && !result->merged_value)) return svn_error_create @@ -1364,6 +1363,8 @@ generate_propconflict(svn_boolean_t *conflict_remains, new_value = result->merged_value; else { + svn_stringbuf_t *merged_stringbuf; + SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf, result->merged_file ? result->merged_file : @@ -2339,6 +2340,17 @@ svn_wc__read_conflicts(const apr_array_header_t **conflicts, return SVN_NO_ERROR; } +svn_error_t * +svn_wc__read_conflict_descriptions2_t(const apr_array_header_t **conflicts, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_wc__read_conflicts(conflicts, NULL, wc_ctx->db, local_abspath, + FALSE, FALSE, result_pool, scratch_pool); +} + /*** Resolving a conflict automatically ***/ @@ -2477,15 +2489,12 @@ resolve_prop_conflict_on_node(svn_boolean_t *did_resolve, if (!merged_value) { - svn_stream_t *stream; - svn_string_t *merged_propval; + svn_stringbuf_t *merged_propval; - SVN_ERR(svn_stream_open_readonly(&stream, merged_file, - scratch_pool, scratch_pool)); - SVN_ERR(svn_string_from_stream(&merged_propval, stream, - scratch_pool, scratch_pool)); + SVN_ERR(svn_stringbuf_from_file2(&merged_propval, merged_file, + scratch_pool)); - merged_value = merged_propval; + merged_value = svn_stringbuf__morph_into_string(merged_propval); } svn_hash_sets(resolve_from, conflicted_propname, merged_value); } @@ -2594,6 +2603,35 @@ resolve_prop_conflict_on_node(svn_boolean_t *did_resolve, return SVN_NO_ERROR; } +/* + * Record a tree conflict resolution failure due to error condition ERR + * in the RESOLVE_LATER hash table. If the hash table is not available + * (meaning the caller does not wish to retry resolution later), or if + * the error condition does not indicate circumstances where another + * existing tree conflict is blocking the resolution attempt, then + * return the error ERR itself. + */ +static svn_error_t * +handle_tree_conflict_resolution_failure(const char *local_abspath, + svn_error_t *err, + apr_hash_t *resolve_later) +{ + const char *dup_abspath; + + if (!resolve_later + || (err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE + && err->apr_err != SVN_ERR_WC_FOUND_CONFLICT)) + return svn_error_trace(err); /* Give up. Do not retry resolution later. */ + + svn_error_clear(err); + dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later), + local_abspath); + + svn_hash_sets(resolve_later, dup_abspath, dup_abspath); + + return SVN_NO_ERROR; /* Caller may retry after resolving other conflicts. */ +} + /* * Resolve the tree conflict found in DB/LOCAL_ABSPATH according to * CONFLICT_CHOICE. @@ -2603,9 +2641,11 @@ resolve_prop_conflict_on_node(svn_boolean_t *did_resolve, * * It is not an error if there is no tree conflict. * - * If the conflict can't be resolved yet because another tree conflict is - * blocking a storage location, store the tree conflict in the RESOLVE_LATER - * hash. + * If the conflict can't be resolved yet (e.g. because another tree conflict + * is blocking a storage location), and RESOLVE_LATER is not NULL, store the + * tree conflict in RESOLVE_LATER and do not mark the conflict resolved. + * Else if RESOLVE_LATER is NULL, do not mark the conflict resolved and + * return the error which prevented the conflict from being marked resolved. */ static svn_error_t * resolve_tree_conflict_on_node(svn_boolean_t *did_resolve, @@ -2670,8 +2710,9 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve, { svn_skel_t *new_conflicts; - /* Raise moved-away conflicts on any children moved out of - * this directory, and leave this directory as-is. + /* Raise local moved-away vs. incoming edit conflicts on + * any children moved out of this directory, and leave + * this directory as-is. * * The newly conflicted moved-away children will be updated * if they are resolved with 'mine_conflict' as well. */ @@ -2680,21 +2721,8 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve, scratch_pool); if (err) - { - const char *dup_abspath; - - if (!resolve_later - || err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE) - return svn_error_trace(err); - - svn_error_clear(err); - dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later), - local_abspath); - - svn_hash_sets(resolve_later, dup_abspath, dup_abspath); - - return SVN_NO_ERROR; /* Retry after other conflicts */ - } + SVN_ERR(handle_tree_conflict_resolution_failure( + local_abspath, err, resolve_later)); /* We might now have a moved-away on *this* path, let's try to resolve that directly if that is the case */ @@ -2713,7 +2741,7 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve, if (!new_conflicts || !tree_conflicted) { /* TC is marked resolved by calling - svn_wc__db_resolve_delete_raise_moved_away */ + svn_wc__db_op_raise_moved_away */ *did_resolve = TRUE; return SVN_NO_ERROR; } @@ -2761,21 +2789,8 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve, scratch_pool); if (err) - { - const char *dup_abspath; - - if (!resolve_later - || err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE) - return svn_error_trace(err); - - svn_error_clear(err); - dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later), - local_abspath); - - svn_hash_sets(resolve_later, dup_abspath, dup_abspath); - - return SVN_NO_ERROR; /* Retry after other conflicts */ - } + SVN_ERR(handle_tree_conflict_resolution_failure( + local_abspath, err, resolve_later)); else *did_resolve = TRUE; } @@ -2973,12 +2988,13 @@ conflict_status_walker(void *baton, { struct conflict_status_walker_baton *cswb = baton; svn_wc__db_t *db = cswb->db; - + svn_wc_notify_action_t notify_action = svn_wc_notify_resolved; const apr_array_header_t *conflicts; apr_pool_t *iterpool; int i; svn_boolean_t resolved = FALSE; svn_skel_t *conflict; + const svn_wc_conflict_description2_t *cd; if (!status->conflicted) return SVN_NO_ERROR; @@ -2993,7 +3009,6 @@ conflict_status_walker(void *baton, for (i = 0; i < conflicts->nelts; i++) { - const svn_wc_conflict_description2_t *cd; svn_boolean_t did_resolve; svn_wc_conflict_choice_t my_choice = cswb->conflict_choice; svn_wc_conflict_result_t *result = NULL; @@ -3045,7 +3060,10 @@ conflict_status_walker(void *baton, iterpool)); if (did_resolve) - resolved = TRUE; + { + resolved = TRUE; + notify_action = svn_wc_notify_resolved_tree; + } break; case svn_wc_conflict_kind_text: @@ -3069,6 +3087,8 @@ conflict_status_walker(void *baton, SVN_ERR(svn_wc__wq_run(db, local_abspath, cswb->cancel_func, cswb->cancel_baton, iterpool)); + if (resolved) + notify_action = svn_wc_notify_resolved_text; break; case svn_wc_conflict_kind_property: @@ -3089,7 +3109,10 @@ conflict_status_walker(void *baton, iterpool)); if (did_resolve) - resolved = TRUE; + { + resolved = TRUE; + notify_action = svn_wc_notify_resolved_prop; + } break; default: @@ -3100,12 +3123,33 @@ conflict_status_walker(void *baton, /* Notify */ if (cswb->notify_func && resolved) - cswb->notify_func(cswb->notify_baton, - svn_wc_create_notify(local_abspath, - svn_wc_notify_resolved, - iterpool), - iterpool); + { + svn_wc_notify_t *notify; + + /* If our caller asked for all conflicts to be resolved, + * send a general 'resolved' notification. */ + if (cswb->resolve_text && cswb->resolve_tree && + (cswb->resolve_prop == NULL || cswb->resolve_prop[0] == '\0')) + notify_action = svn_wc_notify_resolved; + + /* If we resolved a property conflict, but no specific property was + * requested by the caller, send a general 'resolved' notification. */ + if (notify_action == svn_wc_notify_resolved_prop && + (cswb->resolve_prop == NULL || cswb->resolve_prop[0] == '\0')) + notify_action = svn_wc_notify_resolved; + + notify = svn_wc_create_notify(local_abspath, notify_action, iterpool); + + /* Add the property name for property-specific notifications. */ + if (notify_action == svn_wc_notify_resolved_prop) + { + notify->prop_name = cd->property_name; + SVN_ERR_ASSERT(strlen(notify->prop_name) > 0); + } + + cswb->notify_func(cswb->notify_baton, notify, iterpool); + } if (resolved) cswb->resolved_one = TRUE; @@ -3130,26 +3174,11 @@ svn_wc__resolve_conflicts(svn_wc_context_t *wc_ctx, void *notify_baton, apr_pool_t *scratch_pool) { - svn_node_kind_t kind; - svn_boolean_t conflicted; struct conflict_status_walker_baton cswb; apr_pool_t *iterpool = NULL; svn_error_t *err; - /* ### Just a versioned check? */ - /* Conflicted is set to allow invoking on actual only nodes */ - SVN_ERR(svn_wc__db_read_info(NULL, &kind, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, &conflicted, - NULL, NULL, NULL, NULL, NULL, NULL, - wc_ctx->db, local_abspath, - scratch_pool, scratch_pool)); - - /* When the implementation still used the entry walker, depth - unknown was translated to infinity. */ - if (kind != svn_node_dir) - depth = svn_depth_empty; - else if (depth == svn_depth_unknown) + if (depth == svn_depth_unknown) depth = svn_depth_infinity; cswb.db = wc_ctx->db; @@ -3321,8 +3350,591 @@ svn_wc_create_conflict_result(svn_wc_conflict_choice_t choice, result->choice = choice; result->merged_file = apr_pstrdup(pool, merged_file); result->save_merged = FALSE; + result->merged_value = NULL; /* If we add more fields to svn_wc_conflict_result_t, add them here. */ return result; } + +svn_error_t * +svn_wc__conflict_text_mark_resolved(svn_wc_context_t *wc_ctx, + const char *local_abspath, + svn_wc_conflict_choice_t choice, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool) +{ + svn_skel_t *work_items; + svn_skel_t *conflict; + svn_boolean_t did_resolve; + + SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL, + wc_ctx->db, local_abspath, + scratch_pool, scratch_pool)); + + if (!conflict) + return SVN_NO_ERROR; + + SVN_ERR(build_text_conflict_resolve_items(&work_items, &did_resolve, + wc_ctx->db, local_abspath, + conflict, choice, + NULL, FALSE, NULL, + cancel_func, cancel_baton, + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__db_op_mark_resolved(wc_ctx->db, local_abspath, + TRUE, FALSE, FALSE, + work_items, scratch_pool)); + + SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, + cancel_func, cancel_baton, + scratch_pool)); + + if (did_resolve && notify_func) + notify_func(notify_baton, + svn_wc_create_notify(local_abspath, + svn_wc_notify_resolved_text, + scratch_pool), + scratch_pool); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__conflict_prop_mark_resolved(svn_wc_context_t *wc_ctx, + const char *local_abspath, + const char *propname, + svn_wc_conflict_choice_t choice, + const svn_string_t *merged_value, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool) +{ + svn_boolean_t did_resolve; + svn_skel_t *conflicts; + + SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL, + wc_ctx->db, local_abspath, + scratch_pool, scratch_pool)); + + if (!conflicts) + return SVN_NO_ERROR; + + SVN_ERR(resolve_prop_conflict_on_node(&did_resolve, wc_ctx->db, + local_abspath, conflicts, + propname, choice, NULL, merged_value, + NULL, NULL, scratch_pool)); + + if (did_resolve && notify_func) + { + svn_wc_notify_t *notify; + + /* Send a general notification if no specific property was requested. */ + if (propname == NULL || propname[0] == '\0') + { + notify = svn_wc_create_notify(local_abspath, + svn_wc_notify_resolved, + scratch_pool); + } + else + { + notify = svn_wc_create_notify(local_abspath, + svn_wc_notify_resolved_prop, + scratch_pool); + notify->prop_name = propname; + } + + notify_func(notify_baton, notify, scratch_pool); + } + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__conflict_tree_update_break_moved_away(svn_wc_context_t *wc_ctx, + const char *local_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool) +{ + svn_wc_conflict_reason_t reason; + svn_wc_conflict_action_t action; + svn_wc_operation_t operation; + svn_boolean_t tree_conflicted; + const char *src_op_root_abspath; + const apr_array_header_t *conflicts; + svn_skel_t *conflict_skel; + + SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel, + wc_ctx->db, local_abspath, + FALSE, /* no tempfiles */ + FALSE, /* only tree conflicts */ + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL, + &tree_conflicted, wc_ctx->db, + local_abspath, conflict_skel, + scratch_pool, scratch_pool)); + if (!tree_conflicted) + return SVN_NO_ERROR; + + SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, + &src_op_root_abspath, + wc_ctx->db, local_abspath, + conflict_skel, + scratch_pool, scratch_pool)); + + /* Make sure the expected conflict is recorded. */ + if (operation != svn_wc_operation_update && + operation != svn_wc_operation_switch) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict operation '%s' on '%s'"), + svn_token__to_word(operation_map, operation), + svn_dirent_local_style(local_abspath, + scratch_pool)); + if (reason != svn_wc_conflict_reason_deleted && + reason != svn_wc_conflict_reason_replaced && + reason != svn_wc_conflict_reason_moved_away) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict reason '%s' on '%s'"), + svn_token__to_word(reason_map, reason), + svn_dirent_local_style(local_abspath, + scratch_pool)); + + /* Break moves for any children moved out of this directory, + * and leave this directory deleted. */ + if (action != svn_wc_conflict_action_delete) + { + SVN_ERR(svn_wc__db_op_break_moved_away( + wc_ctx->db, local_abspath, src_op_root_abspath, TRUE, + notify_func, notify_baton, scratch_pool)); + /* Conflict was marked resolved by db_op_break_moved_away() call .*/ + + if (notify_func) + notify_func(notify_baton, + svn_wc_create_notify(local_abspath, + svn_wc_notify_resolved_tree, + scratch_pool), + scratch_pool); + return SVN_NO_ERROR; + } + /* else # The move is/moves are already broken */ + + SVN_ERR(svn_wc__db_op_mark_resolved(wc_ctx->db, local_abspath, + FALSE, FALSE, TRUE, + NULL, scratch_pool)); + SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, cancel_func, cancel_baton, + scratch_pool)); + + if (notify_func) + notify_func(notify_baton, + svn_wc_create_notify(local_abspath, + svn_wc_notify_resolved_tree, + scratch_pool), + scratch_pool); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__conflict_tree_update_raise_moved_away(svn_wc_context_t *wc_ctx, + const char *local_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool) +{ + svn_wc_conflict_reason_t reason; + svn_wc_conflict_action_t action; + svn_wc_operation_t operation; + svn_boolean_t tree_conflicted; + const apr_array_header_t *conflicts; + svn_skel_t *conflict_skel; + + SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel, + wc_ctx->db, local_abspath, + FALSE, /* no tempfiles */ + FALSE, /* only tree conflicts */ + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL, + &tree_conflicted, wc_ctx->db, + local_abspath, conflict_skel, + scratch_pool, scratch_pool)); + if (!tree_conflicted) + return SVN_NO_ERROR; + + SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, NULL, + wc_ctx->db, local_abspath, + conflict_skel, + scratch_pool, scratch_pool)); + + /* Make sure the expected conflict is recorded. */ + if (operation != svn_wc_operation_update && + operation != svn_wc_operation_switch) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict operation '%s' on '%s'"), + svn_token__to_word(operation_map, operation), + svn_dirent_local_style(local_abspath, + scratch_pool)); + if (reason != svn_wc_conflict_reason_deleted && + reason != svn_wc_conflict_reason_replaced) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict reason '%s' on '%s'"), + svn_token__to_word(reason_map, reason), + svn_dirent_local_style(local_abspath, + scratch_pool)); + if (action != svn_wc_conflict_action_edit) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict action '%s' on '%s'"), + svn_token__to_word(action_map, action), + svn_dirent_local_style(local_abspath, + scratch_pool)); + + /* Raise local moved-away vs. incoming edit conflicts on any children + * moved out of this directory, and leave this directory as-is. + * The user may choose to update newly conflicted moved-away children + * when resolving them. If this function raises an error, the conflict + * cannot be resolved yet because other conflicts or obstructions + * prevent us from propagating the conflict to moved-away children. */ + SVN_ERR(svn_wc__db_op_raise_moved_away(wc_ctx->db, local_abspath, + notify_func, notify_baton, + scratch_pool)); + + /* The conflict was marked resolved by svn_wc__db_op_raise_moved_away(). */ + if (notify_func) + notify_func(notify_baton, + svn_wc_create_notify(local_abspath, + svn_wc_notify_resolved_tree, + scratch_pool), + scratch_pool); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__conflict_tree_update_moved_away_node(svn_wc_context_t *wc_ctx, + const char *local_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool) +{ + svn_wc_conflict_reason_t reason; + svn_wc_conflict_action_t action; + svn_wc_operation_t operation; + svn_boolean_t tree_conflicted; + const char *src_op_root_abspath; + const apr_array_header_t *conflicts; + svn_skel_t *conflict_skel; + + SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel, + wc_ctx->db, local_abspath, + FALSE, /* no tempfiles */ + FALSE, /* only tree conflicts */ + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL, + &tree_conflicted, wc_ctx->db, + local_abspath, conflict_skel, + scratch_pool, scratch_pool)); + if (!tree_conflicted) + return SVN_NO_ERROR; + + SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, + &src_op_root_abspath, + wc_ctx->db, local_abspath, + conflict_skel, + scratch_pool, scratch_pool)); + + /* Make sure the expected conflict is recorded. */ + if (operation != svn_wc_operation_update && + operation != svn_wc_operation_switch) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict operation '%s' on '%s'"), + svn_token__to_word(operation_map, operation), + svn_dirent_local_style(local_abspath, + scratch_pool)); + if (reason != svn_wc_conflict_reason_moved_away) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict reason '%s' on '%s'"), + svn_token__to_word(reason_map, reason), + svn_dirent_local_style(local_abspath, + scratch_pool)); + if (action != svn_wc_conflict_action_edit) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict action '%s' on '%s'"), + svn_token__to_word(action_map, action), + svn_dirent_local_style(local_abspath, + scratch_pool)); + + /* Update the moved-away conflict victim. */ + SVN_ERR(svn_wc__db_update_moved_away_conflict_victim(wc_ctx->db, + local_abspath, + src_op_root_abspath, + operation, + action, + reason, + cancel_func, + cancel_baton, + notify_func, + notify_baton, + scratch_pool)); + + SVN_ERR(svn_wc__db_op_mark_resolved(wc_ctx->db, local_abspath, + FALSE, FALSE, TRUE, + NULL, scratch_pool)); + SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, cancel_func, cancel_baton, + scratch_pool)); + + if (notify_func) + notify_func(notify_baton, + svn_wc_create_notify(local_abspath, + svn_wc_notify_resolved_tree, + scratch_pool), + scratch_pool); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__conflict_tree_update_incoming_move(svn_wc_context_t *wc_ctx, + const char *local_abspath, + const char *dest_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool) +{ + svn_wc_conflict_reason_t local_change; + svn_wc_conflict_action_t incoming_change; + svn_wc_operation_t operation; + svn_boolean_t tree_conflicted; + const apr_array_header_t *conflicts; + svn_skel_t *conflict_skel; + + SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel, + wc_ctx->db, local_abspath, + FALSE, /* no tempfiles */ + FALSE, /* only tree conflicts */ + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL, + &tree_conflicted, wc_ctx->db, + local_abspath, conflict_skel, + scratch_pool, scratch_pool)); + if (!tree_conflicted) + return SVN_NO_ERROR; + + SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change, &incoming_change, + NULL, wc_ctx->db, local_abspath, + conflict_skel, + scratch_pool, scratch_pool)); + + /* Make sure the expected conflict is recorded. */ + if (operation != svn_wc_operation_update && + operation != svn_wc_operation_switch && + operation != svn_wc_operation_merge) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict operation '%s' on '%s'"), + svn_token__to_word(operation_map, operation), + svn_dirent_local_style(local_abspath, + scratch_pool)); + if (local_change != svn_wc_conflict_reason_edited) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict reason '%s' on '%s'"), + svn_token__to_word(reason_map, local_change), + svn_dirent_local_style(local_abspath, + scratch_pool)); + if (incoming_change != svn_wc_conflict_action_delete) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict action '%s' on '%s'"), + svn_token__to_word(action_map, incoming_change), + svn_dirent_local_style(local_abspath, + scratch_pool)); + + SVN_ERR(svn_wc__db_update_incoming_move(wc_ctx->db, local_abspath, + dest_abspath, operation, + incoming_change, local_change, + cancel_func, cancel_baton, + notify_func, notify_baton, + scratch_pool)); + + SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, cancel_func, cancel_baton, + scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__conflict_tree_update_local_add(svn_wc_context_t *wc_ctx, + const char *local_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool) +{ + svn_wc_conflict_reason_t local_change; + svn_wc_conflict_action_t incoming_change; + svn_wc_operation_t operation; + svn_boolean_t tree_conflicted; + const apr_array_header_t *conflicts; + svn_skel_t *conflict_skel; + + SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel, + wc_ctx->db, local_abspath, + FALSE, /* no tempfiles */ + FALSE, /* only tree conflicts */ + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL, + &tree_conflicted, wc_ctx->db, + local_abspath, conflict_skel, + scratch_pool, scratch_pool)); + if (!tree_conflicted) + return SVN_NO_ERROR; + + SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change, &incoming_change, + NULL, wc_ctx->db, local_abspath, + conflict_skel, + scratch_pool, scratch_pool)); + + /* Make sure the expected conflict is recorded. */ + if (operation != svn_wc_operation_update) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict operation '%s' on '%s'"), + svn_token__to_word(operation_map, operation), + svn_dirent_local_style(local_abspath, + scratch_pool)); + if (local_change != svn_wc_conflict_reason_added) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict reason '%s' on '%s'"), + svn_token__to_word(reason_map, local_change), + svn_dirent_local_style(local_abspath, + scratch_pool)); + if (incoming_change != svn_wc_conflict_action_add) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Unexpected conflict action '%s' on '%s'"), + svn_token__to_word(action_map, incoming_change), + svn_dirent_local_style(local_abspath, + scratch_pool)); + + SVN_ERR(svn_wc__db_update_local_add(wc_ctx->db, local_abspath, + cancel_func, cancel_baton, + notify_func, notify_baton, + scratch_pool)); + + SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, cancel_func, cancel_baton, + scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__guess_incoming_move_target_nodes(apr_array_header_t **possible_targets, + svn_wc_context_t *wc_ctx, + const char *victim_abspath, + svn_node_kind_t victim_node_kind, + const char *moved_to_repos_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_array_header_t *candidates; + apr_pool_t *iterpool; + int i; + apr_size_t longest_ancestor_len = 0; + + *possible_targets = apr_array_make(result_pool, 1, sizeof(const char *)); + SVN_ERR(svn_wc__find_repos_node_in_wc(&candidates, wc_ctx->db, victim_abspath, + moved_to_repos_relpath, + scratch_pool, scratch_pool)); + + /* Find a "useful move target" node in our set of candidates. + * Since there is no way to be certain, filter out nodes which seem + * unlikely candidates, and return the first node which is "good enough". + * Nodes which are tree conflict victims don't count, and nodes which + * cannot be modified (e.g. replaced or deleted nodes) don't count. + * Nodes which are of a different node kind don't count either. + * Ignore switched nodes as well, since that is an unlikely case during + * update/swtich/merge conflict resolution. And externals shouldn't even + * be on our candidate list in the first place. + * If multiple candidates match these criteria, choose the one which + * shares the longest common ancestor with the victim. */ + iterpool = svn_pool_create(scratch_pool); + for (i = 0; i < candidates->nelts; i++) + { + const char *local_abspath; + const char *ancestor_abspath; + apr_size_t ancestor_len; + svn_boolean_t tree_conflicted; + svn_wc__db_status_t status; + svn_boolean_t is_wcroot; + svn_boolean_t is_switched; + svn_node_kind_t node_kind; + const char *moved_to_abspath; + int insert_index; + + svn_pool_clear(iterpool); + + local_abspath = APR_ARRAY_IDX(candidates, i, const char *); + + SVN_ERR(svn_wc__internal_conflicted_p(NULL, NULL, &tree_conflicted, + wc_ctx->db, local_abspath, + iterpool)); + if (tree_conflicted) + continue; + + SVN_ERR(svn_wc__db_read_info(&status, &node_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, + wc_ctx->db, local_abspath, iterpool, + iterpool)); + if (status != svn_wc__db_status_normal && + status != svn_wc__db_status_added) + continue; + + if (node_kind != victim_node_kind) + continue; + + SVN_ERR(svn_wc__db_is_switched(&is_wcroot, &is_switched, NULL, + wc_ctx->db, local_abspath, iterpool)); + if (is_wcroot || is_switched) + continue; + + /* This might be a move target. Fingers crossed ;-) */ + moved_to_abspath = apr_pstrdup(result_pool, local_abspath); + + /* Insert the move target into the list. Targets which are closer + * (path-wise) to the conflict victim are more likely to be a good + * match, so put them at the front of the list. */ + ancestor_abspath = svn_dirent_get_longest_ancestor(local_abspath, + victim_abspath, + iterpool); + ancestor_len = strlen(ancestor_abspath); + if (ancestor_len >= longest_ancestor_len) + { + longest_ancestor_len = ancestor_len; + insert_index = 0; /* prepend */ + } + else + { + insert_index = (*possible_targets)->nelts; /* append */ + } + svn_sort__array_insert(*possible_targets, &moved_to_abspath, + insert_index); + } + + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} diff --git a/subversion/libsvn_wc/copy.c b/subversion/libsvn_wc/copy.c index 30a0db58cc6a..7d4256feabad 100644 --- a/subversion/libsvn_wc/copy.c +++ b/subversion/libsvn_wc/copy.c @@ -791,10 +791,11 @@ copy_or_move(svn_boolean_t *record_move_on_delete, break; /* OK to add */ default: - return svn_error_createf(SVN_ERR_ENTRY_EXISTS, NULL, - _("There is already a versioned item '%s'"), - svn_dirent_local_style(dst_abspath, - scratch_pool)); + if (!metadata_only) + return svn_error_createf(SVN_ERR_ENTRY_EXISTS, NULL, + _("There is already a versioned item '%s'"), + svn_dirent_local_style(dst_abspath, + scratch_pool)); } } @@ -1104,8 +1105,8 @@ svn_wc__move2(svn_wc_context_t *wc_ctx, { svn_error_t *err; - err = svn_error_trace(svn_io_file_rename(src_abspath, dst_abspath, - scratch_pool)); + err = svn_error_trace(svn_io_file_rename2(src_abspath, dst_abspath, + FALSE, scratch_pool)); /* Let's try if we can keep wc.db consistent even when the move fails. Deleting the target is a wc.db only operation, while diff --git a/subversion/libsvn_wc/crop.c b/subversion/libsvn_wc/crop.c index 3a46b42d4be2..51f130aa2620 100644 --- a/subversion/libsvn_wc/crop.c +++ b/subversion/libsvn_wc/crop.c @@ -106,7 +106,12 @@ crop_children(svn_wc__db_t *db, svn_boolean_t modified, all_deletes; if (child_status != svn_wc__db_status_deleted) - continue; /* Leave local additions alone */ + { + /* ### TODO: Check for issue #4636 constraints, but not only on + this node, but also at all its descendants: We don't want + to remove moved_from information here! */ + continue; /* Leave local additions alone */ + } SVN_ERR(svn_wc__node_has_local_mods(&modified, &all_deletes, db, child_abspath, FALSE, diff --git a/subversion/libsvn_wc/deprecated.c b/subversion/libsvn_wc/deprecated.c index dcb5e42f749b..e54a86df903b 100644 --- a/subversion/libsvn_wc/deprecated.c +++ b/subversion/libsvn_wc/deprecated.c @@ -39,6 +39,7 @@ #include "private/svn_subr_private.h" #include "private/svn_wc_private.h" +#include "private/svn_io_private.h" #include "wc.h" #include "entries.h" @@ -478,20 +479,49 @@ svn_wc_transmit_text_deltas2(const char **tempfile, const char *local_abspath; svn_wc_context_t *wc_ctx; const svn_checksum_t *new_text_base_md5_checksum; + svn_stream_t *tempstream; + svn_error_t *err; SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool)); SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL /* config */, svn_wc__adm_get_db(adm_access), pool)); + if (tempfile) + { + apr_file_t *f; + + /* The temporary file can't be the same location as in 1.6 because the + * admin directory no longer exists. */ + SVN_ERR(svn_io_open_unique_file3(&f, tempfile, NULL, + svn_io_file_del_none, + pool, pool)); + tempstream = svn_stream__from_aprfile(f, FALSE, TRUE, pool); + } + else + { + tempstream = NULL; + } + + err = svn_wc__internal_transmit_text_deltas(svn_stream_disown(tempstream, pool), + (digest + ? &new_text_base_md5_checksum + : NULL), + NULL, wc_ctx->db, + local_abspath, fulltext, + editor, file_baton, + pool, pool); + if (tempfile) + { + err = svn_error_compose_create(err, svn_stream_close(tempstream)); + + if (err) + { + err = svn_error_compose_create( + err, svn_io_remove_file2(*tempfile, TRUE, pool)); + } + } - SVN_ERR(svn_wc__internal_transmit_text_deltas(tempfile, - (digest - ? &new_text_base_md5_checksum - : NULL), - NULL, wc_ctx->db, - local_abspath, fulltext, - editor, file_baton, - pool, pool)); + SVN_ERR(err); if (digest) memcpy(digest, new_text_base_md5_checksum->digest, APR_MD5_DIGESTSIZE); diff --git a/subversion/libsvn_wc/diff.h b/subversion/libsvn_wc/diff.h index 2df88e16a3e3..c91c5ffc3748 100644 --- a/subversion/libsvn_wc/diff.h +++ b/subversion/libsvn_wc/diff.h @@ -52,6 +52,7 @@ svn_error_t * svn_wc__diff_local_only_file(svn_wc__db_t *db, const char *local_abspath, const char *relpath, + const char *moved_from_relpath, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, svn_boolean_t diff_pristine, @@ -75,6 +76,7 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db, const char *local_abspath, const char *relpath, svn_depth_t depth, + const char *moved_from_relpath, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, svn_boolean_t diff_pristine, diff --git a/subversion/libsvn_wc/diff_editor.c b/subversion/libsvn_wc/diff_editor.c index fc059a5d4dea..9b1b0d50baa0 100644 --- a/subversion/libsvn_wc/diff_editor.c +++ b/subversion/libsvn_wc/diff_editor.c @@ -145,6 +145,9 @@ struct dir_baton_t /* TRUE if the node is to be compared with an unrelated node*/ svn_boolean_t ignoring_ancestry; + /* TRUE if the directory was reported incomplete to the repository */ + svn_boolean_t is_incomplete; + /* Processor state */ void *pdb; svn_boolean_t skip; @@ -741,9 +744,29 @@ walk_local_nodes_diff(struct edit_baton_t *eb, if (eb->local_before_remote && local_only) { + const char *moved_from_relpath; + + if (info->moved_here) + { + const char *moved_from_abspath; + + SVN_ERR(svn_wc__db_scan_moved(&moved_from_abspath, + NULL, NULL, NULL, + db, child_abspath, + iterpool, iterpool)); + SVN_ERR_ASSERT(moved_from_abspath != NULL); + + moved_from_relpath = svn_dirent_skip_ancestor( + eb->anchor_abspath, + moved_from_abspath); + } + else + moved_from_relpath = NULL; + if (info->kind == svn_node_file && diff_files) SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, child_relpath, + moved_from_relpath, eb->processor, dir_baton, eb->diff_pristine, eb->cancel_func, @@ -753,6 +776,7 @@ 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, + moved_from_relpath, eb->processor, dir_baton, eb->diff_pristine, eb->cancel_func, @@ -807,9 +831,29 @@ walk_local_nodes_diff(struct edit_baton_t *eb, if (!eb->local_before_remote && local_only) { + const char *moved_from_relpath; + + if (info->moved_here) + { + const char *moved_from_abspath; + + SVN_ERR(svn_wc__db_scan_moved(&moved_from_abspath, + NULL, NULL, NULL, + db, child_abspath, + iterpool, iterpool)); + SVN_ERR_ASSERT(moved_from_abspath != NULL); + + moved_from_relpath = svn_dirent_skip_ancestor( + eb->anchor_abspath, + moved_from_abspath); + } + else + moved_from_relpath = NULL; + if (info->kind == svn_node_file && diff_files) SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, child_relpath, + moved_from_relpath, eb->processor, dir_baton, eb->diff_pristine, eb->cancel_func, @@ -817,12 +861,13 @@ walk_local_nodes_diff(struct edit_baton_t *eb, iterpool)); else if (info->kind == svn_node_dir && diff_dirs) SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath, - child_relpath, depth_below_here, - eb->processor, dir_baton, - eb->diff_pristine, - eb->cancel_func, - eb->cancel_baton, - iterpool)); + child_relpath, depth_below_here, + moved_from_relpath, + eb->processor, dir_baton, + eb->diff_pristine, + eb->cancel_func, + eb->cancel_baton, + iterpool)); } } } @@ -873,6 +918,7 @@ svn_error_t * svn_wc__diff_local_only_file(svn_wc__db_t *db, const char *local_abspath, const char *relpath, + const char *moved_from_relpath, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, svn_boolean_t diff_pristine, @@ -935,6 +981,7 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db, { copyfrom_src = svn_diff__source_create(original_revision, scratch_pool); copyfrom_src->repos_relpath = original_repos_relpath; + copyfrom_src->moved_from_relpath = moved_from_relpath; } if (props_mod || !SVN_IS_VALID_REVNUM(revision)) @@ -1013,6 +1060,7 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db, const char *local_abspath, const char *relpath, svn_depth_t depth, + const char *moved_from_relpath, const svn_diff_tree_processor_t *processor, void *processor_parent_baton, svn_boolean_t diff_pristine, @@ -1049,6 +1097,7 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db, { copyfrom_src = svn_diff__source_create(original_revision, scratch_pool); copyfrom_src->repos_relpath = original_repos_relpath; + copyfrom_src->moved_from_relpath = moved_from_relpath; } /* svn_wc__db_status_incomplete should never happen, as the result won't be @@ -1136,12 +1185,40 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db, child_relpath = svn_relpath_join(relpath, name, iterpool); + if (info->moved_here) + { + const char *moved_from_abspath; + const char *a_abspath; + const char *a_relpath; + + a_relpath = relpath; + a_abspath = local_abspath; + while (*a_relpath) + { + a_relpath = svn_relpath_dirname(a_relpath, iterpool); + a_abspath = svn_dirent_dirname(a_abspath, iterpool); + } + + SVN_ERR(svn_wc__db_scan_moved(&moved_from_abspath, + NULL, NULL, NULL, + db, child_abspath, + iterpool, iterpool)); + SVN_ERR_ASSERT(moved_from_abspath != NULL); + + moved_from_relpath = svn_dirent_skip_ancestor( + a_abspath, + moved_from_abspath); + } + else + moved_from_relpath = NULL; + switch (info->kind) { case svn_node_file: case svn_node_symlink: SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, child_relpath, + moved_from_relpath, processor, pdb, diff_pristine, cancel_func, cancel_baton, @@ -1154,6 +1231,7 @@ 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, + moved_from_relpath, processor, pdb, diff_pristine, cancel_func, @@ -1202,6 +1280,8 @@ handle_local_only(struct dir_baton_t *pb, { struct edit_baton_t *eb = pb->eb; const struct svn_wc__db_info_t *info; + const char *child_abspath; + const char *moved_from_relpath; svn_boolean_t repos_delete = (pb->deletes && svn_hash_gets(pb->deletes, name)); @@ -1220,10 +1300,8 @@ handle_local_only(struct dir_baton_t *pb, switch (info->status) { - case svn_wc__db_status_incomplete: - return SVN_NO_ERROR; /* Not local only */ - case svn_wc__db_status_normal: + case svn_wc__db_status_incomplete: if (!repos_delete) return SVN_NO_ERROR; /* Local and remote */ svn_hash_sets(pb->deletes, name, NULL); @@ -1239,6 +1317,25 @@ handle_local_only(struct dir_baton_t *pb, break; } + child_abspath = svn_dirent_join(pb->local_abspath, name, scratch_pool); + + if (info->moved_here) + { + const char *moved_from_abspath; + + SVN_ERR(svn_wc__db_scan_moved(&moved_from_abspath, + NULL, NULL, NULL, + eb->db, child_abspath, + scratch_pool, scratch_pool)); + SVN_ERR_ASSERT(moved_from_abspath != NULL); + + moved_from_relpath = svn_dirent_skip_ancestor( + eb->anchor_abspath, + moved_from_abspath); + } + else + moved_from_relpath = NULL; + if (info->kind == svn_node_dir) { svn_depth_t depth ; @@ -1250,9 +1347,10 @@ handle_local_only(struct dir_baton_t *pb, SVN_ERR(svn_wc__diff_local_only_dir( eb->db, - svn_dirent_join(pb->local_abspath, name, scratch_pool), + child_abspath, svn_relpath_join(pb->relpath, name, scratch_pool), repos_delete ? svn_depth_infinity : depth, + moved_from_relpath, eb->processor, pb->pdb, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -1261,8 +1359,9 @@ handle_local_only(struct dir_baton_t *pb, else SVN_ERR(svn_wc__diff_local_only_file( eb->db, - svn_dirent_join(pb->local_abspath, name, scratch_pool), + child_abspath, svn_relpath_join(pb->relpath, name, scratch_pool), + moved_from_relpath, eb->processor, pb->pdb, eb->diff_pristine, eb->cancel_func, eb->cancel_baton, @@ -1608,25 +1707,47 @@ open_directory(const char *path, db->repos_only = TRUE; if (!db->repos_only) - switch (info->status) - { - case svn_wc__db_status_normal: - break; - case svn_wc__db_status_deleted: - db->repos_only = TRUE; - - if (!info->have_more_work) - svn_hash_sets(pb->compared, - apr_pstrdup(pb->pool, db->name), ""); - break; - case svn_wc__db_status_added: - if (eb->ignore_ancestry) - db->ignoring_ancestry = TRUE; - else + { + switch (info->status) + { + case svn_wc__db_status_normal: + case svn_wc__db_status_incomplete: + db->is_incomplete = (info->status == + svn_wc__db_status_incomplete); + break; + case svn_wc__db_status_deleted: db->repos_only = TRUE; - break; - default: - SVN_ERR_MALFUNCTION(); + + if (!info->have_more_work) + svn_hash_sets(pb->compared, + apr_pstrdup(pb->pool, db->name), ""); + break; + case svn_wc__db_status_added: + if (eb->ignore_ancestry) + db->ignoring_ancestry = TRUE; + else + db->repos_only = TRUE; + break; + default: + SVN_ERR_MALFUNCTION(); + } + + if (info->status == svn_wc__db_status_added + || info->status == svn_wc__db_status_deleted) + { + svn_wc__db_status_t base_status; + + /* Node is shadowed; check BASE */ + SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, + eb->db, db->local_abspath, + dir_pool, dir_pool)); + + if (base_status == svn_wc__db_status_incomplete) + db->is_incomplete = TRUE; + } } if (!db->repos_only) @@ -1714,7 +1835,7 @@ close_directory(void *dir_baton, { apr_hash_t *repos_props; - if (db->added) + if (db->added || db->is_incomplete) { repos_props = apr_hash_make(scratch_pool); } @@ -1891,6 +2012,7 @@ open_file(const char *path, switch (info->status) { case svn_wc__db_status_normal: + case svn_wc__db_status_incomplete: break; case svn_wc__db_status_deleted: fb->repos_only = TRUE; diff --git a/subversion/libsvn_wc/diff_local.c b/subversion/libsvn_wc/diff_local.c index e1cb3294b4ba..61ec06767e3a 100644 --- a/subversion/libsvn_wc/diff_local.c +++ b/subversion/libsvn_wc/diff_local.c @@ -281,7 +281,8 @@ diff_status_callback(void *baton, { local_only = TRUE; /* Only report additions */ } - else if (db_status == svn_wc__db_status_normal) + else if (db_status == svn_wc__db_status_normal + || db_status == svn_wc__db_status_incomplete) { /* Simple diff */ base_kind = db_kind; @@ -297,7 +298,8 @@ diff_status_callback(void *baton, eb->db, local_abspath, scratch_pool, scratch_pool)); - if (base_status != svn_wc__db_status_normal) + if (base_status != svn_wc__db_status_normal + && base_status != svn_wc__db_status_incomplete) return SVN_NO_ERROR; } else @@ -312,7 +314,8 @@ diff_status_callback(void *baton, eb->db, local_abspath, scratch_pool, scratch_pool)); - if (base_status != svn_wc__db_status_normal) + if (base_status != svn_wc__db_status_normal + && base_status != svn_wc__db_status_incomplete) local_only = TRUE; else if (base_kind != db_kind || !eb->ignore_ancestry) { @@ -388,9 +391,20 @@ diff_status_callback(void *baton, if (local_only && (db_status != svn_wc__db_status_deleted)) { + /* Moved from. Relative from diff anchor*/ + const char *moved_from_relpath = NULL; + + if (status->moved_from_abspath) + { + moved_from_relpath = svn_dirent_skip_ancestor( + eb->anchor_abspath, + status->moved_from_abspath); + } + if (db_kind == svn_node_file) SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath, child_relpath, + moved_from_relpath, eb->processor, eb->cur ? eb->cur->baton : NULL, FALSE, @@ -400,6 +414,7 @@ diff_status_callback(void *baton, else if (db_kind == svn_node_dir) SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath, child_relpath, depth_below_here, + moved_from_relpath, eb->processor, eb->cur ? eb->cur->baton : NULL, FALSE, diff --git a/subversion/libsvn_wc/entries.c b/subversion/libsvn_wc/entries.c index 1be6a8bec870..5748aa3cb857 100644 --- a/subversion/libsvn_wc/entries.c +++ b/subversion/libsvn_wc/entries.c @@ -1800,7 +1800,7 @@ write_entry(struct write_baton **entry_node, normal replace+copied base base+work add+copied replace+copied work work+work - although obviously the node is a directory rather then a file. + although obviously the node is a directory rather than a file. There are then more conversion states where the parent is replaced. @@ -2004,7 +2004,7 @@ write_entry(struct write_baton **entry_node, if (entry_node && entry->tree_conflict_data) { /* Issues #3840/#3916: 1.6 stores multiple tree conflicts on the - parent node, 1.7 stores them directly on the conflited nodes. + parent node, 1.7 stores them directly on the conflicted nodes. So "((skel1) (skel2))" becomes "(skel1)" and "(skel2)" */ svn_skel_t *skel; diff --git a/subversion/libsvn_wc/externals.c b/subversion/libsvn_wc/externals.c index 4cbd4f0e4b26..be42cdf4fb58 100644 --- a/subversion/libsvn_wc/externals.c +++ b/subversion/libsvn_wc/externals.c @@ -475,6 +475,8 @@ struct edit_baton /* Introducing a new file external */ svn_boolean_t added; + svn_wc_conflict_resolver_func2_t conflict_func; + void *conflict_baton; svn_cancel_func_t cancel_func; void *cancel_baton; svn_wc_notify_func2_t notify_func; @@ -963,6 +965,18 @@ close_file(void *file_baton, /* Run the work queue to complete the installation */ SVN_ERR(svn_wc__wq_run(eb->db, eb->wri_abspath, eb->cancel_func, eb->cancel_baton, pool)); + + if (conflict_skel && eb->conflict_func) + SVN_ERR(svn_wc__conflict_invoke_resolver(eb->db, + eb->local_abspath, + svn_node_file, + conflict_skel, + NULL /* merge_options */, + eb->conflict_func, + eb->conflict_baton, + eb->cancel_func, + eb->cancel_baton, + pool)); } /* Notify */ @@ -1053,6 +1067,8 @@ svn_wc__get_file_external_editor(const svn_delta_editor_t **editor, const char *recorded_url, const svn_opt_revision_t *recorded_peg_rev, const svn_opt_revision_t *recorded_rev, + svn_wc_conflict_resolver_func2_t conflict_func, + void *conflict_baton, svn_cancel_func_t cancel_func, void *cancel_baton, svn_wc_notify_func2_t notify_func, @@ -1104,6 +1120,8 @@ svn_wc__get_file_external_editor(const svn_delta_editor_t **editor, else eb->recorded_revision = SVN_INVALID_REVNUM; /* Not fixed/HEAD */ + eb->conflict_func = conflict_func; + eb->conflict_baton = conflict_baton; eb->cancel_func = cancel_func; eb->cancel_baton = cancel_baton; eb->notify_func = notify_func; diff --git a/subversion/libsvn_wc/node.c b/subversion/libsvn_wc/node.c index 560a899ea043..586477637274 100644 --- a/subversion/libsvn_wc/node.c +++ b/subversion/libsvn_wc/node.c @@ -906,7 +906,8 @@ svn_wc__rename_wc(svn_wc_context_t *wc_ctx, { SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, wcroot_abspath, scratch_pool)); - SVN_ERR(svn_io_file_rename(from_abspath, dst_abspath, scratch_pool)); + SVN_ERR(svn_io_file_rename2(from_abspath, dst_abspath, FALSE, + scratch_pool)); } else return svn_error_createf( diff --git a/subversion/libsvn_wc/old-and-busted.c b/subversion/libsvn_wc/old-and-busted.c index 8cd94af2733b..b2e8d240f15e 100644 --- a/subversion/libsvn_wc/old-and-busted.c +++ b/subversion/libsvn_wc/old-and-busted.c @@ -1203,7 +1203,8 @@ svn_wc__read_entries_old(apr_hash_t **entries, /* Open the entries file. */ SVN_ERR(svn_wc__open_adm_stream(&stream, dir_abspath, SVN_WC__ADM_ENTRIES, scratch_pool, scratch_pool)); - SVN_ERR(svn_string_from_stream(&buf, stream, scratch_pool, scratch_pool)); + SVN_ERR(svn_string_from_stream2(&buf, stream, SVN__STREAM_CHUNK_SIZE, + scratch_pool)); /* We own the returned data; it is modifiable, so cast away... */ curp = (char *)buf->data; diff --git a/subversion/libsvn_wc/props.c b/subversion/libsvn_wc/props.c index 664bcf170664..f56899d86002 100644 --- a/subversion/libsvn_wc/props.c +++ b/subversion/libsvn_wc/props.c @@ -2170,11 +2170,8 @@ svn_wc_canonicalize_svn_prop(const svn_string_t **propval_p, /* Keep this static, it may get stored (for read-only purposes) in a hash that outlives this function. */ - static const svn_string_t boolean_value = - { - SVN_PROP_BOOLEAN_TRUE, - sizeof(SVN_PROP_BOOLEAN_TRUE) - 1 - }; + static const svn_string_t boolean_value + = SVN__STATIC_STRING(SVN_PROP_BOOLEAN_TRUE); SVN_ERR(validate_prop_against_node_kind(propname, path, kind, pool)); diff --git a/subversion/libsvn_wc/status.c b/subversion/libsvn_wc/status.c index 83fd3d4a377b..b8cbc0ed30d9 100644 --- a/subversion/libsvn_wc/status.c +++ b/subversion/libsvn_wc/status.c @@ -69,6 +69,7 @@ typedef struct svn_wc__internal_status_t svn_wc_status3_t s; /* First member; same pointer*/ svn_boolean_t has_descendants; + svn_boolean_t op_root; /* Make sure to update hash_stash() when adding values here */ } svn_wc__internal_status_t; @@ -587,7 +588,8 @@ assemble_status(svn_wc__internal_status_t **status, This filter should match the filter in is_sendable_status() */ if (! get_all) if (((node_status == svn_wc_status_none) - || (node_status == svn_wc_status_normal)) + || (node_status == svn_wc_status_normal) + || (node_status == svn_wc_status_deleted && !info->op_root)) && (! switched_p) && (! info->locked) @@ -606,6 +608,7 @@ assemble_status(svn_wc__internal_status_t **status, inner_stat = apr_pcalloc(result_pool, sizeof(*inner_stat)); stat = &inner_stat->s; inner_stat->has_descendants = info->has_descendants; + inner_stat->op_root = info->op_root; switch (info->kind) { @@ -1484,6 +1487,7 @@ hash_stash(void *baton, /* Copy the internal/private data. */ svn_wc__internal_status_t *is = new_status; is->has_descendants = old_status->has_descendants; + is->op_root = old_status->op_root; assert(! svn_hash_gets(stat_hash, path)); svn_hash_sets(stat_hash, apr_pstrdup(hash_pool, path), new_status); @@ -1865,7 +1869,9 @@ is_sendable_status(const svn_wc__internal_status_t *i_status, /* If the text, property or tree state is interesting, send it. */ if ((status->node_status != svn_wc_status_none) - && (status->node_status != svn_wc_status_normal)) + && (status->node_status != svn_wc_status_normal) + && !(status->node_status == svn_wc_status_deleted + && !i_status->op_root)) return TRUE; /* If it's switched, send it. */ diff --git a/subversion/libsvn_wc/translate.c b/subversion/libsvn_wc/translate.c index 0e16235d7827..bc5db887e24d 100644 --- a/subversion/libsvn_wc/translate.c +++ b/subversion/libsvn_wc/translate.c @@ -440,3 +440,20 @@ svn_wc__sync_flags_with_props(svn_boolean_t *did_set, return SVN_NO_ERROR; } + +svn_error_t * +svn_wc__translated_stream(svn_stream_t **stream, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + const char *versioned_abspath, + apr_uint32_t flags, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_error_trace( + svn_wc__internal_translated_stream(stream, wc_ctx->db, + local_abspath, + versioned_abspath, + flags, result_pool, + scratch_pool)); +} diff --git a/subversion/libsvn_wc/upgrade.c b/subversion/libsvn_wc/upgrade.c index aebf4eb1eb88..3b9ab3a35319 100644 --- a/subversion/libsvn_wc/upgrade.c +++ b/subversion/libsvn_wc/upgrade.c @@ -535,7 +535,7 @@ svn_wc__wipe_postupgrade(const char *dir_abspath, int i; if (cancel_func) - SVN_ERR((*cancel_func)(cancel_baton)); + SVN_ERR(cancel_func(cancel_baton)); err = get_versioned_subdirs(&subdirs, &delete_dir, dir_abspath, TRUE, scratch_pool, iterpool); @@ -653,178 +653,6 @@ ensure_repos_info(svn_wc_entry_t *entry, } -/* - * Read tree conflict descriptions from @a conflict_data. Set @a *conflicts - * to a hash of pointers to svn_wc_conflict_description2_t objects indexed by - * svn_wc_conflict_description2_t.local_abspath, all newly allocated in @a - * pool. @a dir_path is the path to the working copy directory whose conflicts - * are being read. The conflicts read are the tree conflicts on the immediate - * child nodes of @a dir_path. Do all allocations in @a pool. - * - * Note: There were some concerns about this function: - * - * ### this is BAD. the CONFLICTS structure should not be dependent upon - * ### DIR_PATH. each conflict should be labeled with an entry name, not - * ### a whole path. (and a path which happens to vary based upon invocation - * ### of the user client and these APIs) - * - * those assumptions were baked into former versions of the data model, so - * they have to stick around here. But they have been removed from the - * New Way. */ -static svn_error_t * -read_tree_conflicts(apr_hash_t **conflicts, - const char *conflict_data, - const char *dir_path, - apr_pool_t *pool) -{ - const svn_skel_t *skel; - apr_pool_t *iterpool; - - *conflicts = apr_hash_make(pool); - - if (conflict_data == NULL) - return SVN_NO_ERROR; - - skel = svn_skel__parse(conflict_data, strlen(conflict_data), pool); - if (skel == NULL) - return svn_error_create(SVN_ERR_WC_CORRUPT, NULL, - _("Error parsing tree conflict skel")); - - iterpool = svn_pool_create(pool); - for (skel = skel->children; skel != NULL; skel = skel->next) - { - const svn_wc_conflict_description2_t *conflict; - - svn_pool_clear(iterpool); - SVN_ERR(svn_wc__deserialize_conflict(&conflict, skel, dir_path, - pool, iterpool)); - if (conflict != NULL) - svn_hash_sets(*conflicts, - svn_dirent_basename(conflict->local_abspath, pool), - conflict); - } - svn_pool_destroy(iterpool); - - return SVN_NO_ERROR; -} - -/* */ -static svn_error_t * -migrate_single_tree_conflict_data(svn_sqlite__db_t *sdb, - const char *tree_conflict_data, - apr_int64_t wc_id, - const char *local_relpath, - apr_pool_t *scratch_pool) -{ - apr_hash_t *conflicts; - apr_hash_index_t *hi; - apr_pool_t *iterpool; - - SVN_ERR(read_tree_conflicts(&conflicts, tree_conflict_data, local_relpath, - scratch_pool)); - - iterpool = svn_pool_create(scratch_pool); - for (hi = apr_hash_first(scratch_pool, conflicts); - hi; - hi = apr_hash_next(hi)) - { - const svn_wc_conflict_description2_t *conflict = apr_hash_this_val(hi); - const char *conflict_relpath; - const char *conflict_data; - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - svn_skel_t *skel; - - svn_pool_clear(iterpool); - - conflict_relpath = svn_dirent_join(local_relpath, - svn_dirent_basename( - conflict->local_abspath, iterpool), - iterpool); - - SVN_ERR(svn_wc__serialize_conflict(&skel, conflict, iterpool, iterpool)); - conflict_data = svn_skel__unparse(skel, iterpool)->data; - - /* See if we need to update or insert an ACTUAL node. */ - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_ACTUAL_NODE)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, conflict_relpath)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - SVN_ERR(svn_sqlite__reset(stmt)); - - if (have_row) - { - /* There is an existing ACTUAL row, so just update it. */ - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPDATE_ACTUAL_CONFLICT)); - } - else - { - /* We need to insert an ACTUAL row with the tree conflict data. */ - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_INSERT_ACTUAL_CONFLICT)); - } - - SVN_ERR(svn_sqlite__bindf(stmt, "iss", wc_id, conflict_relpath, - conflict_data)); - if (!have_row) - SVN_ERR(svn_sqlite__bind_text(stmt, 4, local_relpath)); - - SVN_ERR(svn_sqlite__step_done(stmt)); - } - - svn_pool_destroy(iterpool); - - return SVN_NO_ERROR; -} - - -/* */ -static svn_error_t * -migrate_tree_conflict_data(svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - - /* Iterate over each node which has a set of tree conflicts, then insert - all of them into the new schema. */ - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT)); - - /* Get all the existing tree conflict data. */ - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - while (have_row) - { - apr_int64_t wc_id; - const char *local_relpath; - const char *tree_conflict_data; - - svn_pool_clear(iterpool); - - wc_id = svn_sqlite__column_int64(stmt, 0); - local_relpath = svn_sqlite__column_text(stmt, 1, iterpool); - tree_conflict_data = svn_sqlite__column_text(stmt, 2, iterpool); - - SVN_ERR(migrate_single_tree_conflict_data(sdb, tree_conflict_data, - wc_id, local_relpath, - iterpool)); - - /* We don't need to do anything but step over the previously - prepared statement. */ - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - } - SVN_ERR(svn_sqlite__reset(stmt)); - - /* Erase all the old tree conflict data. */ - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPGRADE_21_ERASE_OLD_CONFLICTS)); - SVN_ERR(svn_sqlite__step_done(stmt)); - - svn_pool_destroy(iterpool); - return SVN_NO_ERROR; -} - /* ### need much more docco ### this function should be called within a sqlite transaction. it makes @@ -1318,234 +1146,6 @@ migrate_text_bases(apr_hash_t **text_bases_info, return SVN_NO_ERROR; } -static svn_error_t * -bump_to_20(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_NODES)); - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_20)); - return SVN_NO_ERROR; -} - -static svn_error_t * -bump_to_21(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_21)); - SVN_ERR(migrate_tree_conflict_data(sdb, scratch_pool)); - return SVN_NO_ERROR; -} - -static svn_error_t * -bump_to_22(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_22)); - return SVN_NO_ERROR; -} - -static svn_error_t * -bump_to_23(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - const char *wcroot_abspath = ((struct bump_baton *)baton)->wcroot_abspath; - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPGRADE_23_HAS_WORKING_NODES)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - SVN_ERR(svn_sqlite__reset(stmt)); - if (have_row) - return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, - _("The working copy at '%s' is format 22 with " - "WORKING nodes; use a format 22 client to " - "diff/revert before using this client"), - wcroot_abspath); - - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_23)); - return SVN_NO_ERROR; -} - -static svn_error_t * -bump_to_24(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_24)); - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_NODES_TRIGGERS)); - return SVN_NO_ERROR; -} - -static svn_error_t * -bump_to_25(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_25)); - return SVN_NO_ERROR; -} - -static svn_error_t * -bump_to_26(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_26)); - return SVN_NO_ERROR; -} - -static svn_error_t * -bump_to_27(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - const char *wcroot_abspath = ((struct bump_baton *)baton)->wcroot_abspath; - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - SVN_ERR(svn_sqlite__reset(stmt)); - if (have_row) - return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL, - _("The working copy at '%s' is format 26 with " - "conflicts; use a format 26 client to resolve " - "before using this client"), - wcroot_abspath); - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_27)); - return SVN_NO_ERROR; -} - -static svn_error_t * -bump_to_28(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_28)); - return SVN_NO_ERROR; -} - -/* If FINFO indicates that ABSPATH names a file, rename it to - * '<ABSPATH>.svn-base'. - * - * Ignore any file whose name is not the expected length, in order to make - * life easier for any developer who runs this code twice or has some - * non-standard files in the pristine directory. - * - * A callback for bump_to_29(), implementing #svn_io_walk_func_t. */ -static svn_error_t * -rename_pristine_file(void *baton, - const char *abspath, - const apr_finfo_t *finfo, - apr_pool_t *pool) -{ - if (finfo->filetype == APR_REG - && (strlen(svn_dirent_basename(abspath, pool)) - == PRISTINE_BASENAME_OLD_LEN)) - { - const char *new_abspath - = apr_pstrcat(pool, abspath, PRISTINE_STORAGE_EXT, SVN_VA_NULL); - - SVN_ERR(svn_io_file_rename(abspath, new_abspath, pool)); - } - return SVN_NO_ERROR; -} - -static svn_error_t * -upgrade_externals(struct bump_baton *bb, - svn_sqlite__db_t *sdb, - apr_pool_t *scratch_pool) -{ - svn_sqlite__stmt_t *stmt; - svn_sqlite__stmt_t *stmt_add; - svn_boolean_t have_row; - apr_pool_t *iterpool; - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_SELECT_EXTERNAL_PROPERTIES)); - - SVN_ERR(svn_sqlite__get_statement(&stmt_add, sdb, - STMT_INSERT_EXTERNAL)); - - /* ### For this intermediate upgrade we just assume WC_ID = 1. - ### Before this bump we lost track of externals all the time, - ### so lets keep this easy. */ - SVN_ERR(svn_sqlite__bindf(stmt, "is", (apr_int64_t)1, "")); - - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - - iterpool = svn_pool_create(scratch_pool); - while (have_row) - { - apr_hash_t *props; - const char *externals; - - svn_pool_clear(iterpool); - - SVN_ERR(svn_sqlite__column_properties(&props, stmt, 0, - iterpool, iterpool)); - - externals = svn_prop_get_value(props, SVN_PROP_EXTERNALS); - - if (externals) - { - apr_array_header_t *ext; - const char *local_relpath; - const char *local_abspath; - int i; - - local_relpath = svn_sqlite__column_text(stmt, 1, NULL); - local_abspath = svn_dirent_join(bb->wcroot_abspath, local_relpath, - iterpool); - - SVN_ERR(svn_wc_parse_externals_description3(&ext, local_abspath, - externals, FALSE, - iterpool)); - - for (i = 0; i < ext->nelts; i++) - { - const svn_wc_external_item2_t *item; - const char *item_relpath; - - item = APR_ARRAY_IDX(ext, i, const svn_wc_external_item2_t *); - item_relpath = svn_relpath_join(local_relpath, item->target_dir, - iterpool); - - /* Insert dummy externals definitions: Insert an unknown - external, to make sure it will be cleaned up when it is not - updated on the next update. */ - SVN_ERR(svn_sqlite__bindf(stmt_add, "isssssis", - (apr_int64_t)1, /* wc_id */ - item_relpath, - svn_relpath_dirname(item_relpath, - iterpool), - "normal", - "unknown", - local_relpath, - (apr_int64_t)1, /* repos_id */ - "" /* repos_relpath */)); - SVN_ERR(svn_sqlite__insert(NULL, stmt_add)); - } - } - - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - } - - svn_pool_destroy(iterpool); - return svn_error_trace(svn_sqlite__reset(stmt)); -} - -static svn_error_t * -bump_to_29(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool) -{ - struct bump_baton *bb = baton; - const char *wcroot_abspath = bb->wcroot_abspath; - const char *pristine_dir_abspath; - - /* Rename all pristine files, adding a ".svn-base" suffix. */ - pristine_dir_abspath = svn_dirent_join_many(scratch_pool, wcroot_abspath, - svn_wc_get_adm_dir(scratch_pool), - PRISTINE_STORAGE_RELPATH, - SVN_VA_NULL); - SVN_ERR(svn_io_dir_walk2(pristine_dir_abspath, APR_FINFO_MIN, - rename_pristine_file, NULL, scratch_pool)); - - /* Externals */ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_EXTERNALS)); - - SVN_ERR(upgrade_externals(bb, sdb, scratch_pool)); - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_29)); - return SVN_NO_ERROR; -} - svn_error_t * svn_wc__upgrade_conflict_skel_from_raw(svn_skel_t **conflicts, svn_wc__db_t *db, @@ -1774,41 +1374,10 @@ bump_to_31(void *baton, apr_pool_t *iterpool = svn_pool_create(scratch_pool); apr_array_header_t *empty_iprops = apr_array_make( scratch_pool, 0, sizeof(svn_prop_inherited_item_t *)); - svn_boolean_t iprops_column_exists = FALSE; svn_error_t *err; - /* Add the inherited_props column to NODES if it does not yet exist. - * - * When using a format >= 31 client to upgrade from old formats which - * did not yet have a NODES table, the inherited_props column has - * already been created as part of the NODES table. Attemping to add - * the inherited_props column will raise an error in this case, so check - * if the column exists first. - * - * Checking for the existence of a column before ALTER TABLE is not - * possible within SQLite. We need to run a separate query and evaluate - * its result in C first. - */ - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_PRAGMA_TABLE_INFO_NODES)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - while (have_row) - { - const char *column_name = svn_sqlite__column_text(stmt, 1, NULL); - - if (strcmp(column_name, "inherited_props") == 0) - { - iprops_column_exists = TRUE; - break; - } - - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - } - SVN_ERR(svn_sqlite__reset(stmt)); - if (!iprops_column_exists) - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_31_ALTER_TABLE)); - /* Run additional statements to finalize the upgrade to format 31. */ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_31_FINALIZE)); + SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_31)); /* Set inherited_props to an empty array for the roots of all switched subtrees in the WC. This allows subsequent updates @@ -2090,6 +1659,15 @@ svn_wc__upgrade_sdb(int *result_format, svn_dirent_local_style(wcroot_abspath, scratch_pool), start_format); + else if (start_format < 29) + return svn_error_createf(SVN_ERR_WC_UPGRADE_REQUIRED, NULL, + _("Working copy '%s' is an old development " + "version (format %d); to upgrade it, " + "use a Subversion 1.7-1.9 client, then " + "use the current client"), + svn_dirent_local_style(wcroot_abspath, + scratch_pool), + start_format); /* ### need lock-out. only one upgrade at a time. note that other code ### cannot use this un-upgraded database until we finish the upgrade. */ @@ -2098,66 +1676,6 @@ svn_wc__upgrade_sdb(int *result_format, intentional. */ switch (start_format) { - case 19: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_20, &bb, - scratch_pool)); - *result_format = 20; - /* FALLTHROUGH */ - - case 20: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_21, &bb, - scratch_pool)); - *result_format = 21; - /* FALLTHROUGH */ - - case 21: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_22, &bb, - scratch_pool)); - *result_format = 22; - /* FALLTHROUGH */ - - case 22: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_23, &bb, - scratch_pool)); - *result_format = 23; - /* FALLTHROUGH */ - - case 23: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_24, &bb, - scratch_pool)); - *result_format = 24; - /* FALLTHROUGH */ - - case 24: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_25, &bb, - scratch_pool)); - *result_format = 25; - /* FALLTHROUGH */ - - case 25: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_26, &bb, - scratch_pool)); - *result_format = 26; - /* FALLTHROUGH */ - - case 26: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_27, &bb, - scratch_pool)); - *result_format = 27; - /* FALLTHROUGH */ - - case 27: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_28, &bb, - scratch_pool)); - *result_format = 28; - /* FALLTHROUGH */ - - case 28: - SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_29, &bb, - scratch_pool)); - *result_format = 29; - /* FALLTHROUGH */ - case 29: SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_30, &bb, scratch_pool)); @@ -2513,7 +2031,7 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx, /* Renaming the db file is what makes the pre-wcng into a wcng */ db_from = svn_wc__adm_child(data.root_abspath, SDB_FILE, scratch_pool); db_to = svn_wc__adm_child(local_abspath, SDB_FILE, scratch_pool); - SVN_ERR(svn_io_file_rename(db_from, db_to, scratch_pool)); + SVN_ERR(svn_io_file_rename2(db_from, db_to, FALSE, scratch_pool)); /* Now we have a working wcng, tidy up the droppings */ SVN_ERR(svn_wc__db_open(&db, NULL /* ### config */, FALSE, FALSE, diff --git a/subversion/libsvn_wc/wc-checks.h b/subversion/libsvn_wc/wc-checks.h index e867506d4e9b..c1d356ced965 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.9.7/subversion/libsvn_wc/token-map.h. +/* This file is automatically generated from wc-checks.sql and /opt/svnrm/tempdir/subversion-1.10.0/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 f548d9174d3a..98064242d706 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.9.7/subversion/libsvn_wc/token-map.h. +/* This file is automatically generated from wc-metadata.sql and /opt/svnrm/tempdir/subversion-1.10.0/subversion/libsvn_wc/token-map.h. * Do not edit this file -- edit the source and rerun gen-make.py */ #define STMT_CREATE_SCHEMA 0 @@ -63,14 +63,6 @@ " locked_levels INTEGER NOT NULL DEFAULT -1, " \ " PRIMARY KEY (wc_id, local_dir_relpath) " \ " ); " \ - "PRAGMA user_version = " \ - APR_STRINGIFY(SVN_WC__VERSION) \ - "; " \ - "" - -#define STMT_CREATE_NODES 1 -#define STMT_1_INFO {"STMT_CREATE_NODES", NULL} -#define STMT_1 \ "CREATE TABLE NODES ( " \ " wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " \ " local_relpath TEXT NOT NULL, " \ @@ -108,11 +100,6 @@ "CREATE VIEW NODES_BASE AS " \ " SELECT * FROM nodes " \ " WHERE op_depth = 0; " \ - "" - -#define STMT_CREATE_NODES_TRIGGERS 2 -#define STMT_2_INFO {"STMT_CREATE_NODES_TRIGGERS", NULL} -#define STMT_2 \ "CREATE TRIGGER nodes_insert_trigger " \ "AFTER INSERT ON nodes " \ "WHEN NEW.checksum IS NOT NULL " \ @@ -136,11 +123,6 @@ " UPDATE pristine SET refcount = refcount - 1 " \ " WHERE checksum = OLD.checksum; " \ "END; " \ - "" - -#define STMT_CREATE_EXTERNALS 3 -#define STMT_3_INFO {"STMT_CREATE_EXTERNALS", NULL} -#define STMT_3 \ "CREATE TABLE EXTERNALS ( " \ " wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " \ " local_relpath TEXT NOT NULL, " \ @@ -157,11 +139,14 @@ "CREATE UNIQUE INDEX I_EXTERNALS_DEFINED ON EXTERNALS (wc_id, " \ " def_local_relpath, " \ " local_relpath); " \ + "PRAGMA user_version = " \ + APR_STRINGIFY(SVN_WC__VERSION) \ + "; " \ "" -#define STMT_INSTALL_SCHEMA_STATISTICS 4 -#define STMT_4_INFO {"STMT_INSTALL_SCHEMA_STATISTICS", NULL} -#define STMT_4 \ +#define STMT_INSTALL_SCHEMA_STATISTICS 1 +#define STMT_1_INFO {"STMT_INSTALL_SCHEMA_STATISTICS", NULL} +#define STMT_1 \ "ANALYZE sqlite_master; " \ "DELETE FROM sqlite_stat1 " \ "WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK', 'EXTERNALS'); " \ @@ -186,183 +171,9 @@ "ANALYZE sqlite_master; " \ "" -#define STMT_UPGRADE_TO_20 5 -#define STMT_5_INFO {"STMT_UPGRADE_TO_20", NULL} -#define STMT_5 \ - "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); " \ - "UPDATE WORKING_NODE SET checksum = (SELECT checksum FROM pristine " \ - " WHERE md5_checksum = WORKING_NODE.checksum) " \ - "WHERE EXISTS (SELECT 1 FROM pristine " \ - " WHERE md5_checksum = WORKING_NODE.checksum); " \ - "INSERT INTO NODES ( " \ - " wc_id, local_relpath, op_depth, parent_relpath, " \ - " repos_id, repos_path, revision, " \ - " presence, depth, moved_here, moved_to, kind, " \ - " changed_revision, changed_date, changed_author, " \ - " checksum, properties, translated_size, last_mod_time, " \ - " dav_cache, symlink_target, file_external ) " \ - "SELECT wc_id, local_relpath, 0 , parent_relpath, " \ - " repos_id, repos_relpath, revnum, " \ - " presence, depth, NULL , NULL , kind, " \ - " changed_rev, changed_date, changed_author, " \ - " checksum, properties, translated_size, last_mod_time, " \ - " dav_cache, symlink_target, file_external " \ - "FROM BASE_NODE; " \ - "INSERT INTO NODES ( " \ - " wc_id, local_relpath, op_depth, parent_relpath, " \ - " repos_id, repos_path, revision, " \ - " presence, depth, moved_here, moved_to, kind, " \ - " changed_revision, changed_date, changed_author, " \ - " checksum, properties, translated_size, last_mod_time, " \ - " dav_cache, symlink_target, file_external ) " \ - "SELECT wc_id, local_relpath, 2 , parent_relpath, " \ - " copyfrom_repos_id, copyfrom_repos_path, copyfrom_revnum, " \ - " presence, depth, NULL , NULL , kind, " \ - " changed_rev, changed_date, changed_author, " \ - " checksum, properties, translated_size, last_mod_time, " \ - " NULL , symlink_target, NULL " \ - "FROM WORKING_NODE; " \ - "DROP TABLE BASE_NODE; " \ - "DROP TABLE WORKING_NODE; " \ - "PRAGMA user_version = 20; " \ - "" - -#define STMT_UPGRADE_TO_21 6 -#define STMT_6_INFO {"STMT_UPGRADE_TO_21", NULL} -#define STMT_6 \ - "PRAGMA user_version = 21; " \ - "" - -#define STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT 7 -#define STMT_7_INFO {"STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT", NULL} -#define STMT_7 \ - "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 8 -#define STMT_8_INFO {"STMT_UPGRADE_21_ERASE_OLD_CONFLICTS", NULL} -#define STMT_8 \ - "UPDATE actual_node SET tree_conflict_data = NULL " \ - "" - -#define STMT_UPGRADE_TO_22 9 -#define STMT_9_INFO {"STMT_UPGRADE_TO_22", NULL} -#define STMT_9 \ - "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 10 -#define STMT_10_INFO {"STMT_UPGRADE_TO_23", NULL} -#define STMT_10 \ - "PRAGMA user_version = 23; " \ - "" - -#define STMT_UPGRADE_23_HAS_WORKING_NODES 11 -#define STMT_11_INFO {"STMT_UPGRADE_23_HAS_WORKING_NODES", NULL} -#define STMT_11 \ - "SELECT 1 FROM nodes WHERE op_depth > 0 " \ - "LIMIT 1 " \ - "" - -#define STMT_UPGRADE_TO_24 12 -#define STMT_12_INFO {"STMT_UPGRADE_TO_24", NULL} -#define STMT_12 \ - "UPDATE pristine SET refcount = " \ - " (SELECT COUNT(*) FROM nodes " \ - " WHERE checksum = pristine.checksum ); " \ - "PRAGMA user_version = 24; " \ - "" - -#define STMT_UPGRADE_TO_25 13 -#define STMT_13_INFO {"STMT_UPGRADE_TO_25", NULL} -#define STMT_13 \ - "DROP VIEW IF EXISTS NODES_CURRENT; " \ - "CREATE VIEW NODES_CURRENT AS " \ - " SELECT * FROM nodes " \ - " JOIN (SELECT wc_id, local_relpath, MAX(op_depth) AS op_depth FROM nodes " \ - " GROUP BY wc_id, local_relpath) AS filter " \ - " ON nodes.wc_id = filter.wc_id " \ - " AND nodes.local_relpath = filter.local_relpath " \ - " AND nodes.op_depth = filter.op_depth; " \ - "PRAGMA user_version = 25; " \ - "" - -#define STMT_UPGRADE_TO_26 14 -#define STMT_14_INFO {"STMT_UPGRADE_TO_26", NULL} -#define STMT_14 \ - "DROP VIEW IF EXISTS NODES_BASE; " \ - "CREATE VIEW NODES_BASE AS " \ - " SELECT * FROM nodes " \ - " WHERE op_depth = 0; " \ - "PRAGMA user_version = 26; " \ - "" - -#define STMT_UPGRADE_TO_27 15 -#define STMT_15_INFO {"STMT_UPGRADE_TO_27", NULL} -#define STMT_15 \ - "PRAGMA user_version = 27; " \ - "" - -#define STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS 16 -#define STMT_16_INFO {"STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS", NULL} -#define STMT_16 \ - "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) " \ - " AND (tree_conflict_data IS NULL)) " \ - "LIMIT 1 " \ - "" - -#define STMT_UPGRADE_TO_28 17 -#define STMT_17_INFO {"STMT_UPGRADE_TO_28", NULL} -#define STMT_17 \ - "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 18 -#define STMT_18_INFO {"STMT_UPGRADE_TO_29", NULL} -#define STMT_18 \ - "DROP TRIGGER IF EXISTS nodes_update_checksum_trigger; " \ - "DROP TRIGGER IF EXISTS nodes_insert_trigger; " \ - "DROP TRIGGER IF EXISTS nodes_delete_trigger; " \ - "CREATE TRIGGER nodes_update_checksum_trigger " \ - "AFTER UPDATE OF checksum ON nodes " \ - "WHEN NEW.checksum IS NOT OLD.checksum " \ - "BEGIN " \ - " UPDATE pristine SET refcount = refcount + 1 " \ - " WHERE checksum = NEW.checksum; " \ - " UPDATE pristine SET refcount = refcount - 1 " \ - " WHERE checksum = OLD.checksum; " \ - "END; " \ - "CREATE TRIGGER nodes_insert_trigger " \ - "AFTER INSERT ON nodes " \ - "WHEN NEW.checksum IS NOT NULL " \ - "BEGIN " \ - " UPDATE pristine SET refcount = refcount + 1 " \ - " WHERE checksum = NEW.checksum; " \ - "END; " \ - "CREATE TRIGGER nodes_delete_trigger " \ - "AFTER DELETE ON nodes " \ - "WHEN OLD.checksum IS NOT NULL " \ - "BEGIN " \ - " UPDATE pristine SET refcount = refcount - 1 " \ - " WHERE checksum = OLD.checksum; " \ - "END; " \ - "PRAGMA user_version = 29; " \ - "" - -#define STMT_UPGRADE_TO_30 19 -#define STMT_19_INFO {"STMT_UPGRADE_TO_30", NULL} -#define STMT_19 \ +#define STMT_UPGRADE_TO_30 2 +#define STMT_2_INFO {"STMT_UPGRADE_TO_30", NULL} +#define STMT_2 \ "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); " \ @@ -370,9 +181,9 @@ "UPDATE nodes SET file_external=1 WHERE file_external IS NOT NULL; " \ "" -#define STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE 20 -#define STMT_20_INFO {"STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE", NULL} -#define STMT_20 \ +#define STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE 3 +#define STMT_3_INFO {"STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE", NULL} +#define STMT_3 \ "SELECT wc_id, local_relpath, " \ " conflict_old, conflict_working, conflict_new, prop_reject, tree_conflict_data " \ "FROM actual_node " \ @@ -384,24 +195,19 @@ "ORDER by wc_id, local_relpath " \ "" -#define STMT_UPGRADE_30_SET_CONFLICT 21 -#define STMT_21_INFO {"STMT_UPGRADE_30_SET_CONFLICT", NULL} -#define STMT_21 \ +#define STMT_UPGRADE_30_SET_CONFLICT 4 +#define STMT_4_INFO {"STMT_UPGRADE_30_SET_CONFLICT", NULL} +#define STMT_4 \ "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 22 -#define STMT_22_INFO {"STMT_UPGRADE_TO_31_ALTER_TABLE", NULL} -#define STMT_22 \ +#define STMT_UPGRADE_TO_31 5 +#define STMT_5_INFO {"STMT_UPGRADE_TO_31", NULL} +#define STMT_5 \ "ALTER TABLE NODES ADD COLUMN inherited_props BLOB; " \ - "" - -#define STMT_UPGRADE_TO_31_FINALIZE 23 -#define STMT_23_INFO {"STMT_UPGRADE_TO_31_FINALIZE", NULL} -#define STMT_23 \ "DROP INDEX IF EXISTS I_ACTUAL_CHANGELIST; " \ "DROP INDEX IF EXISTS I_EXTERNALS_PARENT; " \ "DROP INDEX I_NODES_PARENT; " \ @@ -413,9 +219,9 @@ "PRAGMA user_version = 31; " \ "" -#define STMT_UPGRADE_31_SELECT_WCROOT_NODES 24 -#define STMT_24_INFO {"STMT_UPGRADE_31_SELECT_WCROOT_NODES", NULL} -#define STMT_24 \ +#define STMT_UPGRADE_31_SELECT_WCROOT_NODES 6 +#define STMT_6_INFO {"STMT_UPGRADE_31_SELECT_WCROOT_NODES", NULL} +#define STMT_6 \ "SELECT l.wc_id, l.local_relpath FROM nodes as l " \ "LEFT OUTER JOIN nodes as r " \ "ON l.wc_id = r.wc_id " \ @@ -427,21 +233,6 @@ " 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 25 -#define STMT_25_INFO {"STMT_UPGRADE_TO_32", NULL} -#define STMT_25 \ - "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); " \ - "DROP INDEX I_NODES_PARENT; " \ - "CREATE UNIQUE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath, " \ - " local_relpath, op_depth); " \ - "DROP INDEX I_ACTUAL_PARENT; " \ - "CREATE UNIQUE INDEX I_ACTUAL_PARENT ON ACTUAL_NODE (wc_id, parent_relpath, " \ - " local_relpath); " \ - "-- format: YYY " \ - "" - #define WC_METADATA_SQL_99 \ "CREATE TABLE ACTUAL_NODE_BACKUP ( " \ " wc_id INTEGER NOT NULL, " \ @@ -491,25 +282,6 @@ STMT_4, \ STMT_5, \ STMT_6, \ - STMT_7, \ - STMT_8, \ - STMT_9, \ - STMT_10, \ - STMT_11, \ - STMT_12, \ - STMT_13, \ - STMT_14, \ - STMT_15, \ - STMT_16, \ - STMT_17, \ - STMT_18, \ - STMT_19, \ - STMT_20, \ - STMT_21, \ - STMT_22, \ - STMT_23, \ - STMT_24, \ - STMT_25, \ NULL \ } @@ -522,24 +294,5 @@ STMT_4_INFO, \ STMT_5_INFO, \ STMT_6_INFO, \ - STMT_7_INFO, \ - STMT_8_INFO, \ - STMT_9_INFO, \ - STMT_10_INFO, \ - STMT_11_INFO, \ - STMT_12_INFO, \ - STMT_13_INFO, \ - STMT_14_INFO, \ - STMT_15_INFO, \ - STMT_16_INFO, \ - STMT_17_INFO, \ - STMT_18_INFO, \ - STMT_19_INFO, \ - STMT_20_INFO, \ - STMT_21_INFO, \ - STMT_22_INFO, \ - STMT_23_INFO, \ - STMT_24_INFO, \ - STMT_25_INFO, \ {NULL, NULL} \ } diff --git a/subversion/libsvn_wc/wc-metadata.sql b/subversion/libsvn_wc/wc-metadata.sql index f52df93f462a..e34cf1422e60 100644 --- a/subversion/libsvn_wc/wc-metadata.sql +++ b/subversion/libsvn_wc/wc-metadata.sql @@ -229,11 +229,6 @@ CREATE TABLE WC_LOCK ( ); -PRAGMA user_version = --- define: SVN_WC__VERSION -; - - /* ------------------------------------------------------------------------- */ /* The NODES table describes the way WORKING nodes are layered on top of @@ -279,7 +274,6 @@ PRAGMA user_version = An 'svn revert foo/bar' would remove the NODES of (2). */ --- STMT_CREATE_NODES CREATE TABLE NODES ( /* Working copy location related fields */ @@ -503,8 +497,6 @@ CREATE VIEW NODES_BASE AS SELECT * FROM nodes WHERE op_depth = 0; --- STMT_CREATE_NODES_TRIGGERS - CREATE TRIGGER nodes_insert_trigger AFTER INSERT ON nodes WHEN NEW.checksum IS NOT NULL @@ -532,8 +524,6 @@ BEGIN WHERE checksum = OLD.checksum; END; --- STMT_CREATE_EXTERNALS - CREATE TABLE EXTERNALS ( /* Working copy location related fields (like NODES)*/ @@ -572,6 +562,12 @@ CREATE UNIQUE INDEX I_EXTERNALS_DEFINED ON EXTERNALS (wc_id, def_local_relpath, local_relpath); + +PRAGMA user_version = +-- define: SVN_WC__VERSION +; + + /* ------------------------------------------------------------------------- */ /* This statement provides SQLite with the necessary information about our indexes to make better decisions in the query planner. @@ -630,208 +626,6 @@ INSERT INTO sqlite_stat1(tbl, idx, stat) VALUES ANALYZE sqlite_master; /* Loads sqlite_stat1 data for query optimizer */ /* ------------------------------------------------------------------------- */ -/* Format 20 introduces NODES and removes BASE_NODE and WORKING_NODE */ - --- STMT_UPGRADE_TO_20 - -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); - -UPDATE WORKING_NODE SET checksum = (SELECT checksum FROM pristine - WHERE md5_checksum = WORKING_NODE.checksum) -WHERE EXISTS (SELECT 1 FROM pristine - WHERE md5_checksum = WORKING_NODE.checksum); - -INSERT INTO NODES ( - wc_id, local_relpath, op_depth, parent_relpath, - repos_id, repos_path, revision, - presence, depth, moved_here, moved_to, kind, - changed_revision, changed_date, changed_author, - checksum, properties, translated_size, last_mod_time, - dav_cache, symlink_target, file_external ) -SELECT wc_id, local_relpath, 0 /*op_depth*/, parent_relpath, - repos_id, repos_relpath, revnum, - presence, depth, NULL /*moved_here*/, NULL /*moved_to*/, kind, - changed_rev, changed_date, changed_author, - checksum, properties, translated_size, last_mod_time, - dav_cache, symlink_target, file_external -FROM BASE_NODE; -INSERT INTO NODES ( - wc_id, local_relpath, op_depth, parent_relpath, - repos_id, repos_path, revision, - presence, depth, moved_here, moved_to, kind, - changed_revision, changed_date, changed_author, - checksum, properties, translated_size, last_mod_time, - dav_cache, symlink_target, file_external ) -SELECT wc_id, local_relpath, 2 /*op_depth*/, parent_relpath, - copyfrom_repos_id, copyfrom_repos_path, copyfrom_revnum, - presence, depth, NULL /*moved_here*/, NULL /*moved_to*/, kind, - changed_rev, changed_date, changed_author, - checksum, properties, translated_size, last_mod_time, - NULL /*dav_cache*/, symlink_target, NULL /*file_external*/ -FROM WORKING_NODE; - -DROP TABLE BASE_NODE; -DROP TABLE WORKING_NODE; - -PRAGMA user_version = 20; - - -/* ------------------------------------------------------------------------- */ - -/* Format 21 involves no schema changes, it moves the tree conflict victim - information to victime nodes, rather than parents. */ - --- STMT_UPGRADE_TO_21 -PRAGMA user_version = 21; - -/* For format 21 bump code */ --- STMT_UPGRADE_21_SELECT_OLD_TREE_CONFLICT -SELECT wc_id, local_relpath, tree_conflict_data -FROM actual_node -WHERE tree_conflict_data IS NOT NULL - -/* For format 21 bump code */ --- STMT_UPGRADE_21_ERASE_OLD_CONFLICTS -UPDATE actual_node SET tree_conflict_data = NULL - -/* ------------------------------------------------------------------------- */ - -/* Format 22 simply moves the tree conflict information from the conflict_data - column to the tree_conflict_data column. */ - --- STMT_UPGRADE_TO_22 -UPDATE actual_node SET tree_conflict_data = conflict_data; -UPDATE actual_node SET conflict_data = NULL; - -PRAGMA user_version = 22; - - -/* ------------------------------------------------------------------------- */ - -/* Format 23 involves no schema changes, it introduces multi-layer - op-depth processing for NODES. */ - --- STMT_UPGRADE_TO_23 -PRAGMA user_version = 23; - --- STMT_UPGRADE_23_HAS_WORKING_NODES -SELECT 1 FROM nodes WHERE op_depth > 0 -LIMIT 1 - -/* ------------------------------------------------------------------------- */ - -/* Format 24 involves no schema changes; it starts using the pristine - table's refcount column correctly. */ - --- STMT_UPGRADE_TO_24 -UPDATE pristine SET refcount = - (SELECT COUNT(*) FROM nodes - WHERE checksum = pristine.checksum /*OR checksum = pristine.md5_checksum*/); - -PRAGMA user_version = 24; - -/* ------------------------------------------------------------------------- */ - -/* Format 25 introduces the NODES_CURRENT view. */ - --- STMT_UPGRADE_TO_25 -DROP VIEW IF EXISTS NODES_CURRENT; -CREATE VIEW NODES_CURRENT AS - SELECT * FROM nodes - JOIN (SELECT wc_id, local_relpath, MAX(op_depth) AS op_depth FROM nodes - GROUP BY wc_id, local_relpath) AS filter - ON nodes.wc_id = filter.wc_id - AND nodes.local_relpath = filter.local_relpath - AND nodes.op_depth = filter.op_depth; - -PRAGMA user_version = 25; - -/* ------------------------------------------------------------------------- */ - -/* Format 26 introduces the NODES_BASE view. */ - --- STMT_UPGRADE_TO_26 -DROP VIEW IF EXISTS NODES_BASE; -CREATE VIEW NODES_BASE AS - SELECT * FROM nodes - WHERE op_depth = 0; - -PRAGMA user_version = 26; - -/* ------------------------------------------------------------------------- */ - -/* Format 27 involves no schema changes, it introduces stores - conflict files as relpaths rather than names in ACTUAL_NODE. */ - --- STMT_UPGRADE_TO_27 -PRAGMA user_version = 27; - -/* For format 27 bump code */ --- STMT_UPGRADE_27_HAS_ACTUAL_NODES_CONFLICTS -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) - AND (tree_conflict_data IS NULL)) -LIMIT 1 - - -/* ------------------------------------------------------------------------- */ - -/* Format 28 involves no schema changes, it only converts MD5 pristine - references to SHA1. */ - --- STMT_UPGRADE_TO_28 - -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; - -/* ------------------------------------------------------------------------- */ - -/* Format 29 introduces the EXTERNALS table (See STMT_CREATE_TRIGGERS) and - optimizes a few trigger definitions. ... */ - --- STMT_UPGRADE_TO_29 - -DROP TRIGGER IF EXISTS nodes_update_checksum_trigger; -DROP TRIGGER IF EXISTS nodes_insert_trigger; -DROP TRIGGER IF EXISTS nodes_delete_trigger; - -CREATE TRIGGER nodes_update_checksum_trigger -AFTER UPDATE OF checksum ON nodes -WHEN NEW.checksum IS NOT OLD.checksum - /* AND (NEW.checksum IS NOT NULL OR OLD.checksum IS NOT NULL) */ -BEGIN - UPDATE pristine SET refcount = refcount + 1 - WHERE checksum = NEW.checksum; - UPDATE pristine SET refcount = refcount - 1 - WHERE checksum = OLD.checksum; -END; - -CREATE TRIGGER nodes_insert_trigger -AFTER INSERT ON nodes -WHEN NEW.checksum IS NOT NULL -BEGIN - UPDATE pristine SET refcount = refcount + 1 - WHERE checksum = NEW.checksum; -END; - -CREATE TRIGGER nodes_delete_trigger -AFTER DELETE ON nodes -WHEN OLD.checksum IS NOT NULL -BEGIN - UPDATE pristine SET refcount = refcount - 1 - WHERE checksum = OLD.checksum; -END; - -PRAGMA user_version = 29; - -/* ------------------------------------------------------------------------- */ - /* Format 30 creates a new NODES index for move information, and a new PRISTINE index for the md5_checksum column. It also activates use of skel-based conflict storage -- see notes/wc-ng/conflict-storage-2.0. @@ -870,9 +664,9 @@ WHERE wc_id = ?1 and local_relpath = ?2 /* Format 31 adds the inherited_props column to the NODES table. C code then initializes the update/switch roots to make sure future updates fetch the inherited properties */ --- STMT_UPGRADE_TO_31_ALTER_TABLE +-- STMT_UPGRADE_TO_31 ALTER TABLE NODES ADD COLUMN inherited_props BLOB; --- STMT_UPGRADE_TO_31_FINALIZE + DROP INDEX IF EXISTS I_ACTUAL_CHANGELIST; DROP INDEX IF EXISTS I_EXTERNALS_PARENT; @@ -906,25 +700,8 @@ WHERE l.op_depth = 0 /* ------------------------------------------------------------------------- */ /* Format 32 .... */ --- STMT_UPGRADE_TO_32 - -/* Drop old index. ### Remove this part from the upgrade to 31 once bumped */ -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); - -DROP INDEX I_NODES_PARENT; -CREATE UNIQUE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath, - local_relpath, op_depth); - -DROP INDEX I_ACTUAL_PARENT; -CREATE UNIQUE INDEX I_ACTUAL_PARENT ON ACTUAL_NODE (wc_id, parent_relpath, - local_relpath); - -/* ------------------------------------------------------------------------- */ - -/* Format YYY introduces new handling for conflict information. */ --- format: YYY +/* -- STMT_UPGRADE_TO_32 +PRAGMA user_version = 32; */ /* ------------------------------------------------------------------------- */ diff --git a/subversion/libsvn_wc/wc-queries.h b/subversion/libsvn_wc/wc-queries.h index 2a7594067ed6..b333e95ffdbe 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.9.7/subversion/libsvn_wc/token-map.h. +/* This file is automatically generated from wc-queries.sql and 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 @@ -23,7 +23,7 @@ " lock_token, lock_owner, lock_comment, lock_date " \ "FROM nodes " \ "LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id " \ - " AND nodes.repos_path = lock.repos_relpath " \ + " AND nodes.repos_path = lock.repos_relpath AND nodes.op_depth=0 " \ "WHERE wc_id = ?1 AND local_relpath = ?2 " \ "ORDER BY op_depth DESC " \ "" @@ -132,7 +132,7 @@ " lock_comment, lock_date, local_relpath, moved_here, moved_to, file_external " \ "FROM nodes " \ "LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id " \ - " AND nodes.repos_path = lock.repos_relpath AND op_depth = 0 " \ + " AND nodes.repos_path = lock.repos_relpath AND nodes.op_depth = 0 " \ "WHERE wc_id = ?1 AND parent_relpath = ?2 " \ "ORDER BY local_relpath DESC, op_depth DESC " \ "" @@ -146,7 +146,7 @@ " lock_comment, lock_date, local_relpath, moved_here, moved_to, file_external " \ "FROM nodes " \ "LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id " \ - " AND nodes.repos_path = lock.repos_relpath AND op_depth = 0 " \ + " AND nodes.repos_path = lock.repos_relpath " \ "WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0 " \ "ORDER BY local_relpath DESC " \ "" @@ -1627,37 +1627,44 @@ "PRAGMA journal_mode = DELETE " \ "" -#define STMT_INSERT_ACTUAL_NODE 152 -#define STMT_152_INFO {"STMT_INSERT_ACTUAL_NODE", NULL} +#define STMT_FIND_REPOS_PATH_IN_WC 152 +#define STMT_152_INFO {"STMT_FIND_REPOS_PATH_IN_WC", NULL} #define STMT_152 \ + "SELECT local_relpath FROM nodes_current " \ + " WHERE wc_id = ?1 AND repos_path = ?2 " \ + "" + +#define STMT_INSERT_ACTUAL_NODE 153 +#define STMT_153_INFO {"STMT_INSERT_ACTUAL_NODE", NULL} +#define STMT_153 \ "INSERT OR REPLACE INTO actual_node ( " \ " wc_id, local_relpath, parent_relpath, properties, changelist, conflict_data) " \ "VALUES (?1, ?2, ?3, ?4, ?5, ?6) " \ "" -#define STMT_SELECT_ALL_FILES 153 -#define STMT_153_INFO {"STMT_SELECT_ALL_FILES", NULL} -#define STMT_153 \ +#define STMT_SELECT_ALL_FILES 154 +#define STMT_154_INFO {"STMT_SELECT_ALL_FILES", NULL} +#define STMT_154 \ "SELECT local_relpath FROM nodes_current " \ "WHERE wc_id = ?1 AND parent_relpath = ?2 AND kind = 'file' " \ "" -#define STMT_UPDATE_NODE_PROPS 154 -#define STMT_154_INFO {"STMT_UPDATE_NODE_PROPS", NULL} -#define STMT_154 \ +#define STMT_UPDATE_NODE_PROPS 155 +#define STMT_155_INFO {"STMT_UPDATE_NODE_PROPS", NULL} +#define STMT_155 \ "UPDATE nodes SET properties = ?4 " \ "WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 " \ "" -#define STMT_PRAGMA_TABLE_INFO_NODES 155 -#define STMT_155_INFO {"STMT_PRAGMA_TABLE_INFO_NODES", NULL} -#define STMT_155 \ +#define STMT_PRAGMA_TABLE_INFO_NODES 156 +#define STMT_156_INFO {"STMT_PRAGMA_TABLE_INFO_NODES", NULL} +#define STMT_156 \ "PRAGMA table_info(\"NODES\") " \ "" -#define STMT_CREATE_TARGET_PROP_CACHE 156 -#define STMT_156_INFO {"STMT_CREATE_TARGET_PROP_CACHE", NULL} -#define STMT_156 \ +#define STMT_CREATE_TARGET_PROP_CACHE 157 +#define STMT_157_INFO {"STMT_CREATE_TARGET_PROP_CACHE", NULL} +#define STMT_157 \ "DROP TABLE IF EXISTS target_prop_cache; " \ "CREATE TEMPORARY TABLE target_prop_cache ( " \ " local_relpath TEXT NOT NULL PRIMARY KEY, " \ @@ -1666,9 +1673,9 @@ "); " \ "" -#define STMT_CACHE_TARGET_PROPS 157 -#define STMT_157_INFO {"STMT_CACHE_TARGET_PROPS", NULL} -#define STMT_157 \ +#define STMT_CACHE_TARGET_PROPS 158 +#define STMT_158_INFO {"STMT_CACHE_TARGET_PROPS", NULL} +#define STMT_158 \ "INSERT INTO target_prop_cache(local_relpath, kind, properties) " \ " SELECT n.local_relpath, n.kind, " \ " IFNULL((SELECT properties FROM actual_node AS a " \ @@ -1687,9 +1694,9 @@ " ORDER BY t.local_relpath " \ "" -#define STMT_CACHE_TARGET_PRISTINE_PROPS 158 -#define STMT_158_INFO {"STMT_CACHE_TARGET_PRISTINE_PROPS", NULL} -#define STMT_158 \ +#define STMT_CACHE_TARGET_PRISTINE_PROPS 159 +#define STMT_159_INFO {"STMT_CACHE_TARGET_PRISTINE_PROPS", NULL} +#define STMT_159 \ "INSERT INTO target_prop_cache(local_relpath, kind, properties) " \ " SELECT n.local_relpath, n.kind, " \ " CASE n.presence " \ @@ -1714,22 +1721,22 @@ " ORDER BY t.local_relpath " \ "" -#define STMT_SELECT_ALL_TARGET_PROP_CACHE 159 -#define STMT_159_INFO {"STMT_SELECT_ALL_TARGET_PROP_CACHE", NULL} -#define STMT_159 \ +#define STMT_SELECT_ALL_TARGET_PROP_CACHE 160 +#define STMT_160_INFO {"STMT_SELECT_ALL_TARGET_PROP_CACHE", NULL} +#define STMT_160 \ "SELECT local_relpath, properties FROM target_prop_cache " \ "ORDER BY local_relpath " \ "" -#define STMT_DROP_TARGET_PROP_CACHE 160 -#define STMT_160_INFO {"STMT_DROP_TARGET_PROP_CACHE", NULL} -#define STMT_160 \ +#define STMT_DROP_TARGET_PROP_CACHE 161 +#define STMT_161_INFO {"STMT_DROP_TARGET_PROP_CACHE", NULL} +#define STMT_161 \ "DROP TABLE target_prop_cache; " \ "" -#define STMT_CREATE_REVERT_LIST 161 -#define STMT_161_INFO {"STMT_CREATE_REVERT_LIST", NULL} -#define STMT_161 \ +#define STMT_CREATE_REVERT_LIST 162 +#define STMT_162_INFO {"STMT_CREATE_REVERT_LIST", NULL} +#define STMT_162 \ "DROP TABLE IF EXISTS revert_list; " \ "CREATE TEMPORARY TABLE revert_list ( " \ " local_relpath TEXT NOT NULL, " \ @@ -1787,26 +1794,26 @@ "END " \ "" -#define STMT_DROP_REVERT_LIST_TRIGGERS 162 -#define STMT_162_INFO {"STMT_DROP_REVERT_LIST_TRIGGERS", NULL} -#define STMT_162 \ +#define STMT_DROP_REVERT_LIST_TRIGGERS 163 +#define STMT_163_INFO {"STMT_DROP_REVERT_LIST_TRIGGERS", NULL} +#define STMT_163 \ "DROP TRIGGER trigger_revert_list_nodes; " \ "DROP TRIGGER trigger_revert_list_actual_delete; " \ "DROP TRIGGER trigger_revert_list_actual_update " \ "" -#define STMT_SELECT_REVERT_LIST 163 -#define STMT_163_INFO {"STMT_SELECT_REVERT_LIST", NULL} -#define STMT_163 \ +#define STMT_SELECT_REVERT_LIST 164 +#define STMT_164_INFO {"STMT_SELECT_REVERT_LIST", NULL} +#define STMT_164 \ "SELECT actual, notify, kind, op_depth, repos_id, conflict_data " \ "FROM revert_list " \ "WHERE local_relpath = ?1 " \ "ORDER BY actual DESC " \ "" -#define STMT_SELECT_REVERT_LIST_COPIED_CHILDREN 164 -#define STMT_164_INFO {"STMT_SELECT_REVERT_LIST_COPIED_CHILDREN", NULL} -#define STMT_164 \ +#define STMT_SELECT_REVERT_LIST_COPIED_CHILDREN 165 +#define STMT_165_INFO {"STMT_SELECT_REVERT_LIST_COPIED_CHILDREN", NULL} +#define STMT_165 \ "SELECT local_relpath, kind " \ "FROM revert_list " \ "WHERE (((local_relpath) > (CASE (?1) WHEN '' THEN '' ELSE (?1) || '/' END)) AND ((local_relpath) < CASE (?1) WHEN '' THEN X'FFFF' ELSE (?1) || '0' END)) " \ @@ -1815,15 +1822,15 @@ "ORDER BY local_relpath " \ "" -#define STMT_DELETE_REVERT_LIST 165 -#define STMT_165_INFO {"STMT_DELETE_REVERT_LIST", NULL} -#define STMT_165 \ +#define STMT_DELETE_REVERT_LIST 166 +#define STMT_166_INFO {"STMT_DELETE_REVERT_LIST", NULL} +#define STMT_166 \ "DELETE FROM revert_list WHERE local_relpath = ?1 " \ "" -#define STMT_SELECT_REVERT_LIST_RECURSIVE 166 -#define STMT_166_INFO {"STMT_SELECT_REVERT_LIST_RECURSIVE", NULL} -#define STMT_166 \ +#define STMT_SELECT_REVERT_LIST_RECURSIVE 167 +#define STMT_167_INFO {"STMT_SELECT_REVERT_LIST_RECURSIVE", NULL} +#define STMT_167 \ "SELECT p.local_relpath, n.kind, a.notify, a.kind " \ "FROM (SELECT DISTINCT local_relpath " \ " FROM revert_list " \ @@ -1834,32 +1841,32 @@ "ORDER BY p.local_relpath " \ "" -#define STMT_DELETE_REVERT_LIST_RECURSIVE 167 -#define STMT_167_INFO {"STMT_DELETE_REVERT_LIST_RECURSIVE", NULL} -#define STMT_167 \ +#define STMT_DELETE_REVERT_LIST_RECURSIVE 168 +#define STMT_168_INFO {"STMT_DELETE_REVERT_LIST_RECURSIVE", NULL} +#define STMT_168 \ "DELETE FROM revert_list " \ "WHERE (local_relpath = ?1 " \ " OR (((local_relpath) > (CASE (?1) WHEN '' THEN '' ELSE (?1) || '/' END)) AND ((local_relpath) < CASE (?1) WHEN '' THEN X'FFFF' ELSE (?1) || '0' END))) " \ "" -#define STMT_DROP_REVERT_LIST 168 -#define STMT_168_INFO {"STMT_DROP_REVERT_LIST", NULL} -#define STMT_168 \ +#define STMT_DROP_REVERT_LIST 169 +#define STMT_169_INFO {"STMT_DROP_REVERT_LIST", NULL} +#define STMT_169 \ "DROP TABLE IF EXISTS revert_list " \ "" -#define STMT_CREATE_DELETE_LIST 169 -#define STMT_169_INFO {"STMT_CREATE_DELETE_LIST", NULL} -#define STMT_169 \ +#define STMT_CREATE_DELETE_LIST 170 +#define STMT_170_INFO {"STMT_CREATE_DELETE_LIST", NULL} +#define STMT_170 \ "DROP TABLE IF EXISTS delete_list; " \ "CREATE TEMPORARY TABLE delete_list ( " \ " local_relpath TEXT PRIMARY KEY NOT NULL UNIQUE " \ " ) " \ "" -#define STMT_INSERT_DELETE_LIST 170 -#define STMT_170_INFO {"STMT_INSERT_DELETE_LIST", NULL} -#define STMT_170 \ +#define STMT_INSERT_DELETE_LIST 171 +#define STMT_171_INFO {"STMT_INSERT_DELETE_LIST", NULL} +#define STMT_171 \ "INSERT INTO delete_list(local_relpath) " \ "SELECT ?2 " \ "UNION ALL " \ @@ -1875,22 +1882,22 @@ "ORDER by local_relpath " \ "" -#define STMT_SELECT_DELETE_LIST 171 -#define STMT_171_INFO {"STMT_SELECT_DELETE_LIST", NULL} -#define STMT_171 \ +#define STMT_SELECT_DELETE_LIST 172 +#define STMT_172_INFO {"STMT_SELECT_DELETE_LIST", NULL} +#define STMT_172 \ "SELECT local_relpath FROM delete_list " \ "ORDER BY local_relpath " \ "" -#define STMT_FINALIZE_DELETE 172 -#define STMT_172_INFO {"STMT_FINALIZE_DELETE", NULL} -#define STMT_172 \ +#define STMT_FINALIZE_DELETE 173 +#define STMT_173_INFO {"STMT_FINALIZE_DELETE", NULL} +#define STMT_173 \ "DROP TABLE IF EXISTS delete_list " \ "" -#define STMT_CREATE_UPDATE_MOVE_LIST 173 -#define STMT_173_INFO {"STMT_CREATE_UPDATE_MOVE_LIST", NULL} -#define STMT_173 \ +#define STMT_CREATE_UPDATE_MOVE_LIST 174 +#define STMT_174_INFO {"STMT_CREATE_UPDATE_MOVE_LIST", NULL} +#define STMT_174 \ "DROP TABLE IF EXISTS update_move_list; " \ "CREATE TEMPORARY TABLE update_move_list ( " \ " local_relpath TEXT PRIMARY KEY NOT NULL UNIQUE, " \ @@ -1901,39 +1908,39 @@ " ) " \ "" -#define STMT_INSERT_UPDATE_MOVE_LIST 174 -#define STMT_174_INFO {"STMT_INSERT_UPDATE_MOVE_LIST", NULL} -#define STMT_174 \ +#define STMT_INSERT_UPDATE_MOVE_LIST 175 +#define STMT_175_INFO {"STMT_INSERT_UPDATE_MOVE_LIST", NULL} +#define STMT_175 \ "INSERT INTO update_move_list(local_relpath, action, kind, content_state, " \ " prop_state) " \ "VALUES (?1, ?2, ?3, ?4, ?5) " \ "" -#define STMT_SELECT_UPDATE_MOVE_LIST 175 -#define STMT_175_INFO {"STMT_SELECT_UPDATE_MOVE_LIST", NULL} -#define STMT_175 \ +#define STMT_SELECT_UPDATE_MOVE_LIST 176 +#define STMT_176_INFO {"STMT_SELECT_UPDATE_MOVE_LIST", NULL} +#define STMT_176 \ "SELECT local_relpath, action, kind, content_state, prop_state " \ "FROM update_move_list " \ "ORDER BY local_relpath " \ "" -#define STMT_FINALIZE_UPDATE_MOVE 176 -#define STMT_176_INFO {"STMT_FINALIZE_UPDATE_MOVE", NULL} -#define STMT_176 \ +#define STMT_FINALIZE_UPDATE_MOVE 177 +#define STMT_177_INFO {"STMT_FINALIZE_UPDATE_MOVE", NULL} +#define STMT_177 \ "DROP TABLE IF EXISTS update_move_list " \ "" -#define STMT_MOVE_NOTIFY_TO_REVERT 177 -#define STMT_177_INFO {"STMT_MOVE_NOTIFY_TO_REVERT", NULL} -#define STMT_177 \ +#define STMT_MOVE_NOTIFY_TO_REVERT 178 +#define STMT_178_INFO {"STMT_MOVE_NOTIFY_TO_REVERT", NULL} +#define STMT_178 \ "INSERT INTO revert_list (local_relpath, notify, kind, actual) " \ " SELECT local_relpath, 2, kind, 1 FROM update_move_list; " \ "DROP TABLE update_move_list " \ "" -#define STMT_SELECT_MIN_MAX_REVISIONS 178 -#define STMT_178_INFO {"STMT_SELECT_MIN_MAX_REVISIONS", NULL} -#define STMT_178 \ +#define STMT_SELECT_MIN_MAX_REVISIONS 179 +#define STMT_179_INFO {"STMT_SELECT_MIN_MAX_REVISIONS", NULL} +#define STMT_179 \ "SELECT MIN(revision), MAX(revision), " \ " MIN(changed_revision), MAX(changed_revision) FROM nodes " \ " WHERE wc_id = ?1 " \ @@ -1944,9 +1951,9 @@ " AND op_depth = 0 " \ "" -#define STMT_HAS_SPARSE_NODES 179 -#define STMT_179_INFO {"STMT_HAS_SPARSE_NODES", NULL} -#define STMT_179 \ +#define STMT_HAS_SPARSE_NODES 180 +#define STMT_180_INFO {"STMT_HAS_SPARSE_NODES", NULL} +#define STMT_180 \ "SELECT 1 FROM nodes " \ "WHERE wc_id = ?1 " \ " AND (local_relpath = ?2 " \ @@ -1958,9 +1965,9 @@ "LIMIT 1 " \ "" -#define STMT_SUBTREE_HAS_TREE_MODIFICATIONS 180 -#define STMT_180_INFO {"STMT_SUBTREE_HAS_TREE_MODIFICATIONS", NULL} -#define STMT_180 \ +#define STMT_SUBTREE_HAS_TREE_MODIFICATIONS 181 +#define STMT_181_INFO {"STMT_SUBTREE_HAS_TREE_MODIFICATIONS", NULL} +#define STMT_181 \ "SELECT 1 FROM nodes " \ "WHERE wc_id = ?1 " \ " AND (local_relpath = ?2 " \ @@ -1969,9 +1976,9 @@ "LIMIT 1 " \ "" -#define STMT_SUBTREE_HAS_PROP_MODIFICATIONS 181 -#define STMT_181_INFO {"STMT_SUBTREE_HAS_PROP_MODIFICATIONS", NULL} -#define STMT_181 \ +#define STMT_SUBTREE_HAS_PROP_MODIFICATIONS 182 +#define STMT_182_INFO {"STMT_SUBTREE_HAS_PROP_MODIFICATIONS", NULL} +#define STMT_182 \ "SELECT 1 FROM actual_node " \ "WHERE wc_id = ?1 " \ " AND (local_relpath = ?2 " \ @@ -1980,9 +1987,9 @@ "LIMIT 1 " \ "" -#define STMT_HAS_SWITCHED 182 -#define STMT_182_INFO {"STMT_HAS_SWITCHED", NULL} -#define STMT_182 \ +#define STMT_HAS_SWITCHED 183 +#define STMT_183_INFO {"STMT_HAS_SWITCHED", NULL} +#define STMT_183 \ "SELECT 1 " \ "FROM nodes " \ "WHERE wc_id = ?1 " \ @@ -1994,47 +2001,47 @@ "LIMIT 1 " \ "" -#define STMT_SELECT_MOVED_FROM_RELPATH 183 -#define STMT_183_INFO {"STMT_SELECT_MOVED_FROM_RELPATH", NULL} -#define STMT_183 \ +#define STMT_SELECT_MOVED_FROM_RELPATH 184 +#define STMT_184_INFO {"STMT_SELECT_MOVED_FROM_RELPATH", NULL} +#define STMT_184 \ "SELECT local_relpath, op_depth FROM nodes " \ "WHERE wc_id = ?1 AND moved_to = ?2 AND op_depth > 0 " \ "" -#define STMT_UPDATE_MOVED_TO_RELPATH 184 -#define STMT_184_INFO {"STMT_UPDATE_MOVED_TO_RELPATH", NULL} -#define STMT_184 \ +#define STMT_UPDATE_MOVED_TO_RELPATH 185 +#define STMT_185_INFO {"STMT_UPDATE_MOVED_TO_RELPATH", NULL} +#define STMT_185 \ "UPDATE nodes SET moved_to = ?4 " \ "WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 " \ "" -#define STMT_CLEAR_MOVED_TO_RELPATH 185 -#define STMT_185_INFO {"STMT_CLEAR_MOVED_TO_RELPATH", NULL} -#define STMT_185 \ +#define STMT_CLEAR_MOVED_TO_RELPATH 186 +#define STMT_186_INFO {"STMT_CLEAR_MOVED_TO_RELPATH", NULL} +#define STMT_186 \ "UPDATE nodes SET moved_to = NULL " \ "WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 " \ "" -#define STMT_CLEAR_MOVED_HERE_RECURSIVE 186 -#define STMT_186_INFO {"STMT_CLEAR_MOVED_HERE_RECURSIVE", NULL} -#define STMT_186 \ +#define STMT_CLEAR_MOVED_HERE_RECURSIVE 187 +#define STMT_187_INFO {"STMT_CLEAR_MOVED_HERE_RECURSIVE", NULL} +#define STMT_187 \ "UPDATE nodes SET moved_here = NULL " \ "WHERE wc_id = ?1 " \ " AND (local_relpath = ?2 OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \ " AND op_depth = ?3 " \ "" -#define STMT_SELECT_MOVED_HERE_CHILDREN 187 -#define STMT_187_INFO {"STMT_SELECT_MOVED_HERE_CHILDREN", NULL} -#define STMT_187 \ +#define STMT_SELECT_MOVED_HERE_CHILDREN 188 +#define STMT_188_INFO {"STMT_SELECT_MOVED_HERE_CHILDREN", NULL} +#define STMT_188 \ "SELECT moved_to, local_relpath FROM nodes " \ "WHERE wc_id = ?1 AND op_depth > 0 " \ " AND (((moved_to) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((moved_to) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \ "" -#define STMT_SELECT_MOVED_FOR_DELETE 188 -#define STMT_188_INFO {"STMT_SELECT_MOVED_FOR_DELETE", NULL} -#define STMT_188 \ +#define STMT_SELECT_MOVED_FOR_DELETE 189 +#define STMT_189_INFO {"STMT_SELECT_MOVED_FOR_DELETE", NULL} +#define STMT_189 \ "SELECT local_relpath, moved_to, op_depth, " \ " (SELECT CASE WHEN r.moved_here THEN r.op_depth END FROM nodes r " \ " WHERE r.wc_id = ?1 " \ @@ -2048,9 +2055,9 @@ " AND op_depth >= ?3 " \ "" -#define STMT_SELECT_MOVED_FROM_FOR_DELETE 189 -#define STMT_189_INFO {"STMT_SELECT_MOVED_FROM_FOR_DELETE", NULL} -#define STMT_189 \ +#define STMT_SELECT_MOVED_FROM_FOR_DELETE 190 +#define STMT_190_INFO {"STMT_SELECT_MOVED_FROM_FOR_DELETE", NULL} +#define STMT_190 \ "SELECT local_relpath, op_depth, " \ " (SELECT CASE WHEN r.moved_here THEN r.op_depth END FROM nodes r " \ " WHERE r.wc_id = ?1 " \ @@ -2061,25 +2068,25 @@ "WHERE wc_id = ?1 AND moved_to = ?2 AND op_depth > 0 " \ "" -#define STMT_UPDATE_MOVED_TO_DESCENDANTS 190 -#define STMT_190_INFO {"STMT_UPDATE_MOVED_TO_DESCENDANTS", NULL} -#define STMT_190 \ +#define STMT_UPDATE_MOVED_TO_DESCENDANTS 191 +#define STMT_191_INFO {"STMT_UPDATE_MOVED_TO_DESCENDANTS", NULL} +#define STMT_191 \ "UPDATE nodes SET moved_to = (CASE WHEN (?2) = '' THEN (CASE WHEN (?3) = '' THEN (moved_to) WHEN (moved_to) = '' THEN (?3) ELSE (?3) || '/' || (moved_to) END) WHEN (?3) = '' THEN (CASE WHEN (?2) = '' THEN (moved_to) WHEN SUBSTR((moved_to), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(moved_to) THEN '' WHEN SUBSTR((moved_to), LENGTH(?2)+1, 1) = '/' THEN SUBSTR((moved_to), LENGTH(?2)+2) END END) WHEN SUBSTR((moved_to), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(moved_to) THEN (?3) WHEN SUBSTR((moved_to), LENGTH(?2)+1, 1) = '/' THEN (?3) || SUBSTR((moved_to), LENGTH(?2)+1) END END) " \ " WHERE wc_id = ?1 " \ " AND (((moved_to) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((moved_to) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \ "" -#define STMT_CLEAR_MOVED_TO_DESCENDANTS 191 -#define STMT_191_INFO {"STMT_CLEAR_MOVED_TO_DESCENDANTS", NULL} -#define STMT_191 \ +#define STMT_CLEAR_MOVED_TO_DESCENDANTS 192 +#define STMT_192_INFO {"STMT_CLEAR_MOVED_TO_DESCENDANTS", NULL} +#define STMT_192 \ "UPDATE nodes SET moved_to = NULL " \ " WHERE wc_id = ?1 " \ " AND (((moved_to) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((moved_to) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \ "" -#define STMT_SELECT_MOVED_PAIR3 192 -#define STMT_192_INFO {"STMT_SELECT_MOVED_PAIR3", NULL} -#define STMT_192 \ +#define STMT_SELECT_MOVED_PAIR3 193 +#define STMT_193_INFO {"STMT_SELECT_MOVED_PAIR3", NULL} +#define STMT_193 \ "SELECT n.local_relpath, d.moved_to, d.op_depth, n.kind " \ "FROM nodes n " \ "JOIN nodes d ON d.wc_id = ?1 AND d.local_relpath = n.local_relpath " \ @@ -2105,9 +2112,9 @@ "ORDER BY n.local_relpath " \ "" -#define STMT_SELECT_MOVED_OUTSIDE 193 -#define STMT_193_INFO {"STMT_SELECT_MOVED_OUTSIDE", NULL} -#define STMT_193 \ +#define STMT_SELECT_MOVED_OUTSIDE 194 +#define STMT_194_INFO {"STMT_SELECT_MOVED_OUTSIDE", NULL} +#define STMT_194 \ "SELECT local_relpath, moved_to, op_depth FROM nodes " \ "WHERE wc_id = ?1 " \ " AND (local_relpath = ?2 OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \ @@ -2116,9 +2123,9 @@ " AND NOT (((moved_to) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((moved_to) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \ "" -#define STMT_SELECT_MOVED_DESCENDANTS_SRC 194 -#define STMT_194_INFO {"STMT_SELECT_MOVED_DESCENDANTS_SRC", NULL} -#define STMT_194 \ +#define STMT_SELECT_MOVED_DESCENDANTS_SRC 195 +#define STMT_195_INFO {"STMT_SELECT_MOVED_DESCENDANTS_SRC", NULL} +#define STMT_195 \ "SELECT s.op_depth, n.local_relpath, n.kind, n.repos_path, s.moved_to " \ "FROM nodes n " \ "JOIN nodes s ON s.wc_id = n.wc_id AND s.local_relpath = n.local_relpath " \ @@ -2132,9 +2139,9 @@ " AND s.moved_to IS NOT NULL " \ "" -#define STMT_COMMIT_UPDATE_ORIGIN 195 -#define STMT_195_INFO {"STMT_COMMIT_UPDATE_ORIGIN", NULL} -#define STMT_195 \ +#define STMT_COMMIT_UPDATE_ORIGIN 196 +#define STMT_196_INFO {"STMT_COMMIT_UPDATE_ORIGIN", NULL} +#define STMT_196 \ "UPDATE nodes SET repos_id = ?4, " \ " repos_path = (CASE WHEN (?2) = '' THEN (CASE WHEN (?5) = '' THEN (local_relpath) WHEN (local_relpath) = '' THEN (?5) ELSE (?5) || '/' || (local_relpath) END) WHEN (?5) = '' THEN (CASE WHEN (?2) = '' THEN (local_relpath) WHEN SUBSTR((local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(local_relpath) THEN '' WHEN SUBSTR((local_relpath), LENGTH(?2)+1, 1) = '/' THEN SUBSTR((local_relpath), LENGTH(?2)+2) END END) WHEN SUBSTR((local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(local_relpath) THEN (?5) WHEN SUBSTR((local_relpath), LENGTH(?2)+1, 1) = '/' THEN (?5) || SUBSTR((local_relpath), LENGTH(?2)+1) END END), " \ " revision = ?6 " \ @@ -2144,16 +2151,16 @@ " AND op_depth = ?3 " \ "" -#define STMT_HAS_LAYER_BETWEEN 196 -#define STMT_196_INFO {"STMT_HAS_LAYER_BETWEEN", NULL} -#define STMT_196 \ +#define STMT_HAS_LAYER_BETWEEN 197 +#define STMT_197_INFO {"STMT_HAS_LAYER_BETWEEN", NULL} +#define STMT_197 \ "SELECT 1 FROM NODES " \ "WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3 AND op_depth < ?4 " \ "" -#define STMT_SELECT_REPOS_PATH_REVISION 197 -#define STMT_197_INFO {"STMT_SELECT_REPOS_PATH_REVISION", NULL} -#define STMT_197 \ +#define STMT_SELECT_REPOS_PATH_REVISION 198 +#define STMT_198_INFO {"STMT_SELECT_REPOS_PATH_REVISION", NULL} +#define STMT_198 \ "SELECT local_relpath, repos_path, revision FROM nodes " \ "WHERE wc_id = ?1 " \ " AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \ @@ -2161,17 +2168,17 @@ "ORDER BY local_relpath " \ "" -#define STMT_SELECT_HAS_NON_FILE_CHILDREN 198 -#define STMT_198_INFO {"STMT_SELECT_HAS_NON_FILE_CHILDREN", NULL} -#define STMT_198 \ +#define STMT_SELECT_HAS_NON_FILE_CHILDREN 199 +#define STMT_199_INFO {"STMT_SELECT_HAS_NON_FILE_CHILDREN", NULL} +#define STMT_199 \ "SELECT 1 FROM nodes " \ "WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = ?3 AND kind != 'file' " \ "LIMIT 1 " \ "" -#define STMT_SELECT_HAS_GRANDCHILDREN 199 -#define STMT_199_INFO {"STMT_SELECT_HAS_GRANDCHILDREN", NULL} -#define STMT_199 \ +#define STMT_SELECT_HAS_GRANDCHILDREN 200 +#define STMT_200_INFO {"STMT_SELECT_HAS_GRANDCHILDREN", NULL} +#define STMT_200 \ "SELECT 1 FROM nodes " \ "WHERE wc_id = ?1 " \ " AND (((parent_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((parent_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \ @@ -2180,20 +2187,11 @@ "LIMIT 1 " \ "" -#define STMT_SELECT_ALL_NODES 200 -#define STMT_200_INFO {"STMT_SELECT_ALL_NODES", NULL} -#define STMT_200 \ - "SELECT op_depth, local_relpath, parent_relpath, file_external FROM nodes " \ - "WHERE wc_id = ?1 " \ - "" - -#define STMT_SELECT_IPROPS 201 -#define STMT_201_INFO {"STMT_SELECT_IPROPS", NULL} +#define STMT_SELECT_ALL_NODES 201 +#define STMT_201_INFO {"STMT_SELECT_ALL_NODES", NULL} #define STMT_201 \ - "SELECT inherited_props FROM nodes " \ + "SELECT op_depth, local_relpath, parent_relpath, file_external FROM nodes " \ "WHERE wc_id = ?1 " \ - " AND local_relpath = ?2 " \ - " AND op_depth = 0 " \ "" #define STMT_UPDATE_IPROP 202 @@ -2303,14 +2301,6 @@ " locked_levels INTEGER NOT NULL DEFAULT -1, " \ " PRIMARY KEY (wc_id, local_dir_relpath) " \ " ); " \ - "PRAGMA user_version = " \ - APR_STRINGIFY(SVN_WC__VERSION) \ - "; " \ - "" - -#define STMT_CREATE_NODES 208 -#define STMT_208_INFO {"STMT_CREATE_NODES", NULL} -#define STMT_208 \ "CREATE TABLE NODES ( " \ " wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " \ " local_relpath TEXT NOT NULL, " \ @@ -2348,11 +2338,6 @@ "CREATE VIEW NODES_BASE AS " \ " SELECT * FROM nodes " \ " WHERE op_depth = 0; " \ - "" - -#define STMT_CREATE_NODES_TRIGGERS 209 -#define STMT_209_INFO {"STMT_CREATE_NODES_TRIGGERS", NULL} -#define STMT_209 \ "CREATE TRIGGER nodes_insert_trigger " \ "AFTER INSERT ON nodes " \ "WHEN NEW.checksum IS NOT NULL " \ @@ -2376,11 +2361,6 @@ " UPDATE pristine SET refcount = refcount - 1 " \ " WHERE checksum = OLD.checksum; " \ "END; " \ - "" - -#define STMT_CREATE_EXTERNALS 210 -#define STMT_210_INFO {"STMT_CREATE_EXTERNALS", NULL} -#define STMT_210 \ "CREATE TABLE EXTERNALS ( " \ " wc_id INTEGER NOT NULL REFERENCES WCROOT (id), " \ " local_relpath TEXT NOT NULL, " \ @@ -2397,11 +2377,14 @@ "CREATE UNIQUE INDEX I_EXTERNALS_DEFINED ON EXTERNALS (wc_id, " \ " def_local_relpath, " \ " local_relpath); " \ + "PRAGMA user_version = " \ + APR_STRINGIFY(SVN_WC__VERSION) \ + "; " \ "" -#define STMT_INSTALL_SCHEMA_STATISTICS 211 -#define STMT_211_INFO {"STMT_INSTALL_SCHEMA_STATISTICS", NULL} -#define STMT_211 \ +#define STMT_INSTALL_SCHEMA_STATISTICS 208 +#define STMT_208_INFO {"STMT_INSTALL_SCHEMA_STATISTICS", NULL} +#define STMT_208 \ "ANALYZE sqlite_master; " \ "DELETE FROM sqlite_stat1 " \ "WHERE tbl in ('NODES', 'ACTUAL_NODE', 'LOCK', 'WC_LOCK', 'EXTERNALS'); " \ @@ -2426,183 +2409,9 @@ "ANALYZE sqlite_master; " \ "" -#define STMT_UPGRADE_TO_20 212 -#define STMT_212_INFO {"STMT_UPGRADE_TO_20", NULL} -#define STMT_212 \ - "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); " \ - "UPDATE WORKING_NODE SET checksum = (SELECT checksum FROM pristine " \ - " WHERE md5_checksum = WORKING_NODE.checksum) " \ - "WHERE EXISTS (SELECT 1 FROM pristine " \ - " WHERE md5_checksum = WORKING_NODE.checksum); " \ - "INSERT INTO NODES ( " \ - " wc_id, local_relpath, op_depth, parent_relpath, " \ - " repos_id, repos_path, revision, " \ - " presence, depth, moved_here, moved_to, kind, " \ - " changed_revision, changed_date, changed_author, " \ - " checksum, properties, translated_size, last_mod_time, " \ - " dav_cache, symlink_target, file_external ) " \ - "SELECT wc_id, local_relpath, 0 , parent_relpath, " \ - " repos_id, repos_relpath, revnum, " \ - " presence, depth, NULL , NULL , kind, " \ - " changed_rev, changed_date, changed_author, " \ - " checksum, properties, translated_size, last_mod_time, " \ - " dav_cache, symlink_target, file_external " \ - "FROM BASE_NODE; " \ - "INSERT INTO NODES ( " \ - " wc_id, local_relpath, op_depth, parent_relpath, " \ - " repos_id, repos_path, revision, " \ - " presence, depth, moved_here, moved_to, kind, " \ - " changed_revision, changed_date, changed_author, " \ - " checksum, properties, translated_size, last_mod_time, " \ - " dav_cache, symlink_target, file_external ) " \ - "SELECT wc_id, local_relpath, 2 , parent_relpath, " \ - " copyfrom_repos_id, copyfrom_repos_path, copyfrom_revnum, " \ - " presence, depth, NULL , NULL , kind, " \ - " changed_rev, changed_date, changed_author, " \ - " checksum, properties, translated_size, last_mod_time, " \ - " NULL , symlink_target, NULL " \ - "FROM WORKING_NODE; " \ - "DROP TABLE BASE_NODE; " \ - "DROP TABLE WORKING_NODE; " \ - "PRAGMA user_version = 20; " \ - "" - -#define STMT_UPGRADE_TO_21 213 -#define STMT_213_INFO {"STMT_UPGRADE_TO_21", NULL} -#define STMT_213 \ - "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 \ - "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 \ - "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 \ - "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 \ - "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 \ - "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 \ - "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 \ - "DROP VIEW IF EXISTS NODES_CURRENT; " \ - "CREATE VIEW NODES_CURRENT AS " \ - " SELECT * FROM nodes " \ - " JOIN (SELECT wc_id, local_relpath, MAX(op_depth) AS op_depth FROM nodes " \ - " GROUP BY wc_id, local_relpath) AS filter " \ - " ON nodes.wc_id = filter.wc_id " \ - " AND nodes.local_relpath = filter.local_relpath " \ - " AND nodes.op_depth = filter.op_depth; " \ - "PRAGMA user_version = 25; " \ - "" - -#define STMT_UPGRADE_TO_26 221 -#define STMT_221_INFO {"STMT_UPGRADE_TO_26", NULL} -#define STMT_221 \ - "DROP VIEW IF EXISTS NODES_BASE; " \ - "CREATE VIEW NODES_BASE AS " \ - " SELECT * FROM nodes " \ - " WHERE op_depth = 0; " \ - "PRAGMA user_version = 26; " \ - "" - -#define STMT_UPGRADE_TO_27 222 -#define STMT_222_INFO {"STMT_UPGRADE_TO_27", NULL} -#define STMT_222 \ - "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 \ - "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) " \ - " AND (tree_conflict_data IS NULL)) " \ - "LIMIT 1 " \ - "" - -#define STMT_UPGRADE_TO_28 224 -#define STMT_224_INFO {"STMT_UPGRADE_TO_28", NULL} -#define STMT_224 \ - "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 \ - "DROP TRIGGER IF EXISTS nodes_update_checksum_trigger; " \ - "DROP TRIGGER IF EXISTS nodes_insert_trigger; " \ - "DROP TRIGGER IF EXISTS nodes_delete_trigger; " \ - "CREATE TRIGGER nodes_update_checksum_trigger " \ - "AFTER UPDATE OF checksum ON nodes " \ - "WHEN NEW.checksum IS NOT OLD.checksum " \ - "BEGIN " \ - " UPDATE pristine SET refcount = refcount + 1 " \ - " WHERE checksum = NEW.checksum; " \ - " UPDATE pristine SET refcount = refcount - 1 " \ - " WHERE checksum = OLD.checksum; " \ - "END; " \ - "CREATE TRIGGER nodes_insert_trigger " \ - "AFTER INSERT ON nodes " \ - "WHEN NEW.checksum IS NOT NULL " \ - "BEGIN " \ - " UPDATE pristine SET refcount = refcount + 1 " \ - " WHERE checksum = NEW.checksum; " \ - "END; " \ - "CREATE TRIGGER nodes_delete_trigger " \ - "AFTER DELETE ON nodes " \ - "WHEN OLD.checksum IS NOT NULL " \ - "BEGIN " \ - " UPDATE pristine SET refcount = refcount - 1 " \ - " WHERE checksum = OLD.checksum; " \ - "END; " \ - "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 209 +#define STMT_209_INFO {"STMT_UPGRADE_TO_30", NULL} +#define STMT_209 \ "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); " \ @@ -2610,9 +2419,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 210 +#define STMT_210_INFO {"STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE", NULL} +#define STMT_210 \ "SELECT wc_id, local_relpath, " \ " conflict_old, conflict_working, conflict_new, prop_reject, tree_conflict_data " \ "FROM actual_node " \ @@ -2624,24 +2433,19 @@ "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 211 +#define STMT_211_INFO {"STMT_UPGRADE_30_SET_CONFLICT", NULL} +#define STMT_211 \ "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 212 +#define STMT_212_INFO {"STMT_UPGRADE_TO_31", NULL} +#define STMT_212 \ "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 \ "DROP INDEX IF EXISTS I_ACTUAL_CHANGELIST; " \ "DROP INDEX IF EXISTS I_EXTERNALS_PARENT; " \ "DROP INDEX I_NODES_PARENT; " \ @@ -2653,9 +2457,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 213 +#define STMT_213_INFO {"STMT_UPGRADE_31_SELECT_WCROOT_NODES", NULL} +#define STMT_213 \ "SELECT l.wc_id, l.local_relpath FROM nodes as l " \ "LEFT OUTER JOIN nodes as r " \ "ON l.wc_id = r.wc_id " \ @@ -2667,21 +2471,6 @@ " 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 \ - "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); " \ - "DROP INDEX I_NODES_PARENT; " \ - "CREATE UNIQUE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath, " \ - " local_relpath, op_depth); " \ - "DROP INDEX I_ACTUAL_PARENT; " \ - "CREATE UNIQUE INDEX I_ACTUAL_PARENT ON ACTUAL_NODE (wc_id, parent_relpath, " \ - " local_relpath); " \ - "-- format: YYY " \ - "" - #define WC_QUERIES_SQL_99 \ "CREATE TABLE ACTUAL_NODE_BACKUP ( " \ " wc_id INTEGER NOT NULL, " \ @@ -2722,9 +2511,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 214 +#define STMT_214_INFO {"STMT_VERIFICATION_TRIGGERS", NULL} +#define STMT_214 \ "CREATE TEMPORARY TRIGGER no_repository_updates BEFORE UPDATE ON repository " \ "BEGIN " \ " SELECT RAISE(FAIL, 'Updates to REPOSITORY are not allowed.'); " \ @@ -2763,9 +2552,9 @@ "END; " \ "" -#define STMT_STATIC_VERIFY 234 -#define STMT_234_INFO {"STMT_STATIC_VERIFY", NULL} -#define STMT_234 \ +#define STMT_STATIC_VERIFY 215 +#define STMT_215_INFO {"STMT_STATIC_VERIFY", NULL} +#define STMT_215 \ "SELECT local_relpath, op_depth, 1, 'Invalid parent relpath set in NODES' " \ "FROM nodes n WHERE local_relpath != '' " \ " AND (parent_relpath IS NULL " \ @@ -3154,25 +2943,6 @@ STMT_213, \ STMT_214, \ STMT_215, \ - STMT_216, \ - STMT_217, \ - STMT_218, \ - STMT_219, \ - STMT_220, \ - STMT_221, \ - STMT_222, \ - STMT_223, \ - STMT_224, \ - STMT_225, \ - STMT_226, \ - STMT_227, \ - STMT_228, \ - STMT_229, \ - STMT_230, \ - STMT_231, \ - STMT_232, \ - STMT_233, \ - STMT_234, \ NULL \ } @@ -3394,24 +3164,5 @@ STMT_213_INFO, \ STMT_214_INFO, \ STMT_215_INFO, \ - STMT_216_INFO, \ - STMT_217_INFO, \ - STMT_218_INFO, \ - STMT_219_INFO, \ - STMT_220_INFO, \ - STMT_221_INFO, \ - STMT_222_INFO, \ - STMT_223_INFO, \ - STMT_224_INFO, \ - STMT_225_INFO, \ - STMT_226_INFO, \ - STMT_227_INFO, \ - STMT_228_INFO, \ - STMT_229_INFO, \ - STMT_230_INFO, \ - 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 3a8bf92a2776..86cf9216a058 100644 --- a/subversion/libsvn_wc/wc-queries.sql +++ b/subversion/libsvn_wc/wc-queries.sql @@ -46,7 +46,7 @@ SELECT op_depth, nodes.repos_id, nodes.repos_path, presence, kind, revision, lock_token, lock_owner, lock_comment, lock_date FROM nodes LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id - AND nodes.repos_path = lock.repos_relpath + AND nodes.repos_path = lock.repos_relpath AND nodes.op_depth=0 WHERE wc_id = ?1 AND local_relpath = ?2 ORDER BY op_depth DESC @@ -134,7 +134,7 @@ SELECT op_depth, nodes.repos_id, nodes.repos_path, presence, kind, revision, lock_comment, lock_date, local_relpath, moved_here, moved_to, file_external FROM nodes LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id - AND nodes.repos_path = lock.repos_relpath AND op_depth = 0 + AND nodes.repos_path = lock.repos_relpath AND nodes.op_depth = 0 WHERE wc_id = ?1 AND parent_relpath = ?2 ORDER BY local_relpath DESC, op_depth DESC @@ -148,7 +148,7 @@ SELECT op_depth, nodes.repos_id, nodes.repos_path, presence, kind, revision, lock_comment, lock_date, local_relpath, moved_here, moved_to, file_external FROM nodes LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id - AND nodes.repos_path = lock.repos_relpath AND op_depth = 0 + AND nodes.repos_path = lock.repos_relpath WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0 ORDER BY local_relpath DESC @@ -1291,6 +1291,10 @@ PRAGMA locking_mode = exclusive; exclusive-locking is mostly used on remote file systems. */ PRAGMA journal_mode = DELETE +-- STMT_FIND_REPOS_PATH_IN_WC +SELECT local_relpath FROM nodes_current + WHERE wc_id = ?1 AND repos_path = ?2 + /* ------------------------------------------------------------------------- */ /* these are used in entries.c */ @@ -1747,13 +1751,6 @@ WHERE wc_id = ?1 /* Queries for cached inherited properties. */ -/* Select the inherited properties of a single base node. */ --- STMT_SELECT_IPROPS -SELECT inherited_props FROM nodes -WHERE wc_id = ?1 - AND local_relpath = ?2 - AND op_depth = 0 - /* Update the inherited properties of a single base node. */ -- STMT_UPDATE_IPROP UPDATE nodes diff --git a/subversion/libsvn_wc/wc.h b/subversion/libsvn_wc/wc.h index ab6870d1a74f..f8bbebd93ade 100644 --- a/subversion/libsvn_wc/wc.h +++ b/subversion/libsvn_wc/wc.h @@ -158,6 +158,8 @@ extern "C" { * Bumped in r1395109. * * == 1.8.x shipped with format 31 + * == 1.9.x shipped with format 31 + * == 1.10.x shipped with format 31 * * Please document any further format changes here. */ @@ -479,7 +481,7 @@ svn_wc__conflicted_for_update_p(svn_boolean_t *conflicted_p, /* Internal version of svn_wc_transmit_text_deltas3(). */ svn_error_t * -svn_wc__internal_transmit_text_deltas(const char **tempfile, +svn_wc__internal_transmit_text_deltas(svn_stream_t *tempstream, const svn_checksum_t **new_text_base_md5_checksum, const svn_checksum_t **new_text_base_sha1_checksum, svn_wc__db_t *db, diff --git a/subversion/libsvn_wc/wc_db.c b/subversion/libsvn_wc/wc_db.c index ee17b85e3a58..bc87b2f9d8d9 100644 --- a/subversion/libsvn_wc/wc_db.c +++ b/subversion/libsvn_wc/wc_db.c @@ -1371,9 +1371,6 @@ init_db(/* output values */ /* Create the database's schema. */ SVN_ERR(svn_sqlite__exec_statements(db, STMT_CREATE_SCHEMA)); - SVN_ERR(svn_sqlite__exec_statements(db, STMT_CREATE_NODES)); - SVN_ERR(svn_sqlite__exec_statements(db, STMT_CREATE_NODES_TRIGGERS)); - SVN_ERR(svn_sqlite__exec_statements(db, STMT_CREATE_EXTERNALS)); SVN_ERR(svn_wc__db_install_schema_statistics(db, scratch_pool)); @@ -6698,8 +6695,14 @@ svn_wc__db_op_mark_resolved_internal(svn_wc__db_wcroot_t *wcroot, conflict_data = svn_sqlite__column_blob(stmt, 2, &conflict_len, scratch_pool); - conflicts = svn_skel__parse(conflict_data, conflict_len, scratch_pool); SVN_ERR(svn_sqlite__reset(stmt)); + SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool)); + + if (!conflict_data) + return SVN_NO_ERROR; + + conflicts = svn_skel__parse(conflict_data, conflict_len, scratch_pool); + SVN_ERR(svn_wc__conflict_skel_resolve(&resolved_all, conflicts, db, wcroot->abspath, @@ -6731,8 +6734,6 @@ svn_wc__db_op_mark_resolved_internal(svn_wc__db_wcroot_t *wcroot, SVN_ERR(svn_sqlite__step_done(stmt)); } - SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool)); - return SVN_NO_ERROR; } @@ -10164,7 +10165,7 @@ db_read_repos_info(svn_revnum_t *revision, local_relpath), result_pool); } - else + else if (base_del_relpath) { SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, revision, repos_relpath, @@ -10184,6 +10185,8 @@ db_read_repos_info(svn_revnum_t *revision, local_relpath), result_pool); } + else + SVN_ERR_MALFUNCTION(); } else if (status == svn_wc__db_status_excluded) { @@ -10614,68 +10617,6 @@ svn_wc__db_prop_retrieve_recursive(apr_hash_t **values, return svn_error_trace(svn_sqlite__reset(stmt)); } -/* The body of svn_wc__db_read_cached_iprops(). */ -static svn_error_t * -db_read_cached_iprops(apr_array_header_t **iprops, - 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; - - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_IPROPS)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - - 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)); - } - - SVN_ERR(svn_sqlite__column_iprops(iprops, stmt, 0, - result_pool, scratch_pool)); - - SVN_ERR(svn_sqlite__reset(stmt)); - - return SVN_NO_ERROR; -} - -svn_error_t * -svn_wc__db_read_cached_iprops(apr_array_header_t **iprops, - svn_wc__db_t *db, - const char *local_abspath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - svn_wc__db_wcroot_t *wcroot; - const char *local_relpath; - - SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); - - SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, - db, local_abspath, - scratch_pool, scratch_pool)); - VERIFY_USABLE_WCROOT(wcroot); - - /* Don't use with_txn yet, as we perform just a single transaction */ - SVN_ERR(db_read_cached_iprops(iprops, wcroot, local_relpath, - result_pool, scratch_pool)); - - if (!*iprops) - { - *iprops = apr_array_make(result_pool, 0, - sizeof(svn_prop_inherited_item_t *)); - } - - return SVN_NO_ERROR; -} - /* Remove all prop name value pairs from PROP_HASH where the property name is not PROPNAME. */ static void @@ -11398,7 +11339,9 @@ relocate_txn(svn_wc__db_wcroot_t *wcroot, SVN_ERR(svn_wc__db_fetch_repos_info(NULL, &repos_uuid, wcroot, old_repos_id, scratch_pool)); - SVN_ERR_ASSERT(repos_uuid); /* This function affects all the children of the given local_relpath, + SVN_ERR_ASSERT(repos_uuid); + + /* This function affects all the children of the given local_relpath, but the way that it does this is through the repos inheritance mechanism. So, we only need to rewrite the repos_id of the given local_relpath, as well as any children with a non-null repos_id, as well as various @@ -11425,6 +11368,11 @@ relocate_txn(svn_wc__db_wcroot_t *wcroot, SVN_ERR(svn_sqlite__step_done(stmt)); } + /* ### TODO: Update urls stored in inherited properties... + What about urls in conflicts? + # We can probably keep these as they are only used + for showing full urls to the user */ + return SVN_NO_ERROR; } @@ -16628,3 +16576,47 @@ svn_wc__db_process_commit_queue(svn_wc__db_t *db, return SVN_NO_ERROR; } + +svn_error_t * +svn_wc__find_repos_node_in_wc(apr_array_header_t **local_abspath_list, + svn_wc__db_t *db, + const char *wri_abspath, + const char *repos_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *wri_relpath; + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row; + + SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &wri_relpath, db, + wri_abspath, scratch_pool, + scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_FIND_REPOS_PATH_IN_WC)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, repos_relpath)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + + *local_abspath_list = apr_array_make(result_pool, have_row ? 1 : 0, + sizeof(const char*)); + while (have_row) + { + const char *local_relpath; + const char *local_abspath; + + local_relpath = svn_sqlite__column_text(stmt, 0, NULL); + local_abspath = svn_dirent_join(wcroot->abspath, local_relpath, + result_pool); + APR_ARRAY_PUSH(*local_abspath_list, const char *) = local_abspath; + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + + return svn_error_trace(svn_sqlite__reset(stmt)); +} + diff --git a/subversion/libsvn_wc/wc_db.h b/subversion/libsvn_wc/wc_db.h index a947be04ee76..0bf6432100fb 100644 --- a/subversion/libsvn_wc/wc_db.h +++ b/subversion/libsvn_wc/wc_db.h @@ -1644,7 +1644,12 @@ svn_wc__db_op_mark_conflict(svn_wc__db_t *db, apr_pool_t *scratch_pool); -/* ### caller maintains ACTUAL, and how the resolution occurred. we're just +/* Clear all or some of the conflicts stored on LOCAL_ABSPATH, if any. + + Any work items that are necessary as part of resolving this node + can be passed in WORK_ITEMS. + +### caller maintains ACTUAL, and how the resolution occurred. we're just ### recording state. ### ### I'm not sure that these three values are the best way to do this, @@ -3043,7 +3048,7 @@ svn_wc__db_wclock_obtain(svn_wc__db_t *db, svn_boolean_t steal_lock, apr_pool_t *scratch_pool); -/* Set LOCK_ABSPATH to the path of the the directory that owns the +/* Set LOCK_ABSPATH to the path of the directory that owns the lock on LOCAL_ABSPATH, or NULL, if LOCAL_ABSPATH is not locked. */ svn_error_t* svn_wc__db_wclock_find_root(const char **lock_abspath, @@ -3399,6 +3404,33 @@ svn_wc__db_update_moved_away_conflict_victim(svn_wc__db_t *db, void *notify_baton, apr_pool_t *scratch_pool); +/* Merge local changes from tree conflict victim at LOCAL_ABSPATH into the + directory at DEST_ABSPATH. This function requires that LOCAL_ABSPATH is + a directory and a tree-conflict victim. DST_ABSPATH must be a directory. */ +svn_error_t * +svn_wc__db_update_incoming_move(svn_wc__db_t *db, + const char *local_abspath, + const char *dest_abspath, + svn_wc_operation_t operation, + svn_wc_conflict_action_t action, + svn_wc_conflict_reason_t reason, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool); + +/* Merge locally added dir tree conflict victim at LOCAL_ABSPATH with the + * directory since added to the BASE layer by an update operation. */ +svn_error_t * +svn_wc__db_update_local_add(svn_wc__db_t *db, + const char *local_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool); + /* LOCAL_ABSPATH is moved to MOVE_DST_ABSPATH. MOVE_SRC_ROOT_ABSPATH * is the root of the move to MOVE_DST_OP_ROOT_ABSPATH. * DELETE_ABSPATH is the op-root of the move; it's the same @@ -3433,7 +3465,7 @@ svn_wc__db_op_raise_moved_away(svn_wc__db_t *db, apr_pool_t *scratch_pool); /* Breaks all moves of nodes that exist at or below LOCAL_ABSPATH as - shadowed (read: deleted) by the opration rooted at + shadowed (read: deleted) by the operation rooted at delete_op_root_abspath. */ svn_error_t * @@ -3454,6 +3486,22 @@ svn_wc__required_lock_for_resolve(const char **required_abspath, const char *local_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool); + +/* Return an array of const char * elements, which represent local absolute + * paths for nodes, within the working copy indicated by WRI_ABSPATH, which + * correspond to REPOS_RELPATH. If no such nodes exist, return an empty array. + * + * Note that this function returns each and every such node that is known + * in the WC, including, for example, nodes that were children of a directory + * which has been replaced. + */ +svn_error_t * +svn_wc__find_repos_node_in_wc(apr_array_header_t **local_abspath_list, + svn_wc__db_t *db, + const char *wri_abspath, + const char *repos_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* @} */ typedef svn_error_t * (*svn_wc__db_verify_cb_t)(void *baton, diff --git a/subversion/libsvn_wc/wc_db_pristine.c b/subversion/libsvn_wc/wc_db_pristine.c index 9118d7068810..90b35774df48 100644 --- a/subversion/libsvn_wc/wc_db_pristine.c +++ b/subversion/libsvn_wc/wc_db_pristine.c @@ -227,7 +227,6 @@ svn_wc__db_pristine_read(svn_stream_t **contents, const char *local_relpath; const char *pristine_abspath; - SVN_ERR_ASSERT(contents != NULL); SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); /* Some 1.6-to-1.7 wc upgrades created rows without checksums and @@ -317,9 +316,10 @@ pristine_install_txn(svn_sqlite__db_t *sdb, { return svn_error_createf( SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL, - _("New pristine text '%s' has different size: %ld versus %ld"), + _("New pristine text '%s' has different size: %s versus %s"), svn_checksum_to_cstring_display(sha1_checksum, scratch_pool), - (long int)finfo1.size, (long int)finfo2.size); + apr_off_t_toa(scratch_pool, finfo1.size), + apr_off_t_toa(scratch_pool, finfo2.size)); } } #endif @@ -333,13 +333,12 @@ pristine_install_txn(svn_sqlite__db_t *sdb, * an orphan file and it doesn't matter if we overwrite it.) */ { apr_finfo_t finfo; - SVN_ERR(svn_stream__install_get_info(&finfo, install_stream, APR_FINFO_SIZE, - scratch_pool)); + SVN_ERR(svn_stream__install_get_info(&finfo, install_stream, + APR_FINFO_SIZE, scratch_pool)); SVN_ERR(svn_stream__install_stream(install_stream, pristine_abspath, - TRUE, scratch_pool)); + TRUE, scratch_pool)); - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_INSERT_PRISTINE)); + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_PRISTINE)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool)); SVN_ERR(svn_sqlite__bind_int64(stmt, 3, finfo.size)); @@ -569,7 +568,8 @@ maybe_transfer_one_pristine(svn_wc__db_wcroot_t *src_wcroot, /* Move the file to its target location. (If it is already there, it is * an orphan file and it doesn't matter if we overwrite it.) */ - err = svn_io_file_rename(tmp_abspath, pristine_abspath, scratch_pool); + err = svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE, + scratch_pool); /* Maybe the directory doesn't exist yet? */ if (err && APR_STATUS_IS_ENOENT(err->apr_err)) @@ -587,7 +587,8 @@ maybe_transfer_one_pristine(svn_wc__db_wcroot_t *src_wcroot, /* We could create a directory: retry install */ svn_error_clear(err); - SVN_ERR(svn_io_file_rename(tmp_abspath, pristine_abspath, scratch_pool)); + SVN_ERR(svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE, + scratch_pool)); } else SVN_ERR(err); @@ -686,42 +687,6 @@ svn_wc__db_pristine_transfer(svn_wc__db_t *db, -/* Remove the file at FILE_ABSPATH in such a way that we could re-create a - * new file of the same name at any time thereafter. - * - * On Windows, the file will not disappear immediately from the directory if - * it is still being read so the best thing to do is first rename it to a - * unique name. */ -static svn_error_t * -remove_file(const char *file_abspath, - svn_wc__db_wcroot_t *wcroot, - svn_boolean_t ignore_enoent, - apr_pool_t *scratch_pool) -{ -#ifdef WIN32 - svn_error_t *err; - const char *temp_abspath; - const char *temp_dir_abspath - = pristine_get_tempdir(wcroot, scratch_pool, scratch_pool); - - /* To rename the file to a unique name in the temp dir, first create a - * uniquely named file in the temp dir and then overwrite it. */ - SVN_ERR(svn_io_open_unique_file3(NULL, &temp_abspath, temp_dir_abspath, - svn_io_file_del_none, - scratch_pool, scratch_pool)); - err = svn_io_file_rename(file_abspath, temp_abspath, scratch_pool); - if (err && ignore_enoent && APR_STATUS_IS_ENOENT(err->apr_err)) - svn_error_clear(err); - else - SVN_ERR(err); - file_abspath = temp_abspath; -#endif - - SVN_ERR(svn_io_remove_file2(file_abspath, ignore_enoent, scratch_pool)); - - return SVN_NO_ERROR; -} - /* If the pristine text referenced by SHA1_CHECKSUM in WCROOT/SDB, whose path * within the pristine store is PRISTINE_ABSPATH, has a reference count of * zero, delete it (both the database row and the disk file). @@ -757,8 +722,8 @@ pristine_remove_if_unreferenced_txn(svn_sqlite__db_t *sdb, svn_boolean_t ignore_enoent = TRUE; #endif - SVN_ERR(remove_file(pristine_abspath, wcroot, ignore_enoent, - scratch_pool)); + SVN_ERR(svn_io_remove_file2(pristine_abspath, ignore_enoent, + scratch_pool)); } return SVN_NO_ERROR; @@ -949,11 +914,28 @@ svn_wc__db_pristine_check(svn_boolean_t *present, { const char *pristine_abspath; svn_node_kind_t kind_on_disk; + svn_error_t *err; SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath, sha1_checksum, scratch_pool, scratch_pool)); - SVN_ERR(svn_io_check_path(pristine_abspath, &kind_on_disk, scratch_pool)); - if (kind_on_disk != svn_node_file) + err = svn_io_check_path(pristine_abspath, &kind_on_disk, scratch_pool); +#ifdef WIN32 + if (err && err->apr_err == APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED)) + { + svn_error_clear(err); + /* Possible race condition: The filename is locked, but there is no + file or dir with this name. Let's fall back on checking the DB. + + This case is triggered by the pristine store tests on deleting + a file that is still open via another handle, where this other + handle has a FILE_SHARE_DELETE share mode. + */ + } + else +#endif + if (err) + return svn_error_trace(err); + else if (kind_on_disk != svn_node_file) { *present = FALSE; return SVN_NO_ERROR; diff --git a/subversion/libsvn_wc/wc_db_update_move.c b/subversion/libsvn_wc/wc_db_update_move.c index 46cbeae361c8..ba7117581ec1 100644 --- a/subversion/libsvn_wc/wc_db_update_move.c +++ b/subversion/libsvn_wc/wc_db_update_move.c @@ -21,13 +21,16 @@ * ==================================================================== */ -/* This file implements an editor and an edit driver which are used - * to resolve an "incoming edit, local move-away" tree conflict resulting - * from an update (or switch). +/* This implements editors and edit drivers which are used to resolve + * "incoming edit, local move-away", "incoming move, local edit", and + * "incoming add, local add" tree conflicts resulting from an update + * (or switch). * - * Our goal is to be able to resolve this conflict such that the end - * result is just the same as if the user had run the update *before* - * the local move. + * Our goal is to be able to resolve conflicts such that the end result + * is just the same as if the user had run the update *before* the local + * (or incoming) move or local add. + * + * -- Updating local moves -- * * When an update (or switch) produces incoming changes for a locally * moved-away subtree, it updates the base nodes of the moved-away tree @@ -72,6 +75,58 @@ * representing a replacement, but this editor only reads from the * single-op-depth layer of it, and makes no changes of any kind * within the source tree. + * + * -- Updating incoming moves -- + * + * When an update (or switch) produces an incoming move, it deletes the + * moved node at the old location from the BASE tree and adds a node at + * the new location to the BASE tree. If the old location contains local + * changes, a tree conflict is raised, and the former BASE tree which + * the local changes were based on (the tree conflict victim) is re-added + * as a copy which contains these local changes. + * + * The driver sees two NODES trees: The op-root of the copy, and the + * WORKING layer on top of this copy which represents the local changes. + * The driver will compare the two NODES trees and drive an editor to + * change the move destination's WORKING tree so that it now contains + * the local changes seen in the copy of the victim's tree. + * + * We require that no local changes exist at the destination, in order + * to avoid tree conflicts where the "incoming" and "local" change both + * originated in the working copy, because the resolver code cannot handle + * such tree conflicts at present. + * + * The whole drive occurs as one single wc.db transaction. At the end + * of the transaction the destination NODES table should have a WORKING + * layer that is equivalent to the WORKING layer found in the copied victim + * tree, and there should be workqueue items to make any required changes + * to working files/directories in the move destination, and there should be + * tree-conflicts in the move destination where it was not possible to + * update the working files/directories. + * + * -- Updating local adds -- + * + * When an update (or switch) adds a directory tree it creates corresponding + * nodes in the BASE tree. Any existing locally added nodes are bumped to a + * higher layer with the top-most locally added directory as op-root. + * In-between, the update inserts a base-deleted layer, i.e. it schedules the + * directory in the BASE tree for removal upon the next commit, to be replaced + * by the locally added directory. + * + * The driver sees two NODES trees: The BASE layer, and the WORKING layer + * which represents the locally added tree. + * The driver will compare the two NODES trees and drive an editor to + * merge WORKING tree nodes with the nodes in the BASE tree. + * + * The whole drive occurs as one single wc.db transaction. + * Directories which exist in both trees become part of the BASE tree, with + * properties merged. + * Files which exist in both trees are merged (there is no common ancestor, + * so the common ancestor in this merge is the empty file). + * Files and directories which exist only in the WORKING layer become + * local-add op-roots of their own. + * Mismatching node kinds produce new 'incoming add vs local add upon update' + * tree conflicts which must be resolved individually later on. */ #define SVN_WC__I_AM_WC_DB @@ -357,7 +412,7 @@ create_tree_conflict(svn_skel_t **conflict_p, move_src_op_root_relpath, scratch_pool) : NULL; const char *old_repos_relpath_part - = old_repos_relpath + = old_repos_relpath && old_version ? svn_relpath_skip_ancestor(old_version->path_in_repos, old_repos_relpath) : NULL; @@ -400,7 +455,7 @@ create_tree_conflict(svn_skel_t **conflict_p, if (conflict_operation != svn_wc_operation_update && conflict_operation != svn_wc_operation_switch) - return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + return svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL, _("'%s' already in conflict"), path_for_error_message(wcroot, local_relpath, scratch_pool)); @@ -424,7 +479,7 @@ create_tree_conflict(svn_skel_t **conflict_p, && strcmp(move_src_op_root_relpath, svn_dirent_skip_ancestor(wcroot->abspath, existing_abspath)))) - return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, + return svn_error_createf(SVN_ERR_WC_FOUND_CONFLICT, NULL, _("'%s' already in conflict"), path_for_error_message(wcroot, local_relpath, @@ -448,10 +503,14 @@ create_tree_conflict(svn_skel_t **conflict_p, result_pool, scratch_pool)); - conflict_old_version = svn_wc_conflict_version_create2( - old_version->repos_url, old_version->repos_uuid, - old_repos_relpath, old_version->peg_rev, - old_kind, scratch_pool); + if (old_version) + conflict_old_version = svn_wc_conflict_version_create2( + old_version->repos_url, + old_version->repos_uuid, + old_repos_relpath, old_version->peg_rev, + old_kind, scratch_pool); + else + conflict_old_version = NULL; conflict_new_version = svn_wc_conflict_version_create2( new_version->repos_url, new_version->repos_uuid, @@ -491,7 +550,7 @@ create_node_tree_conflict(svn_skel_t **conflict_p, update_move_baton_t *umb = nmb->umb; const char *dst_repos_relpath; const char *dst_root_relpath = svn_relpath_prefix(nmb->dst_relpath, - nmb->umb->dst_op_depth, + umb->dst_op_depth, scratch_pool); dst_repos_relpath = @@ -500,8 +559,6 @@ create_node_tree_conflict(svn_skel_t **conflict_p, nmb->dst_relpath), scratch_pool); - - return svn_error_trace( create_tree_conflict(conflict_p, umb->wcroot, dst_local_relpath, svn_relpath_prefix(dst_local_relpath, @@ -737,6 +794,111 @@ tc_editor_add_directory(node_move_baton_t *nmb, } static svn_error_t * +copy_working_node(const char *src_relpath, + const char *dst_relpath, + svn_wc__db_wcroot_t *wcroot, + apr_pool_t *scratch_pool) +{ + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row; + const char *dst_parent_relpath = svn_relpath_dirname(dst_relpath, + scratch_pool); + + /* Add a WORKING row for the new node, based on the source. */ + SVN_ERR(svn_sqlite__get_statement(&stmt,wcroot->sdb, + STMT_INSERT_WORKING_NODE_COPY_FROM)); + SVN_ERR(svn_sqlite__bindf(stmt, "issdst", wcroot->wc_id, src_relpath, + dst_relpath, relpath_depth(dst_relpath), + dst_parent_relpath, presence_map, + svn_wc__db_status_normal)); + SVN_ERR(svn_sqlite__step_done(stmt)); + + /* Copy properties over. ### This loses changelist association. */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_ACTUAL_NODE)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, src_relpath)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + if (have_row) + { + apr_size_t props_size; + const char *properties; + + properties = svn_sqlite__column_blob(stmt, 1, &props_size, + scratch_pool); + SVN_ERR(svn_sqlite__reset(stmt)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_INSERT_ACTUAL_NODE)); + SVN_ERR(svn_sqlite__bindf(stmt, "issbs", + wcroot->wc_id, dst_relpath, + svn_relpath_dirname(dst_relpath, + scratch_pool), + properties, props_size, NULL)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + SVN_ERR(svn_sqlite__reset(stmt)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +tc_editor_incoming_add_directory(node_move_baton_t *nmb, + const char *dst_relpath, + svn_node_kind_t old_kind, + apr_hash_t *props, + const char *src_relpath, + apr_pool_t *scratch_pool) +{ + update_move_baton_t *b = nmb->umb; + const char *dst_abspath; + svn_node_kind_t wc_kind; + svn_skel_t *work_item = NULL; + svn_skel_t *conflict = NULL; + svn_wc_conflict_reason_t reason = svn_wc_conflict_reason_unversioned; + + SVN_ERR(mark_parent_edited(nmb, scratch_pool)); + if (nmb->skip) + return SVN_NO_ERROR; + + dst_abspath = svn_dirent_join(b->wcroot->abspath, dst_relpath, scratch_pool); + + /* Check for unversioned tree-conflict */ + SVN_ERR(svn_io_check_path(dst_abspath, &wc_kind, scratch_pool)); + + if (wc_kind == old_kind) + wc_kind = svn_node_none; /* Node will be gone once we install */ + + if (wc_kind != svn_node_none && wc_kind != old_kind) /* replace */ + { + SVN_ERR(create_node_tree_conflict(&conflict, nmb, dst_relpath, + old_kind, svn_node_dir, + reason, + (old_kind == svn_node_none) + ? svn_wc_conflict_action_add + : svn_wc_conflict_action_replace, + NULL, + scratch_pool, scratch_pool)); + nmb->skip = TRUE; + } + else + { + SVN_ERR(copy_working_node(src_relpath, dst_relpath, b->wcroot, + scratch_pool)); + SVN_ERR(svn_wc__wq_build_dir_install(&work_item, b->db, dst_abspath, + scratch_pool, scratch_pool)); + } + + SVN_ERR(update_move_list_add(b->wcroot, dst_relpath, b->db, + (old_kind == svn_node_none) + ? svn_wc_notify_update_add + : svn_wc_notify_update_replace, + svn_node_dir, + svn_wc_notify_state_inapplicable, + svn_wc_notify_state_inapplicable, + conflict, work_item, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * tc_editor_add_file(node_move_baton_t *nmb, const char *relpath, svn_node_kind_t old_kind, @@ -824,6 +986,85 @@ tc_editor_add_file(node_move_baton_t *nmb, return SVN_NO_ERROR; } +static svn_error_t * +tc_editor_incoming_add_file(node_move_baton_t *nmb, + const char *dst_relpath, + svn_node_kind_t old_kind, + const svn_checksum_t *checksum, + apr_hash_t *props, + const char *src_relpath, + const char *content_abspath, + apr_pool_t *scratch_pool) +{ + update_move_baton_t *b = nmb->umb; + svn_wc_conflict_reason_t reason = svn_wc_conflict_reason_unversioned; + svn_node_kind_t wc_kind; + const char *dst_abspath; + svn_skel_t *work_items = NULL; + svn_skel_t *work_item = NULL; + svn_skel_t *conflict = NULL; + + SVN_ERR(mark_parent_edited(nmb, scratch_pool)); + if (nmb->skip) + { + SVN_ERR(svn_io_remove_file2(content_abspath, TRUE, scratch_pool)); + return SVN_NO_ERROR; + } + + dst_abspath = svn_dirent_join(b->wcroot->abspath, dst_relpath, scratch_pool); + + /* Check for unversioned tree-conflict */ + SVN_ERR(svn_io_check_path(dst_abspath, &wc_kind, scratch_pool)); + + if (wc_kind != svn_node_none && wc_kind != old_kind) /* replace */ + { + SVN_ERR(create_node_tree_conflict(&conflict, nmb, dst_relpath, + old_kind, svn_node_file, + reason, + (old_kind == svn_node_none) + ? svn_wc_conflict_action_add + : svn_wc_conflict_action_replace, + NULL, + scratch_pool, scratch_pool)); + nmb->skip = TRUE; + SVN_ERR(svn_io_remove_file2(content_abspath, TRUE, scratch_pool)); + } + else + { + const char *src_abspath; + + SVN_ERR(copy_working_node(src_relpath, dst_relpath, b->wcroot, + scratch_pool)); + + /* Update working file. */ + src_abspath = svn_dirent_join(b->wcroot->abspath, src_relpath, + scratch_pool); + SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db, dst_abspath, + src_abspath, + FALSE /* FIXME: use_commit_times?*/, + TRUE /* record_file_info */, + scratch_pool, scratch_pool)); + work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); + + /* Queue removal of temporary content copy. */ + SVN_ERR(svn_wc__wq_build_file_remove(&work_item, b->db, + b->wcroot->abspath, src_abspath, + scratch_pool, scratch_pool)); + + work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); + } + + SVN_ERR(update_move_list_add(b->wcroot, dst_relpath, b->db, + (old_kind == svn_node_none) + ? svn_wc_notify_update_add + : svn_wc_notify_update_replace, + svn_node_file, + svn_wc_notify_state_inapplicable, + svn_wc_notify_state_inapplicable, + conflict, work_items, scratch_pool)); + return SVN_NO_ERROR; +} + /* All the info we need about one version of a working node. */ typedef struct working_node_version_t { @@ -860,6 +1101,11 @@ create_conflict_markers(svn_skel_t **work_items, part = svn_relpath_skip_ancestor(original_version->path_in_repos, repos_relpath); + if (part == NULL) + part = svn_relpath_skip_ancestor(conflicted_version->path_in_repos, + repos_relpath); + SVN_ERR_ASSERT(part != NULL); + conflicted_version->path_in_repos = svn_relpath_join(conflicted_version->path_in_repos, part, scratch_pool); original_version->path_in_repos = repos_relpath; @@ -873,6 +1119,13 @@ create_conflict_markers(svn_skel_t **work_items, conflicted_version, scratch_pool, scratch_pool)); } + else if (operation == svn_wc_operation_merge) + { + SVN_ERR(svn_wc__conflict_skel_set_op_merge( + conflict_skel, original_version, + conflicted_version, + scratch_pool, scratch_pool)); + } else { SVN_ERR(svn_wc__conflict_skel_set_op_switch( @@ -1197,6 +1450,217 @@ tc_editor_alter_file(node_move_baton_t *nmb, } static svn_error_t * +tc_editor_update_incoming_moved_file(node_move_baton_t *nmb, + const char *dst_relpath, + const char *src_relpath, + const svn_checksum_t *src_checksum, + const svn_checksum_t *dst_checksum, + apr_hash_t *dst_props, + apr_hash_t *src_props, + svn_boolean_t do_text_merge, + apr_pool_t *scratch_pool) +{ + update_move_baton_t *b = nmb->umb; + working_node_version_t old_version, new_version; + const char *dst_abspath = svn_dirent_join(b->wcroot->abspath, + dst_relpath, + scratch_pool); + svn_skel_t *conflict_skel = NULL; + enum svn_wc_merge_outcome_t merge_outcome; + svn_wc_notify_state_t prop_state = svn_wc_notify_state_unchanged; + svn_wc_notify_state_t content_state = svn_wc_notify_state_unchanged; + svn_skel_t *work_item, *work_items = NULL; + svn_node_kind_t dst_kind_on_disk; + const char *dst_repos_relpath; + svn_boolean_t tree_conflict = FALSE; + svn_node_kind_t dst_db_kind; + svn_error_t *err; + + SVN_ERR(mark_node_edited(nmb, scratch_pool)); + if (nmb->skip) + return SVN_NO_ERROR; + + err = svn_wc__db_base_get_info_internal(NULL, &dst_db_kind, NULL, + &dst_repos_relpath, + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + b->wcroot, dst_relpath, + scratch_pool, scratch_pool); + if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) + { + const char *dst_parent_relpath; + const char *dst_parent_repos_relpath; + const char *src_abspath; + + /* If the file cannot be found, it was either deleted at the + * move destination, or it was moved after its parent was moved. + * We cannot deal with this problem right now. Instead, we will + * raise a new tree conflict at the location where this file should + * have been, and let another run of the resolver deal with the + * new conflict later on. */ + + svn_error_clear(err); + + /* Create a WORKING node for this file at the move destination. */ + SVN_ERR(copy_working_node(src_relpath, dst_relpath, b->wcroot, + scratch_pool)); + + /* Raise a tree conflict at the new WORKING node. */ + dst_db_kind = svn_node_none; + SVN_ERR(create_node_tree_conflict(&conflict_skel, nmb, dst_relpath, + svn_node_file, dst_db_kind, + svn_wc_conflict_reason_edited, + svn_wc_conflict_action_delete, + NULL, scratch_pool, scratch_pool)); + dst_parent_relpath = svn_relpath_dirname(dst_relpath, scratch_pool); + SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, NULL, + &dst_parent_repos_relpath, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, b->wcroot, + dst_parent_relpath, + scratch_pool, scratch_pool)); + dst_repos_relpath = svn_relpath_join(dst_parent_repos_relpath, + svn_relpath_basename(dst_relpath, + scratch_pool), + scratch_pool); + tree_conflict = TRUE; + + /* Schedule a copy of the victim's file content to the new node's path. */ + src_abspath = svn_dirent_join(b->wcroot->abspath, src_relpath, + scratch_pool); + SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db, + dst_abspath, + src_abspath, + FALSE /*FIXME: use_commit_times?*/, + TRUE /* record_file_info */, + scratch_pool, scratch_pool)); + work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); + } + else + SVN_ERR(err); + + if ((dst_db_kind == svn_node_none || dst_db_kind != svn_node_file) && + conflict_skel == NULL) + { + SVN_ERR(create_node_tree_conflict(&conflict_skel, nmb, dst_relpath, + svn_node_file, dst_db_kind, + dst_db_kind == svn_node_none + ? svn_wc_conflict_reason_missing + : svn_wc_conflict_reason_obstructed, + svn_wc_conflict_action_edit, + NULL, + scratch_pool, scratch_pool)); + tree_conflict = TRUE; + } + + SVN_ERR(svn_io_check_path(dst_abspath, &dst_kind_on_disk, scratch_pool)); + if ((dst_kind_on_disk == svn_node_none || dst_kind_on_disk != svn_node_file) + && conflict_skel == NULL) + { + SVN_ERR(create_node_tree_conflict(&conflict_skel, nmb, dst_relpath, + svn_node_file, dst_kind_on_disk, + dst_kind_on_disk == svn_node_none + ? svn_wc_conflict_reason_missing + : svn_wc_conflict_reason_obstructed, + svn_wc_conflict_action_edit, + NULL, + scratch_pool, scratch_pool)); + tree_conflict = TRUE; + } + + old_version.location_and_kind = b->old_version; + new_version.location_and_kind = b->new_version; + + old_version.checksum = src_checksum; + old_version.props = src_props; + new_version.checksum = dst_checksum; + new_version.props = dst_props; + + /* Merge properties and text content if there is no tree conflict. */ + if (conflict_skel == NULL) + { + apr_hash_t *actual_props; + apr_array_header_t *propchanges; + + SVN_ERR(update_working_props(&prop_state, &conflict_skel, &propchanges, + &actual_props, b, dst_relpath, + &old_version, &new_version, + scratch_pool, scratch_pool)); + if (do_text_merge) + { + const char *old_pristine_abspath; + const char *src_abspath; + const char *label_left; + const char *label_target; + + /* + * Run a 3-way merge to update the file at its post-move location, + * using the pre-move file's pristine text as the merge base, the + * post-move content as the merge-right version, and the current + * content of the working file at the pre-move location as the + * merge-left version. + */ + SVN_ERR(svn_wc__db_pristine_get_path(&old_pristine_abspath, + b->db, b->wcroot->abspath, + src_checksum, + scratch_pool, scratch_pool)); + src_abspath = svn_dirent_join(b->wcroot->abspath, src_relpath, + scratch_pool); + label_left = apr_psprintf(scratch_pool, ".r%ld", + b->old_version->peg_rev); + label_target = apr_psprintf(scratch_pool, ".r%ld", + b->new_version->peg_rev); + SVN_ERR(svn_wc__internal_merge(&work_item, &conflict_skel, + &merge_outcome, b->db, + old_pristine_abspath, + src_abspath, + dst_abspath, + dst_abspath, + label_left, + _(".working"), + label_target, + actual_props, + FALSE, /* dry-run */ + NULL, /* diff3-cmd */ + NULL, /* merge options */ + propchanges, + b->cancel_func, b->cancel_baton, + scratch_pool, scratch_pool)); + + work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); + + if (merge_outcome == svn_wc_merge_conflict) + content_state = svn_wc_notify_state_conflicted; + else + content_state = svn_wc_notify_state_merged; + } + } + + /* If there are any conflicts to be stored, convert them into work items + * too. */ + if (conflict_skel) + { + SVN_ERR(create_conflict_markers(&work_item, dst_abspath, b->db, + dst_repos_relpath, conflict_skel, + b->operation, &old_version, &new_version, + svn_node_file, !tree_conflict, + scratch_pool, scratch_pool)); + + work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); + } + + SVN_ERR(update_move_list_add(b->wcroot, dst_relpath, b->db, + svn_wc_notify_update_update, + svn_node_file, + content_state, + prop_state, + conflict_skel, work_items, scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * tc_editor_delete(node_move_baton_t *nmb, const char *relpath, svn_node_kind_t old_kind, @@ -1327,6 +1791,93 @@ tc_editor_delete(node_move_baton_t *nmb, return SVN_NO_ERROR; } +/* Handle node deletion for an incoming move. */ +static svn_error_t * +tc_incoming_editor_delete(node_move_baton_t *nmb, + const char *relpath, + svn_node_kind_t old_kind, + svn_node_kind_t new_kind, + apr_pool_t *scratch_pool) +{ + update_move_baton_t *b = nmb->umb; + svn_sqlite__stmt_t *stmt; + const char *local_abspath; + svn_boolean_t is_modified, is_all_deletes; + svn_skel_t *work_items = NULL; + svn_skel_t *conflict = NULL; + + SVN_ERR(mark_parent_edited(nmb, scratch_pool)); + if (nmb->skip) + return SVN_NO_ERROR; + + /* Check before retracting delete to catch delete-delete + conflicts. This catches conflicts on the node itself; deleted + children are caught as local modifications below.*/ + if (nmb->shadowed) + { + SVN_ERR(mark_tc_on_op_root(nmb, + old_kind, new_kind, + svn_wc_conflict_action_delete, + scratch_pool)); + return SVN_NO_ERROR; + } + + local_abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool); + SVN_ERR(svn_wc__node_has_local_mods(&is_modified, &is_all_deletes, + nmb->umb->db, local_abspath, FALSE, + NULL, NULL, scratch_pool)); + if (is_modified) + { + svn_wc_conflict_reason_t reason; + + /* No conflict means no NODES rows at the relpath op-depth + so it's easy to convert the modified tree into a copy. + + Note the following assumptions for relpath: + * it is not shadowed + * it is not the/an op-root. (or we can't make us a copy) + */ + + SVN_ERR(svn_wc__db_op_make_copy_internal(b->wcroot, relpath, FALSE, + NULL, NULL, scratch_pool)); + + reason = svn_wc_conflict_reason_edited; + + SVN_ERR(create_node_tree_conflict(&conflict, nmb, relpath, + old_kind, new_kind, reason, + (new_kind == svn_node_none) + ? svn_wc_conflict_action_delete + : svn_wc_conflict_action_replace, + NULL, + scratch_pool, scratch_pool)); + nmb->skip = TRUE; + } + else + { + /* Delete the WORKING node at DST_RELPATH. */ + SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb, + STMT_INSERT_DELETE_FROM_NODE_RECURSIVE)); + SVN_ERR(svn_sqlite__bindf(stmt, "isdd", + b->wcroot->wc_id, relpath, + 0, relpath_depth(relpath))); + SVN_ERR(svn_sqlite__step_done(stmt)); + } + + /* Only notify if add_file/add_dir is not going to notify */ + if (conflict || (new_kind == svn_node_none)) + SVN_ERR(update_move_list_add(b->wcroot, relpath, b->db, + svn_wc_notify_update_delete, + new_kind, + svn_wc_notify_state_inapplicable, + svn_wc_notify_state_inapplicable, + conflict, work_items, scratch_pool)); + else if (work_items) + SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_items, + scratch_pool)); + + return SVN_NO_ERROR; +} + /* * Driver code. * @@ -1618,28 +2169,30 @@ suitable_for_move(svn_wc__db_wcroot_t *wcroot, while (have_row) { svn_revnum_t node_revision = svn_sqlite__column_revnum(stmt, 2); - const char *relpath = svn_sqlite__column_text(stmt, 0, NULL); + const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL); + const char *relpath; svn_pool_clear(iterpool); - relpath = svn_relpath_skip_ancestor(local_relpath, relpath); + relpath = svn_relpath_skip_ancestor(local_relpath, child_relpath); relpath = svn_relpath_join(repos_relpath, relpath, iterpool); - if (revision != node_revision) + if (strcmp(relpath, svn_sqlite__column_text(stmt, 1, NULL))) return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, svn_sqlite__reset(stmt), - _("Cannot apply update because move source " - "%s' is a mixed-revision working copy"), - path_for_error_message(wcroot, local_relpath, + _("Cannot apply update because '%s' is a " + "switched path (please switch it back to " + "its original URL and try again)"), + path_for_error_message(wcroot, child_relpath, scratch_pool)); - if (strcmp(relpath, svn_sqlite__column_text(stmt, 1, NULL))) + if (revision != node_revision) return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, svn_sqlite__reset(stmt), - _("Cannot apply update because move source " - "'%s' is a switched subtree"), - path_for_error_message(wcroot, - local_relpath, + _("Cannot apply update because '%s' is a " + "mixed-revision working copy (please " + "update and try again)"), + path_for_error_message(wcroot, local_relpath, scratch_pool)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); @@ -1827,6 +2380,1236 @@ svn_wc__db_update_moved_away_conflict_victim(svn_wc__db_t *db, return SVN_NO_ERROR; } +static svn_error_t * +get_working_info(apr_hash_t **props, + const svn_checksum_t **checksum, + apr_array_header_t **children, + svn_node_kind_t *kind, + const char *local_relpath, + svn_wc__db_wcroot_t *wcroot, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_wc__db_status_t status; + const char *repos_relpath; + svn_node_kind_t db_kind; + svn_error_t *err; + + err = svn_wc__db_read_info_internal(&status, &db_kind, NULL, &repos_relpath, + NULL, NULL, NULL, NULL, NULL, + checksum, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + wcroot, local_relpath, + result_pool, scratch_pool); + + /* If there is no node, or only a node that describes a delete + of a lower layer we report this node as not existing. */ + if ((err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) + || (!err && status != svn_wc__db_status_added + && status != svn_wc__db_status_normal)) + { + svn_error_clear(err); + + if (kind) + *kind = svn_node_none; + if (checksum) + *checksum = NULL; + if (props) + *props = NULL; + if (children) + *children = apr_array_make(result_pool, 0, sizeof(const char *)); + + return SVN_NO_ERROR; + } + else + SVN_ERR(err); + + SVN_ERR(svn_wc__db_read_props_internal(props, wcroot, local_relpath, + result_pool, scratch_pool)); + + if (kind) + *kind = db_kind; + + if (children && db_kind == svn_node_dir) + { + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row; + + *children = apr_array_make(result_pool, 16, sizeof(const char *)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_WORKING_CHILDREN)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + while (have_row) + { + const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL); + + APR_ARRAY_PUSH(*children, const char *) + = svn_relpath_basename(child_relpath, result_pool); + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + SVN_ERR(svn_sqlite__reset(stmt)); + } + else if (children) + *children = apr_array_make(result_pool, 0, sizeof(const char *)); + + return SVN_NO_ERROR; +} + +/* Apply changes found in the victim node at SRC_RELPATH to the incoming + * move at DST_RELPATH. */ +static svn_error_t * +update_incoming_moved_node(node_move_baton_t *nmb, + svn_wc__db_wcroot_t *wcroot, + const char *src_relpath, + const char *dst_relpath, + apr_pool_t *scratch_pool) +{ + update_move_baton_t *b = nmb->umb; + svn_node_kind_t orig_kind, working_kind; + const char *victim_relpath = src_relpath; + const svn_checksum_t *orig_checksum, *working_checksum; + apr_hash_t *orig_props, *working_props; + apr_array_header_t *orig_children, *working_children; + + if (b->cancel_func) + SVN_ERR(b->cancel_func(b->cancel_baton)); + + /* Compare the tree conflict victim's copied layer (the "original") with + * the working layer, i.e. look for changes layered on top of the copy. */ + SVN_ERR(get_info(&orig_props, &orig_checksum, &orig_children, &orig_kind, + victim_relpath, b->src_op_depth, wcroot, scratch_pool, + scratch_pool)); + SVN_ERR(get_working_info(&working_props, &working_checksum, + &working_children, &working_kind, victim_relpath, + wcroot, scratch_pool, scratch_pool)); + + if (working_kind == svn_node_none + || (orig_kind != svn_node_none && orig_kind != working_kind)) + { + SVN_ERR(tc_incoming_editor_delete(nmb, dst_relpath, orig_kind, + working_kind, scratch_pool)); + } + + if (nmb->skip) + return SVN_NO_ERROR; + + if (working_kind != svn_node_none && orig_kind != working_kind) + { + if (working_kind == svn_node_file || working_kind == svn_node_symlink) + { + const char *victim_abspath; + const char *wctemp_abspath; + svn_stream_t *working_stream; + svn_stream_t *temp_stream; + const char *temp_abspath; + svn_error_t *err; + + /* Copy the victim's content to a safe place and add it from there. */ + SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&wctemp_abspath, b->db, + b->wcroot->abspath, + scratch_pool, + scratch_pool)); + victim_abspath = svn_dirent_join(b->wcroot->abspath, + victim_relpath, scratch_pool); + SVN_ERR(svn_stream_open_readonly(&working_stream, victim_abspath, + scratch_pool, scratch_pool)); + SVN_ERR(svn_stream_open_unique(&temp_stream, &temp_abspath, + wctemp_abspath, svn_io_file_del_none, + scratch_pool, scratch_pool)); + err = svn_stream_copy3(working_stream, temp_stream, + b->cancel_func, b->cancel_baton, + scratch_pool); + if (err && err->apr_err == SVN_ERR_CANCELLED) + { + svn_error_t *err2; + + err2 = svn_io_remove_file2(temp_abspath, TRUE, scratch_pool); + return svn_error_compose_create(err, err2); + } + else + SVN_ERR(err); + + SVN_ERR(tc_editor_incoming_add_file(nmb, dst_relpath, orig_kind, + working_checksum, working_props, + victim_relpath, temp_abspath, + scratch_pool)); + } + else if (working_kind == svn_node_dir) + { + SVN_ERR(tc_editor_incoming_add_directory(nmb, dst_relpath, + orig_kind, working_props, + victim_relpath, + scratch_pool)); + } + } + else if (working_kind != svn_node_none) + { + svn_boolean_t props_equal; + + SVN_ERR(props_match(&props_equal, orig_props, working_props, + scratch_pool)); + + if (working_kind == svn_node_file || working_kind == svn_node_symlink) + { + svn_boolean_t is_modified; + + SVN_ERR(svn_wc__internal_file_modified_p(&is_modified, b->db, + svn_dirent_join( + b->wcroot->abspath, + victim_relpath, + scratch_pool), + FALSE /* exact_comparison */, + scratch_pool)); + if (!props_equal || is_modified) + SVN_ERR(tc_editor_update_incoming_moved_file(nmb, dst_relpath, + victim_relpath, + working_checksum, + orig_checksum, + orig_props, + working_props, + is_modified, + scratch_pool)); + } + else if (working_kind == svn_node_dir) + { + if (!props_equal) + SVN_ERR(tc_editor_alter_directory(nmb, dst_relpath, + orig_props, working_props, + scratch_pool)); + } + } + + if (nmb->skip) + return SVN_NO_ERROR; + + if (working_kind == svn_node_dir) + { + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + int i = 0, j = 0; + + while (i < orig_children->nelts || j < working_children->nelts) + { + const char *child_name; + svn_boolean_t orig_only = FALSE, working_only = FALSE; + node_move_baton_t cnmb = { 0 }; + + cnmb.pb = nmb; + cnmb.umb = nmb->umb; + cnmb.shadowed = nmb->shadowed; + + svn_pool_clear(iterpool); + if (i >= orig_children->nelts) + { + working_only = TRUE; + child_name = APR_ARRAY_IDX(working_children, j, const char *); + } + else if (j >= working_children->nelts) + { + orig_only = TRUE; + child_name = APR_ARRAY_IDX(orig_children, i, const char *); + } + else + { + const char *orig_name = APR_ARRAY_IDX(orig_children, i, + const char *); + const char *working_name = APR_ARRAY_IDX(working_children, j, + const char *); + int cmp = strcmp(orig_name, working_name); + + if (cmp > 0) + working_only = TRUE; + else if (cmp < 0) + orig_only = TRUE; + + child_name = working_only ? working_name : orig_name; + } + + cnmb.src_relpath = svn_relpath_join(src_relpath, child_name, + iterpool); + cnmb.dst_relpath = svn_relpath_join(dst_relpath, child_name, + iterpool); + + SVN_ERR(update_incoming_moved_node(&cnmb, wcroot, cnmb.src_relpath, + cnmb.dst_relpath, iterpool)); + + if (!working_only) + ++i; + if (!orig_only) + ++j; + + if (nmb->skip) /* Does parent now want a skip? */ + break; + } + } + + return SVN_NO_ERROR; +} + +/* The body of svn_wc__db_update_incoming_move(). */ +static svn_error_t * +update_incoming_move(svn_revnum_t *old_rev, + svn_revnum_t *new_rev, + svn_wc__db_t *db, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + const char *dst_relpath, + svn_wc_operation_t operation, + svn_wc_conflict_action_t action, + svn_wc_conflict_reason_t reason, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) +{ + update_move_baton_t umb = { NULL }; + svn_wc_conflict_version_t old_version; + svn_wc_conflict_version_t new_version; + apr_int64_t repos_id; + node_move_baton_t nmb = { 0 }; + svn_boolean_t is_modified; + + SVN_ERR_ASSERT(svn_relpath_skip_ancestor(dst_relpath, local_relpath) == NULL); + + /* For incoming moves during update/switch, the move source is a copied + * tree which was copied from the pre-update BASE revision while raising + * the tree conflict, when the update attempted to delete the move source. + * This copy is our "original" state (SRC of the diff) and the local changes + * on top of this copy at the top-most WORKING layer are used to drive the + * editor (DST of the diff). + * + * The move destination, where changes are applied to, is now in the BASE + * tree at DST_RELPATH. This repository-side move is the "incoming change" + * recorded for any tree conflicts created during the editor drive. + * We assume this path contains no local changes, and create local changes + * in DST_RELPATH corresponding to changes contained in the conflict victim. + * + * DST_OP_DEPTH is used to infer the "op-root" of the incoming move. This + * "op-root" is virtual because all nodes belonging to the incoming move + * live in the BASE tree. It is used for constructing repository paths + * when new tree conflicts need to be raised. + */ + umb.src_op_depth = relpath_depth(local_relpath); /* SRC of diff */ + umb.dst_op_depth = relpath_depth(dst_relpath); /* virtual DST op-root */ + + SVN_ERR(verify_write_lock(wcroot, local_relpath, scratch_pool)); + SVN_ERR(verify_write_lock(wcroot, dst_relpath, scratch_pool)); + + /* Make sure there are no local modifications in the move destination. */ + SVN_ERR(svn_wc__node_has_local_mods(&is_modified, NULL, db, + svn_dirent_join(wcroot->abspath, + dst_relpath, + scratch_pool), + TRUE, cancel_func, cancel_baton, + scratch_pool)); + if (is_modified) + return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL, + _("Cannot merge local changes from '%s' because " + "'%s' already contains other local changes " + "(please commit or revert these other changes " + "and try again)"), + svn_dirent_local_style( + svn_dirent_join(wcroot->abspath, local_relpath, + scratch_pool), + scratch_pool), + svn_dirent_local_style( + svn_dirent_join(wcroot->abspath, dst_relpath, + scratch_pool), + scratch_pool)); + + /* Check for switched subtrees and mixed-revision working copy. */ + SVN_ERR(suitable_for_move(wcroot, dst_relpath, scratch_pool)); + + /* Read version info from the updated incoming post-move location. */ + SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &new_version.node_kind, + &new_version.peg_rev, + &new_version.path_in_repos, + &repos_id, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + wcroot, dst_relpath, + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__db_fetch_repos_info(&new_version.repos_url, + &new_version.repos_uuid, + wcroot, repos_id, + scratch_pool)); + + /* Read version info from the victim's location. */ + SVN_ERR(svn_wc__db_depth_get_info(NULL, &old_version.node_kind, + &old_version.peg_rev, + &old_version.path_in_repos, &repos_id, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, wcroot, + local_relpath, umb.src_op_depth, + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__db_fetch_repos_info(&old_version.repos_url, + &old_version.repos_uuid, + wcroot, repos_id, + scratch_pool)); + *old_rev = old_version.peg_rev; + *new_rev = new_version.peg_rev; + + umb.operation = operation; + umb.old_version= &old_version; + umb.new_version= &new_version; + umb.db = db; + umb.wcroot = wcroot; + umb.cancel_func = cancel_func; + umb.cancel_baton = cancel_baton; + + /* Create a new, and empty, list for notification information. */ + SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, + STMT_CREATE_UPDATE_MOVE_LIST)); + + /* Drive the editor... */ + + nmb.umb = &umb; + nmb.src_relpath = local_relpath; + nmb.dst_relpath = dst_relpath; + /* nmb.shadowed = FALSE; */ + /* nmb.edited = FALSE; */ + /* nmb.skip_children = FALSE; */ + + /* We walk the conflict victim, comparing each node with the equivalent node + * at the WORKING layer, applying any local changes to nodes at the move + * destination. */ + SVN_ERR(update_incoming_moved_node(&nmb, wcroot, local_relpath, dst_relpath, + scratch_pool)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__db_update_incoming_move(svn_wc__db_t *db, + const char *local_abspath, + const char *dest_abspath, + svn_wc_operation_t operation, + svn_wc_conflict_action_t action, + svn_wc_conflict_reason_t reason, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + svn_revnum_t old_rev, new_rev; + const char *local_relpath; + const char *dest_relpath; + + /* ### Check for mixed-rev src or dst? */ + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, + db, local_abspath, + scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + dest_relpath + = svn_dirent_skip_ancestor(wcroot->abspath, dest_abspath); + + SVN_WC__DB_WITH_TXN(update_incoming_move(&old_rev, &new_rev, db, wcroot, + local_relpath, dest_relpath, + operation, action, reason, + cancel_func, cancel_baton, + scratch_pool), + wcroot); + + /* Send all queued up notifications. */ + SVN_ERR(svn_wc__db_update_move_list_notify(wcroot, old_rev, new_rev, + notify_func, notify_baton, + scratch_pool)); + if (notify_func) + { + svn_wc_notify_t *notify; + + notify = svn_wc_create_notify(svn_dirent_join(wcroot->abspath, + local_relpath, + scratch_pool), + svn_wc_notify_update_completed, + scratch_pool); + notify->kind = svn_node_none; + notify->content_state = svn_wc_notify_state_inapplicable; + notify->prop_state = svn_wc_notify_state_inapplicable; + notify->revision = new_rev; + notify_func(notify_baton, notify, scratch_pool); + } + + + return SVN_NO_ERROR; +} + +typedef struct update_local_add_baton_t { + int add_op_depth; + svn_wc__db_t *db; + svn_wc__db_wcroot_t *wcroot; + svn_cancel_func_t cancel_func; + void *cancel_baton; + + /* We refer to these if raising new tree conflicts. */ + const svn_wc_conflict_version_t *new_version; +} update_local_add_baton_t; + +typedef struct added_node_baton_t { + struct update_local_add_baton_t *b; + struct added_node_baton_t *pb; + const char *local_relpath; + svn_boolean_t skip; + svn_boolean_t edited; +} added_node_baton_t; + + +static svn_error_t * +update_local_add_mark_node_edited(added_node_baton_t *nb, + apr_pool_t *scratch_pool) +{ + if (nb->edited) + return SVN_NO_ERROR; + + if (nb->pb) + { + SVN_ERR(update_local_add_mark_node_edited(nb->pb, scratch_pool)); + + if (nb->pb->skip) + nb->skip = TRUE; + } + + nb->edited = TRUE; + + return SVN_NO_ERROR; +} + +static svn_error_t * +update_local_add_mark_parent_edited(added_node_baton_t *nb, + apr_pool_t *scratch_pool) +{ + SVN_ERR_ASSERT(nb && nb->pb); + + SVN_ERR(update_local_add_mark_node_edited(nb->pb, scratch_pool)); + + if (nb->pb->skip) + nb->skip = TRUE; + + return SVN_NO_ERROR; +} + +static svn_error_t * +mark_update_add_add_tree_conflict(added_node_baton_t *nb, + svn_node_kind_t base_kind, + svn_node_kind_t working_kind, + svn_wc_conflict_reason_t local_change, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) + +{ + svn_wc__db_t *db = nb->b->db; + svn_wc__db_wcroot_t *wcroot = nb->b->wcroot; + svn_wc_conflict_version_t *new_version; + svn_skel_t *conflict; + + new_version = svn_wc_conflict_version_dup(nb->b->new_version, result_pool); + + /* Fill in conflict info templates with info for this node. */ + SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, &new_version->peg_rev, + &new_version->path_in_repos, + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + wcroot, nb->local_relpath, + scratch_pool, scratch_pool)); + new_version->node_kind = base_kind; + + SVN_ERR(create_tree_conflict(&conflict, wcroot, nb->local_relpath, + nb->local_relpath, db, NULL, new_version, + svn_wc_operation_update, + svn_node_none, base_kind, NULL, + local_change, svn_wc_conflict_action_add, + NULL, scratch_pool, scratch_pool)); + + SVN_ERR(update_move_list_add(wcroot, nb->local_relpath, db, + svn_wc_notify_tree_conflict, working_kind, + svn_wc_notify_state_inapplicable, + svn_wc_notify_state_inapplicable, + conflict, NULL, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +update_local_add_notify_obstructed_or_missing(added_node_baton_t *nb, + svn_node_kind_t working_kind, + svn_node_kind_t kind_on_disk, + apr_pool_t *scratch_pool) +{ + svn_wc_notify_state_t content_state; + + if (kind_on_disk == svn_node_none) + content_state = svn_wc_notify_state_missing; + else + content_state = svn_wc_notify_state_obstructed; + + SVN_ERR(update_move_list_add(nb->b->wcroot, nb->local_relpath, nb->b->db, + svn_wc_notify_skip, working_kind, + content_state, svn_wc_notify_state_inapplicable, + NULL, NULL, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +tc_editor_update_add_new_file(added_node_baton_t *nb, + svn_node_kind_t base_kind, + const svn_checksum_t *base_checksum, + apr_hash_t *base_props, + svn_node_kind_t working_kind, + const svn_checksum_t *working_checksum, + apr_hash_t *working_props, + apr_pool_t *scratch_pool) +{ + const char *local_abspath; + svn_node_kind_t kind_on_disk; + + SVN_ERR(update_local_add_mark_parent_edited(nb, scratch_pool)); + if (nb->skip) + return SVN_NO_ERROR; + + if (base_kind != svn_node_none) + { + SVN_ERR(mark_update_add_add_tree_conflict(nb, base_kind, svn_node_file, + svn_wc_conflict_reason_added, + scratch_pool, scratch_pool)); + nb->skip = TRUE; + return SVN_NO_ERROR; + } + + /* Check for obstructions. */ + local_abspath = svn_dirent_join(nb->b->wcroot->abspath, nb->local_relpath, + scratch_pool); + SVN_ERR(svn_io_check_path(local_abspath, &kind_on_disk, scratch_pool)); + if (kind_on_disk != svn_node_file) + { + SVN_ERR(update_local_add_notify_obstructed_or_missing(nb, working_kind, + kind_on_disk, + scratch_pool)); + nb->skip = TRUE; + return SVN_NO_ERROR; + } + + /* Nothing else to do. Locally added files are an op-root in NODES. */ + + SVN_ERR(update_move_list_add(nb->b->wcroot, nb->local_relpath, nb->b->db, + svn_wc_notify_update_add, svn_node_file, + svn_wc_notify_state_inapplicable, + svn_wc_notify_state_inapplicable, + NULL, NULL, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +tc_editor_update_add_new_directory(added_node_baton_t *nb, + svn_node_kind_t base_kind, + apr_hash_t *base_props, + apr_hash_t *working_props, + apr_pool_t *scratch_pool) +{ + const char *local_abspath; + svn_node_kind_t kind_on_disk; + + SVN_ERR(update_local_add_mark_parent_edited(nb, scratch_pool)); + if (nb->skip) + return SVN_NO_ERROR; + + if (base_kind != svn_node_none) + { + SVN_ERR(mark_update_add_add_tree_conflict(nb, base_kind, svn_node_dir, + svn_wc_conflict_reason_added, + scratch_pool, scratch_pool)); + nb->skip = TRUE; + return SVN_NO_ERROR; + } + + /* Check for obstructions. */ + local_abspath = svn_dirent_join(nb->b->wcroot->abspath, nb->local_relpath, + scratch_pool); + SVN_ERR(svn_io_check_path(local_abspath, &kind_on_disk, scratch_pool)); + if (kind_on_disk != svn_node_dir) + { + SVN_ERR(update_local_add_notify_obstructed_or_missing(nb, svn_node_dir, + kind_on_disk, + scratch_pool)); + nb->skip = TRUE; + return SVN_NO_ERROR; + } + + /* Nothing else to do. Locally added directories are an op-root in NODES. */ + + SVN_ERR(update_move_list_add(nb->b->wcroot, nb->local_relpath, nb->b->db, + svn_wc_notify_update_add, svn_node_dir, + svn_wc_notify_state_inapplicable, + svn_wc_notify_state_inapplicable, + NULL, NULL, scratch_pool)); + return SVN_NO_ERROR; +} + +static svn_error_t * +update_incoming_add_merge_props(svn_wc_notify_state_t *prop_state, + svn_skel_t **conflict_skel, + const char *local_relpath, + apr_hash_t *base_props, + apr_hash_t *working_props, + svn_wc__db_t *db, + svn_wc__db_wcroot_t *wcroot, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + apr_hash_t *new_actual_props; + apr_array_header_t *propchanges; + const char *local_abspath = svn_dirent_join(wcroot->abspath, + local_relpath, + scratch_pool); + + /* + * Run a 3-way prop merge to update the props, using the empty props + * as the merge base, the post-update props as the merge-left version, and + * the current props of the added working file as the merge-right version. + */ + SVN_ERR(svn_prop_diffs(&propchanges, working_props, + apr_hash_make(scratch_pool), scratch_pool)); + SVN_ERR(svn_wc__merge_props(conflict_skel, prop_state, &new_actual_props, + db, local_abspath, + apr_hash_make(scratch_pool), + base_props, working_props, propchanges, + result_pool, scratch_pool)); + + /* Install the new actual props. */ + if (apr_hash_count(new_actual_props) > 0) + SVN_ERR(svn_wc__db_op_set_props_internal(wcroot, local_relpath, + new_actual_props, + svn_wc__has_magic_property( + propchanges), + scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +tc_editor_update_add_merge_files(added_node_baton_t *nb, + const svn_checksum_t *working_checksum, + const svn_checksum_t *base_checksum, + apr_hash_t *working_props, + apr_hash_t *base_props, + apr_pool_t *scratch_pool) +{ + update_local_add_baton_t *b = nb->b; + apr_array_header_t *propchanges; + svn_boolean_t is_modified; + enum svn_wc_merge_outcome_t merge_outcome; + svn_skel_t *conflict_skel = NULL; + svn_wc_notify_state_t prop_state, content_state; + svn_skel_t *work_items = NULL; + svn_node_kind_t kind_on_disk; + const char *local_abspath = svn_dirent_join(b->wcroot->abspath, + nb->local_relpath, + scratch_pool); + + SVN_ERR(update_local_add_mark_node_edited(nb, scratch_pool)); + if (nb->skip) + return SVN_NO_ERROR; + + /* Check for on-disk obstructions or missing files. */ + SVN_ERR(svn_io_check_path(local_abspath, &kind_on_disk, scratch_pool)); + if (kind_on_disk != svn_node_file) + { + SVN_ERR(update_local_add_notify_obstructed_or_missing(nb, svn_node_file, + kind_on_disk, + scratch_pool)); + nb->skip = TRUE; + return SVN_NO_ERROR; + } + + SVN_ERR(update_incoming_add_merge_props(&prop_state, &conflict_skel, + nb->local_relpath, + base_props, working_props, + b->db, b->wcroot, + scratch_pool, scratch_pool)); + + SVN_ERR(svn_wc__internal_file_modified_p(&is_modified, + b->db, local_abspath, + FALSE /* exact_comparison */, + scratch_pool)); + if (!is_modified) + { + svn_skel_t *work_item = NULL; + + SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db, + local_abspath, NULL, + /* FIXME: use_commit_times? */ + FALSE, + TRUE, /* record_file_info */ + scratch_pool, scratch_pool)); + work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); + content_state = svn_wc_notify_state_changed; + } + else + { + const char *empty_file_abspath; + const char *pristine_abspath; + svn_skel_t *work_item = NULL; + + /* + * Run a 3-way merge to update the file, using the empty file + * merge base, the post-update pristine text as the merge-left version, + * and the locally added content of the working file as the merge-right + * version. + */ + SVN_ERR(svn_io_open_unique_file3(NULL, &empty_file_abspath, NULL, + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__db_pristine_get_path(&pristine_abspath, b->db, + b->wcroot->abspath, base_checksum, + scratch_pool, scratch_pool)); + + /* Create a property diff which shows all props as added. */ + SVN_ERR(svn_prop_diffs(&propchanges, working_props, + apr_hash_make(scratch_pool), scratch_pool)); + + SVN_ERR(svn_wc__internal_merge(&work_item, &conflict_skel, + &merge_outcome, b->db, + empty_file_abspath, + pristine_abspath, + local_abspath, + local_abspath, + NULL, NULL, NULL, /* diff labels */ + apr_hash_make(scratch_pool), + FALSE, /* dry-run */ + NULL, /* diff3-cmd */ + NULL, /* merge options */ + propchanges, + b->cancel_func, b->cancel_baton, + scratch_pool, scratch_pool)); + + work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); + + if (merge_outcome == svn_wc_merge_conflict) + content_state = svn_wc_notify_state_conflicted; + else + content_state = svn_wc_notify_state_merged; + } + + /* If there are any conflicts to be stored, convert them into work items + * too. */ + if (conflict_skel) + { + svn_wc_conflict_version_t *new_version; + svn_node_kind_t new_kind; + svn_revnum_t new_rev; + const char *repos_relpath; + + new_version = svn_wc_conflict_version_dup(nb->b->new_version, + scratch_pool); + SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &new_kind, &new_rev, + &repos_relpath, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + b->wcroot, nb->local_relpath, + scratch_pool, scratch_pool)); + /* Fill in conflict info templates with info for this node. */ + new_version->path_in_repos = repos_relpath; + new_version->node_kind = new_kind; + new_version->peg_rev = new_rev; + + /* Create conflict markers. */ + SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_skel, NULL, + new_version, scratch_pool, + scratch_pool)); + if (prop_state == svn_wc_notify_state_conflicted) + SVN_ERR(svn_wc__conflict_create_markers(&work_items, b->db, + local_abspath, + conflict_skel, + scratch_pool, + scratch_pool)); + } + + SVN_ERR(update_move_list_add(b->wcroot, nb->local_relpath, b->db, + svn_wc_notify_update_update, + svn_node_file, content_state, prop_state, + conflict_skel, work_items, scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +tc_editor_update_add_merge_dirprops(added_node_baton_t *nb, + apr_hash_t *working_props, + apr_hash_t *base_props, + apr_pool_t *scratch_pool) +{ + update_local_add_baton_t *b = nb->b; + svn_skel_t *conflict_skel = NULL; + svn_wc_notify_state_t prop_state; + svn_skel_t *work_items = NULL; + svn_node_kind_t kind_on_disk; + const char *local_abspath = svn_dirent_join(b->wcroot->abspath, + nb->local_relpath, + scratch_pool); + + SVN_ERR(update_local_add_mark_node_edited(nb, scratch_pool)); + if (nb->skip) + return SVN_NO_ERROR; + + /* Check for on-disk obstructions or missing files. */ + SVN_ERR(svn_io_check_path(local_abspath, &kind_on_disk, scratch_pool)); + if (kind_on_disk != svn_node_dir) + { + SVN_ERR(update_local_add_notify_obstructed_or_missing(nb, svn_node_dir, + kind_on_disk, + scratch_pool)); + nb->skip = TRUE; + return SVN_NO_ERROR; + } + + SVN_ERR(update_incoming_add_merge_props(&prop_state, &conflict_skel, + nb->local_relpath, + base_props, working_props, + b->db, b->wcroot, + scratch_pool, scratch_pool)); + + /* If there are any conflicts to be stored, convert them into work items. */ + if (conflict_skel && prop_state == svn_wc_notify_state_conflicted) + { + svn_wc_conflict_version_t *new_version; + svn_node_kind_t new_kind; + svn_revnum_t new_rev; + const char *repos_relpath; + + new_version = svn_wc_conflict_version_dup(nb->b->new_version, + scratch_pool); + SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &new_kind, &new_rev, + &repos_relpath, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + b->wcroot, nb->local_relpath, + scratch_pool, scratch_pool)); + /* Fill in conflict info templates with info for this node. */ + new_version->path_in_repos = repos_relpath; + new_version->node_kind = new_kind; + new_version->peg_rev = new_rev; + + /* Create conflict markers. */ + SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_skel, NULL, + new_version, scratch_pool, + scratch_pool)); + SVN_ERR(svn_wc__conflict_create_markers(&work_items, b->db, + local_abspath, + conflict_skel, + scratch_pool, + scratch_pool)); + } + + SVN_ERR(update_move_list_add(b->wcroot, nb->local_relpath, b->db, + svn_wc_notify_update_update, svn_node_dir, + svn_wc_notify_state_inapplicable, prop_state, + conflict_skel, work_items, scratch_pool)); + + return SVN_NO_ERROR; +} + +static svn_error_t * +update_locally_added_node(added_node_baton_t *nb, + apr_pool_t *scratch_pool) +{ + update_local_add_baton_t *b = nb->b; + svn_wc__db_wcroot_t *wcroot = b->wcroot; + svn_wc__db_t *db = b->db; + svn_node_kind_t base_kind, working_kind; + const svn_checksum_t *base_checksum; + apr_hash_t *base_props, *working_props; + apr_array_header_t *base_children, *working_children; + const char *local_abspath = svn_dirent_join(wcroot->abspath, + nb->local_relpath, + scratch_pool); + + if (b->cancel_func) + SVN_ERR(b->cancel_func(b->cancel_baton)); + + if (nb->skip) + return SVN_NO_ERROR; + + /* Compare the tree conflict victim's BASE layer to the working layer. */ + SVN_ERR(get_info(&base_props, &base_checksum, &base_children, &base_kind, + nb->local_relpath, 0, wcroot, scratch_pool, scratch_pool)); + SVN_ERR(get_working_info(&working_props, NULL, &working_children, + &working_kind, nb->local_relpath, wcroot, + scratch_pool, scratch_pool)); + if (working_kind == svn_node_none) + { + svn_node_kind_t kind_on_disk; + svn_skel_t *work_item = NULL; + + /* Skip obstructed nodes. */ + SVN_ERR(svn_io_check_path(local_abspath, &kind_on_disk, + scratch_pool)); + if (kind_on_disk != base_kind && kind_on_disk != svn_node_none) + { + SVN_ERR(update_move_list_add(nb->b->wcroot, nb->local_relpath, + nb->b->db, + svn_wc_notify_skip, + base_kind, + svn_wc_notify_state_obstructed, + svn_wc_notify_state_inapplicable, + NULL, NULL, scratch_pool)); + nb->skip = TRUE; + return SVN_NO_ERROR; + } + + /* The working tree has no node here. The working copy of this node + * is currently not installed because the base tree is shadowed. + * Queue an installation of this node into the working copy. */ + if (base_kind == svn_node_file || base_kind == svn_node_symlink) + SVN_ERR(svn_wc__wq_build_file_install(&work_item, db, local_abspath, + NULL, + /* FIXME: use_commit_times? */ + FALSE, + TRUE, /* record_file_info */ + scratch_pool, scratch_pool)); + else if (base_kind == svn_node_dir) + SVN_ERR(svn_wc__wq_build_dir_install(&work_item, db, local_abspath, + scratch_pool, scratch_pool)); + + if (work_item) + SVN_ERR(update_move_list_add(wcroot, nb->local_relpath, db, + svn_wc_notify_update_add, + base_kind, + svn_wc_notify_state_inapplicable, + svn_wc_notify_state_inapplicable, + NULL, work_item, scratch_pool)); + return SVN_NO_ERROR; + } + + if (base_kind != working_kind) + { + if (working_kind == svn_node_file || working_kind == svn_node_symlink) + { + svn_checksum_t *working_checksum = NULL; + + if (base_checksum) + SVN_ERR(svn_io_file_checksum2(&working_checksum, local_abspath, + base_checksum->kind, scratch_pool)); + SVN_ERR(tc_editor_update_add_new_file(nb, base_kind, base_checksum, + base_props, working_kind, + working_checksum, working_props, + scratch_pool)); + } + else if (working_kind == svn_node_dir) + SVN_ERR(tc_editor_update_add_new_directory(nb, base_kind, base_props, + working_props, + scratch_pool)); + } + else + { + svn_boolean_t props_equal; + + SVN_ERR(props_match(&props_equal, base_props, working_props, + scratch_pool)); + + if (working_kind == svn_node_file || working_kind == svn_node_symlink) + { + svn_checksum_t *working_checksum; + + SVN_ERR_ASSERT(base_checksum); + SVN_ERR(svn_io_file_checksum2(&working_checksum, local_abspath, + base_checksum->kind, scratch_pool)); + if (!props_equal || !svn_checksum_match(base_checksum, + working_checksum)) + SVN_ERR(tc_editor_update_add_merge_files(nb, working_checksum, + base_checksum, + working_props, base_props, + scratch_pool)); + } + else if (working_kind == svn_node_dir && !props_equal) + SVN_ERR(tc_editor_update_add_merge_dirprops(nb, working_props, + base_props, + scratch_pool)); + } + + if (nb->skip) + return SVN_NO_ERROR; + + if (working_kind == svn_node_dir) + { + apr_pool_t *iterpool = svn_pool_create(scratch_pool); + int i = 0, j = 0; + + while (i < base_children->nelts || j < working_children->nelts) + { + const char *child_name; + svn_boolean_t base_only = FALSE, working_only = FALSE; + added_node_baton_t cnb = { 0 }; + + cnb.pb = nb; + cnb.b = nb->b; + cnb.skip = FALSE; + + svn_pool_clear(iterpool); + if (i >= base_children->nelts) + { + working_only = TRUE; + child_name = APR_ARRAY_IDX(working_children, j, const char *); + } + else if (j >= working_children->nelts) + { + base_only = TRUE; + child_name = APR_ARRAY_IDX(base_children, i, const char *); + } + else + { + const char *base_name = APR_ARRAY_IDX(base_children, i, + const char *); + const char *working_name = APR_ARRAY_IDX(working_children, j, + const char *); + int cmp = strcmp(base_name, working_name); + + if (cmp > 0) + working_only = TRUE; + else if (cmp < 0) + base_only = TRUE; + + child_name = working_only ? working_name : base_name; + } + + cnb.local_relpath = svn_relpath_join(nb->local_relpath, child_name, + iterpool); + + SVN_ERR(update_locally_added_node(&cnb, iterpool)); + + if (!working_only) + ++i; + if (!base_only) + ++j; + + if (nb->skip) /* Does parent now want a skip? */ + break; + } + } + + return SVN_NO_ERROR; +} + +/* The body of svn_wc__db_update_local_add(). */ +static svn_error_t * +update_local_add(svn_revnum_t *new_rev, + svn_wc__db_t *db, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool) +{ + update_local_add_baton_t b = { 0 }; + added_node_baton_t nb = { 0 }; + const char *repos_root_url; + const char *repos_uuid; + const char *repos_relpath; + apr_int64_t repos_id; + svn_node_kind_t new_kind; + svn_sqlite__stmt_t *stmt; + + b.add_op_depth = relpath_depth(local_relpath); /* DST op-root */ + + SVN_ERR(verify_write_lock(wcroot, local_relpath, scratch_pool)); + + b.db = db; + b.wcroot = wcroot; + b.cancel_func = cancel_func; + b.cancel_baton = cancel_baton; + + /* Read new version info from the updated BASE node. */ + SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &new_kind, new_rev, + &repos_relpath, &repos_id, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + wcroot, local_relpath, + scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, &repos_uuid, wcroot, + repos_id, scratch_pool)); + b.new_version = svn_wc_conflict_version_create2(repos_root_url, repos_uuid, + repos_relpath, *new_rev, + new_kind, scratch_pool); + + /* Create a new, and empty, list for notification information. */ + SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, + STMT_CREATE_UPDATE_MOVE_LIST)); + + /* Drive the editor... */ + nb.b = &b; + nb.local_relpath = local_relpath; + nb.skip = FALSE; + SVN_ERR(update_locally_added_node(&nb, scratch_pool)); + + /* The conflict victim is now part of the base tree. + * Remove the locally added version of the conflict victim and its children. + * Any children we want to retain are at a higher op-depth so they won't + * be deleted by this statement. */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_DELETE_WORKING_OP_DEPTH)); + SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, + relpath_depth(local_relpath))); + SVN_ERR(svn_sqlite__update(NULL, stmt)); + + /* Remove the tree conflict marker. */ + SVN_ERR(svn_wc__db_op_mark_resolved_internal(wcroot, local_relpath, db, + FALSE, FALSE, TRUE, + NULL, scratch_pool)); + return SVN_NO_ERROR; +} + +svn_error_t * +svn_wc__db_update_local_add(svn_wc__db_t *db, + const char *local_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, + svn_wc_notify_func2_t notify_func, + void *notify_baton, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + svn_revnum_t new_rev; + const char *local_relpath; + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, + db, local_abspath, + scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_WC__DB_WITH_TXN(update_local_add(&new_rev, db, wcroot, + local_relpath, + cancel_func, cancel_baton, + scratch_pool), + wcroot); + + /* Send all queued up notifications. */ + SVN_ERR(svn_wc__db_update_move_list_notify(wcroot, new_rev, new_rev, + notify_func, notify_baton, + scratch_pool)); + if (notify_func) + { + svn_wc_notify_t *notify; + + notify = svn_wc_create_notify(svn_dirent_join(wcroot->abspath, + local_relpath, + scratch_pool), + svn_wc_notify_update_completed, + scratch_pool); + notify->kind = svn_node_none; + notify->content_state = svn_wc_notify_state_inapplicable; + notify->prop_state = svn_wc_notify_state_inapplicable; + notify->revision = new_rev; + notify_func(notify_baton, notify, scratch_pool); + } + + + return SVN_NO_ERROR; +} /* Set *CAN_BUMP to TRUE if DEPTH is sufficient to cover the entire tree LOCAL_RELPATH at OP_DEPTH, to FALSE otherwise. */ static svn_error_t * diff --git a/subversion/libsvn_wc/wc_db_util.c b/subversion/libsvn_wc/wc_db_util.c index 074feffcf9f5..8402c42eaadc 100644 --- a/subversion/libsvn_wc/wc_db_util.c +++ b/subversion/libsvn_wc/wc_db_util.c @@ -127,7 +127,7 @@ svn_wc__db_util_open_db(svn_sqlite__db_t **sdb, { svn_node_kind_t kind; - /* A file stat is much cheaper then a failed database open handled + /* A file stat is much cheaper than a failed database open handled by SQLite. */ SVN_ERR(svn_io_check_path(sdb_abspath, &kind, scratch_pool)); diff --git a/subversion/libsvn_wc/wcroot_anchor.c b/subversion/libsvn_wc/wcroot_anchor.c index 913a61b50ad7..7400aa5c9948 100644 --- a/subversion/libsvn_wc/wcroot_anchor.c +++ b/subversion/libsvn_wc/wcroot_anchor.c @@ -183,6 +183,26 @@ svn_wc__get_wcroot(const char **wcroot_abspath, svn_error_t * +svn_wc__get_shelves_dir(char **dir, + svn_wc_context_t *wc_ctx, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + const char *wcroot_abspath; + + SVN_ERR(svn_wc__get_wcroot(&wcroot_abspath, wc_ctx, local_abspath, + scratch_pool, scratch_pool)); + *dir = svn_dirent_join(wcroot_abspath, ".svn/shelves", result_pool); + + /* Ensure the directory exists. (Other versions of svn don't create it.) */ + SVN_ERR(svn_io_make_dir_recursively(*dir, scratch_pool)); + + return SVN_NO_ERROR; +} + + +svn_error_t * svn_wc_get_actual_target2(const char **anchor, const char **target, svn_wc_context_t *wc_ctx, diff --git a/subversion/libsvn_wc/workqueue.c b/subversion/libsvn_wc/workqueue.c index 18736cc6ff3f..449abcb2192f 100644 --- a/subversion/libsvn_wc/workqueue.c +++ b/subversion/libsvn_wc/workqueue.c @@ -257,7 +257,8 @@ install_committed_file(svn_boolean_t *overwrote_working, if (! same) { - SVN_ERR(svn_io_file_rename(tmp_wfile, file_abspath, scratch_pool)); + SVN_ERR(svn_io_file_rename2(tmp_wfile, file_abspath, FALSE, + scratch_pool)); *overwrote_working = TRUE; } @@ -418,13 +419,13 @@ run_postupgrade(work_item_baton_t *wqb, ### The order may matter for some sufficiently old clients.. but ### this code only runs during upgrade after the files had been ### removed earlier during the upgrade. */ - SVN_ERR(svn_io_write_atomic(format_path, SVN_WC__NON_ENTRIES_STRING, - sizeof(SVN_WC__NON_ENTRIES_STRING) - 1, - NULL, scratch_pool)); + SVN_ERR(svn_io_write_atomic2(format_path, SVN_WC__NON_ENTRIES_STRING, + sizeof(SVN_WC__NON_ENTRIES_STRING) - 1, + NULL, TRUE, scratch_pool)); - SVN_ERR(svn_io_write_atomic(entries_path, SVN_WC__NON_ENTRIES_STRING, - sizeof(SVN_WC__NON_ENTRIES_STRING) - 1, - NULL, scratch_pool)); + SVN_ERR(svn_io_write_atomic2(entries_path, SVN_WC__NON_ENTRIES_STRING, + sizeof(SVN_WC__NON_ENTRIES_STRING) - 1, + NULL, TRUE, scratch_pool)); return SVN_NO_ERROR; } @@ -1127,9 +1128,9 @@ run_prej_install(work_item_baton_t *wqb, scratch_pool, scratch_pool)); /* ... and atomically move it into place. */ - SVN_ERR(svn_io_file_rename(tmp_prejfile_abspath, - prejfile_abspath, - scratch_pool)); + SVN_ERR(svn_io_file_rename2(tmp_prejfile_abspath, + prejfile_abspath, FALSE, + scratch_pool)); return SVN_NO_ERROR; } |