You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/11/04 21:48:30 UTC

svn commit: r1031230 [10/21] - in /subversion/branches/py-tests-as-modules: ./ build/ build/ac-macros/ build/win32/ contrib/client-side/ notes/ notes/http-and-webdav/ notes/wc-ng/ subversion/bindings/ctypes-python/csvn/ subversion/bindings/javahl/nativ...

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_wc/update_editor.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_wc/update_editor.c Thu Nov  4 20:48:21 2010
@@ -224,12 +224,6 @@ struct edit_baton
   svn_wc_conflict_resolver_func_t conflict_func;
   void *conflict_baton;
 
-  /* If the server sends add_file(copyfrom=...) and we don't have the
-     copyfrom file in the working copy, we use this callback to fetch
-     it directly from the repository. */
-  svn_wc_get_file_t fetch_func;
-  void *fetch_baton;
-
   /* Subtrees that were skipped during the edit, and therefore shouldn't
      have their revision/url info updated at the end.  If a path is a
      directory, its descendants will also be skipped.  The keys are absolute
@@ -1097,29 +1091,6 @@ window_handler(svn_txdelta_window_t *win
 }
 
 
-/* Prepare directory for dir_baton DB for updating or checking out.
- * Give it depth DEPTH.
- *
- * If the path already exists, but is not a working copy for
- * ANCESTOR_URL and ANCESTOR_REVISION, then an error will be returned.
- */
-static svn_error_t *
-prep_directory(struct dir_baton *db,
-               const char *ancestor_url,
-               svn_revnum_t ancestor_revision,
-               apr_pool_t *pool)
-{
-  const char *dir_abspath;
-
-  dir_abspath = db->local_abspath;
-
-  /* Make sure the directory exists. */
-  SVN_ERR(svn_wc__ensure_directory(dir_abspath, pool));
-
-  return SVN_NO_ERROR;
-}
-
-
 /* Find the last-change info within ENTRY_PROPS, and return then in the
    CHANGED_* parameters. Each parameter will be initialized to its "none"
    value, and will contain the relavent info if found.
@@ -1556,7 +1527,8 @@ create_tree_conflict(svn_wc_conflict_des
            * calling this function. Do that on the caller's side. */
           right_repos_relpath = eb->switch_relpath;
           right_repos_relpath = apr_pstrcat(result_pool, right_repos_relpath,
-                                            "_THIS_IS_INCOMPLETE", NULL);
+                                            "_THIS_IS_INCOMPLETE",
+                                            (char *)NULL);
         }
     }
   else
@@ -1969,7 +1941,6 @@ do_entry_deletion(struct edit_baton *eb,
   svn_boolean_t conflicted;
   svn_wc_conflict_description2_t *tree_conflict = NULL;
   const char *dir_abspath = svn_dirent_dirname(local_abspath, pool);
-  svn_boolean_t hidden;
   svn_skel_t *work_item;
 
   SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
@@ -2123,7 +2094,7 @@ delete_entry(const char *path,
              apr_pool_t *pool)
 {
   struct dir_baton *pb = parent_baton;
-  const char *base = svn_relpath_basename(path, pool);
+  const char *base = svn_relpath_basename(path, NULL);
   const char *local_abspath;
   const char *their_relpath;
 
@@ -2153,7 +2124,7 @@ static svn_error_t *
 add_directory(const char *path,
               void *parent_baton,
               const char *copyfrom_path,
-              svn_revnum_t copyfrom_revision,
+              svn_revnum_t copyfrom_rev,
               apr_pool_t *pool,
               void **child_baton)
 {
@@ -2168,42 +2139,7 @@ add_directory(const char *path,
   svn_wc_conflict_description2_t *tree_conflict = NULL;
   svn_error_t *err;
 
-  /* Semantic check.  Either both "copyfrom" args are valid, or they're
-     NULL and SVN_INVALID_REVNUM.  A mixture is illegal semantics. */
-  SVN_ERR_ASSERT((copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
-                 || (!copyfrom_path &&
-                     !SVN_IS_VALID_REVNUM(copyfrom_revision)));
-  if (copyfrom_path != NULL)
-    {
-      /* ### todo: for now, this editor doesn't know how to deal with
-         copyfrom args.  Someday it will interpet them as an update
-         optimization, and actually copy one part of the wc to another.
-         Then it will recursively "normalize" all the ancestry in the
-         copied tree.  Someday!
-
-         Note from the future: if someday it does, we'll probably want
-         to tweak libsvn_ra_neon/fetch.c:validate_element() to accept
-         that an add-dir element can contain a delete-entry element
-         (because the dir might be added with history).  Currently
-         that combination will not validate.  See r30161, and see the
-         thread in which this message appears:
-
-      http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=136879
-      From: "David Glasser" <gl...@davidglasser.net>
-      To: "Karl Fogel" <kf...@red-bean.com>, dev@subversion.tigris.org
-      Cc: "Arfrever Frehtes Taifersar Arahesis" <ar...@gmail.com>,
-          glasser@tigris.org
-      Subject: Re: svn commit: r30161 - in trunk/subversion: \
-               libsvn_ra_neon tests/cmdline
-      Date: Fri, 4 Apr 2008 14:47:06 -0700
-      Message-ID: <1e...@mail.gmail.com>
-
-      */
-      return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
-                               _("Failed to add directory '%s': "
-                                 "copyfrom arguments not yet supported"),
-                               svn_dirent_local_style(path, pool));
-    }
+  SVN_ERR_ASSERT(! (copyfrom_path || SVN_IS_VALID_REVNUM(copyfrom_rev)));
 
   SVN_ERR(make_dir_baton(&db, path, eb, pb, TRUE, pool));
   *child_baton = db;
@@ -2466,15 +2402,12 @@ add_directory(const char *path,
 
           /* If we are skipping an add, we need to tell the WC that
            * there's a node supposed to be here which we don't have. */
-          SVN_ERR(svn_wc__db_base_add_absent_node(eb->db, db->local_abspath,
+          SVN_ERR(svn_wc__db_base_add_not_present_node(eb->db, db->local_abspath,
                                                   db->new_relpath,
                                                   eb->repos_root,
                                                   eb->repos_uuid,
-                                                  (eb->target_revision?
-                                                   *eb->target_revision
-                                                   : SVN_INVALID_REVNUM),
+                                                  *eb->target_revision,
                                                   svn_wc__db_kind_dir,
-                                                  svn_wc__db_status_not_present,
                                                   NULL, NULL, pool));
           SVN_ERR(remember_skipped_tree(eb, db->local_abspath));
 
@@ -2517,17 +2450,12 @@ add_directory(const char *path,
                                                        db->ambient_depth,
                                                        pool));
 
-  SVN_ERR(prep_directory(db,
-                         svn_path_url_add_component2(eb->repos_root,
-                                                     db->new_relpath, pool),
-                         *(eb->target_revision),
-                         db->pool));
+  SVN_ERR(svn_wc__ensure_directory(db->local_abspath, pool));
 
   /* If PATH is within a locally deleted tree then make it also
-     scheduled for deletion.  We must do this after the call to
-     prep_directory() otherwise the administrative area for DB->PATH
-     is not present, nor is there an entry for DB->PATH in DB->PATH's
-     entries. */
+     scheduled for deletion.  We should do this at the same time as
+     setting the dir incomplete otherwise the db is temporarily
+     invalid. */
   if (pb->in_deleted_and_tree_conflicted_subtree)
     {
       SVN_ERR(svn_wc__db_temp_op_delete(eb->db, db->local_abspath, pool));
@@ -2969,22 +2897,10 @@ close_directory(void *dir_baton,
          item to write out an old-style props file.  */
       if (new_base_props != NULL)
         {
-          apr_array_header_t *prop_diffs;
-
           SVN_ERR_ASSERT(new_actual_props != NULL);
 
-          /* If the ACTUAL props are the same as the BASE props, then we
-             should "write" a NULL. This will remove the props from the
-             ACTUAL_NODE row, and remove the old-style props file, indicating
-             "no change".  */
-          props = new_actual_props;
-          SVN_ERR(svn_prop_diffs(&prop_diffs, new_actual_props, new_base_props,
-                                 pool));
-          if (prop_diffs->nelts == 0)
-            props = NULL;
-
           SVN_ERR(svn_wc__db_op_set_props(eb->db, db->local_abspath,
-                                          props,
+                                          new_actual_props,
                                           NULL /* conflict */,
                                           NULL /* work_items */,
                                           pool));
@@ -3113,477 +3029,6 @@ absent_directory(const char *path,
 }
 
 
-/* Beginning at DIR_ABSPATH within a working copy, search the working copy
-   copy for a pre-existing versioned file which is exactly equal to
-   COPYFROM_PATH@COPYFROM_REV.
-
-   The current implementation does this by taking the repos_relpath of
-   dir_abspath and copyfrom_relpath to calculate where in the working copy
-   repos_relpath would be and then tries to confirm its guess.
-
-   1) When it finds a copied file there, it looks for its origin to see
-   if the origin matches the copied file good enough to use it as new base
-   contents and properties. If that is the case set NEW_BASE_CONTENTS
-   and NEW_BASE_PROPS to the found restult.
-
-   If the new base information is found check if the node is tree-conflicted,
-   and when that is the case use its in-wc contents and actual properties
-   to set NEW_CONTENTS and NEW_PROPS.
-
-   (If new base info is found, return)
-
-   2) If the node's BASE information matches the expected origin matches the the
-   copy origin good enough use it as NEW_BASE_CONTENTS and NEW_BASE_PROPS.
-
-   If the new base information is found and the db_status of the node is normal,
-   then set NEW_CONTENTS and NEW_PROPS with the found values.
-
-   If data is not found, its values will be set to NULL. 
-
-   Allocate the return values in RESULT_POOL, but perform all temporary allocations
-   in SCRATCH_POOL.
-
-   ### With a centralized datastore this becomes much easier. For now we
-   ### keep the old algorithm because the result is also used for copying
-   ### local changes. This support can probably be removed once we have real
-   ### local file moves.
-*/
-static svn_error_t *
-locate_copyfrom(svn_stream_t **new_base_contents,
-                svn_stream_t **new_contents,
-                apr_hash_t **new_base_props,
-                apr_hash_t **new_props,
-                svn_wc__db_t *db,
-                const char *dir_abspath,
-                const char *copyfrom_relpath,
-                svn_revnum_t copyfrom_rev,
-                apr_pool_t *result_pool,
-                apr_pool_t *scratch_pool)
-{
-  const char *ancestor_abspath, *ancestor_relpath;
-  const char *dir_repos_relpath, *dir_repos_root_url, *dir_repos_uuid;
-  const char *repos_relpath, *repos_root_url, *repos_uuid;
-  const char *local_abspath;
-
-  apr_size_t levels_up;
-  svn_error_t *err;
-
-  SVN_ERR_ASSERT(copyfrom_relpath[0] != '/');
-
-  SVN_ERR(svn_wc__db_scan_base_repos(&dir_repos_relpath, &dir_repos_root_url,
-                                     &dir_repos_uuid,
-                                     db, dir_abspath,
-                                     scratch_pool, scratch_pool));
-
-  /* Be pessimistic.  This function is basically a series of tests
-     that gives dozens of ways to fail our search, returning
-     SVN_NO_ERROR in each case.  If we make it all the way to the
-     bottom, we have a real discovery to return. */
-  *new_base_contents = NULL;
-  *new_contents = NULL;
-  *new_base_props = NULL;
-  *new_props = NULL;
-
-  /* Subtract the dest_dir's URL from the repository "root" URL to get
-     the absolute FS path represented by dest_dir. */
-
-  /* Find nearest FS ancestor dir of current FS path and copyfrom_parent */
-  ancestor_relpath = svn_relpath_get_longest_ancestor(dir_repos_relpath,
-                                                      copyfrom_relpath,
-                                                      scratch_pool);
-
-  /* Move 'up' the working copy to what ought to be the common ancestor dir. */
-  levels_up = svn_path_component_count(dir_repos_relpath)
-              - svn_path_component_count(ancestor_relpath);
-
-  /* Walk up the path dirent safe */
-  ancestor_abspath = dir_abspath;
-  while (levels_up-- > 0)
-    ancestor_abspath = svn_dirent_dirname(ancestor_abspath, scratch_pool);
-
-  /* Verify hypothetical ancestor */
-  err = svn_wc__db_scan_base_repos(&repos_relpath, &repos_root_url,
-                                   &repos_uuid,
-                                   db, ancestor_abspath,
-                                   scratch_pool, scratch_pool);
-
-  if (err && ((err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY) ||
-              (err->apr_err == SVN_ERR_WC_PATH_FOUND)))
-    {
-      svn_error_clear(err);
-      return SVN_NO_ERROR;
-    }
-  else
-    SVN_ERR(err);
-
-  /* If we got this far, we know that the ancestor dir exists, and
-     that it's a working copy too.  But is it from the same
-     repository?  And does it represent the URL we expect it to? */
-  if ((strcmp(dir_repos_uuid, repos_uuid) != 0)
-      || (strcmp(dir_repos_root_url, repos_root_url) != 0)
-      || (strcmp(ancestor_relpath, repos_relpath) != 0))
-    return SVN_NO_ERROR;
-
-  /* Add the remaining components to cwd, then add the remaining relpath to
-     where we hope the copyfrom_relpath file exists. */
-  local_abspath = svn_dirent_join(ancestor_abspath,
-                                 svn_dirent_skip_ancestor(ancestor_relpath,
-                                                          copyfrom_relpath),
-                                 scratch_pool);
-
-  /* Verify file in expected location */
-  {
-    svn_revnum_t rev, changed_rev;
-    svn_wc__db_status_t status, base_status;
-    svn_boolean_t conflicted, have_base;
-    const svn_checksum_t *checksum;
-
-    err = svn_wc__db_read_info(&status, NULL, &rev, &repos_relpath,
-                               &repos_root_url, &repos_uuid, &changed_rev,
-                               NULL, NULL, NULL, NULL, &checksum, NULL, NULL,
-                               NULL, NULL, NULL, NULL, NULL, NULL, &have_base,
-                               NULL, &conflicted, NULL,
-                               db, local_abspath, scratch_pool, scratch_pool);
-
-    if (err && ((err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY ||
-                (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND))))
-      {
-        svn_error_clear(err);
-        return SVN_NO_ERROR;
-      }
-    else
-      SVN_ERR(err);
-
-    /* Check if we have an added node with the right copyfrom information, as
-       this is what you would see on a file move. */
-       
-    if (status == svn_wc__db_status_added)
-      {
-        const char *op_root_abspath;
-        const char *original_repos_relpath, *original_root_url;
-        const char *original_uuid;
-        svn_revnum_t original_rev;
-
-        SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath,
-                                         &repos_relpath, &repos_root_url,
-                                         &repos_uuid, &original_repos_relpath,
-                                         &original_root_url, &original_uuid,
-                                         &original_rev,
-                                         db, local_abspath,
-                                         scratch_pool, scratch_pool));
-
-        if (status == svn_wc__db_status_copied
-            || status == svn_wc__db_status_moved_here)
-          {
-            original_repos_relpath = svn_relpath_join(
-                                    original_repos_relpath,
-                                    svn_dirent_skip_ancestor(op_root_abspath,
-                                                             local_abspath),
-                                    scratch_pool);
-
-            /* If the repository location matches our exact guess and
-               the file's recorded revisions tell us that the file had the
-               same contents at the copyfrom_revision, we can use this
-               data as new_base */
-            if (strcmp(original_repos_relpath, copyfrom_relpath) == 0
-                && strcmp(original_root_url, dir_repos_root_url) == 0
-                && strcmp(original_uuid, dir_repos_uuid) == 0
-                && strcmp(repos_relpath, copyfrom_relpath) == 0
-                && strcmp(repos_root_url, dir_repos_root_url) == 0
-                && strcmp(repos_uuid, dir_repos_uuid) == 0
-
-                && SVN_IS_VALID_REVNUM(changed_rev)
-                && changed_rev <= copyfrom_rev
-                && copyfrom_rev <= original_rev)
-              {
-                svn_node_kind_t kind;
-                svn_boolean_t text_changed;
-
-                /* WORKING_NODE has the right new-BASE information,
-                   so we have at least a partial result. */
-                SVN_ERR(svn_wc__db_pristine_read(new_base_contents,
-                                                 db, local_abspath, checksum,
-                                                 result_pool, scratch_pool));
-                SVN_ERR(svn_wc__get_pristine_props(new_base_props,
-                                                   db, local_abspath,
-                                                   result_pool, scratch_pool));
-
-                /* If the node is conflicted, that might have happened because
-                   the node was deleted. Which might indicate that we have
-                   a file move. In this case we like the real file data */
-                if (!conflicted
-                    && status == svn_wc__db_status_copied)
-                  return SVN_NO_ERROR; /* A local copy is no local modification
-                                          that we should keep */
-
-                /* ### TODO: Add verification to check that the conflict
-                       tells us that this is the right thing to do.
-
-                   ### Pre 1.7 we just assumed that it is ok without checking for
-                       conflicts, so this is not a regression */
-
-                SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
-
-                if (kind != svn_node_file)
-                  return SVN_NO_ERROR; /* Nothing to copy */
-
-                SVN_ERR(svn_wc__internal_text_modified_p(&text_changed, db,
-                                                         local_abspath, FALSE,
-                                                         TRUE, scratch_pool));
-
-                if (!text_changed)
-                  return SVN_NO_ERROR; /* Take the easy route */
-
-                SVN_ERR(svn_stream_open_readonly(new_contents, local_abspath,
-                                                 result_pool, scratch_pool));
-
-                SVN_ERR(svn_wc__get_actual_props(new_props, db, local_abspath,
-                                                 result_pool, scratch_pool));
-
-                return SVN_NO_ERROR;
-              }
-          }
-      }
-
-    if (!have_base)
-      return SVN_NO_ERROR;
-
-    base_status = status;
-
-    if (status != svn_wc__db_status_normal)
-      SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &rev,
-                                       &repos_relpath, &repos_root_url,
-                                       &repos_uuid, &changed_rev, NULL,
-                                       NULL, NULL, NULL, &checksum, NULL,
-                                       NULL, NULL,
-                                       db, local_abspath,
-                                       scratch_pool, scratch_pool));
-
-    if (base_status != svn_wc__db_status_normal)
-      return SVN_NO_ERROR; /* No interesting BASE_NODE */
-
-    if (!repos_relpath || !repos_root_url || !repos_uuid)
-      SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath, &repos_root_url,
-                                         &repos_uuid,
-                                         db, local_abspath,
-                                         scratch_pool, scratch_pool));
-
-    /* Is it from the same repository */
-    if ((strcmp(dir_repos_uuid, repos_uuid) != 0)
-        || (strcmp(dir_repos_root_url, repos_root_url) != 0)
-        || (strcmp(copyfrom_relpath, repos_relpath) != 0))
-      return SVN_NO_ERROR;
-
-    /* Ok, we know that we look at the right node, but do we have the
-       right revision?
-
-       To be sure that the base node has the right properties and text,
-       the node must be the same in copyfrom_rev and changed_rev, which
-       is only true within this specific range
-       */
-    if (!(SVN_IS_VALID_REVNUM(changed_rev)
-          && changed_rev <= copyfrom_rev
-          && copyfrom_rev <= rev))
-      {
-        return SVN_NO_ERROR;
-      }
-
-    /* BASE_NODE has the right new-BASE information,
-       so we have at least a partial result. */
-    SVN_ERR(svn_wc__db_pristine_read(new_base_contents,
-                                     db, local_abspath, checksum,
-                                     result_pool, scratch_pool));
-
-    SVN_ERR(svn_wc__db_base_get_props(new_base_props,
-                                      db, local_abspath, result_pool,
-                                      scratch_pool));
-
-    /* If the node is in status normal, the user probably intended to make
-       a copy of this in-wc node, so copy its local changes over to
-       the new file. */
-    if (status == svn_wc__db_status_normal)
-      {
-        svn_node_kind_t kind;
-        svn_boolean_t text_changed;
-
-        SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
-
-        if (kind != svn_node_file)
-          return SVN_NO_ERROR; /* Nothing to copy */
-
-        SVN_ERR(svn_wc__internal_text_modified_p(&text_changed, db,
-                                                 local_abspath, FALSE,
-                                                 TRUE, scratch_pool));
-
-        if (!text_changed)
-            return SVN_NO_ERROR; /* Take the easy route */
-
-        SVN_ERR(svn_stream_open_readonly(new_contents, local_abspath,
-                                         result_pool, scratch_pool));
-
-        SVN_ERR(svn_wc__get_actual_props(new_props, db, local_abspath,
-                                         result_pool, scratch_pool));
-      }
-  }
-  return SVN_NO_ERROR;
-}
-
-
-/* Given a set of properties PROPS_IN, find all regular properties
-   and shallowly copy them into a new set (allocate the new set in
-   POOL, but the set's members retain their original allocations). */
-static apr_hash_t *
-copy_regular_props(apr_hash_t *props_in,
-                   apr_pool_t *pool)
-{
-  apr_hash_t *props_out = apr_hash_make(pool);
-  apr_hash_index_t *hi;
-
-  for (hi = apr_hash_first(pool, props_in); hi; hi = apr_hash_next(hi))
-    {
-      const char *propname = svn__apr_hash_index_key(hi);
-      const svn_string_t *propval = svn__apr_hash_index_val(hi);
-
-      if (svn_wc_is_normal_prop(propname))
-        apr_hash_set(props_out, propname, APR_HASH_KEY_STRING, propval);
-    }
-  return props_out;
-}
-
-
-/* Do the "with history" part of add_file().
-
-   Attempt to locate COPYFROM_PATH@COPYFROM_REV within the existing working
-   copy.  If a node with such a base is found, copy the base *and working*
-   text and properties from there.  If not found, fetch the text and
-   properties from the repository by calling PB->edit_baton->fetch_func.
-
-   Store the copied base and working text in new temporary files in the adm
-   tmp area of the parent directory, whose baton is PB.  Set
-   TFB->copied_text_base_* and TFB->copied_working_text to their paths and
-   checksums.  Set TFB->copied_*_props to the copied properties.
-
-   After this function returns, subsequent apply_textdelta() commands coming
-   from the server may further alter the file before it is installed.
-
-   Ensure the resulting text base is in the pristine store, and set
-   TFB->copied_text_base_* to its readable abspath and checksums.
-*/
-static svn_error_t *
-add_file_with_history(struct dir_baton *pb,
-                      const char *copyfrom_path,
-                      svn_revnum_t copyfrom_rev,
-                      struct file_baton *tfb,
-                      apr_pool_t *result_pool,
-                      apr_pool_t *scratch_pool)
-{
-  struct edit_baton *eb = pb->edit_baton;
-  svn_stream_t *copied_stream;
-  const char *copied_text_base_tmp_abspath;
-  svn_wc__db_t *db = eb->db;
-  svn_stream_t *new_base_contents, *new_contents;
-  apr_hash_t *new_base_props, *new_props;
-
-  SVN_ERR_ASSERT(copyfrom_path[0] == '/');
-
-  tfb->added_with_history = TRUE;
-
-  /* Attempt to locate the copyfrom_path in the working copy first. */
-  SVN_ERR(locate_copyfrom(&new_base_contents, &new_contents,
-                          &new_base_props, &new_props,
-                          db, pb->local_abspath,
-                          copyfrom_path+1, /* Create repos_relpath */
-                          copyfrom_rev, result_pool, scratch_pool));
-
-  /* Open the text base for writing (this will get us a temporary file).  */
-  SVN_ERR(svn_wc__open_writable_base(&copied_stream,
-                                     &copied_text_base_tmp_abspath,
-  /* Compute an MD5 checksum for the stream as we write stuff into it.
-     ### this is temporary. in many cases, we already *know* the checksum
-     ### since it is a copy. */
-                                     &tfb->copied_text_base_md5_checksum,
-                                     &tfb->copied_text_base_sha1_checksum,
-                                     db, pb->local_abspath,
-                                     result_pool, scratch_pool));
-
-  if (new_base_contents && new_base_props)
-    {
-      /* Copy the existing file's text-base over to the (temporary)
-         new text-base, where the file baton expects it to be.  Get
-         the text base and props from the usual place or from the
-         revert place, depending on scheduling. */
-      SVN_ERR(svn_stream_copy3(new_base_contents, copied_stream,
-                               eb->cancel_func, eb->cancel_baton,
-                               scratch_pool));
-
-      if (!new_props)
-        new_props = new_base_props;
-    }
-  else  /* Couldn't find a file to copy  */
-    {
-      /* Fall back to fetching it from the repository instead. */
-
-      if (! eb->fetch_func)
-        return svn_error_create(SVN_ERR_WC_INVALID_OP_ON_CWD, NULL,
-                                _("No fetch_func supplied to update_editor"));
-
-      /* Fetch the repository file's text-base and base-props;
-         svn_stream_close() automatically closes the text-base file for us. */
-
-      /* copyfrom_path is a absolute path, fetch_func requires a path relative
-         to the root of the repository so skip the first '/'. */
-      SVN_ERR(eb->fetch_func(eb->fetch_baton, copyfrom_path + 1, copyfrom_rev,
-                             copied_stream,
-                             NULL, &new_base_props, scratch_pool));
-      SVN_ERR(svn_stream_close(copied_stream));
-
-      /* Filter out wc-props */
-      /* ### Do we get new values as modification or should these really
-             be installed? */
-      new_base_props = svn_prop_hash_dup(copy_regular_props(new_base_props,
-                                                             scratch_pool),
-                                         result_pool);
-
-      new_props = new_base_props;
-    }
-
-  SVN_ERR(svn_wc__db_pristine_install(db, copied_text_base_tmp_abspath,
-                                      tfb->copied_text_base_sha1_checksum,
-                                      tfb->copied_text_base_md5_checksum,
-                                      scratch_pool));
-
-  tfb->copied_base_props = new_base_props;
-   /* ### Currently we always have to set this even though we don't have
-          a real copy, or update_tests.py 60 "add_moved_file_has_props" fails
-    */
-  tfb->copied_working_props = new_props;
-
-  if (new_contents)
-    {
-      /* If we copied an existing file over, we need to copy its
-         working text too, to preserve any local mods.  (We already
-         read its working *props* into tfb->copied_working_props.) */
-      const char *temp_dir_abspath;
-      svn_stream_t *tmp_contents;
-
-        /* Make a unique file name for the copied working text. */
-      SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath,
-                                             db, pb->local_abspath,
-                                             scratch_pool, scratch_pool));
-
-      SVN_ERR(svn_stream_open_unique(&tmp_contents, &tfb->copied_working_text,
-                                     temp_dir_abspath, svn_io_file_del_none,
-                                     result_pool, scratch_pool));
-
-      SVN_ERR(svn_stream_copy3(new_contents, tmp_contents, eb->cancel_func,
-                               eb->cancel_baton,
-                               scratch_pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
-
 /* An svn_delta_editor_t function. */
 static svn_error_t *
 add_file(const char *path,
@@ -3605,11 +3050,7 @@ add_file(const char *path,
   svn_wc_conflict_description2_t *tree_conflict = NULL;
   svn_error_t *err;
 
-  /* Semantic check.  Either both "copyfrom" args are valid, or they're
-     NULL and SVN_INVALID_REVNUM.  A mixture is illegal semantics. */
-  SVN_ERR_ASSERT((copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_rev))
-                 || (!copyfrom_path &&
-                     !SVN_IS_VALID_REVNUM(copyfrom_rev)));
+  SVN_ERR_ASSERT(! (copyfrom_path || SVN_IS_VALID_REVNUM(copyfrom_rev)));
 
   SVN_ERR(make_file_baton(&fb, pb, path, TRUE, pool));
   *file_baton = fb;
@@ -3839,15 +3280,12 @@ add_file(const char *path,
 
           /* If we are skipping an add, we need to tell the WC that
            * there's a node supposed to be here which we don't have. */
-          SVN_ERR(svn_wc__db_base_add_absent_node(eb->db, fb->local_abspath,
+          SVN_ERR(svn_wc__db_base_add_not_present_node(eb->db, fb->local_abspath,
                                                   fb->new_relpath,
                                                   eb->repos_root,
                                                   eb->repos_uuid,
-                                                  (eb->target_revision?
-                                                   *eb->target_revision
-                                                   : SVN_INVALID_REVNUM),
+                                                  *eb->target_revision,
                                                   svn_wc__db_kind_file,
-                                                  svn_wc__db_status_not_present,
                                                   NULL, NULL, subpool));
           SVN_ERR(remember_skipped_tree(eb, fb->local_abspath));
 
@@ -3876,13 +3314,6 @@ add_file(const char *path,
                       svn_wc_notify_tree_conflict, subpool);
     }
 
-  /* Now, if this is an add with history, do the history part. */
-  if (copyfrom_path && !fb->skip_this)
-    {
-      SVN_ERR(add_file_with_history(pb, copyfrom_path, copyfrom_rev,
-                                    fb, pool, subpool));
-    }
-
   svn_pool_destroy(subpool);
 
   return SVN_NO_ERROR;
@@ -4833,7 +4264,6 @@ close_file(void *file_baton,
    * a text conflict. So flag a tree conflict here. */
   if (fb->adding_file && fb->add_existed)
     {
-      int i;
       svn_boolean_t local_is_link = FALSE;
       svn_boolean_t incoming_is_link = FALSE;
 
@@ -4852,6 +4282,8 @@ close_file(void *file_baton,
         }
       else
         {
+          int i;
+
           for (i = 0; i < regular_props->nelts; ++i)
             {
               const svn_prop_t *prop = &APR_ARRAY_IDX(regular_props, i,
@@ -4917,32 +4349,31 @@ close_file(void *file_baton,
       /* We will ALWAYS have properties to save (after a not-dry-run merge).  */
       SVN_ERR_ASSERT(new_base_props != NULL && new_actual_props != NULL);
 
-    /* Merge the text. This will queue some additional work.  */
-    SVN_ERR(merge_file(&all_work_items, &install_pristine, &install_from,
-                       &content_state, fb, new_text_base_sha1_checksum,
-                       pool, scratch_pool));
-
-    if (install_pristine)
-      {
-        svn_boolean_t record_fileinfo;
-
-        /* If we are installing from the pristine contents, then go ahead and
-           record the fileinfo. That will be the "proper" values. Installing
-           from some random file means the fileinfo does NOT correspond to
-           the pristine (in which case, the fileinfo will be cleared for
-           safety's sake).  */
-        record_fileinfo = install_from == NULL;
-
-        SVN_ERR(svn_wc__wq_build_file_install(&work_item,
-                                              eb->db,
-                                              fb->local_abspath,
-                                              install_from,
-                                              eb->use_commit_times,
-                                              record_fileinfo,
-                                              pool, pool));
-        all_work_items = svn_wc__wq_merge(all_work_items, work_item, pool);
-      }
+      /* Merge the text. This will queue some additional work.  */
+      SVN_ERR(merge_file(&all_work_items, &install_pristine, &install_from,
+                         &content_state, fb, new_text_base_sha1_checksum,
+                         pool, scratch_pool));
+
+      if (install_pristine)
+        {
+          svn_boolean_t record_fileinfo;
+
+          /* If we are installing from the pristine contents, then go ahead and
+             record the fileinfo. That will be the "proper" values. Installing
+             from some random file means the fileinfo does NOT correspond to
+             the pristine (in which case, the fileinfo will be cleared for
+             safety's sake).  */
+          record_fileinfo = install_from == NULL;
 
+          SVN_ERR(svn_wc__wq_build_file_install(&work_item,
+                                                eb->db,
+                                                fb->local_abspath,
+                                                install_from,
+                                                eb->use_commit_times,
+                                                record_fileinfo,
+                                                pool, pool));
+          all_work_items = svn_wc__wq_merge(all_work_items, work_item, pool);
+        }
     }
   else
     {
@@ -5097,7 +4528,8 @@ close_file(void *file_baton,
   /* Deal with the WORKING tree, based on updates to the BASE tree.  */
 
   /* An ancestor was locally-deleted. This file is being added within
-     that tree. We need to schedule this file for deletion.  */
+     that tree. We need to schedule this file for deletion.  This
+     should happen at the same time as svn_wc__db_base_add_file.  */
   if (fb->dir_baton->in_deleted_and_tree_conflicted_subtree && fb->adding_file)
     {
       SVN_ERR(svn_wc__db_temp_op_delete(eb->db, fb->local_abspath, pool));
@@ -5115,23 +4547,10 @@ close_file(void *file_baton,
      properties merge. */
   if (! fb->adding_base_under_local_add)
     {
-      apr_hash_t *props;
-      apr_array_header_t *prop_diffs;
-
       SVN_ERR_ASSERT(new_actual_props != NULL);
 
-      /* If the ACTUAL props are the same as the BASE props, then we
-         should "write" a NULL. This will remove the props from the
-         ACTUAL_NODE row, and remove the old-style props file, indicating
-         "no change".  */
-      props = new_actual_props;
-      SVN_ERR(svn_prop_diffs(&prop_diffs, new_actual_props, new_base_props,
-                             pool));
-      if (prop_diffs->nelts == 0)
-        props = NULL;
-
       SVN_ERR(svn_wc__db_op_set_props(eb->db, fb->local_abspath,
-                                      props,
+                                      new_actual_props,
                                       NULL /* conflict */,
                                       NULL /* work_item */,
                                       pool));
@@ -5336,7 +4755,7 @@ tweak_entries(svn_wc__db_t *db,
       svn_wc__db_status_t status;
 
       const char *child_repos_relpath = NULL;
-      svn_boolean_t excluded;
+      svn_boolean_t excluded, is_file_external;
 
       svn_pool_clear(iterpool);
 
@@ -5346,12 +4765,21 @@ tweak_entries(svn_wc__db_t *db,
                                                child_basename, iterpool);
 
       child_abspath = svn_dirent_join(dir_abspath, child_basename, iterpool);
+
+      /* Skip stuff we've already decided to exclude. */
       excluded = (apr_hash_get(exclude_paths, child_abspath,
                                APR_HASH_KEY_STRING) != NULL);
-
       if (excluded)
         continue;
 
+      /* Skip stuff we've identified as file externals.  (If we're
+         here, we were doing an update of a directory, not the actual
+         switch handling of a file external itself.) */
+      SVN_ERR(svn_wc__internal_is_file_external(&is_file_external, db,
+                                                child_abspath, iterpool));
+      if (is_file_external)
+        continue;
+
       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,
@@ -5577,8 +5005,6 @@ make_editor(svn_revnum_t *target_revisio
             void *conflict_baton,
             svn_wc_external_update_t external_func,
             void *external_baton,
-            svn_wc_get_file_t fetch_func,
-            void *fetch_baton,
             const char *diff3_cmd,
             const apr_array_header_t *preserved_exts,
             const svn_delta_editor_t **editor,
@@ -5653,8 +5079,6 @@ make_editor(svn_revnum_t *target_revisio
   eb->cancel_baton             = cancel_baton;
   eb->conflict_func            = conflict_func;
   eb->conflict_baton           = conflict_baton;
-  eb->fetch_func               = fetch_func;
-  eb->fetch_baton              = fetch_baton;
   eb->allow_unver_obstructions = allow_unver_obstructions;
   eb->skipped_trees            = apr_hash_make(edit_pool);
   eb->ext_patterns             = preserved_exts;
@@ -5724,8 +5148,6 @@ svn_wc_get_update_editor4(const svn_delt
                           svn_boolean_t allow_unver_obstructions,
                           const char *diff3_cmd,
                           const apr_array_header_t *preserved_exts,
-                          svn_wc_get_file_t fetch_func,
-                          void *fetch_baton,
                           svn_wc_conflict_resolver_func_t conflict_func,
                           void *conflict_baton,
                           svn_wc_external_update_t external_func,
@@ -5744,7 +5166,6 @@ svn_wc_get_update_editor4(const svn_delt
                      cancel_func, cancel_baton,
                      conflict_func, conflict_baton,
                      external_func, external_baton,
-                     fetch_func, fetch_baton,
                      diff3_cmd, preserved_exts, editor, edit_baton,
                      result_pool, scratch_pool);
 }
@@ -5763,8 +5184,6 @@ svn_wc_get_switch_editor4(const svn_delt
                           svn_boolean_t allow_unver_obstructions,
                           const char *diff3_cmd,
                           const apr_array_header_t *preserved_exts,
-                          svn_wc_get_file_t fetch_func,
-                          void *fetch_baton,
                           svn_wc_conflict_resolver_func_t conflict_func,
                           void *conflict_baton,
                           svn_wc_external_update_t external_func,
@@ -5786,7 +5205,6 @@ svn_wc_get_switch_editor4(const svn_delt
                      cancel_func, cancel_baton,
                      conflict_func, conflict_baton,
                      external_func, external_baton,
-                     fetch_func, fetch_baton,
                      diff3_cmd, preserved_exts,
                      editor, edit_baton,
                      result_pool, scratch_pool);
@@ -5909,11 +5327,10 @@ svn_wc__check_wc_root(svn_boolean_t *wc_
   svn_wc__db_status_t status;
   svn_wc__db_kind_t my_kind;
 
-  /* Go ahead and initialize our return value to the most common
-     (code-wise) values. */
   if (!kind)
     kind = &my_kind;
 
+  /* Initialize our return values to the most common (code-wise) values. */
   *wc_root = TRUE;
   if (switched)
     *switched = FALSE;
@@ -6051,6 +5468,18 @@ svn_wc__strictly_is_wc_root(svn_boolean_
 
 
 svn_error_t *
+svn_wc_get_wc_root(const char **wcroot_abspath,
+                   svn_wc_context_t *wc_ctx,
+                   const char *local_abspath,
+                   apr_pool_t *scratch_pool,
+                   apr_pool_t *result_pool)
+{
+  return svn_wc__db_get_wcroot(wcroot_abspath, wc_ctx->db,
+                               local_abspath, scratch_pool, result_pool);
+}
+
+
+svn_error_t *
 svn_wc_get_actual_target2(const char **anchor,
                           const char **target,
                           svn_wc_context_t *wc_ctx,
@@ -6114,8 +5543,6 @@ svn_wc_add_repos_file4(svn_wc_context_t 
                        svn_revnum_t copyfrom_rev,
                        svn_cancel_func_t cancel_func,
                        void *cancel_baton,
-                       svn_wc_notify_func2_t notify_func,
-                       void *notify_baton,
                        apr_pool_t *scratch_pool)
 {
   svn_wc__db_t *db = wc_ctx->db;
@@ -6131,7 +5558,6 @@ svn_wc_add_repos_file4(svn_wc_context_t 
   const char *original_root_url;
   const char *original_repos_relpath;
   const char *original_uuid;
-  apr_hash_t *actual_props;
   svn_revnum_t changed_rev;
   apr_time_t changed_date;
   const char *changed_author;
@@ -6253,25 +5679,6 @@ svn_wc_add_repos_file4(svn_wc_context_t 
                                    entry_props, pool, pool));
   }
 
-  /* Add some work items to install the properties.  */
-  {
-    if (new_props == NULL)
-      {
-        actual_props = NULL;
-      }
-    else
-      {
-        apr_array_header_t *prop_diffs;
-
-        SVN_ERR(svn_prop_diffs(&prop_diffs, new_props, new_base_props,
-                               pool));
-        if (prop_diffs->nelts == 0)
-          actual_props = NULL;
-        else
-          actual_props = new_props;
-      }
-  }
-
   /* Copy NEW_BASE_CONTENTS into a temporary file so our log can refer to
      it, and set TMP_TEXT_BASE_ABSPATH to its path.  Compute its
      NEW_TEXT_BASE_MD5_CHECKSUM and NEW_TEXT_BASE_SHA1_CHECKSUM as we copy. */
@@ -6396,7 +5803,7 @@ svn_wc_add_repos_file4(svn_wc_context_t 
   /* ### if below fails, then the above db change would remain :-(  */
 
   SVN_ERR(svn_wc__db_op_set_props(db, local_abspath,
-                                  actual_props,
+                                  new_props,
                                   NULL /* conflict */,
                                   all_work_items,
                                   pool));

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_wc/upgrade.c?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_wc/upgrade.c Thu Nov  4 20:48:21 2010
@@ -720,7 +720,7 @@ db_kind_from_node_kind(svn_node_kind_t n
 static svn_error_t *
 migrate_single_tree_conflict_data(svn_sqlite__db_t *sdb,
                                   const char *tree_conflict_data,
-                                  apr_uint64_t wc_id,
+                                  apr_int64_t wc_id,
                                   const char *local_relpath,
                                   apr_pool_t *scratch_pool)
 {
@@ -847,7 +847,7 @@ migrate_tree_conflicts(svn_sqlite__db_t 
   SVN_ERR(svn_sqlite__step(&have_row, select_stmt));
   while (have_row)
     {
-      apr_uint64_t wc_id;
+      apr_int64_t wc_id;
       const char *local_relpath;
       const char *tree_conflict_data;
 
@@ -987,21 +987,21 @@ migrate_node_props(const char *dir_abspa
                                      apr_pstrcat(scratch_pool,
                                                  name,
                                                  SVN_WC__BASE_EXT,
-                                                 NULL),
+                                                 (char *)NULL),
                                      scratch_pool);
 
       revert_abspath = svn_dirent_join(basedir_abspath,
                                        apr_pstrcat(scratch_pool,
                                                    name,
                                                    SVN_WC__REVERT_EXT,
-                                                   NULL),
+                                                   (char *)NULL),
                                        scratch_pool);
 
       working_abspath = svn_dirent_join(propsdir_abspath,
                                         apr_pstrcat(scratch_pool,
                                                     name,
                                                     SVN_WC__WORK_EXT,
-                                                    NULL),
+                                                    (char *)NULL),
                                         scratch_pool);
     }
 
@@ -1195,6 +1195,16 @@ bump_to_17(void *baton, svn_sqlite__db_t
   return SVN_NO_ERROR;
 }
 
+#if (SVN_WC__VERSION > 19)
+static svn_error_t *
+bump_to_20(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_NODES));
+  SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_UPGRADE_TO_20));
+  return SVN_NO_ERROR;
+}
+#endif
+
 
 #if 0 /* ### no tree conflict migration yet */
 
@@ -1482,22 +1492,28 @@ svn_wc__upgrade_sdb(int *result_format,
         *result_format = 18;
         /* FALLTHROUGH  */
 
-#if (SVN_WC__VERSION > 18)
       case 18:
         return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                                  _("The working copy '%s' is at format 18; "
                                    "use 'tools/dev/wc-ng/bump-to-19.py' to "
                                    "upgrade it"), wcroot_abspath);
+
+#if (SVN_WC__VERSION > 19)
+      case 19:
+        SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_20, &bb,
+                                             scratch_pool));
+        *result_format = 20;
+        /* FALLTHROUGH  */
 #endif
 
       /* ### future bumps go here.  */
 #if 0
-      case 98:
+      case XXX-1:
         /* Revamp the recording of tree conflicts.  */
-        SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_XXX,
-                                             (void *)wcroot_abspath,
+        SVN_ERR(svn_sqlite__with_transaction(sdb, bump_to_XXX, &bb,
                                              scratch_pool));
-        *result_format = 99;
+        *result_format = XXX;
+        /* FALLTHROUGH  */
 #endif
     }
 
@@ -1691,6 +1707,7 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx,
                                     scratch_pool);
   pristine_to = svn_wc__adm_child(local_abspath, PRISTINE_STORAGE_RELPATH,
                                   scratch_pool);
+  SVN_ERR(svn_wc__ensure_directory(pristine_from, scratch_pool));
   SVN_ERR(svn_wc__wq_build_file_move(&work_item, db,
                                      pristine_from, pristine_to,
                                      scratch_pool, scratch_pool));

Modified: subversion/branches/py-tests-as-modules/subversion/libsvn_wc/wc-metadata.sql
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/libsvn_wc/wc-metadata.sql?rev=1031230&r1=1031229&r2=1031230&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/libsvn_wc/wc-metadata.sql (original)
+++ subversion/branches/py-tests-as-modules/subversion/libsvn_wc/wc-metadata.sql Thu Nov  4 20:48:21 2010
@@ -76,250 +76,9 @@ CREATE UNIQUE INDEX I_LOCAL_ABSPATH ON W
 
 /* ------------------------------------------------------------------------- */
 
-/*
-The BASE_NODE table:
-
-  BASE is what we get from the server.  It is the *absolute* pristine copy.
-  You need to use checkout, update, switch, or commit to alter your view of
-  the repository.
-
-  In the BASE tree, each node corresponds to a particular node-rev in the
-  repository.  It can be a mixed-revision tree.  Each node holds either a
-  copy of the node-rev as it exists in the repository (if presence ==
-  'normal'), or a place-holder (if presence == 'absent' or 'excluded' or
-  'not-present').
-                                                  [Quoted from wc_db.h]
-
-Overview of BASE_NODE columns:
-
-  Indexing columns: (wc_id, local_relpath, parent_relpath)
-
-  (presence)
-
-    - The Node-Rev, Content and Last-Change column groups take one of the
-      states shown in the table below, according to the 'presence':
-
-                                    Has           Has       Has
-      'presence'      Meaning       Node-Rev?     Content?  Last-Change?
-      ----------      -----------   -----------   --------  ------------
-      normal      =>  Present       Yes           Yes       Yes
-      incomplete  =>  Incomplete    Yes           Partial   No ### ?
-      absent      =>  Unauthz       Yes           No        No
-      excluded    =>  Unwanted      Yes           No        No
-      not-present =>  Nonexistent   No            No        No
-
-    - If presence==incomplete, this node refers to an existing node-rev but
-      its Content is not fully and correctly stored.  In particular, if it
-      is a directory, some rows that should represent its children may not
-      exist or may be in the wrong state.  This is intended to be a
-      temporary state, e.g. during an update.
-
-    - If presence==absent or ==excluded, this row refers to a node that
-      exists in the repo, but the node is not stored in the WC.
-
-    - If presence==not-present, this row indicates that its parent in the WC
-      is a directory that, in its pristine state, would have a child of this
-      name.  However, this child was updated or switched to a node-revision
-      that does not exist.  Information about which node-revision it was
-      updated or switched to is lost; only the fact that it is currently not
-      present is remembered.
-
-    - The order of precedence of the negative presence values is:
-        'excluded' if administratively excluded from the WC, else
-        'absent' if server doesn't authorize reading the path, else
-        'not-present' if it does not exist in repo.
-
-  Node-Rev columns: (repos_id, repos_relpath, revnum)
-
-    - The Node-Rev group points to the corresponding repository node-rev.
-
-    - If not used (as specified by the 'presence' table above), the values
-      are undefined.
-      ### Perhaps we should set them to null to make it clearer.
-
-  Content columns: (kind, properties, depth, target, checksum)
-                    ----  ----------  -----  ------  --------
-                    'dir'    Yes      Yes    null    null
-                'symlink'    Yes      null   Yes     null
-                   'file'    Yes      null   null    Yes
-                'unknown'    null     null   null    null
-
-    - The Content columns take one of the states shown in the table above.
-      If Content is present, a copy of the Node-Rev's content is stored
-      locally according to one of the first three rows in the table above,
-      otherwise kind==unknown and the other columns are null.
-
-    - If kind==dir, the children are represented by the existence of other
-      BASE_NODE rows.  For each immediate child of 'repos_relpath'@'revnum'
-      in the repo, subject to 'depth', a BASE_NODE row exists with its
-      'local_relpath' being this node's 'local_relpath' plus the child's
-      basename.  (Rows may also exist for additional children which are
-      outside the scope of 'depth' or do not exist as children of this
-      node-rev in the repository, including 'externals' and paths updated to
-      a revision in which they do exist.)  There is no distinction between
-      depth==immediates and depth==infinity here.
-
-    - If kind==symlink, the target path is contained in 'target'.
-
-    - If kind==file, the content is contained in the Pristine Store,
-      referenced by its SHA-1 checksum 'checksum'.
-
-  Last-Change columns: (changed_rev, changed_date, changed_author)
-
-    - Specifies the revision in which the content was last changed before
-      Node-Rev, following copies and not counting the copy operation itself
-      as a change.
-
-    - Does not specify the revision in which this node first appeared at
-      the repository path 'repos_relpath', which could be more recent than
-      the last change of this node's content.
-
-    - Includes a copy of the corresponding date and author rev-props.
-
-    - If not used (as specified by the 'presence' table above), all null.
-      ### Not checked; in practice these columns may have undefined values.
-
-  Working file status: (translated_size, last_mod_time)
-
-    - Present iff kind==file and node has no WORKING_NODE row, otherwise
-      null.  (If kind==file and node has a WORKING_NODE row, the info is
-      recorded in that row).  ### True?
-
-    - Records the status of the working file on disk, for the purpose of
-      detecting quickly whether that file has been modified.
-
-    - Logically belongs to the ACTUAL_NODE table but is recorded in the
-      BASE_NODE and WORKING_NODE tables instead to avoid the overhead of
-      storing an ACTUAL_NODE row for each unmodified file.
-
-    - Records the actual size and mod-time of the disk file at the time when
-      its content was last determined to be logically unmodified relative to
-      its base, taking account of keywords and EOL style.
-
-  (dav_cache)
-
-    - Content is opaque to libsvn_wc.  ### ?
-
-    - Lifetime is managed by the WC: values cleared to null at certain times.
-      ### To be documented.
-
-  (incomplete_children)
-
-    - Obsolete, unused.
-
-  (file_external)
-
-    - ### To be obsoleted?
-*/
-
-CREATE TABLE BASE_NODE (
-  /* specifies the location of this node in the local filesystem. wc_id
-     implies an absolute path, and local_relpath is relative to that
-     location (meaning it will be "" for the wcroot). */
-  wc_id  INTEGER NOT NULL REFERENCES WCROOT (id),
-  local_relpath  TEXT NOT NULL,
-
-  /* The repository this node is part of, and the relative path (from its
-     root) within revision "revnum" of that repository.  These may be NULL,
-     implying they should be derived from the parent and local_relpath.
-     Non-NULL typically indicates a switched node.
-
-     Note: they must both be NULL, or both non-NULL. */
-  repos_id  INTEGER REFERENCES REPOSITORY (id),
-  repos_relpath  TEXT,
-
-  /* parent's local_relpath for aggregating children of a given parent.
-     this will be "" if the parent is the wcroot. NULL if this is the
-     wcroot node. */
-  parent_relpath  TEXT,
-
-  /* Is this node "present" or has it been excluded for some reason?
-     The "base-deleted" presence value is not allowed.  */
-  presence  TEXT NOT NULL,
-
-  /* The node kind: "file", "dir", or "symlink", or "unknown" if the node is
-     not present. */
-  kind  TEXT NOT NULL,
-
-  /* The revision number in which "repos_relpath" applies in "repos_id".
-     this could be NULL for non-present nodes -- no info. */
-  revnum  INTEGER,
-
-  /* If this node is a file, then the SHA-1 checksum of the pristine text. */
-  checksum  TEXT,
-
-  /* The size in bytes of the working file when it had no local text
-     modifications. This means the size of the text when translated from
-     repository-normal format to working copy format with EOL style
-     translated and keywords expanded according to the properties in the
-     "properties" column of this row.
-
-     NULL if this node is not a file or if the size has not (yet) been
-     computed. */
-  translated_size  INTEGER,
-
-  /* Information about the last change to this node. changed_rev must be
-     not-null if this node has presence=="normal". changed_date and
-     changed_author may be null if the corresponding revprops are missing.
-
-     All three values are null for a not-present node.  */
-  changed_rev  INTEGER,
-  changed_date  INTEGER,  /* an APR date/time (usec since 1970) */
-  changed_author  TEXT,
-
-  /* NULL depth means "default" (typically svn_depth_infinity) */
-  depth  TEXT,
-
-  /* for kind==symlink, this specifies the target. */
-  symlink_target  TEXT,
-
-  /* The mod-time of the working file when it was last determined to be
-     logically unmodified relative to its base, taking account of keywords
-     and EOL style.
-
-     NULL if this node is not a file or if this info has not yet been
-     determined.
-   */
-  /* ### Do we need this?  We've currently got various mod time APIs
-     ### internal to libsvn_wc, but those might be used in answering some
-     ### question which is better answered some other way. */
-  last_mod_time  INTEGER,  /* an APR date/time (usec since 1970) */
-
-  /* serialized skel of this node's properties. NULL if we
-     have no information about the properties (a non-present node). */
-  properties  BLOB,
-
-  /* serialized skel of this node's dav-cache.  could be NULL if the
-     node does not have any dav-cache. */
-  dav_cache  BLOB,
-
-  /* ### this column is removed in format 13. it will always be NULL.  */
-  incomplete_children  INTEGER,
-
-  /* The serialized file external information. */
-  /* ### hack.  hack.  hack.
-     ### This information is already stored in properties, but because the
-     ### current working copy implementation is such a pain, we can't
-     ### readily retrieve it, hence this temporary cache column.
-     ### When it is removed, be sure to remove the extra column from
-     ### the db-tests.
-
-     ### Note: This is only here as a hack, and should *NOT* be added
-     ### to any wc_db APIs.  */
-  file_external  TEXT,
-
-  PRIMARY KEY (wc_id, local_relpath)
-  );
-
-CREATE INDEX I_PARENT ON BASE_NODE (wc_id, parent_relpath);
-
-
-/* ------------------------------------------------------------------------- */
-
 /* The PRISTINE table keeps track of pristine texts. Each pristine text is
    stored in a file which may be compressed. Each pristine text is
-   referenced by any number of rows in the BASE_NODE and WORKING_NODE
-   and ACTUAL_NODE tables.
+   referenced by any number of rows in the NODES and ACTUAL_NODE tables.
  */
 CREATE TABLE PRISTINE (
   /* The SHA-1 checksum of the pristine text. This is a unique key. The
@@ -337,7 +96,7 @@ CREATE TABLE PRISTINE (
   size  INTEGER,
 
   /* ### this will probably go away, in favor of counting references
-     ### that exist in BASE_NODE and WORKING_NODE. */
+     ### that exist in NODES. */
   refcount  INTEGER NOT NULL,
 
   /* Alternative MD5 checksum used for communicating with older
@@ -349,173 +108,16 @@ CREATE TABLE PRISTINE (
 
 /* ------------------------------------------------------------------------- */
 
-/* The WORKING_NODE table describes tree changes in the WC relative to the
-   BASE_NODE table.
-
-   The WORKING_NODE row for a given path exists iff a node at this path
-   is itself one of:
-
-     - deleted
-     - moved away [1]
-
-   and/or one of:
-
-     - added
-     - copied here [1]
-     - moved here [1]
-
-   or if this path is a child (or grandchild, etc.) under any such node.
-   (### Exact meaning of "child" when mixed-revision, switched, etc.?)
-
-   [1] The WC-NG "move" operation requires that both the source and
-   destination paths are represented in the BASE_NODE and WORKING_NODE
-   tables. The "copy" operation takes as its source a repository node,
-   regardless whether that node is also represented in the WC.
- */
-CREATE TABLE WORKING_NODE (
-  /* specifies the location of this node in the local filesystem */
-  wc_id  INTEGER NOT NULL REFERENCES WCROOT (id),
-  local_relpath  TEXT NOT NULL,
-
-  /* parent's local_relpath for aggregating children of a given parent.
-     this will be "" if the parent is the wcroot.  Since a wcroot will
-     never have a WORKING node the parent_relpath will never be null. */
-  /* ### would be nice to make this column NOT NULL.  */
-  parent_relpath  TEXT,
-
-  /* Is this node "present" or has it been excluded for some reason?
-     Only allowed values: normal, not-present, incomplete, base-deleted.
-     (the others do not make sense for the WORKING tree)
-
-     normal: this node has been added/copied/moved-here. There may be an
-       underlying BASE node at this location, implying this is a replace.
-       Scan upwards from here looking for copyfrom or moved_here values
-       to detect the type of operation constructing this node.
-
-     not-present: the node (or parent) was originally copied or moved-here.
-       A subtree of that source has since been deleted. There may be
-       underlying BASE node to replace. For a move-here or copy-here, the
-       records are simply removed rather than switched to not-present.
-       Note this reflects a deletion only. It is not possible move-away
-       nodes from the WORKING tree. The purported destination would receive
-       a copy from the original source of a copy-here/move-here, or if the
-       nodes were plain adds, those nodes would be shifted to that target
-       for addition.
-
-     incomplete: nodes are being added into the WORKING tree, and the full
-       information about this node is not (yet) present.
-
-     base-deleted: the underlying BASE node has been marked for deletion due
-       to a delete or a move-away (see the moved_to column to determine
-       which), and has not been replaced.  */
-  presence  TEXT NOT NULL,
-
-  /* the kind of the new node. may be "unknown" if the node is not present. */
-  kind  TEXT NOT NULL,
-
-  /* The SHA-1 checksum of the pristine text, if this node is a file and was
-     moved here or copied here, else NULL. */
-  checksum  TEXT,
-
-  /* The size in bytes of the working file when it had no local text
-     modifications. This means the size of the text when translated from
-     repository-normal format to working copy format with EOL style
-     translated and keywords expanded according to the properties in the
-     "properties" column of this row.
-
-     NULL if this node is not a file, or is not moved here or copied here,
-     or if the size has not (yet) been computed. */
-  translated_size  INTEGER,
-
-  /* If this node was moved here or copied here, then the following fields may
-     have information about their source node. See BASE_NODE.changed_* for
-     more information.
-
-     For an added or not-present node, these are null.  */
-  changed_rev  INTEGER,
-  changed_date  INTEGER,  /* an APR date/time (usec since 1970) */
-  changed_author  TEXT,
-
-  /* NULL depth means "default" (typically svn_depth_infinity) */
-  /* ### depth on WORKING? seems this is a BASE-only concept. how do
-     ### you do "files" on an added-directory? can't really ignore
-     ### the subdirs! */
-  /* ### maybe a WC-to-WC copy can retain a depth?  */
-  depth  TEXT,
-
-  /* for kind==symlink, this specifies the target. */
-  symlink_target  TEXT,
-
-  /* Where this node was copied/moved from. All copyfrom_* fields are set
-     only on the root of the operation, and are NULL for all children. */
-  copyfrom_repos_id  INTEGER REFERENCES REPOSITORY (id),
-  copyfrom_repos_path  TEXT,
-  copyfrom_revnum  INTEGER,
-
-  /* ### JF: For an old-style move, "copyfrom" info stores its source, but a
-     new WC-NG "move" is intended to be a "true rename" so its copyfrom
-     revision is implicit, being in effect (new head - 1) at commit time.
-     For a (new) move, we need to store or deduce the copyfrom local-relpath;
-     perhaps add a column called "moved_from". */
-
-  /* Boolean value, specifying if this node was moved here (rather than just
-     copied). The source of the move is specified in copyfrom_*.  */
-  moved_here  INTEGER,
-
-  /* If the underlying node was moved away (rather than just deleted), this
-     specifies the local_relpath of where the BASE node was moved to.
-     This is set only on the root of a move, and is NULL for all children.
-
-     Note that moved_to never refers to *this* node. It always refers
-     to the "underlying" node, whether that is BASE or a child node
-     implied from a parent's move/copy.  */
-  moved_to  TEXT,
-
-  /* ### Do we need this?  We've currently got various mod time APIs
-     ### internal to libsvn_wc, but those might be used in answering some
-     ### question which is better answered some other way. */
-  last_mod_time  INTEGER,  /* an APR date/time (usec since 1970) */
-
-  /* serialized skel of this node's properties. NULL if we
-     have no information about the properties (a non-present node). */
-  properties  BLOB,
-
-  /* should the node on disk be kept after a schedule delete?
-
-     ### Bert points out that this can disappear once we get to single-db. 
-     ### The entire reason for this flag to exist is
-     ### so that the admin area can exist for the commit of a delete,
-     ### and so the post-commit cleanup knows not to actually delete the dir
-     ### from disk (which is why the flag is only ever set on the this_dir
-     ### entry in WC-OLD.)  With single-db, we don't need to keep the old
-     ### admin area around, so this flag can disappear.
-     ### neels: In contrast, the --keep-local commandline option will not
-     ### disappear. The user will still be able to do
-     ### 'svn delete --keep-local' and keep the to-be-unversioned paths
-     ### in the file system. It just won't be necessary to remember the
-     ### keep-local-ness here, because we either delete the file system paths
-     ### right away during 'svn delete' or we don't at all. There won't be a
-     ### "second pass" for file system deletion at commit time anymore. */
-  keep_local  INTEGER,
-
-  PRIMARY KEY (wc_id, local_relpath)
-  );
-
-CREATE INDEX I_WORKING_PARENT ON WORKING_NODE (wc_id, parent_relpath);
-
-
-/* ------------------------------------------------------------------------- */
-
-/* The ACTUAL_NODE table describes text changes and property changes on each
-   node in the WC, relative to the WORKING_NODE table row for the same path
-   (if present) or else to the BASE_NODE row for the same path.  (Either a
-   WORKING_NODE row or a BASE_NODE row must exist if this node exists, but
-   an ACTUAL_NODE row can exist on its own if it is just recording info on
-   a non-present node - a tree conflict or a changelist, for example.)
+/* The ACTUAL_NODE table describes text changes and property changes
+   on each node in the WC, relative to the NODES table row for the
+   same path. (A NODES row must exist if this node exists, but an
+   ACTUAL_NODE row can exist on its own if it is just recording info
+   on a non-present node - a tree conflict or a changelist, for
+   example.)
 
    The ACTUAL_NODE table row for a given path exists if the node at that
    path is known to have text or property changes relative to its
-   WORKING_NODE row. ("Is known" because a text change on disk may not yet
+   NODES row. ("Is known" because a text change on disk may not yet
    have been discovered and recorded here.)
 
    The ACTUAL_NODE table row for a given path may also exist in other cases,
@@ -732,8 +334,8 @@ CREATE TABLE NODES (
      In case 'op_depth' is greater than 0, this is part of a layer of
      working nodes; in that case, the following presence values apply:
 
-     Only allowed values: normal, not-present, incomplete, base-deleted.
-     (the others do not make sense for the WORKING tree)
+     Only allowed values: normal, not-present, incomplete, base-deleted,
+     excluded.  (the others do not make sense for the WORKING tree)
 
      normal: this node has been added/copied/moved-here. There may be an
        underlying BASE node at this location, implying this is a replace.
@@ -755,15 +357,12 @@ CREATE TABLE NODES (
 
      base-deleted: the underlying BASE node has been marked for deletion due
        to a delete or a move-away (see the moved_to column to determine
-       which), and has not been replaced.  */
-  presence  TEXT NOT NULL,
+       which), and has not been replaced.
 
-  /* NULL depth means "default" (typically svn_depth_infinity) */
-  /* ### depth on WORKING? seems this is a BASE-only concept. how do
-     ### you do "files" on an added-directory? can't really ignore
-     ### the subdirs! */
-  /* ### maybe a WC-to-WC copy can retain a depth?  */
-  depth  TEXT,
+     excluded: this node is administratively excluded (sparse WC). This must
+       be a child (or grandchild etc.) of a copied directory.
+  */
+  presence  TEXT NOT NULL,
 
   /* ### JF: For an old-style move, "copyfrom" info stores its source, but a
      new WC-NG "move" is intended to be a "true rename" so its copyfrom
@@ -784,27 +383,42 @@ CREATE TABLE NODES (
      implied from a parent's move/copy.  */
   moved_to  TEXT,
 
-  /* Repository state fields */
+
+  /* Content fields */
 
   /* the kind of the new node. may be "unknown" if the node is not present. */
   kind  TEXT NOT NULL,
 
-  /* If this node was moved here or copied here, then the following fields may
-     have information about their source node. See BASE_NODE.changed_* for
-     more information.
+  /* serialized skel of this node's properties. NULL if we
+     have no information about the properties (a non-present node). */
+  properties  BLOB,
 
-     For an added or not-present node, these are null.  */
-  changed_revision  INTEGER,
-  changed_date      INTEGER,  /* an APR date/time (usec since 1970) */
-  changed_author    TEXT,
+  /* NULL depth means "default" (typically svn_depth_infinity) */
+  /* ### depth on WORKING? seems this is a BASE-only concept. how do
+     ### you do "files" on an added-directory? can't really ignore
+     ### the subdirs! */
+  /* ### maybe a WC-to-WC copy can retain a depth?  */
+  depth  TEXT,
 
   /* The SHA-1 checksum of the pristine text, if this node is a file and was
      moved here or copied here, else NULL. */
   checksum  TEXT,
 
-  /* serialized skel of this node's properties. NULL if we
-     have no information about the properties (a non-present node). */
-  properties  BLOB,
+  /* for kind==symlink, this specifies the target. */
+  symlink_target  TEXT,
+
+
+  /* Last-Change fields */
+
+  /* If this node was moved here or copied here, then the following fields may
+     have information about their source node.  changed_rev must be not-null
+     if this node has presence=="normal". changed_date and changed_author may
+     be null if the corresponding revprops are missing.
+
+     For an added or not-present node, these are null.  */
+  changed_revision  INTEGER,
+  changed_date      INTEGER,  /* an APR date/time (usec since 1970) */
+  changed_author    TEXT,
 
 
   /* Various cache fields */
@@ -833,9 +447,6 @@ CREATE TABLE NODES (
      node does not have any dav-cache. */
   dav_cache  BLOB,
 
-  /* for kind==symlink, this specifies the target. */
-  symlink_target  TEXT,
-
   /* The serialized file external information. */
   /* ### hack.  hack.  hack.
      ### This information is already stored in properties, but because the
@@ -853,8 +464,7 @@ CREATE TABLE NODES (
 
   );
 
-CREATE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath);
-CREATE INDEX I_NODES_PATH ON NODES (wc_id, local_relpath);
+CREATE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath, op_depth);
 
 
 
@@ -977,6 +587,45 @@ PRAGMA user_version = 17;
 -- STMT_UPGRADE_TO_18
 PRAGMA user_version = 18;
 
+
+/* Format 20 introduces NODES and removes BASE_NODE and WORKING_NODE */
+
+-- STMT_UPGRADE_TO_20
+
+INSERT INTO NODES (
+       wc_id, local_relpath, op_depth, parent_relpath,
+       repos_id, repos_path, revision,
+       presence, depth, moved_here, moved_to, kind,
+       changed_revision, changed_date, changed_author,
+       checksum, properties, translated_size, last_mod_time,
+       dav_cache, symlink_target, file_external )
+SELECT wc_id, local_relpath, 0 AS op_depth, parent_relpath,
+       repos_id, repos_relpath, revnum,
+       presence, depth, NULL AS moved_here, NULL AS moved_to, kind,
+       changed_rev, changed_date, changed_author,
+       checksum, properties, translated_size, last_mod_time,
+       dav_cache, symlink_target, file_external
+FROM BASE_NODE;
+INSERT INTO NODES (
+       wc_id, local_relpath, op_depth, parent_relpath,
+       repos_id, repos_path, revision,
+       presence, depth, moved_here, moved_to, kind,
+       changed_revision, changed_date, changed_author,
+       checksum, properties, translated_size, last_mod_time,
+       dav_cache, symlink_target, file_external )
+SELECT wc_id, local_relpath, 2 AS op_depth, parent_relpath,
+       copyfrom_repos_id, copyfrom_repos_path, copyfrom_revnum,
+       presence, depth, NULL AS moved_here, NULL AS moved_to, kind,
+       changed_rev, changed_date, changed_author,
+       checksum, properties, translated_size, last_mod_time,
+       NULL AS dav_cache, symlink_target, NULL AS file_external
+FROM WORKING_NODE;
+
+DROP TABLE BASE_NODE;
+DROP TABLE WORKING_NODE;
+
+PRAGMA user_version = 20;
+
 /* ------------------------------------------------------------------------- */
 
 /* Format YYY introduces new handling for conflict information.  */
@@ -991,81 +640,6 @@ PRAGMA user_version = 18;
    number will be, however, so we're just marking it as 99 for now.  */
 -- format: 99
 
-/* We cannot directly remove columns, so we use a temporary table instead. */
-/* First create the temporary table without the undesired column(s). */
-CREATE TEMPORARY TABLE BASE_NODE_BACKUP(
-  wc_id  INTEGER NOT NULL,
-  local_relpath  TEXT NOT NULL,
-  repos_id  INTEGER,
-  repos_relpath  TEXT,
-  parent_relpath  TEXT,
-  presence  TEXT NOT NULL,
-  kind  TEXT NOT NULL,
-  revnum  INTEGER,
-  checksum  TEXT,
-  translated_size  INTEGER,
-  changed_rev  INTEGER,
-  changed_date  INTEGER,
-  changed_author  TEXT,
-  depth  TEXT,
-  symlink_target  TEXT,
-  last_mod_time  INTEGER,
-  properties  BLOB,
-  dav_cache  BLOB,
-  file_external  TEXT
-);
-
-/* Copy everything into the temporary table. */
-INSERT INTO BASE_NODE_BACKUP SELECT
-  wc_id, local_relpath, repos_id, repos_relpath, parent_relpath, presence,
-  kind, revnum, checksum, translated_size, changed_rev, changed_date,
-  changed_author, depth, symlink_target, last_mod_time, properties, dav_cache,
-  file_external
-FROM BASE_NODE;
-
-/* Drop the original table. */
-DROP TABLE BASE_NODE;
-
-/* Recreate the original table, this time less the temporary columns.
-   Column descriptions are same as BASE_NODE in format 12 */
-CREATE TABLE BASE_NODE(
-  wc_id  INTEGER NOT NULL REFERENCES WCROOT (id),
-  local_relpath  TEXT NOT NULL,
-  repos_id  INTEGER REFERENCES REPOSITORY (id),
-  repos_relpath  TEXT,
-  parent_relpath  TEXT,
-  presence  TEXT NOT NULL,
-  kind  TEXT NOT NULL,
-  revnum  INTEGER,
-  checksum  TEXT,
-  translated_size  INTEGER,
-  changed_rev  INTEGER,
-  changed_date  INTEGER,
-  changed_author  TEXT,
-  depth  TEXT,
-  symlink_target  TEXT,
-  last_mod_time  INTEGER,
-  properties  BLOB,
-  dav_cache  BLOB,
-  file_external  TEXT,
-
-  PRIMARY KEY (wc_id, local_relpath)
-  );
-
-/* Recreate the index. */
-CREATE INDEX I_PARENT ON BASE_NODE (wc_id, parent_relpath);
-
-/* Copy everything back into the original table. */
-INSERT INTO BASE_NODE SELECT
-  wc_id, local_relpath, repos_id, repos_relpath, parent_relpath, presence,
-  kind, revnum, checksum, translated_size, changed_rev, changed_date,
-  changed_author, depth, symlink_target, last_mod_time, properties, dav_cache,
-  file_external
-FROM BASE_NODE_BACKUP;
-
-/* Drop the temporary table. */
-DROP TABLE BASE_NODE_BACKUP;
-
 /* Now "drop" the tree_conflict_data column from actual_node. */
 CREATE TABLE ACTUAL_NODE_BACKUP (
   wc_id  INTEGER NOT NULL,