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