You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by da...@apache.org on 2010/03/30 22:58:01 UTC

svn commit: r929279 [15/20] - in /subversion/branches/svn-patch-improvements: ./ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/emacs/ notes/feedback/ notes/meetings/ notes/wc-ng/ subversion/ subversion/bindings/javahl...

Modified: subversion/branches/svn-patch-improvements/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/libsvn_wc/upgrade.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/libsvn_wc/upgrade.c Tue Mar 30 20:57:53 2010
@@ -60,6 +60,51 @@
 #define ADM_EMPTY_FILE "empty-file"
 
 
+/* Read the properties from the file at PROPFILE_ABSPATH, returning them
+   as a hash in *PROPS. If the propfile is NOT present, then NULL will
+   be returned in *PROPS.  */
+static svn_error_t *
+read_propfile(apr_hash_t **props,
+              const char *propfile_abspath,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool)
+{
+  svn_error_t *err;
+  svn_stream_t *stream;
+
+  err = svn_stream_open_readonly(&stream, propfile_abspath,
+                                 scratch_pool, scratch_pool);
+  if (err)
+    {
+      if (!APR_STATUS_IS_ENOENT(err->apr_err))
+        return svn_error_return(err);
+
+      svn_error_clear(err);
+
+      /* The propfile was not there. Signal with a NULL.  */
+      *props = NULL;
+      return SVN_NO_ERROR;
+    }
+
+  /* ### does this function need to be smarter? will we see zero-length
+     ### files? see props.c::load_props(). there may be more work here.
+     ### need a historic analysis of 1.x property storage. what will we
+     ### actually run into?  */
+
+  /* ### loggy_write_properties() and immediate_install_props() write
+     ### zero-length files for "no props", so we should be a bit smarter
+     ### in here.  */
+
+  /* ### should we be forgiving in here? I say "no". if we can't be sure,
+     ### then we could effectively corrupt the local working copy.  */
+
+  *props = apr_hash_make(result_pool);
+  SVN_ERR(svn_hash_read2(*props, stream, SVN_HASH_TERMINATOR, result_pool));
+
+  return svn_error_return(svn_stream_close(stream));
+}
+
+
 /* Read one proplist (allocated from RESULT_POOL) from STREAM, and place it
    into ALL_WCPROPS at NAME.  */
 static svn_error_t *
@@ -88,9 +133,9 @@ read_many_wcprops(apr_hash_t **all_wcpro
                   apr_pool_t *result_pool,
                   apr_pool_t *scratch_pool)
 {
-  svn_stream_t *stream;
+  const char *propfile_abspath;
+  apr_hash_t *wcprops;
   apr_hash_t *dirents;
-  svn_error_t *err;
   const char *props_dir_abspath;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   apr_hash_index_t *hi;
@@ -98,22 +143,12 @@ read_many_wcprops(apr_hash_t **all_wcpro
   *all_wcprops = apr_hash_make(result_pool);
 
   /* First, look at dir-wcprops. */
-  err = svn_wc__open_adm_stream(&stream, dir_abspath, WCPROPS_FNAME_FOR_DIR,
-                                iterpool, iterpool);
-  if (err)
-    {
-      /* If the file doesn't exist, it means no wcprops. */
-      if (APR_STATUS_IS_ENOENT(err->apr_err))
-        svn_error_clear(err);
-      else
-        return svn_error_return(err);
-    }
-  else
-    {
-      SVN_ERR(read_one_proplist(*all_wcprops, SVN_WC_ENTRY_THIS_DIR, stream,
-                                result_pool, iterpool));
-      SVN_ERR(svn_stream_close(stream));
-    }
+  propfile_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_FNAME_FOR_DIR,
+                                       scratch_pool);
+  SVN_ERR(read_propfile(&wcprops, propfile_abspath, result_pool, iterpool));
+  if (wcprops != NULL)
+    apr_hash_set(*all_wcprops, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING,
+                 wcprops);
 
   props_dir_abspath = svn_wc__adm_child(dir_abspath, WCPROPS_SUBDIR_FOR_FILES,
                                         scratch_pool);
@@ -125,18 +160,18 @@ read_many_wcprops(apr_hash_t **all_wcpro
        hi;
        hi = apr_hash_next(hi))
     {
-      const char *name = svn_apr_hash_index_key(hi);
-      const char *prop_path;
+      const char *name = svn__apr_hash_index_key(hi);
 
       svn_pool_clear(iterpool);
 
-      prop_path = svn_dirent_join(props_dir_abspath, name, iterpool);
+      propfile_abspath = svn_dirent_join(props_dir_abspath, name, iterpool);
 
-      SVN_ERR(svn_stream_open_readonly(&stream, prop_path,
-                                       iterpool, iterpool));
-      SVN_ERR(read_one_proplist(*all_wcprops, name, stream,
-                                result_pool, iterpool));
-      SVN_ERR(svn_stream_close(stream));
+      SVN_ERR(read_propfile(&wcprops, propfile_abspath,
+                            result_pool, iterpool));
+      SVN_ERR_ASSERT(wcprops != NULL);
+      apr_hash_set(*all_wcprops,
+                   apr_pstrdup(result_pool, name), APR_HASH_KEY_STRING,
+                   wcprops);
     }
 
   svn_pool_destroy(iterpool);
@@ -265,7 +300,7 @@ get_versioned_subdirs(apr_array_header_t
            hi;
            hi = apr_hash_next(hi))
         {
-          const char *name = svn_apr_hash_index_key(hi);
+          const char *name = svn__apr_hash_index_key(hi);
 
           /* skip "this dir"  */
           if (*name == '\0')
@@ -284,6 +319,7 @@ get_versioned_subdirs(apr_array_header_t
 }
 
 
+/* */
 static const char *
 build_lockfile_path(const char *local_dir_abspath,
                     apr_pool_t *result_pool)
@@ -320,6 +356,7 @@ create_physical_lock(const char *abspath
 }
 
 
+/* */
 static void
 wipe_wcprops(const char *wcroot_abspath, apr_pool_t *scratch_pool)
 {
@@ -537,6 +574,7 @@ upgrade_to_wcng(svn_wc__db_t *db,
 }
 
 
+/* */
 static svn_error_t *
 bump_to_13(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -570,6 +608,7 @@ kind_to_word(svn_wc__db_kind_t kind)
 }
 
 
+/* */
 static const char *
 conflict_kind_to_word(svn_wc_conflict_kind_t conflict_kind)
 {
@@ -587,6 +626,7 @@ conflict_kind_to_word(svn_wc_conflict_ki
 }
 
 
+/* */
 static const char *
 conflict_action_to_word(svn_wc_conflict_action_t action)
 {
@@ -594,6 +634,7 @@ conflict_action_to_word(svn_wc_conflict_
 }
 
 
+/* */
 static const char *
 conflict_reason_to_word(svn_wc_conflict_reason_t reason)
 {
@@ -601,6 +642,7 @@ conflict_reason_to_word(svn_wc_conflict_
 }
 
 
+/* */
 static const char *
 wc_operation_to_word(svn_wc_operation_t operation)
 {
@@ -608,6 +650,7 @@ wc_operation_to_word(svn_wc_operation_t 
 }
 
 
+/* */
 static svn_wc__db_kind_t
 db_kind_from_node_kind(svn_node_kind_t node_kind)
 {
@@ -626,6 +669,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,
@@ -650,7 +694,7 @@ migrate_single_tree_conflict_data(svn_sq
        hi = apr_hash_next(hi))
     {
       const svn_wc_conflict_description2_t *conflict =
-          svn_apr_hash_index_val(hi);
+          svn__apr_hash_index_val(hi);
       const char *conflict_relpath;
       apr_int64_t left_repos_id;
       apr_int64_t right_repos_id;
@@ -736,6 +780,7 @@ migrate_single_tree_conflict_data(svn_sq
 }
 
 
+/* */
 static svn_error_t *
 migrate_tree_conflicts(svn_sqlite__db_t *sdb,
                        apr_pool_t *scratch_pool)
@@ -789,6 +834,7 @@ migrate_tree_conflicts(svn_sqlite__db_t 
 #endif /* ### no tree conflict migration yet */
 
 
+/* */
 static svn_error_t *
 migrate_locks(const char *wcroot_abspath,
               svn_sqlite__db_t *sdb,
@@ -805,7 +851,7 @@ migrate_locks(const char *wcroot_abspath
       SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_WC_LOCK));
       /* ### These values are magic, and will need to be updated when we
          ### go to a centralized system. */
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", 1, ""));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", (apr_int64_t)1, ""));
       SVN_ERR(svn_sqlite__step_done(stmt));
     }
 
@@ -813,6 +859,7 @@ migrate_locks(const char *wcroot_abspath
 }
 
 
+/* */
 static svn_error_t *
 bump_to_14(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -826,6 +873,7 @@ bump_to_14(void *baton, svn_sqlite__db_t
 }
 
 
+/* */
 static svn_error_t *
 bump_to_15(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -835,6 +883,7 @@ bump_to_15(void *baton, svn_sqlite__db_t
 }
 
 
+/* */
 static svn_error_t *
 bump_to_16(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -846,6 +895,7 @@ bump_to_16(void *baton, svn_sqlite__db_t
 
 #if 0 /* ### no props migration yet */
 
+/* */
 static svn_error_t *
 migrate_props(const char *wcroot_abspath,
               svn_sqlite__db_t *sdb,
@@ -855,16 +905,21 @@ migrate_props(const char *wcroot_abspath
      (since we aren't yet in a centralized system), and for any properties that
      exist, map them as follows:
 
-     if (node is replaced):
+     if (revert props exist):
        revert  -> BASE
-       working -> ACTUAL
        base    -> WORKING
+       working -> ACTUAL
      else if (prop pristine is working [as defined in props.c] ):
        base    -> WORKING
        working -> ACTUAL
      else:
        base    -> BASE
        working -> ACTUAL
+
+     ### the middle "test" should simply look for a WORKING_NODE row
+
+     Note that it is legal for "working" props to be missing. That implies
+     no local changes to the properties.
   */
   const apr_array_header_t *children;
   apr_pool_t *iterpool;
@@ -873,6 +928,8 @@ migrate_props(const char *wcroot_abspath
   svn_wc__db_t *db;
   int i;
 
+  /* ### the use of DB within this function must go away.  */
+
   /* *sigh*  We actually want to use wc_db APIs to read data, but we aren't
      provided a wc_db, so open one. */
   SVN_ERR(svn_wc__db_open(&db, svn_wc__db_openmode_default, NULL, FALSE, TRUE,
@@ -898,82 +955,82 @@ migrate_props(const char *wcroot_abspath
       svn_boolean_t replaced;
       apr_hash_t *working_props;
       apr_hash_t *base_props;
-      svn_stream_t *stream;
 
       svn_pool_clear(iterpool);
 
       /* Several useful paths. */
       child_abspath = svn_dirent_join(wcroot_abspath, child_relpath, iterpool);
       prop_base_path = svn_dirent_join(props_base_dirpath,
-                            apr_psprintf(iterpool, "%s" SVN_WC__BASE_EXT,
-                                         child_relpath),
-                            iterpool);
+                                       apr_pstrcat(iterpool,
+                                                   child_relpath,
+                                                   SVN_WC__BASE_EXT,
+                                                   NULL),
+                                       iterpool);
       prop_working_path = svn_dirent_join(props_dirpath,
-                            apr_psprintf(iterpool, "%s" SVN_WC__WORK_EXT,
-                                         child_relpath),
-                            iterpool);
+                                          apr_pstrcat(iterpool,
+                                                      child_relpath,
+                                                      SVN_WC__WORK_EXT,
+                                                      NULL),
+                                          iterpool);
       prop_revert_path = svn_dirent_join(props_base_dirpath,
-                            apr_psprintf(iterpool, "%s" SVN_WC__REVERT_EXT,
-                                         child_relpath),
-                            iterpool);
-
-      base_props = apr_hash_make(iterpool);
-      SVN_ERR(svn_stream_open_readonly(&stream, prop_base_path, iterpool,
-                                       iterpool));
-      SVN_ERR(svn_hash_read2(base_props, stream, SVN_HASH_TERMINATOR,
-                             iterpool));
+                                         apr_pstrcat(iterpool,
+                                                     child_relpath,
+                                                     SVN_WC__REVERT_EXT,
+                                                     NULL),
+                                         iterpool);
 
-      /* if node is replaced ... */
-      SVN_ERR(svn_wc__internal_is_replaced(&replaced, db, child_abspath,
-                                           iterpool));
-      if (replaced)
-        {
-          apr_hash_t *revert_props = apr_hash_make(iterpool);
+      SVN_ERR(read_propfile(&base_props, prop_base_path, iterpool, iterpool));
+      SVN_ERR_ASSERT(base_props != NULL);
 
-          SVN_ERR(svn_stream_open_readonly(&stream, prop_revert_path, iterpool,
-                                           iterpool));
-          SVN_ERR(svn_hash_read2(revert_props, stream, SVN_HASH_TERMINATOR,
-                                 iterpool));
-
-          SVN_ERR(svn_wc__db_temp_op_set_pristine_props(db, child_abspath,
-                                                        revert_props, FALSE,
-                                                        iterpool));
-          SVN_ERR(svn_wc__db_temp_op_set_pristine_props(db, child_abspath,
-                                                        base_props, TRUE,
-                                                        iterpool));
+      SVN_ERR(read_propfile(&revert_props, prop_revert_path,
+                            iterpool, iterpool));
+      if (revert_props != NULL)
+        {
+          SVN_ERR(svn_wc__db_temp_base_set_props(db, child_abspath,
+                                                 revert_props, iterpool));
+          SVN_ERR(svn_wc__db_temp_working_set_props(db, child_abspath,
+                                                    base_props, iterpool));
         }
       else
         {
-          SVN_ERR(svn_wc__prop_pristine_is_working(&pristine_is_working, db,
-                                                   child_abspath, iterpool));
-          SVN_ERR(svn_wc__db_temp_op_set_pristine_props(db, child_abspath,
-                                                        base_props,
-                                                        pristine_is_working,
-                                                        iterpool));
+          /* Try writing to the WORKING tree first.  */
+          err = svn_wc__db_temp_working_set_props(db, local_abspath,
+                                                  base_props,
+                                                  scratch_pool);
+          if (err)
+            {
+              if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+                return svn_error_return(err);
+              svn_error_clear(err);
+
+              /* The WORKING node is not present. Try writing to the
+                 BASE node now.  */
+              SVN_ERR(svn_wc__db_temp_base_set_props(db, local_abspath,
+                                                     base_props,
+                                                     scratch_pool));
+            }
         }
 
-      working_props = apr_hash_make(iterpool);
-      SVN_ERR(svn_stream_open_readonly(&stream, prop_working_path, iterpool,
-                                       iterpool));
-      SVN_ERR(svn_hash_read2(working_props, stream, SVN_HASH_TERMINATOR,
-                             iterpool));
-
-      SVN_ERR(svn_wc__db_op_set_props(db, child_abspath, working_props,
-                                      iterpool));
+      /* If the properties file does not exist, then that simply means
+         there were no changes made. Avoid setting new props in that case.  */
+      SVN_ERR(read_propfile(&working_props, prop_working_path,
+                            iterpool, iterpool));
+      if (working_props != NULL)
+        {
+          SVN_ERR(svn_wc__db_op_set_props(db, child_abspath, working_props,
+                                          iterpool));
+        }
     }
 
   /* Now delete the old directories. */
   SVN_ERR(svn_io_remove_dir2(props_dirpath, TRUE, NULL, NULL, iterpool));
   SVN_ERR(svn_io_remove_dir2(props_base_dirpath, TRUE, NULL, NULL,
                              iterpool));
-  SVN_ERR(svn_io_remove_dir2(svn_dirent_join(wcroot_abspath,
-                                      ".svn/" TEMP_DIR "/" PROPS_SUBDIR,
-                                      iterpool),
-                             TRUE, NULL, NULL, iterpool));
-  SVN_ERR(svn_io_remove_dir2(svn_dirent_join(wcroot_abspath,
-                                      ".svn/"  TEMP_DIR "/" PROP_BASE_SUBDIR,
-                                      iterpool),
-                             TRUE, NULL, NULL, iterpool));
+
+#if 0
+  /* ### we are not (yet) taking out a write lock  */
+  SVN_ERR(svn_wc__adm_cleanup_tmp_area(db, wcroot_abspath, iterpool));
+#endif
 
   SVN_ERR(svn_wc__db_close(db));
   svn_pool_destroy(iterpool);
@@ -982,6 +1039,7 @@ migrate_props(const char *wcroot_abspath
 }
 
 
+/* */
 static svn_error_t *
 bump_to_17(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -1001,6 +1059,7 @@ bump_to_17(void *baton, svn_sqlite__db_t
 
 #if 0 /* ### no tree conflict migration yet */
 
+/* */
 static svn_error_t *
 bump_to_XXX(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -1043,7 +1102,7 @@ svn_wc__upgrade_sdb(int *result_format,
                                              (void *)wcroot_abspath,
                                              scratch_pool));
 
-        /* If the transaction succeeded, then we don't need the wcprops        
+        /* If the transaction succeeded, then we don't need the wcprops
            files. We stopped writing them partway through format 12, but
            we may be upgrading from an "early 12" and need to toss those
            files. We aren't going to migrate them because it is *also*
@@ -1111,6 +1170,7 @@ svn_wc__upgrade_sdb(int *result_format,
 }
 
 
+/* */
 static svn_error_t *
 upgrade_working_copy(svn_wc__db_t *db,
                      const char *dir_abspath,

Modified: subversion/branches/svn-patch-improvements/subversion/libsvn_wc/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/libsvn_wc/util.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/libsvn_wc/util.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/libsvn_wc/util.c Tue Mar 30 20:57:53 2010
@@ -236,7 +236,7 @@ void svn_wc__compat_call_notify_func(voi
 }
 
 svn_boolean_t
-svn_wc_match_ignore_list(const char *str, apr_array_header_t *list,
+svn_wc_match_ignore_list(const char *str, const apr_array_header_t *list,
                          apr_pool_t *pool)
 {
   /* For now, we simply forward to svn_cstring_match_glob_list. In the
@@ -247,78 +247,6 @@ svn_wc_match_ignore_list(const char *str
   return svn_cstring_match_glob_list(str, list);
 }
 
-svn_error_t *
-svn_wc__internal_path_switched(svn_boolean_t *switched,
-                               svn_wc__db_t *db,
-                               const char *local_abspath,
-                               apr_pool_t *scratch_pool)
-{
-  const char *parent_abspath;
-  const char *parent_child_url;
-  const svn_wc_entry_t *parent_entry;
-  const svn_wc_entry_t *entry;
-  svn_error_t *err;
-
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
-  if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
-    {
-      *switched = FALSE;
-      return SVN_NO_ERROR;
-    }
-
-  SVN_ERR(svn_wc__get_entry(&entry, db, local_abspath, FALSE, svn_node_unknown,
-                            FALSE, scratch_pool, scratch_pool));
-
-  parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
-  err = svn_wc__get_entry(&parent_entry, db, parent_abspath, FALSE,
-                          svn_node_dir, FALSE, scratch_pool, scratch_pool);
-
-  if (err && (err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY
-        || err->apr_err == SVN_ERR_WC_MISSING))
-    {
-      svn_error_clear(err);
-      *switched = FALSE;
-      return SVN_NO_ERROR;
-    }
-  else if (err)
-    return err;
-
-  /* Without complete entries (and URLs) for WC_PATH and it's parent
-     we return SVN_ERR_ENTRY_MISSING_URL. */
-  if (!parent_entry->url || !entry->url)
-    {
-      const char *no_url_path = parent_entry->url ?
-                            local_abspath : parent_abspath;
-      return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
-                               _("Cannot find a URL for '%s'"),
-                               svn_dirent_local_style(no_url_path,
-                                                      scratch_pool));
-    }
-
-  parent_child_url
-    = svn_path_url_add_component2(parent_entry->url,
-                                  svn_dirent_basename(local_abspath,
-                                                      scratch_pool),
-                                  scratch_pool);
-  *switched = strcmp(parent_child_url, entry->url) != 0;
-
-  return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_wc__path_switched(svn_boolean_t *switched,
-                      svn_wc_context_t *wc_ctx,
-                      const char *local_abspath,
-                      apr_pool_t *scratch_pool)
-{
-  return svn_error_return(svn_wc__internal_path_switched(switched, wc_ctx->db,
-                                                         local_abspath,
-                                                         scratch_pool));
-}
-
-
 svn_wc_conflict_description2_t *
 svn_wc_conflict_description_create_text2(const char *local_abspath,
                                          apr_pool_t *result_pool)
@@ -532,8 +460,8 @@ svn_wc__cd2_to_cd(const svn_wc_conflict_
 
       case svn_wc_conflict_kind_text:
         new_conflict->is_binary = conflict->is_binary;
-        new_conflict->mime_type = conflict->mime_type 
-                              ? apr_pstrdup(result_pool, conflict->mime_type) 
+        new_conflict->mime_type = conflict->mime_type
+                              ? apr_pstrdup(result_pool, conflict->mime_type)
                               : NULL;
         new_conflict->base_file = apr_pstrdup(result_pool,
                                               conflict->base_file);
@@ -541,9 +469,9 @@ svn_wc__cd2_to_cd(const svn_wc_conflict_
                                                conflict->their_file);
         new_conflict->my_file = apr_pstrdup(result_pool,
                                             conflict->my_file);
-        new_conflict->merged_file = conflict->merged_file 
+        new_conflict->merged_file = conflict->merged_file
                                     ? apr_pstrdup(result_pool,
-                                                  conflict->merged_file) 
+                                                  conflict->merged_file)
                                     : NULL;
         break;
 
@@ -593,8 +521,8 @@ svn_wc__cd_to_cd2(const svn_wc_conflict_
 
       case svn_wc_conflict_kind_text:
         new_conflict->is_binary = conflict->is_binary;
-        new_conflict->mime_type = conflict->mime_type 
-                              ? apr_pstrdup(result_pool, conflict->mime_type) 
+        new_conflict->mime_type = conflict->mime_type
+                              ? apr_pstrdup(result_pool, conflict->mime_type)
                               : NULL;
         new_conflict->base_file = apr_pstrdup(result_pool,
                                               conflict->base_file);
@@ -602,9 +530,9 @@ svn_wc__cd_to_cd2(const svn_wc_conflict_
                                                conflict->their_file);
         new_conflict->my_file = apr_pstrdup(result_pool,
                                             conflict->my_file);
-        new_conflict->merged_file = conflict->merged_file 
+        new_conflict->merged_file = conflict->merged_file
                                     ? apr_pstrdup(result_pool,
-                                                  conflict->merged_file) 
+                                                  conflict->merged_file)
                                     : NULL;
         break;
 

Modified: subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc-metadata.sql
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc-metadata.sql?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc-metadata.sql (original)
+++ subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc-metadata.sql Tue Mar 30 20:57:53 2010
@@ -410,6 +410,10 @@ CREATE TABLE ACTUAL_NODE (
 
   /* Three columns containing the checksums of older, left and right conflict
      texts.  Stored in a column to allow storing them in the pristine store  */
+  /* stsp: This is meant for text conflicts, right? What about property
+           conflicts? Why do we need these in a column to refer to the
+           pristine store? Can't we just parse the checksums from
+           conflict_data as well? */
   older_checksum  TEXT,
   left_checksum  TEXT,
   right_checksum  TEXT,

Modified: subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc-queries.sql?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc-queries.sql Tue Mar 30 20:57:53 2010
@@ -190,6 +190,14 @@ where repos_id = ?1 and
 update base_node set last_mod_time = ?3
 where wc_id = ?1 and local_relpath = ?2;
 
+-- STMT_UPDATE_BASE_FILEINFO
+UPDATE BASE_NODE SET translated_size = ?3, last_mod_time = ?4
+WHERE wc_id = ?1 AND local_relpath = ?2;
+
+-- STMT_UPDATE_WORKING_FILEINFO
+UPDATE WORKING_NODE SET translated_size = ?3, last_mod_time = ?4
+WHERE wc_id = ?1 AND local_relpath = ?2;
+
 -- STMT_UPDATE_ACTUAL_TREE_CONFLICTS
 update actual_node set tree_conflict_data = ?3
 where wc_id = ?1 and local_relpath = ?2;
@@ -243,6 +251,14 @@ where wc_id = ?1 and local_relpath = ?2;
 update working_node set presence = ?3
 where wc_id = ?1 and local_relpath =?2;
 
+-- STMT_UPDATE_BASE_PRESENCE_AND_REVNUM
+update base_node set presence = ?3, revnum = ?4
+where wc_id = ?1 and local_relpath = ?2;
+
+-- STMT_UPDATE_BASE_PRESENCE_REVNUM_AND_REPOS_RELPATH
+update base_node set presence = ?3, revnum = ?4, repos_relpath = ?5
+where wc_id = ?1 and local_relpath = ?2;
+
 -- STMT_LOOK_FOR_WORK
 SELECT id FROM WORK_QUEUE LIMIT 1;
 
@@ -321,6 +337,38 @@ SELECT wc_id, local_relpath, parent_relp
     symlink_target, last_mod_time FROM BASE_NODE
 WHERE wc_id = ?1 AND local_relpath = ?2;
 
+-- STMT_INSERT_WORKING_NODE_NORMAL_FROM_BASE_NODE
+INSERT INTO WORKING_NODE (
+    wc_id, local_relpath, parent_relpath, presence, kind, checksum,
+    translated_size, changed_rev, changed_date, changed_author, depth,
+    symlink_target, last_mod_time, properties, copyfrom_repos_id,
+    copyfrom_repos_path, copyfrom_revnum )
+SELECT wc_id, local_relpath, parent_relpath, 'normal', kind, checksum,
+    translated_size, changed_rev, changed_date, changed_author, depth,
+    symlink_target, last_mod_time, properties, repos_id,
+    repos_relpath, revnum FROM BASE_NODE
+WHERE wc_id = ?1 AND local_relpath = ?2;
+
+-- STMT_INSERT_WORKING_NODE_NOT_PRESENT_FROM_BASE_NODE
+INSERT INTO WORKING_NODE (
+    wc_id, local_relpath, parent_relpath, presence, kind, changed_rev,
+    changed_date, changed_author, copyfrom_repos_id,
+    copyfrom_repos_path, copyfrom_revnum )
+SELECT wc_id, local_relpath, parent_relpath, 'not-present', kind, changed_rev,
+    changed_date, changed_author, repos_id,
+    repos_relpath, revnum FROM BASE_NODE
+WHERE wc_id = ?1 AND local_relpath = ?2;
+
+-- STMT_UPDATE_COPYFROM
+UPDATE WORKING_NODE set copyfrom_repos_id = ?3, copyfrom_repos_path = ?4
+WHERE wc_id = ?1 AND local_relpath = ?2;
+
+-- STMT_DETERMINE_TREE_FOR_RECORDING
+SELECT 0 FROM BASE_NODE WHERE wc_id = ?1 AND local_relpath = ?2
+UNION
+SELECT 1 FROM WORKING_NODE WHERE wc_id = ?1 AND local_relpath = ?2;
+
+
 /* ------------------------------------------------------------------------- */
 
 /* these are used in entries.c  */

Modified: subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc.h?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc.h (original)
+++ subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc.h Tue Mar 30 20:57:53 2010
@@ -180,6 +180,61 @@ svn_wc__context_create_with_db(svn_wc_co
                                apr_pool_t *result_pool);
 
 
+/*** Committed Queue ***/
+
+/**
+ * Return the pool associated with QUEUE.  (This so we can keep some
+ * deprecated functions that need to peek inside the QUEUE struct in
+ * deprecated.c).
+ */
+apr_pool_t *
+svn_wc__get_committed_queue_pool(const struct svn_wc_committed_queue_t *queue);
+
+
+/** Internal helper for svn_wc_process_committed_queue2().
+ *
+ * ### If @a queue is NULL, then ...?
+ * ### else:
+ * Bump an item from @a queue (the one associated with @a
+ * local_abspath) to @a new_revnum after a commit succeeds, recursing
+ * if @a recurse is set.
+ *
+ * @a new_date is the (server-side) date of the new revision, or 0.
+ *
+ * @a rev_author is the (server-side) author of the new
+ * revision; it may be @c NULL.
+ *
+ * @a new_dav_cache is a hash of dav property changes to be made to
+ * the @a local_abspath.
+ *   ### [JAF]  Is it? See svn_wc_queue_committed3(). It ends up being
+ *   ### assigned as a whole to wc.db:BASE_NODE:dav_cache.
+ *
+ * If @a no_unlock is set, don't release any user locks on @a
+ * local_abspath; otherwise release them as part of this processing.
+ *
+ * If @keep_changelist is set, don't remove any changeset assignments
+ * from @a local_abspath; otherwise, clear it of such assignments.
+ *
+ * If @a local_abspath is a file and @a checksum is non-NULL, use @a checksum
+ * as the checksum for the new text base. Otherwise, calculate the checksum
+ * if needed.
+ *   ### [JAF]  No, it doesn't calculate the checksum, it stores null in wc.db.
+ */
+svn_error_t *
+svn_wc__process_committed_internal(svn_wc__db_t *db,
+                                   const char *local_abspath,
+                                   svn_boolean_t recurse,
+                                   svn_revnum_t new_revnum,
+                                   apr_time_t new_date,
+                                   const char *rev_author,
+                                   apr_hash_t *new_dav_cache,
+                                   svn_boolean_t no_unlock,
+                                   svn_boolean_t keep_changelist,
+                                   const svn_checksum_t *checksum,
+                                   const svn_wc_committed_queue_t *queue,
+                                   apr_pool_t *scratch_pool);
+
+
 /*** Update traversals. ***/
 
 struct svn_wc_traversal_info_t
@@ -261,6 +316,27 @@ struct svn_wc_traversal_info_t
 /* Ensure that DIR exists. */
 svn_error_t *svn_wc__ensure_directory(const char *path, apr_pool_t *pool);
 
+
+/* Return a hash keyed by 'const char *' property names and with
+   'svn_string_t *' values built from PROPS (which is an array of
+   pointers to svn_prop_t's) or to NULL if PROPS is NULL or empty.
+   PROPS items which lack a value will be ignored.  If PROPS contains
+   multiple properties with the same name, each successive such item
+   reached in a walk from the beginning to the end of the array will
+   overwrite the previous in the returned hash.
+
+   NOTE: While the returned hash will be allocated in RESULT_POOL, the
+   items it holds will share storage with those in PROPS.
+
+   ### This is rather the reverse of svn_prop_hash_to_array(), except
+   ### that function's arrays contains svn_prop_t's, whereas this
+   ### one's contains *pointers* to svn_prop_t's.  So much for
+   ### consistency.  */
+apr_hash_t *
+svn_wc__prop_array_to_hash(const apr_array_header_t *props,
+                           apr_pool_t *result_pool);
+
+
 /* Baton for svn_wc__compat_call_notify_func below. */
 typedef struct svn_wc__compat_notify_baton_t {
   /* Wrapped func/baton. */
@@ -400,14 +476,6 @@ svn_wc__ambient_depth_filter_editor(cons
                                     svn_wc__db_t *db,
                                     apr_pool_t *pool);
 
-/* Similar to svn_wc__path_switched(), but with a wc_db parameter instead of
- * a wc_context. */
-svn_error_t *
-svn_wc__internal_path_switched(svn_boolean_t *switched,
-                               svn_wc__db_t *wc_db,
-                               const char *local_abspath,
-                               apr_pool_t *scratch_pool);
-
 
 /* Similar to svn_wc_conflicted_p3(), but with a wc_db parameter in place of
  * a wc_context. */

Modified: subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc_db.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/libsvn_wc/wc_db.c Tue Mar 30 20:57:53 2010
@@ -264,6 +264,7 @@ static const svn_token_map_t presence_ma
 };
 
 
+/* */
 static svn_filesize_t
 get_translated_size(svn_sqlite__stmt_t *stmt, int slot)
 {
@@ -273,6 +274,7 @@ get_translated_size(svn_sqlite__stmt_t *
 }
 
 
+/* */
 static const char *
 escape_sqlite_like(const char * const str, apr_pool_t *result_pool)
 {
@@ -311,6 +313,7 @@ escape_sqlite_like(const char * const st
 }
 
 
+/* */
 static svn_error_t *
 verify_no_work(svn_sqlite__db_t *sdb)
 {
@@ -329,6 +332,7 @@ verify_no_work(svn_sqlite__db_t *sdb)
 }
 
 
+/* */
 static apr_status_t
 close_wcroot(void *data)
 {
@@ -350,6 +354,7 @@ close_wcroot(void *data)
 }
 
 
+/* */
 static svn_error_t *
 close_many_wcroots(apr_hash_t *roots,
                    apr_pool_t *state_pool,
@@ -359,7 +364,7 @@ close_many_wcroots(apr_hash_t *roots,
 
   for (hi = apr_hash_first(scratch_pool, roots); hi; hi = apr_hash_next(hi))
     {
-      wcroot_t *wcroot = svn_apr_hash_index_val(hi);
+      wcroot_t *wcroot = svn__apr_hash_index_val(hi);
       apr_status_t result;
 
       result = apr_pool_cleanup_run(state_pool, wcroot, close_wcroot);
@@ -517,6 +522,7 @@ get_pristine_fname(const char **pristine
 }
 
 
+/* */
 static svn_error_t *
 fetch_repos_info(const char **repos_root_url,
                  const char **repos_uuid,
@@ -547,7 +553,7 @@ fetch_repos_info(const char **repos_root
 
 /* Scan from LOCAL_RELPATH upwards through parent nodes until we find a parent
    that has values in the 'repos_id' and 'repos_relpath' columns.  Return
-   that information in REPOS_ID and REPOS_RELPATH (either may be NULL). 
+   that information in REPOS_ID and REPOS_RELPATH (either may be NULL).
    Use LOCAL_ABSPATH for diagnostics */
 static svn_error_t *
 scan_upwards_for_repos(apr_int64_t *repos_id,
@@ -694,6 +700,7 @@ get_old_version(int *version,
 }
 
 
+/* */
 static svn_wc__db_pdh_t *
 get_or_create_pdh(svn_wc__db_t *db,
                   const char *local_dir_abspath,
@@ -781,6 +788,7 @@ determine_obstructed_file(svn_boolean_t 
 }
 
 
+/* */
 static svn_error_t *
 fetch_wc_id(apr_int64_t *wc_id,
             svn_sqlite__db_t *sdb,
@@ -804,6 +812,7 @@ fetch_wc_id(apr_int64_t *wc_id,
 }
 
 
+/* */
 static svn_error_t *
 open_db(svn_sqlite__db_t **sdb,
         const char *dir_abspath,
@@ -1256,6 +1265,7 @@ get_statement_for_path(svn_sqlite__stmt_
 }
 
 
+/* */
 static svn_error_t *
 navigate_to_parent(svn_wc__db_pdh_t **parent_pdh,
                    svn_wc__db_t *db,
@@ -1322,6 +1332,7 @@ create_repos_id(apr_int64_t *repos_id,
 }
 
 
+/* */
 static svn_error_t *
 insert_base_node(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -1393,7 +1404,7 @@ insert_base_node(void *baton, svn_sqlite
                                                     name,
                                                     scratch_pool),
                                     pibb->local_relpath,
-                                    pibb->revision));
+                                    (apr_int64_t)pibb->revision));
           SVN_ERR(svn_sqlite__insert(NULL, stmt));
         }
     }
@@ -1402,6 +1413,7 @@ insert_base_node(void *baton, svn_sqlite
 }
 
 
+/* */
 static svn_error_t *
 gather_children(const apr_array_header_t **children,
                 svn_boolean_t base_only,
@@ -1453,6 +1465,7 @@ gather_children(const apr_array_header_t
 }
 
 
+/* */
 static void
 flush_entries(const svn_wc__db_pdh_t *pdh)
 {
@@ -1461,6 +1474,105 @@ flush_entries(const svn_wc__db_pdh_t *pd
 }
 
 
+/* Add a single WORK_ITEM into the given SDB's WORK_QUEUE table. This does
+   not perform its work within a transaction, assuming the caller will
+   manage that.  */
+static svn_error_t *
+add_single_work_item(svn_sqlite__db_t *sdb,
+                     const svn_skel_t *work_item,
+                     apr_pool_t *scratch_pool)
+{
+  svn_stringbuf_t *serialized;
+  svn_sqlite__stmt_t *stmt;
+
+  serialized = svn_skel__unparse(work_item, scratch_pool);
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_WORK_ITEM));
+  SVN_ERR(svn_sqlite__bind_blob(stmt, 1, serialized->data, serialized->len));
+  return svn_error_return(svn_sqlite__insert(NULL, stmt));
+}
+
+
+/* Add work item(s) to the given SDB. Also see add_one_work_item(). This
+   SKEL is usually passed to the various wc_db operation functions. It may
+   be NULL, indicating no additional work items are needed, it may be a
+   single work item, or it may be a list of work items.  */
+static svn_error_t *
+add_work_items(svn_sqlite__db_t *sdb,
+               const svn_skel_t *skel,
+               apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool;
+
+  /* Maybe there are no work items to insert.  */
+  if (skel == NULL)
+    return SVN_NO_ERROR;
+
+  /* Should have a list.  */
+  SVN_ERR_ASSERT(!skel->is_atom);
+
+  /* If SKEL has an atom as its first child, then this is a work item
+     (and that atom is one of the OP_* values).  */
+  if (skel->children->is_atom)
+    return svn_error_return(add_single_work_item(sdb, skel, scratch_pool));
+
+  /* SKEL is a list-of-lists, aka list of work items.  */
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (skel = skel->children; skel; skel = skel->next)
+    {
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(add_single_work_item(sdb, skel, iterpool));
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+
+/* Determine which trees' nodes exist for a given WC_ID and LOCAL_RELPATH
+   in the specified SDB.  */
+static svn_error_t *
+which_trees_exist(svn_boolean_t *base_exists,
+                  svn_boolean_t *working_exists,
+                  svn_sqlite__db_t *sdb,
+                  apr_int64_t wc_id,
+                  const char *local_relpath)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  *base_exists = FALSE;
+  *working_exists = FALSE;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                    STMT_DETERMINE_TREE_FOR_RECORDING));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (have_row)
+    {
+      int value = svn_sqlite__column_int(stmt, 0);
+
+      if (value)
+        *working_exists = TRUE;  /* value == 1  */
+      else
+        *base_exists = TRUE;  /* value == 0  */
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+      if (have_row)
+        {
+          /* If both rows, then both tables.  */
+          *base_exists = TRUE;
+          *working_exists = TRUE;
+        }
+    }
+
+  return svn_error_return(svn_sqlite__reset(stmt));
+}
+
+
+/* */
 static svn_error_t *
 create_db(svn_sqlite__db_t **sdb,
           apr_int64_t *repos_id,
@@ -2247,6 +2359,12 @@ svn_wc__db_base_get_props(apr_hash_t **p
 
   err = svn_sqlite__column_properties(props, stmt, 0, result_pool,
                                       scratch_pool);
+  if (err == NULL && *props == NULL)
+    {
+      /* ### is this a DB constraint violation? the column "probably" should
+         ### never be null.  */
+      *props = apr_hash_make(result_pool);
+    }
 
   return svn_error_compose_create(err, svn_sqlite__reset(stmt));
 }
@@ -2276,6 +2394,8 @@ svn_wc__db_base_set_dav_cache(svn_wc__db
                                  STMT_UPDATE_BASE_DAV_CACHE, scratch_pool));
   SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
 
+  /* ### we should assert that 1 row was affected.  */
+
   return svn_error_return(svn_sqlite__step_done(stmt));
 }
 
@@ -2348,43 +2468,6 @@ svn_wc__db_pristine_read(svn_stream_t **
 
 
 svn_error_t *
-svn_wc__db_pristine_write(svn_stream_t **contents,
-                          svn_wc__db_t *db,
-                          const char *wri_abspath,
-                          const svn_checksum_t *checksum,
-                          apr_pool_t *result_pool,
-                          apr_pool_t *scratch_pool)
-{
-  SVN_ERR_ASSERT(contents != NULL);
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
-  SVN_ERR_ASSERT(checksum != NULL);
-
-  VERIFY_CHECKSUM_KIND(checksum);
-
-  NOT_IMPLEMENTED();
-
-#if 0
-  const char *path;
-
-  SVN_ERR(get_pristine_fname(&path, pdh, checksum,
-#ifndef SVN__SKIP_SUBDIR
-                             TRUE /* create_subdir */,
-#endif
-                             scratch_pool, scratch_pool));
-
-  SVN_ERR(svn_stream_open_writable(contents, path, result_pool, scratch_pool));
-
-  /* ### we should wrap the stream. count the bytes. at close, then we
-     ### should write the count into the sqlite database. */
-  /* ### euh... no. stream closure could happen after an error, so there
-     ### isn't enough information here.  */
-
-  return SVN_NO_ERROR;
-#endif
-}
-
-
-svn_error_t *
 svn_wc__db_pristine_get_tempdir(const char **temp_dir_abspath,
                                 svn_wc__db_t *db,
                                 const char *wri_abspath,
@@ -2659,18 +2742,22 @@ svn_wc__db_op_set_props(svn_wc__db_t *db
                                          scratch_pool));
 }
 
-svn_error_t *
-svn_wc__db_temp_op_set_pristine_props(svn_wc__db_t *db,
-                                      const char *local_abspath,
-                                      const apr_hash_t *props,
-                                      svn_boolean_t on_working,
-                                      apr_pool_t *scratch_pool)
+
+/* Set properties in a given table. The row must exist.  */
+static svn_error_t *
+set_properties(svn_wc__db_t *db,
+               const char *local_abspath,
+               const apr_hash_t *props,
+               int stmt_idx,
+               const char *table_name,
+               apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   int affected_rows;
-  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
-                                 on_working ? STMT_UPDATE_WORKING_PROPS
-                                            : STMT_UPDATE_BASE_PROPS,
+
+  SVN_ERR_ASSERT(props != NULL);
+
+  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath, stmt_idx,
                                  scratch_pool));
 
   SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
@@ -2681,11 +2768,38 @@ svn_wc__db_temp_op_set_pristine_props(sv
                              _("Can't store properties for '%s' in '%s'."),
                              svn_dirent_local_style(local_abspath,
                                                     scratch_pool),
-                             on_working ? "working_node" : "base_node");
+                             table_name);
 
   return SVN_NO_ERROR;
 }
 
+
+svn_error_t *
+svn_wc__db_temp_base_set_props(svn_wc__db_t *db,
+                               const char *local_abspath,
+                               const apr_hash_t *props,
+                               apr_pool_t *scratch_pool)
+{
+  return svn_error_return(set_properties(db, local_abspath, props,
+                                         STMT_UPDATE_BASE_PROPS,
+                                         "base_node",
+                                         scratch_pool));
+}
+
+
+svn_error_t *
+svn_wc__db_temp_working_set_props(svn_wc__db_t *db,
+                                  const char *local_abspath,
+                                  const apr_hash_t *props,
+                                  apr_pool_t *scratch_pool)
+{
+  return svn_error_return(set_properties(db, local_abspath, props,
+                                         STMT_UPDATE_WORKING_PROPS,
+                                         "working_node",
+                                         scratch_pool));
+}
+
+
 svn_error_t *
 svn_wc__db_op_delete(svn_wc__db_t *db,
                      const char *local_abspath,
@@ -2728,6 +2842,7 @@ struct set_changelist_baton
   const char *changelist;
 };
 
+/* */
 static svn_error_t *
 set_changelist_txn(void *baton,
                    svn_sqlite__db_t *sdb,
@@ -2881,6 +2996,7 @@ struct set_tc_baton
 };
 
 
+/* */
 static svn_error_t *
 set_tc_txn(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -2890,10 +3006,6 @@ set_tc_txn(void *baton, svn_sqlite__db_t
   const char *tree_conflict_data;
   apr_hash_t *conflicts;
 
-  /* ### f13: just insert, remove or replace the row from the CONFLICT_VICTIM
-     ### table, rather than all this parsing, unparsing garbage. (and we
-     ### probably won't need a transaction, either.)*/
-
   /* Get the conflict information for the parent of LOCAL_ABSPATH. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_ACTUAL_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "is", stb->wc_id, stb->local_relpath));
@@ -3053,9 +3165,6 @@ svn_wc__db_op_read_tree_conflict(
 
   VERIFY_USABLE_PDH(pdh);
 
-  /* ### f13: just read the row from the CONFLICT_VICTIM table, rather than
-     ### all this parsing, unparsing garbage. */
-
   /* Get the conflict information for the parent of LOCAL_ABSPATH. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     STMT_SELECT_ACTUAL_NODE));
@@ -3100,7 +3209,7 @@ svn_wc__db_temp_op_remove_entry(svn_wc__
   svn_wc__db_pdh_t *pdh;
   svn_sqlite__stmt_t *stmt;
   svn_sqlite__db_t *sdb;
-  wcroot_t *wcroot;
+  apr_int64_t wc_id;
   const char *current_relpath;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
@@ -3126,19 +3235,19 @@ svn_wc__db_temp_op_remove_entry(svn_wc__
         flush_entries(pdh);
     }
 
-  wcroot = pdh->wcroot;
-  sdb = wcroot->sdb;
+  sdb = pdh->wcroot->sdb;
+  wc_id = pdh->wcroot->wc_id;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_BASE_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, current_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, current_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_ACTUAL_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, current_relpath));
 
   return svn_error_return(svn_sqlite__step_done(stmt));
 }
@@ -3153,8 +3262,6 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
 {
   svn_wc__db_pdh_t *pdh;
   svn_sqlite__stmt_t *stmt;
-  svn_sqlite__db_t *sdb;
-  wcroot_t *wcroot;
   const char *current_relpath;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath) &&
@@ -3165,22 +3272,21 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
-  wcroot = pdh->wcroot;
-  sdb = wcroot->sdb;
-
   /* ### We set depth on working and base to match entry behavior.
          Maybe these should be separated later? */
 
   if (flush_entry_cache)
     flush_entries(pdh);
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_UPDATE_BASE_DEPTH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_UPDATE_BASE_DEPTH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, current_relpath));
   SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_depth_to_word(depth)));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_UPDATE_WORKING_DEPTH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_UPDATE_WORKING_DEPTH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, current_relpath));
   SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_depth_to_word(depth)));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
@@ -3191,7 +3297,6 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
 
       err = navigate_to_parent(&pdh, db, pdh, svn_sqlite__mode_readwrite,
                                scratch_pool);
-
       if (err && err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)
         {
           /* No parent to update */
@@ -3207,6 +3312,7 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
   return SVN_NO_ERROR;
 }
 
+
 /* Update the working node for LOCAL_ABSPATH setting presence=STATUS */
 static svn_error_t *
 db_working_update_presence(svn_wc__db_status_t status,
@@ -3216,21 +3322,18 @@ db_working_update_presence(svn_wc__db_st
 {
   svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
-  wcroot_t *wcroot;
   svn_sqlite__stmt_t *stmt;
-  svn_sqlite__db_t *sdb;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
   SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
                               svn_sqlite__mode_readwrite,
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
-  wcroot = pdh->wcroot;
-  sdb = wcroot->sdb;
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_UPDATE_WORKING_PRESENCE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__bind_token(stmt, 3, presence_map, status));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_UPDATE_WORKING_PRESENCE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "ist", pdh->wcroot->wc_id, local_relpath,
+                            presence_map, status));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   flush_entries(pdh);
@@ -3242,6 +3345,7 @@ db_working_update_presence(svn_wc__db_st
   return SVN_NO_ERROR;
 }
 
+
 /* Delete working and actual nodes for LOCAL_ABSPATH */
 static svn_error_t *
 db_working_actual_remove(svn_wc__db_t *db,
@@ -3250,8 +3354,6 @@ db_working_actual_remove(svn_wc__db_t *d
 {
   svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
-  wcroot_t *wcroot;
-  svn_sqlite__db_t *sdb;
   svn_sqlite__stmt_t *stmt;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
@@ -3260,36 +3362,39 @@ db_working_actual_remove(svn_wc__db_t *d
                               scratch_pool, scratch_pool));
 
   VERIFY_USABLE_PDH(pdh);
-  wcroot = pdh->wcroot;
-  sdb = wcroot->sdb;
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_WORKING_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_DELETE_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_ACTUAL_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_DELETE_ACTUAL_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   flush_entries(pdh);
 
-  if (!strcmp(local_relpath, ""))
+  if (*local_relpath == '\0')
     {
       /* ### Delete parent stub. Remove when db is centralised. */
       SVN_ERR(navigate_to_parent(&pdh, db, pdh, svn_sqlite__mode_readwrite,
                                  scratch_pool));
       local_relpath = svn_dirent_basename(local_abspath, NULL);
       VERIFY_USABLE_PDH(pdh);
-      wcroot = pdh->wcroot;
-      sdb = wcroot->sdb;
-      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_WORKING_NODE));
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+
+      SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                        STMT_DELETE_WORKING_NODE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                pdh->wcroot->wc_id, local_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
+
       flush_entries(pdh);
     }
 
   return SVN_NO_ERROR;
 }
 
+
 /* Insert a working node for LOCAL_ABSPATH with presence=STATUS. */
 static svn_error_t *
 db_working_insert(svn_wc__db_status_t status,
@@ -3299,47 +3404,46 @@ db_working_insert(svn_wc__db_status_t st
 {
   svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
-  wcroot_t *wcroot;
   svn_sqlite__stmt_t *stmt;
-  svn_sqlite__db_t *sdb;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
   SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
                               svn_sqlite__mode_readwrite,
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
-  wcroot = pdh->wcroot;
-  sdb = wcroot->sdb;
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     STMT_INSERT_WORKING_NODE_FROM_BASE_NODE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__bind_token(stmt, 3, presence_map, status));
+  SVN_ERR(svn_sqlite__bindf(stmt, "ist", pdh->wcroot->wc_id, local_relpath,
+                            presence_map, status));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
   flush_entries(pdh);
 
-  if (!strcmp(local_relpath, ""))
+  if (*local_relpath == '\0')
     {
       /* ### Insert parent stub. Remove when db is centralised. */
       SVN_ERR(navigate_to_parent(&pdh, db, pdh, svn_sqlite__mode_readwrite,
                                  scratch_pool));
       local_relpath = svn_dirent_basename(local_abspath, NULL);
       VERIFY_USABLE_PDH(pdh);
-      wcroot = pdh->wcroot;
-      sdb = wcroot->sdb;
+
       /* ### Should the parent stub have a full row like this? */
-      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                    STMT_INSERT_WORKING_NODE_FROM_BASE_NODE));
-      SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-      SVN_ERR(svn_sqlite__bind_token(stmt, 3, presence_map, status));
+      SVN_ERR(svn_sqlite__get_statement(
+                &stmt, pdh->wcroot->sdb,
+                STMT_INSERT_WORKING_NODE_FROM_BASE_NODE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "ist",
+                                pdh->wcroot->wc_id, local_relpath,
+                                presence_map, status));
       SVN_ERR(svn_sqlite__step_done(stmt));
+
       flush_entries(pdh);
     }
 
   return SVN_NO_ERROR;
 }
 
+
 /* Set *ROOT_OF_COPY to TRUE if LOCAL_ABSPATH is an add or the root of
    a copy, to FALSE otherwise. */
 static svn_error_t*
@@ -3365,10 +3469,10 @@ is_add_or_root_of_copy(svn_boolean_t *ad
 
   SVN_ERR_ASSERT(status == svn_wc__db_status_added
                  || status == svn_wc__db_status_copied);
+  SVN_ERR_ASSERT(op_root_abspath != NULL);
 
   *add_or_root_of_copy = (status == svn_wc__db_status_added
-                          || (op_root_abspath
-                              && !strcmp(local_abspath, op_root_abspath)));
+                          || !strcmp(local_abspath, op_root_abspath));
 
   if (*add_or_root_of_copy && status == svn_wc__db_status_copied)
     {
@@ -3377,14 +3481,16 @@ is_add_or_root_of_copy(svn_boolean_t *ad
              here because I just need to detect whether this is an
              instance of the merge bug, and that's easier than fixing
              scan_addition or merge. */
-      const char *parent_abspath = svn_dirent_dirname(local_abspath,
-                                                      scratch_pool);
+      const char *parent_abspath;
+      const char *name;
       svn_wc__db_status_t parent_status;
       const char *parent_original_repos_relpath, *parent_original_repos_root;
       const char *parent_original_repos_uuid;
       svn_revnum_t parent_original_revision;
       svn_error_t *err;
 
+      svn_dirent_split(local_abspath, &parent_abspath, &name, scratch_pool);
+
       err = svn_wc__db_scan_addition(&parent_status,
                                      NULL, NULL, NULL, NULL,
                                      &parent_original_repos_relpath,
@@ -3406,8 +3512,7 @@ is_add_or_root_of_copy(svn_boolean_t *ad
                && !strcmp(original_repos_root, parent_original_repos_root)
                && !strcmp(original_repos_relpath,
                           svn_dirent_join(parent_original_repos_relpath,
-                                          svn_dirent_basename(local_abspath,
-                                                              scratch_pool),
+                                          name,
                                           scratch_pool)))
         /* An instance of the merge bug */
         *add_or_root_of_copy = FALSE;
@@ -3416,6 +3521,7 @@ is_add_or_root_of_copy(svn_boolean_t *ad
   return SVN_NO_ERROR;
 }
 
+
 /* Delete LOCAL_ABSPATH.  Implements the delete transition from
    notes/wc-ng/transitions. */
 svn_error_t *
@@ -3430,7 +3536,8 @@ svn_wc__db_temp_op_delete(svn_wc__db_t *
   err = svn_wc__db_base_get_info(&base_status,
                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-                                 db, local_abspath, scratch_pool, scratch_pool);
+                                 db, local_abspath,
+                                 scratch_pool, scratch_pool);
   if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
     {
       base_none = TRUE;
@@ -3441,8 +3548,10 @@ svn_wc__db_temp_op_delete(svn_wc__db_t *
   else
     return svn_error_return(err);
 
+  /* ### should error on excluded, too. excluded nodes could be removed
+     ### from our metadata, but they cannot be scheduled for deletion.  */
   if (!base_none && base_status == svn_wc__db_status_absent)
-    return SVN_NO_ERROR; /* ### return an error? */
+    return SVN_NO_ERROR; /* ### should return an error.... WHICH ONE? */
 
   err = db_working_get_status(&working_status,
                               db, local_abspath, scratch_pool);
@@ -3457,7 +3566,7 @@ svn_wc__db_temp_op_delete(svn_wc__db_t *
     return svn_error_return(err);
 
   if (base_none && working_none)
-    return SVN_NO_ERROR; /* ### return an error? */
+    return SVN_NO_ERROR; /* ### should return PATH_NOT_FOUND */
 
   new_working_none = working_none;
   new_working_status = working_status;
@@ -3524,6 +3633,7 @@ svn_wc__db_temp_op_delete(svn_wc__db_t *
   return SVN_NO_ERROR;
 }
 
+
 svn_error_t *
 svn_wc__db_read_info(svn_wc__db_status_t *status,
                      svn_wc__db_kind_t *kind,
@@ -3997,6 +4107,7 @@ svn_wc__db_read_props(apr_hash_t **props
   if (have_row)
     return SVN_NO_ERROR;
 
+  /* No local changes. Return the pristine props for this node.  */
   return svn_error_return(
       svn_wc__db_read_pristine_props(props, db, local_abspath,
                                      result_pool, scratch_pool));
@@ -4011,36 +4122,41 @@ svn_wc__db_read_pristine_props(apr_hash_
                                apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row, have_value;
-  svn_error_t *err = NULL;
+  svn_boolean_t have_row;
+  svn_error_t *err;
+
   *props = NULL;
 
   SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
                                  STMT_SELECT_WORKING_PROPS, scratch_pool));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
-  if (have_row && !svn_sqlite__column_is_null(stmt, 0))
+  /* If there is a WORKING row, then we're done.
+
+     For adds/copies/moves, then properties are in this row.
+     For deletes, there are no properties.
+
+     Regardless, we never look at BASE. The properties (or not) are here.  */
+  if (have_row)
     {
-      have_value = TRUE;
       err = svn_sqlite__column_properties(props, stmt, 0, result_pool,
                                           scratch_pool);
+      SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+      if (*props == NULL)
+        {
+          /* ### is this a DB constraint violation? the column "probably"
+             ### should never be null. maybe we should leave it null for
+             ### delete operations, so this is okay.  */
+          *props = apr_hash_make(result_pool);
+        }
+      return SVN_NO_ERROR;
     }
-  else
-    have_value = FALSE;
-
-  SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
-
-  if (have_value)
-    return SVN_NO_ERROR;
-
-  err = svn_wc__db_base_get_props(props, db, local_abspath,
-                                  result_pool, scratch_pool);
-
-  if (err && (!have_row || err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND))
-    return svn_error_return(err);
+  SVN_ERR(svn_sqlite__reset(stmt));
 
-  svn_error_clear(err);
-  return SVN_NO_ERROR;
+  /* No WORKING node, so the props must be in the BASE node.  */
+  return svn_error_return(svn_wc__db_base_get_props(props, db, local_abspath,
+                                                    result_pool,
+                                                    scratch_pool));
 }
 
 
@@ -4067,6 +4183,7 @@ struct relocate_baton
 };
 
 
+/* */
 static svn_error_t *
 relocate_txn(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -4248,6 +4365,7 @@ struct commit_baton {
 };
 
 
+/* */
 static svn_error_t *
 commit_node(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
 {
@@ -4454,6 +4572,7 @@ commit_node(void *baton, svn_sqlite__db_
 }
 
 
+/* */
 static svn_error_t *
 determine_repos_info(apr_int64_t *repos_id,
                      const char **repos_relpath,
@@ -4587,6 +4706,179 @@ svn_wc__db_global_commit(svn_wc__db_t *d
 }
 
 
+struct update_baton {
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+
+  const char *new_repos_relpath;
+  svn_revnum_t new_revision;
+  const apr_hash_t *new_props;
+  svn_revnum_t new_changed_rev;
+  apr_time_t new_changed_date;
+  const char *new_changed_author;
+  const apr_array_header_t *new_children;
+  const svn_checksum_t *new_checksum;
+  const char *new_target;
+  const svn_skel_t *conflict;
+  const svn_skel_t *work_items;
+};
+
+
+svn_error_t *
+svn_wc__db_global_update(svn_wc__db_t *db,
+                         const char *local_abspath,
+                         const char *new_repos_relpath,
+                         svn_revnum_t new_revision,
+                         const apr_hash_t *new_props,
+                         svn_revnum_t new_changed_rev,
+                         apr_time_t new_changed_date,
+                         const char *new_changed_author,
+                         const apr_array_header_t *new_children,
+                         const svn_checksum_t *new_checksum,
+                         const char *new_target,
+                         const svn_skel_t *conflict,
+                         const svn_skel_t *work_items,
+                         apr_pool_t *scratch_pool)
+{
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+  struct update_baton ub;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+  /* ### allow NULL for NEW_REPOS_RELPATH to indicate "no change"?  */
+  SVN_ERR_ASSERT(svn_relpath_is_canonical(new_repos_relpath, scratch_pool));
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_revision));
+  SVN_ERR_ASSERT(new_props != NULL);
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_changed_rev));
+  SVN_ERR_ASSERT((new_children != NULL
+                  && new_checksum == NULL
+                  && new_target == NULL)
+                 || (new_children == NULL
+                     && new_checksum != NULL
+                     && new_target == NULL)
+                 || (new_children == NULL
+                     && new_checksum == NULL
+                     && new_target != NULL));
+
+  SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+                              svn_sqlite__mode_readwrite,
+                              scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(pdh);
+
+  ub.pdh = pdh;
+  ub.local_relpath = local_relpath;
+
+  ub.new_repos_relpath = new_repos_relpath;
+  ub.new_revision = new_revision;
+  ub.new_props = new_props;
+  ub.new_changed_rev = new_changed_rev;
+  ub.new_changed_date = new_changed_date;
+  ub.new_changed_author = new_changed_author;
+  ub.new_children = new_children;
+  ub.new_checksum = new_checksum;
+  ub.new_target = new_target;
+
+  ub.conflict = conflict;
+  ub.work_items = work_items;
+
+  NOT_IMPLEMENTED();
+
+#if 0
+  SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb, update_node, &ub,
+                                       scratch_pool));
+#endif
+
+  /* We *totally* monkeyed the entries. Toss 'em.  */
+  flush_entries(pdh);
+
+  return SVN_NO_ERROR;
+}
+
+
+struct record_baton {
+  apr_int64_t wc_id;
+  const char *local_relpath;
+
+  svn_filesize_t translated_size;
+  apr_time_t last_mod_time;
+
+  /* For error reporting.  */
+  const char *local_abspath;
+};
+
+
+/* Record TRANSLATED_SIZE and LAST_MOD_TIME into the WORKING tree if a
+   node is present; otherwise, record it into the BASE tree. One of them
+   must exist.  */
+static svn_error_t *
+record_fileinfo(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
+{
+  struct record_baton *rb = baton;
+  svn_boolean_t base_exists;
+  svn_boolean_t working_exists;
+  svn_sqlite__stmt_t *stmt;
+  int affected_rows;
+
+  SVN_ERR(which_trees_exist(&base_exists, &working_exists,
+                            sdb, rb->wc_id, rb->local_relpath));
+  if (!base_exists && !working_exists)
+    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                             _("Could not find node '%s' for recording file "
+                               "information."),
+                             svn_dirent_local_style(rb->local_abspath,
+                                                    scratch_pool));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                    working_exists
+                                      ? STMT_UPDATE_WORKING_FILEINFO
+                                      : STMT_UPDATE_BASE_FILEINFO));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isii",
+                            rb->wc_id, rb->local_relpath,
+                            rb->translated_size, rb->last_mod_time));
+  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+  SVN_ERR_ASSERT(affected_rows == 1);
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_global_record_fileinfo(svn_wc__db_t *db,
+                                  const char *local_abspath,
+                                  svn_filesize_t translated_size,
+                                  apr_time_t last_mod_time,
+                                  apr_pool_t *scratch_pool)
+{
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+  struct record_baton rb;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+                              svn_sqlite__mode_readwrite,
+                              scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(pdh);
+
+  rb.wc_id = pdh->wcroot->wc_id;
+  rb.local_relpath = local_relpath;
+
+  rb.translated_size = translated_size;
+  rb.last_mod_time = last_mod_time;
+
+  rb.local_abspath = local_abspath;
+
+  SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb, record_fileinfo, &rb,
+                                       scratch_pool));
+
+  /* We *totally* monkeyed the entries. Toss 'em.  */
+  flush_entries(pdh);
+
+  return SVN_NO_ERROR;
+}
+
+
 svn_error_t *
 svn_wc__db_lock_add(svn_wc__db_t *db,
                     const char *local_abspath,
@@ -5138,8 +5430,8 @@ svn_wc__db_upgrade_apply_dav_cache(svn_s
        hi;
        hi = apr_hash_next(hi))
     {
-      const char *local_relpath = svn_apr_hash_index_key(hi);
-      apr_hash_t *props = svn_apr_hash_index_val(hi);
+      const char *local_relpath = svn__apr_hash_index_key(hi);
+      apr_hash_t *props = svn__apr_hash_index_val(hi);
 
       svn_pool_clear(iterpool);
 
@@ -5195,8 +5487,6 @@ svn_wc__db_wq_add(svn_wc__db_t *db,
 {
   svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
-  svn_stringbuf_t *serialized;
-  svn_sqlite__stmt_t *stmt;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
   SVN_ERR_ASSERT(work_item != NULL);
@@ -5226,12 +5516,10 @@ svn_wc__db_wq_add(svn_wc__db_t *db,
     }
 #endif
 
-  serialized = svn_skel__unparse(work_item, scratch_pool);
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
-                                    STMT_INSERT_WORK_ITEM));
-  SVN_ERR(svn_sqlite__bind_blob(stmt, 1, serialized->data, serialized->len));
-  return svn_error_return(svn_sqlite__insert(NULL, stmt));
+  /* Add the work item(s) to the WORK_QUEUE.  */
+  return svn_error_return(add_work_items(pdh->wcroot->sdb,
+                                         work_item,
+                                         scratch_pool));
 }
 
 
@@ -5590,8 +5878,8 @@ svn_wc__db_temp_get_all_access(svn_wc__d
        hi;
        hi = apr_hash_next(hi))
     {
-      const void *key = svn_apr_hash_index_key(hi);
-      const svn_wc__db_pdh_t *pdh = svn_apr_hash_index_val(hi);
+      const void *key = svn__apr_hash_index_key(hi);
+      const svn_wc__db_pdh_t *pdh = svn__apr_hash_index_val(hi);
 
       if (pdh->adm_access != NULL)
         apr_hash_set(result, key, APR_HASH_KEY_STRING, pdh->adm_access);
@@ -5799,7 +6087,7 @@ svn_wc__db_read_conflict_victims(const a
           hi = apr_hash_next(hi))
         {
           const char *child_name =
-              svn_dirent_basename(svn_apr_hash_index_key(hi), result_pool);
+              svn_dirent_basename(svn__apr_hash_index_key(hi), result_pool);
 
           /* Using a hash avoids duplicates */
           apr_hash_set(found, child_name, APR_HASH_KEY_STRING, child_name);
@@ -6042,7 +6330,7 @@ svn_wc__db_wclock_set(svn_wc__db_t *db,
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
                                     STMT_INSERT_WC_LOCK));
   SVN_ERR(svn_sqlite__bindf(stmt, "isi", pdh->wcroot->wc_id, local_relpath,
-                            levels_to_lock));
+                            (apr_int64_t) levels_to_lock));
   err = svn_sqlite__insert(NULL, stmt);
   if (err)
     return svn_error_createf(SVN_ERR_WC_LOCKED, err,
@@ -6054,6 +6342,7 @@ svn_wc__db_wclock_set(svn_wc__db_t *db,
 }
 
 
+/* */
 static svn_error_t *
 is_wclocked(svn_boolean_t *locked,
             svn_wc__db_t *db,
@@ -6329,3 +6618,430 @@ svn_wc__db_temp_op_set_working_last_chan
 
   return SVN_NO_ERROR;
 }
+
+struct start_directory_update_baton
+{
+  svn_wc__db_t *db;
+  const char *local_abspath;
+  apr_int64_t wc_id;
+  const char *local_relpath;
+  svn_revnum_t new_rev;
+  const char *new_repos_relpath;
+};
+
+static svn_error_t *
+start_directory_update_txn(void *baton,
+                           svn_sqlite__db_t *db,
+                           apr_pool_t *scratch_pool)
+{
+  struct start_directory_update_baton *du = baton;
+  const char *repos_relpath;
+  svn_sqlite__stmt_t *stmt;
+
+  SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath, NULL, NULL,
+                                     du->db, du->local_abspath,
+                                     scratch_pool, scratch_pool));
+
+  if (strcmp(du->new_repos_relpath, repos_relpath) == 0)
+    {
+      /* Just update revision and status */
+      SVN_ERR(svn_sqlite__get_statement(
+                        &stmt, db,
+                        STMT_UPDATE_BASE_PRESENCE_AND_REVNUM));
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "isti",
+                                du->wc_id,
+                                du->local_relpath,
+                                presence_map, svn_wc__db_status_incomplete,
+                                (apr_int64_t)du->new_rev));
+    }
+  else
+    {
+      /* ### TODO: Maybe check if we can make repos_relpath NULL. */
+      SVN_ERR(svn_sqlite__get_statement(
+                        &stmt, db,
+                        STMT_UPDATE_BASE_PRESENCE_REVNUM_AND_REPOS_RELPATH));
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "istis",
+                                du->wc_id,
+                                du->local_relpath,
+                                presence_map, svn_wc__db_status_incomplete,
+                                (apr_int64_t)du->new_rev,
+                                du->new_repos_relpath));
+    }
+
+  return svn_error_return(svn_sqlite__step_done(stmt));
+}
+
+svn_error_t *
+svn_wc__db_temp_op_start_directory_update(svn_wc__db_t *db,
+                                          const char *local_abspath,
+                                          const char* new_repos_relpath,
+                                          svn_revnum_t new_rev,
+                                          apr_pool_t *scratch_pool)
+{
+  svn_wc__db_pdh_t *pdh;
+  struct start_directory_update_baton du;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_rev));
+  SVN_ERR_ASSERT(svn_relpath_is_canonical(new_repos_relpath, scratch_pool));
+
+  SVN_ERR(parse_local_abspath(&pdh, &du.local_relpath, db, local_abspath,
+                              svn_sqlite__mode_readwrite,
+                              scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(pdh);
+
+  du.db = db;
+  du.wc_id = pdh->wcroot->wc_id;
+  du.local_abspath = local_abspath;
+  du.new_rev = new_rev;
+  du.new_repos_relpath = new_repos_relpath;
+
+  SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb,
+                                       start_directory_update_txn, &du,
+                                       scratch_pool));
+
+  flush_entries(pdh);
+
+  return SVN_NO_ERROR;
+}
+
+/* Baton for make_copy_txn */
+struct make_copy_baton
+{
+  svn_wc__db_t *db;
+  const char *local_abspath;
+
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+  svn_boolean_t remove_base;
+  svn_boolean_t is_root;
+};
+
+/* Transaction callback for svn_wc__db_temp_op_make_copy */
+static svn_error_t *
+make_copy_txn(void *baton,
+              svn_sqlite__db_t *sdb,
+              apr_pool_t *scratch_pool)
+{
+  struct make_copy_baton *mcb = baton;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  svn_boolean_t remove_working = FALSE;
+  svn_boolean_t check_base = TRUE;
+  svn_boolean_t add_working_normal = FALSE;
+  svn_boolean_t add_working_not_present = FALSE;
+  const apr_array_header_t *children;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  svn_wc__db_kind_t kind;
+  int i;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", mcb->pdh->wcroot->wc_id,
+                            mcb->local_relpath));
+
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  if (have_row)
+    {
+      svn_wc__db_status_t working_status;
+
+      working_status = svn_sqlite__column_token(stmt, 0, presence_map);
+      kind = svn_sqlite__column_token(stmt, 1, kind_map);
+      SVN_ERR(svn_sqlite__reset(stmt));
+
+      SVN_ERR_ASSERT(working_status == svn_wc__db_status_normal
+                     || working_status == svn_wc__db_status_base_deleted
+                     || working_status == svn_wc__db_status_not_present
+                     || working_status == svn_wc__db_status_incomplete);
+
+      /* Make existing deletions of BASE_NODEs remove WORKING_NODEs */
+      if (working_status == svn_wc__db_status_base_deleted)
+        {
+          remove_working = TRUE;
+          add_working_not_present = TRUE;
+        }
+
+      check_base = FALSE;
+    }
+  else
+    SVN_ERR(svn_sqlite__reset(stmt));
+
+  if (check_base)
+    {
+      svn_wc__db_status_t base_status;
+
+      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_BASE_NODE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "is", mcb->pdh->wcroot->wc_id, 
+                                mcb->local_relpath));
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+      /* If there is no BASE_NODE, we don't have to copy anything */
+      if (!have_row)
+        return svn_error_return(svn_sqlite__reset(stmt));
+
+      base_status = svn_sqlite__column_token(stmt, 2, presence_map);
+      kind = svn_sqlite__column_token(stmt, 3, kind_map);
+
+      SVN_ERR(svn_sqlite__reset(stmt));
+
+      switch (base_status)
+        {
+          case svn_wc__db_status_normal:
+          case svn_wc__db_status_incomplete:
+            add_working_normal = TRUE;
+            break;
+          case svn_wc__db_status_not_present:
+            add_working_not_present = TRUE;
+            break;
+          case svn_wc__db_status_excluded:
+          case svn_wc__db_status_absent:
+            /* ### Make the copy match the WC or the repository? */
+            add_working_not_present = TRUE; /* ### Match WC */
+            break;
+          default:
+            SVN_ERR_MALFUNCTION();
+        }
+    }
+
+  /* Get the BASE children, as WORKING children don't need modifications */
+  SVN_ERR(svn_wc__db_base_get_children(&children, mcb->db, mcb->local_abspath,
+                                       scratch_pool, iterpool));
+
+  for (i = 0; i < children->nelts; i++)
+    {
+      const char *name = APR_ARRAY_IDX(children, i, const char *);
+      struct make_copy_baton cbt;
+
+      svn_pool_clear(iterpool);
+      cbt.local_abspath = svn_dirent_join(mcb->local_abspath, name, iterpool);
+
+      SVN_ERR(parse_local_abspath(&cbt.pdh, &cbt.local_relpath, mcb->db,
+                                  cbt.local_abspath,
+                                  svn_sqlite__mode_readwrite,
+                                  iterpool, iterpool));
+
+      VERIFY_USABLE_PDH(cbt.pdh);
+
+      cbt.db = mcb->db;
+      cbt.remove_base = mcb->remove_base;
+      cbt.is_root = FALSE;
+
+      SVN_ERR(make_copy_txn(&cbt, cbt.pdh->wcroot->sdb, iterpool));
+    }
+
+  if (remove_working)
+    {
+      /* Remove current WORKING_NODE record */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                        STMT_DELETE_WORKING_NODE));
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                mcb->pdh->wcroot->wc_id,
+                                mcb->local_relpath));
+
+      SVN_ERR(svn_sqlite__step_done(stmt));
+    }
+
+  if (add_working_normal)
+    {
+      /* Add a copy of the BASE_NODE to WORKING_NODE */
+
+      SVN_ERR(svn_sqlite__get_statement(
+                        &stmt, sdb,
+                        STMT_INSERT_WORKING_NODE_NORMAL_FROM_BASE_NODE));
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                mcb->pdh->wcroot->wc_id,
+                                mcb->local_relpath));
+
+      SVN_ERR(svn_sqlite__step_done(stmt));
+    }
+  else if (add_working_not_present)
+    {
+      /* Add a not present WORKING_NODE */
+
+      SVN_ERR(svn_sqlite__get_statement(
+                        &stmt, sdb,
+                        STMT_INSERT_WORKING_NODE_NOT_PRESENT_FROM_BASE_NODE));
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                mcb->pdh->wcroot->wc_id,
+                                mcb->local_relpath));
+
+      SVN_ERR(svn_sqlite__step_done(stmt));
+    }
+
+  if (mcb->is_root && (add_working_normal || add_working_not_present))
+    {
+      const char *repos_relpath, *repos_root_url, *repos_uuid;
+      apr_int64_t repos_id;
+      /* Make sure the copy origin is set on the root even if the node
+         didn't have a local relpath */
+
+      SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath, &repos_root_url,
+                                         &repos_uuid, mcb->db,
+                                         mcb->local_abspath,
+                                         iterpool, iterpool));
+
+      SVN_ERR(create_repos_id(&repos_id, repos_root_url, repos_uuid, sdb,
+                              iterpool));
+
+      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_UPDATE_COPYFROM));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isis",
+                                mcb->pdh->wcroot->wc_id,
+                                mcb->local_relpath,
+                                repos_id,
+                                repos_relpath));
+
+      SVN_ERR(svn_sqlite__step_done(stmt));
+    }
+
+  /* And now, do the same for the parent stub :( If we kind from the
+     working node could the base node be different?  Not until we move
+     to a single db and then the parent stubs should go away. */
+  if (kind == svn_wc__db_kind_dir)
+    {
+      if (remove_working)
+        {
+          const char *local_relpath;
+          svn_wc__db_pdh_t *pdh;
+
+          /* Remove WORKING_NODE stub */
+          SVN_ERR(navigate_to_parent(&pdh, mcb->db, mcb->pdh,
+                                     svn_sqlite__mode_readwrite,
+                                     iterpool));
+          local_relpath = svn_dirent_basename(mcb->local_abspath, NULL);
+          VERIFY_USABLE_PDH(pdh);
+
+          SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                            STMT_DELETE_WORKING_NODE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+        }
+
+      if (add_working_normal)
+        {
+          const char *local_relpath;
+          svn_wc__db_pdh_t *pdh;
+
+          /* Add a copy of the BASE_NODE to WORKING_NODE for the stub */
+          SVN_ERR(navigate_to_parent(&pdh, mcb->db, mcb->pdh,
+                                     svn_sqlite__mode_readwrite,
+                                     iterpool));
+          local_relpath = svn_dirent_basename(mcb->local_abspath, NULL);
+          VERIFY_USABLE_PDH(pdh);
+
+          /* Remove old data */
+          SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                            STMT_DELETE_WORKING_NODE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+
+          /* And insert the right data */
+          SVN_ERR(svn_sqlite__get_statement(
+                        &stmt, pdh->wcroot->sdb,
+                        STMT_INSERT_WORKING_NODE_NORMAL_FROM_BASE_NODE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+        }
+      else if (add_working_not_present)
+        {
+          const char *local_relpath;
+          svn_wc__db_pdh_t *pdh;
+
+          /* Add a not present WORKING_NODE stub */
+          SVN_ERR(navigate_to_parent(&pdh, mcb->db, mcb->pdh,
+                                     svn_sqlite__mode_readwrite,
+                                     iterpool));
+          local_relpath = svn_dirent_basename(mcb->local_abspath, NULL);
+          VERIFY_USABLE_PDH(pdh);
+
+          /* Remove old data */
+          SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                            STMT_DELETE_WORKING_NODE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+
+          /* And insert the right data */
+          SVN_ERR(svn_sqlite__get_statement(
+                        &stmt, pdh->wcroot->sdb,
+                        STMT_INSERT_WORKING_NODE_NOT_PRESENT_FROM_BASE_NODE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+        }
+    }
+
+  /* Remove the BASE_NODE if the caller asked us to do that */
+  if (mcb->remove_base)
+    {
+      const char *local_relpath;
+      svn_wc__db_pdh_t *pdh;
+
+      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+                                        STMT_DELETE_BASE_NODE));
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                mcb->pdh->wcroot->wc_id,
+                                mcb->local_relpath));
+
+      SVN_ERR(svn_sqlite__step_done(stmt));
+
+      /* Remove BASE_NODE_STUB */
+      if (kind == svn_wc__db_kind_dir)
+        {
+          SVN_ERR(navigate_to_parent(&pdh, mcb->db, mcb->pdh,
+                                     svn_sqlite__mode_readwrite,
+                                     iterpool));
+          local_relpath = svn_dirent_basename(mcb->local_abspath, NULL);
+          VERIFY_USABLE_PDH(pdh);
+
+          SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                            STMT_DELETE_BASE_NODE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "is",
+                                    pdh->wcroot->wc_id, local_relpath));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+        }
+    }
+
+  svn_pool_destroy(iterpool);
+
+  flush_entries(mcb->pdh);
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_temp_op_make_copy(svn_wc__db_t *db,
+                             const char *local_abspath,
+                             svn_boolean_t remove_base,
+                             apr_pool_t *scratch_pool)
+{
+  struct make_copy_baton mcb;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(parse_local_abspath(&mcb.pdh, &mcb.local_relpath, db, local_abspath,
+                              svn_sqlite__mode_readwrite,
+                              scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(mcb.pdh);
+
+  mcb.db = db;
+  mcb.local_abspath = local_abspath;
+  mcb.remove_base = remove_base;
+  mcb.is_root = TRUE;
+
+  SVN_ERR(svn_sqlite__with_transaction(mcb.pdh->wcroot->sdb,
+                                       make_copy_txn, &mcb,
+                                       scratch_pool));
+
+  return SVN_NO_ERROR;
+}