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/10/20 19:57:43 UTC

svn commit: r1025655 [4/6] - in /subversion/branches/object-model: ./ build/win32/ notes/http-and-webdav/ notes/wc-ng/ subversion/bindings/ctypes-python/csvn/ subversion/include/ subversion/libsvn_client/ subversion/libsvn_diff/ subversion/libsvn_fs_fs...

Modified: subversion/branches/object-model/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_wc/wc_db.c?rev=1025655&r1=1025654&r2=1025655&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/object-model/subversion/libsvn_wc/wc_db.c Wed Oct 20 17:57:41 2010
@@ -225,8 +225,38 @@ add_work_items(svn_sqlite__db_t *sdb,
                const svn_skel_t *skel,
                apr_pool_t *scratch_pool);
 
+static svn_error_t *
+insert_incomplete_children(svn_sqlite__db_t *sdb,
+                           apr_int64_t wc_id,
+                           const char *local_relpath,
+                           svn_revnum_t revision,
+                           const apr_array_header_t *children,
+                           apr_int64_t op_depth,
+                           apr_pool_t *scratch_pool);
 
-/* */
+static svn_error_t *
+db_read_pristine_props(apr_hash_t **props,
+                       svn_wc__db_pdh_t *pdh,
+                       const char *local_relpath,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool);
+
+
+/* Return the absolute path, in local path style, of LOCAL_RELPATH in WCROOT. */
+static const char *
+path_for_error_message(const svn_wc__db_wcroot_t *wcroot,
+                       const char *local_relpath,
+                       apr_pool_t *result_pool)
+{
+  const char *local_abspath
+    = svn_dirent_join(wcroot->abspath, local_relpath, result_pool);
+
+  return svn_dirent_local_style(local_abspath, result_pool);
+}
+
+
+/* Return a file size from column SLOT of the SQLITE statement STMT, or
+ * SVN_INVALID_FILESIZE if the column value is NULL. */
 static svn_filesize_t
 get_translated_size(svn_sqlite__stmt_t *stmt, int slot)
 {
@@ -236,6 +266,34 @@ get_translated_size(svn_sqlite__stmt_t *
 }
 
 
+/* Return a lock info structure constructed from the given columns of the
+ * SQLITE statement STMT, or return NULL if the token column value is null. */
+static svn_wc__db_lock_t *
+lock_from_columns(svn_sqlite__stmt_t *stmt,
+                  int col_token,
+                  int col_owner,
+                  int col_comment,
+                  int col_date,
+                  apr_pool_t *result_pool)
+{
+  svn_wc__db_lock_t *lock;
+
+  if (svn_sqlite__column_is_null(stmt, col_token))
+    {
+      lock = NULL;
+    }
+  else
+    {
+      lock = apr_pcalloc(result_pool, sizeof(svn_wc__db_lock_t));
+      lock->token = svn_sqlite__column_text(stmt, col_token, result_pool);
+      lock->owner = svn_sqlite__column_text(stmt, col_owner, result_pool);
+      lock->comment = svn_sqlite__column_text(stmt, col_comment, result_pool);
+      lock->date = svn_sqlite__column_int64(stmt, col_date);
+    }
+  return lock;
+}
+
+
 /* */
 static const char *
 escape_sqlite_like(const char * const str, apr_pool_t *result_pool)
@@ -367,7 +425,9 @@ get_pristine_fname(const char **pristine
 }
 
 
-/* */
+/* Look up REPOS_ID in SDB and set *REPOS_ROOT_URL and/or *REPOS_UUID to
+ * its root URL and UUID respectively.  Either output parameter may be
+ * NULL if not wanted. */
 static svn_error_t *
 fetch_repos_info(const char **repos_root_url,
                  const char **repos_uuid,
@@ -395,22 +455,69 @@ fetch_repos_info(const char **repos_root
   return svn_error_return(svn_sqlite__reset(stmt));
 }
 
+/* Set *REPOS_ROOT_URL, *REPOS_UUID, *REVISION and *REPOS_RELPATH from the
+ * given columns of the SQLITE statement STMT, or to NULL if the respective
+ * column value is null.  Any of the output parameters may be NULL if not
+ * required. */
+static svn_error_t *
+repos_location_from_columns(const char **repos_root_url,
+                            const char **repos_uuid,
+                            svn_revnum_t *revision,
+                            const char **repos_relpath,
+                            svn_wc__db_pdh_t *pdh,
+                            svn_sqlite__stmt_t *stmt,
+                            int col_repos_id,
+                            int col_revision,
+                            int col_repos_relpath,
+                            apr_pool_t *result_pool)
+{
+  svn_error_t *err = SVN_NO_ERROR;
+
+  if (repos_root_url || repos_uuid)
+    {
+      /* Fetch repository information via REPOS_ID. */
+      if (svn_sqlite__column_is_null(stmt, col_repos_id))
+        {
+          if (repos_root_url)
+            *repos_root_url = NULL;
+          if (repos_uuid)
+            *repos_uuid = NULL;
+        }
+      else
+        {
+          err = fetch_repos_info(repos_root_url, repos_uuid,
+                                 pdh->wcroot->sdb,
+                                 svn_sqlite__column_int64(stmt, col_repos_id),
+                                 result_pool);
+        }
+    }
+  if (revision)
+    {
+      *revision = svn_sqlite__column_revnum(stmt, col_revision);
+    }
+  if (repos_relpath)
+    {
+      *repos_relpath = svn_sqlite__column_text(stmt, col_repos_relpath,
+                                               result_pool);
+    }
+
+  return err;
+}
+
+
 /* 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).
-   Use LOCAL_ABSPATH for diagnostics */
+   that information in REPOS_ID and REPOS_RELPATH (either may be NULL). */
 static svn_error_t *
 scan_upwards_for_repos(apr_int64_t *repos_id,
                        const char **repos_relpath,
                        const svn_wc__db_wcroot_t *wcroot,
-                       const char *local_abspath,
                        const char *local_relpath,
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool)
 {
   const char *relpath_suffix = "";
-  const char *current_basename = svn_dirent_basename(local_relpath,
-                                                     scratch_pool);
+  const char *current_basename = svn_dirent_basename(local_relpath, NULL);
   const char *current_relpath = local_relpath;
   svn_sqlite__stmt_t *stmt;
 
@@ -437,14 +544,14 @@ scan_upwards_for_repos(apr_int64_t *repo
               err = svn_error_createf(
                 SVN_ERR_WC_CORRUPT, NULL,
                 _("Parent(s) of '%s' should have been present."),
-                svn_dirent_local_style(local_abspath, scratch_pool));
+                path_for_error_message(wcroot, local_relpath, scratch_pool));
             }
           else
             {
               err = svn_error_createf(
                 SVN_ERR_WC_PATH_NOT_FOUND, NULL,
                 _("The node '%s' was not found."),
-                svn_dirent_local_style(local_abspath, scratch_pool));
+                path_for_error_message(wcroot, local_relpath, scratch_pool));
             }
 
           return svn_error_compose_create(err, svn_sqlite__reset(stmt));
@@ -478,7 +585,7 @@ scan_upwards_for_repos(apr_int64_t *repo
           return svn_error_createf(
             SVN_ERR_WC_CORRUPT, NULL,
             _("Parent(s) of '%s' should have repository information."),
-            svn_relpath_local_style(local_abspath, scratch_pool));
+            path_for_error_message(wcroot, local_relpath, scratch_pool));
         }
 
       /* Strip a path segment off the end, and append it to the suffix
@@ -631,28 +738,12 @@ insert_base_node(void *baton, svn_sqlite
   SVN_ERR(svn_sqlite__insert(NULL, stmt));
 
   if (pibb->kind == svn_wc__db_kind_dir && pibb->children)
-    {
-      int i;
-
-      SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE));
-
-      for (i = pibb->children->nelts; i--; )
-        {
-          const char *name = APR_ARRAY_IDX(pibb->children, i, const char *);
-
-          SVN_ERR(svn_sqlite__bindf(stmt, "isisnnrsns",
-                                    pibb->wc_id,
-                                    svn_relpath_join(pibb->local_relpath,
-                                                     name,
-                                                     scratch_pool),
-                                    (apr_int64_t)0 /* BASE */,
-                                    pibb->local_relpath, /* parent_relpath */
-                                    pibb->revision,
-                                    "incomplete",
-                                    "unknown"));
-          SVN_ERR(svn_sqlite__insert(NULL, stmt));
-        }
-    }
+    SVN_ERR(insert_incomplete_children(sdb, pibb->wc_id,
+                                       pibb->local_relpath,
+                                       pibb->revision,
+                                       pibb->children,
+                                       0 /* BASE */,
+                                       scratch_pool));
 
   SVN_ERR(add_work_items(sdb, pibb->work_items, scratch_pool));
 
@@ -740,16 +831,19 @@ copy_working_from_base(void *baton,
 }
 
 
-/* Insert WORKING rows for each (const char *) child name in CHILDREN,
-   whose parent directory is LOCAL_RELPATH.  For each child, set
-   presence='incomplete', kind='unknown', op_depth=OP_DEPTH. */
-static svn_error_t *
-insert_incomplete_working_children(svn_sqlite__db_t *sdb,
-                                   apr_int64_t wc_id,
-                                   const char *local_relpath,
-                                   const apr_array_header_t *children,
-                                   apr_int64_t op_depth,
-                                   apr_pool_t *scratch_pool)
+/* Insert a row in NODES for each (const char *) child name in CHILDREN,
+   whose parent directory is LOCAL_RELPATH, at op_depth=OP_DEPTH.  Set each
+   child's presence to 'incomplete', kind to 'unknown', and revision to
+   REVISION (which should match the parent's revision).  The child's
+   repos_id and repos_relpath will be inherited from the parent. */
+static svn_error_t *
+insert_incomplete_children(svn_sqlite__db_t *sdb,
+                           apr_int64_t wc_id,
+                           const char *local_relpath,
+                           svn_revnum_t revision,
+                           const apr_array_header_t *children,
+                           apr_int64_t op_depth,
+                           apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   int i;
@@ -760,12 +854,13 @@ insert_incomplete_working_children(svn_s
     {
       const char *name = APR_ARRAY_IDX(children, i, const char *);
 
-      SVN_ERR(svn_sqlite__bindf(stmt, "isisnnnsns",
+      SVN_ERR(svn_sqlite__bindf(stmt, "isisnnrsns",
                                 wc_id,
                                 svn_relpath_join(local_relpath, name,
                                                  scratch_pool),
                                 op_depth,
                                 local_relpath,
+                                revision,
                                 "incomplete", /* 8, presence */
                                 "unknown"));  /* 10, kind */
 
@@ -840,11 +935,12 @@ insert_working_node(void *baton,
      (The only time we'd want a different depth is during a recursive
      simple add, but we never insert children here during a simple add.) */
   if (piwb->kind == svn_wc__db_kind_dir && piwb->children)
-    SVN_ERR(insert_incomplete_working_children(sdb, piwb->wc_id,
-                                               piwb->local_relpath,
-                                               piwb->children,
-                                               piwb->op_depth,
-                                               scratch_pool));
+    SVN_ERR(insert_incomplete_children(sdb, piwb->wc_id,
+                                       piwb->local_relpath,
+                                       piwb->original_revnum,
+                                       piwb->children,
+                                       piwb->op_depth,
+                                       scratch_pool));
 
   SVN_ERR(add_work_items(sdb, piwb->work_items, scratch_pool));
 
@@ -1762,51 +1858,12 @@ svn_wc__db_base_get_info(svn_wc__db_stat
         {
           *status = svn_sqlite__column_token(stmt, 2, presence_map);
         }
-      if (revision)
-        {
-          *revision = svn_sqlite__column_revnum(stmt, 4);
-        }
-      if (repos_relpath)
-        {
-          *repos_relpath = svn_sqlite__column_text(stmt, 1, result_pool);
-        }
+      err = repos_location_from_columns(repos_root_url, repos_uuid, revision,
+                                        repos_relpath,
+                                        pdh, stmt, 0, 4, 1, result_pool);
       if (lock)
         {
-          if (svn_sqlite__column_is_null(stmt, 14))
-            {
-              *lock = NULL;
-            }
-          else
-            {
-              *lock = apr_pcalloc(result_pool, sizeof(svn_wc__db_lock_t));
-              (*lock)->token = svn_sqlite__column_text(stmt, 14, result_pool);
-              if (!svn_sqlite__column_is_null(stmt, 15))
-                (*lock)->owner = svn_sqlite__column_text(stmt, 15,
-                                                         result_pool);
-              if (!svn_sqlite__column_is_null(stmt, 16))
-                (*lock)->comment = svn_sqlite__column_text(stmt, 16,
-                                                           result_pool);
-              if (!svn_sqlite__column_is_null(stmt, 17))
-                (*lock)->date = svn_sqlite__column_int64(stmt, 17);
-            }
-        }
-      if (repos_root_url || repos_uuid)
-        {
-          /* Fetch repository information via REPOS_ID. */
-          if (svn_sqlite__column_is_null(stmt, 0))
-            {
-              if (repos_root_url)
-                *repos_root_url = NULL;
-              if (repos_uuid)
-                *repos_uuid = NULL;
-            }
-          else
-            {
-              err = fetch_repos_info(repos_root_url, repos_uuid,
-                                     pdh->wcroot->sdb,
-                                     svn_sqlite__column_int64(stmt, 0),
-                                     result_pool);
-            }
+          *lock = lock_from_columns(stmt, 14, 15, 16, 17, result_pool);
         }
       if (changed_rev)
         {
@@ -2513,27 +2570,6 @@ svn_wc__db_pristine_repair(svn_wc__db_t 
 }
 
 
-svn_error_t *
-svn_wc__db_repos_ensure(apr_int64_t *repos_id,
-                        svn_wc__db_t *db,
-                        const char *local_abspath,
-                        const char *repos_root_url,
-                        const char *repos_uuid,
-                        apr_pool_t *scratch_pool)
-{
-  svn_wc__db_pdh_t *pdh;
-  const char *local_relpath;
-
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
-                              local_abspath, svn_sqlite__mode_readwrite,
-                              scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(pdh);
-
-  return svn_error_return(create_repos_id(repos_id, repos_root_url,
-                                          repos_uuid, pdh->wcroot->sdb,
-                                          scratch_pool));
-}
-
 /* Helper for svn_wc__db_op_copy to handle copying from one db to
    another */
 static svn_error_t *
@@ -2931,12 +2967,13 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
       SVN_ERR(svn_sqlite__step_done(stmt));
 
       if (kind == svn_wc__db_kind_dir)
-        SVN_ERR(insert_incomplete_working_children(dst_pdh->wcroot->sdb,
-                                                   dst_pdh->wcroot->wc_id,
-                                                   dst_relpath,
-                                                   children,
-                                                   op_depth,
-                                                   scratch_pool));
+        SVN_ERR(insert_incomplete_children(dst_pdh->wcroot->sdb,
+                                           dst_pdh->wcroot->wc_id,
+                                           dst_relpath,
+                                           copyfrom_rev,
+                                           children,
+                                           op_depth,
+                                           scratch_pool));
     }
   else
     {
@@ -3087,7 +3124,16 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db
       iwb.original_revnum = original_revision;
     }
 
+#ifdef SVN_WC__OP_DEPTH
+  iwb.op_depth = relpath_depth(local_relpath);
+
+  /* ### TODO? If the WC parent dir is already a copy from
+   * dirname(original_repos_relpath)@original_revision, then this is a
+   * redundant copy as far is the repos is concerned, so it should share
+   * the same op_depth.  But that's a degenerate case.  Is it needed? */
+#else
   iwb.op_depth = 2;  /* ### temporary op_depth */
+#endif
 
   iwb.checksum = checksum;
 
@@ -3299,7 +3345,7 @@ struct set_props_baton
 {
   apr_hash_t *props;
 
-  apr_int64_t wc_id;
+  svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
 
   const svn_skel_t *conflict;
@@ -3307,6 +3353,38 @@ struct set_props_baton
 };
 
 
+/* Set the ACTUAL_NODE properties column for (WC_ID, LOCAL_RELPATH) to
+ * PROPS. */
+static svn_error_t *
+set_actual_props(apr_int64_t wc_id,
+                 const char *local_relpath,
+                 apr_hash_t *props,
+                 svn_sqlite__db_t *db,
+                 apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  int affected_rows;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_UPDATE_ACTUAL_PROPS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
+  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+  if (affected_rows == 1 || !props)
+    return SVN_NO_ERROR; /* We are done */
+
+  /* We have to insert a row in ACTUAL */
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_ACTUAL_PROPS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+  if (*local_relpath != '\0')
+    SVN_ERR(svn_sqlite__bind_text(stmt, 3,
+                                  svn_relpath_dirname(local_relpath,
+                                                      scratch_pool)));
+  SVN_ERR(svn_sqlite__bind_properties(stmt, 4, props, scratch_pool));
+  return svn_error_return(svn_sqlite__step_done(stmt));
+}
+
 /* Set the 'properties' column in the 'ACTUAL_NODE' table to BATON->props.
    Create an entry in the ACTUAL table for the node if it does not yet
    have one.
@@ -3316,8 +3394,7 @@ static svn_error_t *
 set_props_txn(void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool)
 {
   struct set_props_baton *spb = baton;
-  svn_sqlite__stmt_t *stmt;
-  int affected_rows;
+  apr_hash_t *pristine_props;
 
   /* ### we dunno what to do with CONFLICT yet.  */
   SVN_ERR_ASSERT(spb->conflict == NULL);
@@ -3325,24 +3402,25 @@ set_props_txn(void *baton, svn_sqlite__d
   /* First order of business: insert all the work items.  */
   SVN_ERR(add_work_items(db, spb->work_items, scratch_pool));
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_UPDATE_ACTUAL_PROPS));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", spb->wc_id, spb->local_relpath));
-  SVN_ERR(svn_sqlite__bind_properties(stmt, 3, spb->props, scratch_pool));
-  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+  /* Check if the props are modified. If no changes, then wipe out the
+     ACTUAL props.  PRISTINE_PROPS==NULL means that any
+     ACTUAL props are okay as provided, so go ahead and set them.  */
+  SVN_ERR(db_read_pristine_props(&pristine_props, spb->pdh, spb->local_relpath,
+                                 scratch_pool, scratch_pool));
+  if (spb->props && pristine_props)
+    {
+      apr_array_header_t *prop_diffs;
 
-  if (affected_rows == 1 || !spb->props)
-    return SVN_NO_ERROR; /* We are done */
+      SVN_ERR(svn_prop_diffs(&prop_diffs, spb->props, pristine_props,
+                             scratch_pool));
+      if (prop_diffs->nelts == 0)
+        spb->props = NULL;
+    }
 
-  /* We have to insert a row in ACTUAL */
+  SVN_ERR(set_actual_props(spb->pdh->wcroot->wc_id, spb->local_relpath,
+                           spb->props, db, scratch_pool));
 
-  SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_ACTUAL_PROPS));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", spb->wc_id, spb->local_relpath));
-  if (*spb->local_relpath != '\0')
-    SVN_ERR(svn_sqlite__bind_text(stmt, 3,
-                                  svn_relpath_dirname(spb->local_relpath,
-                                                      scratch_pool)));
-  SVN_ERR(svn_sqlite__bind_properties(stmt, 4, spb->props, scratch_pool));
-  return svn_error_return(svn_sqlite__step_done(stmt));
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -3364,7 +3442,7 @@ svn_wc__db_op_set_props(svn_wc__db_t *db
   VERIFY_USABLE_PDH(pdh);
 
   spb.props = props;
-  spb.wc_id = pdh->wcroot->wc_id;
+  spb.pdh = pdh;
   spb.conflict = conflict;
   spb.work_items = work_items;
 
@@ -3661,8 +3739,7 @@ set_tc_txn(void *baton, svn_sqlite__db_t
   SVN_ERR(svn_wc__read_tree_conflicts(&conflicts, tree_conflict_data,
                                       stb->parent_abspath, scratch_pool));
 
-  apr_hash_set(conflicts, svn_dirent_basename(stb->local_abspath,
-                                              scratch_pool),
+  apr_hash_set(conflicts, svn_dirent_basename(stb->local_abspath, NULL),
                APR_HASH_KEY_STRING, stb->tree_conflict);
 
   if (apr_hash_count(conflicts) == 0 && !have_row)
@@ -3691,6 +3768,11 @@ set_tc_txn(void *baton, svn_sqlite__db_t
   SVN_ERR(svn_sqlite__bindf(stmt, "iss", stb->wc_id, stb->local_relpath,
                             tree_conflict_data));
 
+  if (!have_row && stb->local_relpath[0])
+    SVN_ERR(svn_sqlite__bind_text(stmt, 4,
+                                  svn_dirent_dirname(stb->local_relpath,
+                                                     scratch_pool)));
+
   return svn_error_return(svn_sqlite__step_done(stmt));
 }
 
@@ -3836,31 +3918,32 @@ svn_wc__db_op_read_tree_conflict(
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 {
-  const char *parent_abspath;
-  apr_hash_t *tree_conflicts;
-  svn_error_t *err;
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-  parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
 
-  err = svn_wc__db_op_read_all_tree_conflicts(&tree_conflicts, db,
-                                              parent_abspath,
-                                              result_pool, scratch_pool);
-  if (err && SVN_WC__ERR_IS_NOT_CURRENT_WC(err))
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+                              local_abspath, svn_sqlite__mode_readonly,
+                              scratch_pool, scratch_pool));
+
+  if (local_relpath[0])
     {
-       /* We walked off the top of a working copy.  */
-       svn_error_clear(err);
-       *tree_conflict = NULL;
-       return SVN_NO_ERROR;
-    }
-  else if (err)
-    return svn_error_return(err);
+      const char * parent_abspath;
+      apr_hash_t *tree_conflicts;
 
-  if (tree_conflicts)
-    *tree_conflict = apr_hash_get(tree_conflicts,
-                                  svn_dirent_basename(local_abspath,
-                                                      scratch_pool),
-                                  APR_HASH_KEY_STRING);
+      parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
+
+      SVN_ERR(svn_wc__db_op_read_all_tree_conflicts(&tree_conflicts, db,
+                                                    parent_abspath,
+                                                    result_pool, scratch_pool));
+      if (tree_conflicts)
+        *tree_conflict = apr_hash_get(tree_conflicts,
+                                      svn_dirent_basename(local_abspath, NULL),
+                                      APR_HASH_KEY_STRING);
+      else
+        *tree_conflict = NULL;
+    }
   else
     *tree_conflict = NULL;
 
@@ -4434,47 +4517,31 @@ svn_wc__db_read_info(svn_wc__db_status_t
         {
           *kind = node_kind;
         }
-      if (revision)
+      if (op_depth != 0)
         {
-          if (op_depth != 0)
+          if (repos_root_url)
+            *repos_root_url = NULL;
+          if (repos_uuid)
+            *repos_uuid = NULL;
+          if (revision)
             *revision = SVN_INVALID_REVNUM;
-          else
-            *revision = svn_sqlite__column_revnum(stmt_info, 5);
-        }
-      if (repos_relpath)
-        {
-          if (op_depth != 0)
-            {
-              /* Our path is implied by our parent somewhere up the tree.
-                 With the NULL value and status, the caller will know to
-                 search up the tree for the base of our path.  */
-              *repos_relpath = NULL;
-            }
-          else
-            *repos_relpath = svn_sqlite__column_text(stmt_info, 2,
-                                                     result_pool);
+          if (repos_relpath)
+            /* Our path is implied by our parent somewhere up the tree.
+               With the NULL value and status, the caller will know to
+               search up the tree for the base of our path.  */
+            *repos_relpath = NULL;
         }
-      if (repos_root_url || repos_uuid)
+      else
         {
           /* Fetch repository information via REPOS_ID. If we have a
              WORKING_NODE (and have been added), then the repository
              we're being added to will be dependent upon a parent. The
              caller can scan upwards to locate the repository.  */
-          if (op_depth != 0 || svn_sqlite__column_is_null(stmt_info, 1))
-            {
-              if (repos_root_url)
-                *repos_root_url = NULL;
-              if (repos_uuid)
-                *repos_uuid = NULL;
-            }
-          else
-            err = svn_error_compose_create(
-                     err,
-                     fetch_repos_info(repos_root_url,
-                                      repos_uuid,
-                                      pdh->wcroot->sdb,
-                                      svn_sqlite__column_int64(stmt_info, 1),
-                                      result_pool));
+          err = svn_error_compose_create(
+            err, repos_location_from_columns(repos_root_url, repos_uuid,
+                                             revision, repos_relpath,
+                                             pdh, stmt_info, 1, 5, 2,
+                                             result_pool));
         }
       if (changed_rev)
         {
@@ -4551,41 +4618,25 @@ svn_wc__db_read_info(svn_wc__db_status_t
           else
             *changelist = NULL;
         }
-      if (original_repos_relpath)
+      if (op_depth == 0)
         {
-          if (op_depth != 0)
-            *original_repos_relpath = svn_sqlite__column_text(stmt_info, 2,
-                                                              result_pool);
-          else
+          if (original_root_url)
+            *original_root_url = NULL;
+          if (original_uuid)
+            *original_uuid = NULL;
+          if (original_revision)
+            *original_revision = SVN_INVALID_REVNUM;
+          if (original_repos_relpath)
             *original_repos_relpath = NULL;
         }
-
-      if (original_root_url || original_uuid)
-        {
-          if (op_depth == 0 || svn_sqlite__column_is_null(stmt_info, 1))
-            {
-              if (original_root_url)
-                *original_root_url = NULL;
-              if (original_uuid)
-                *original_uuid = NULL;
-            }
-          else 
-            {
-              /* Fetch repository information via COPYFROM_REPOS_ID. */
-              err = svn_error_compose_create(
-                     err,
-                     fetch_repos_info(original_root_url, original_uuid,
-                                      pdh->wcroot->sdb,
-                                      svn_sqlite__column_int64(stmt_info, 1),
-                                      result_pool));
-            }
-        }
-      if (original_revision)
+      else
         {
-          if (op_depth != 0)
-            *original_revision = svn_sqlite__column_revnum(stmt_info, 5);
-          else
-            *original_revision = SVN_INVALID_REVNUM;
+          err = svn_error_compose_create(
+            err, repos_location_from_columns(original_root_url, original_uuid,
+                                             original_revision,
+                                             original_repos_relpath,
+                                             pdh, stmt_info, 1, 5, 2,
+                                             result_pool));
         }
       if (props_mod)
         {
@@ -4609,20 +4660,10 @@ svn_wc__db_read_info(svn_wc__db_status_t
 
       if (lock)
         {
-            if (op_depth != 0 || svn_sqlite__column_is_null(stmt_info, 15))
-              *lock = NULL;
-            else
-            {
-                *lock = apr_pcalloc(result_pool, sizeof(svn_wc__db_lock_t));
-                (*lock)->token = svn_sqlite__column_text(stmt_info, 15,
-                                                        result_pool);
-                (*lock)->owner = svn_sqlite__column_text(stmt_info, 16,
-                                                        result_pool);
-                (*lock)->comment = svn_sqlite__column_text(stmt_info, 17,
-                                                            result_pool);
-                if (!svn_sqlite__column_is_null(stmt_info, 18))
-                  (*lock)->date = svn_sqlite__column_int64(stmt_info, 18);
-            }
+          if (op_depth != 0)
+            *lock = NULL;
+          else
+            *lock = lock_from_columns(stmt_info, 15, 16, 17, 18, result_pool);
         }
 
       if (have_work)
@@ -4682,6 +4723,251 @@ svn_wc__db_read_info(svn_wc__db_status_t
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__db_read_children_info(apr_hash_t **nodes,
+                              apr_hash_t **conflicts,
+                              svn_wc__db_t *db,
+                              const char *dir_abspath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool)
+{
+  svn_wc__db_pdh_t *pdh;
+  const char *dir_relpath;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  const char *repos_root_url = NULL;
+  apr_int64_t last_repos_id;
+  apr_hash_t *tree_conflicts;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath));
+
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &dir_relpath, db,
+                                             dir_abspath,
+                                             svn_sqlite__mode_readonly,
+                                             scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(pdh);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_SELECT_NODE_CHILDREN_INFO));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, dir_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  *nodes = apr_hash_make(result_pool);
+  while (have_row)
+    {
+      struct svn_wc__db_info_t *child;
+      const char *child_relpath = svn_sqlite__column_text(stmt, 19, NULL);
+      const char *name = svn_relpath_basename(child_relpath, NULL);
+      svn_error_t *err;
+      int *op_depth, row_op_depth;
+      svn_boolean_t new_child;
+
+      child = apr_hash_get(*nodes, name, APR_HASH_KEY_STRING);
+      if (child)
+        new_child = FALSE;
+      else
+        {
+          child = apr_palloc(result_pool,
+                             sizeof(struct svn_wc__db_info_t) + sizeof(int));
+          new_child = TRUE;
+        }
+
+      op_depth = (int *)(char*)(child + 1);
+      row_op_depth = svn_sqlite__column_int(stmt, 0);
+
+      if (new_child || *op_depth < row_op_depth)
+        {
+          apr_hash_t *properties;
+
+          *op_depth = row_op_depth;
+
+          child->kind = svn_sqlite__column_token(stmt, 4, kind_map);
+
+          child->status = svn_sqlite__column_token(stmt, 3, presence_map);
+          if (*op_depth != 0)
+            {
+              if (child->status == svn_wc__db_status_not_present
+                  || child->status == svn_wc__db_status_base_deleted)
+                child->status = svn_wc__db_status_deleted;
+              else if (child->status == svn_wc__db_status_normal)
+                child->status = svn_wc__db_status_added;
+            }
+
+          if (*op_depth != 0)
+            child->revnum = SVN_INVALID_REVNUM;
+          else
+            child->revnum = svn_sqlite__column_revnum(stmt, 5);
+
+
+          if (*op_depth != 0)
+            child->repos_relpath = NULL;
+          else
+            child->repos_relpath = svn_sqlite__column_text(stmt, 2,
+                                                           result_pool);
+
+          if (*op_depth != 0 || svn_sqlite__column_is_null(stmt, 1))
+            {
+              child->repos_root_url = NULL;
+            }
+          else
+            {
+              const char *repos_uuid;
+              apr_int64_t repos_id = svn_sqlite__column_int64(stmt, 1);
+              if (!repos_root_url)
+                {
+                  err = fetch_repos_info(&repos_root_url, &repos_uuid,
+                                         pdh->wcroot->sdb, repos_id,
+                                         result_pool);
+                  if (err)
+                    SVN_ERR(svn_error_compose_create(err,
+                                                     svn_sqlite__reset(stmt)));
+                  last_repos_id = repos_id;
+                }
+
+              /* Assume working copy is all one repos_id so that a
+                 single cached value is sufficient. */
+              SVN_ERR_ASSERT(repos_id == last_repos_id);
+              child->repos_root_url = repos_root_url;
+            }
+
+          child->changed_rev = svn_sqlite__column_revnum(stmt, 8);
+
+          child->changed_date = svn_sqlite__column_int64(stmt, 9);
+
+          child->changed_author = svn_sqlite__column_text(stmt, 10,
+                                                          result_pool);
+
+          child->last_mod_time = svn_sqlite__column_int64(stmt, 13);
+
+          if (child->kind != svn_wc__db_kind_dir)
+            child->depth = svn_depth_unknown;
+          else
+            {
+              const char *depth = svn_sqlite__column_text(stmt, 11,
+                                                          scratch_pool);
+              if (depth)
+                child->depth = svn_depth_from_word(depth);
+              else
+                child->depth = svn_depth_unknown;
+            }
+
+          child->translated_size = get_translated_size(stmt, 7);
+
+          child->lock = lock_from_columns(stmt, 15, 16, 17, 18, result_pool);
+
+          err = svn_sqlite__column_properties(&properties, stmt, 14,
+                                              scratch_pool, scratch_pool);
+          if (err)
+            SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+          child->has_props = properties && !!apr_hash_count(properties);
+#ifdef HAVE_SYMLINK
+          child->special = (child->has_props
+                            && apr_hash_get(properties, SVN_PROP_SPECIAL,
+                                            APR_HASH_KEY_STRING));
+#endif
+
+          child->changelist = NULL;
+          child->have_base = (*op_depth == 0);
+          child->props_mod = FALSE;
+          child->conflicted = FALSE;
+
+          apr_hash_set(*nodes, apr_pstrdup(result_pool, name),
+                       APR_HASH_KEY_STRING, child);
+        }
+      else if (row_op_depth == 0)
+        {
+          child->have_base = TRUE;
+        }
+
+      err = svn_sqlite__step(&have_row, stmt);
+      if (err)
+        SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+    }
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_SELECT_ACTUAL_CHILDREN_INFO));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, dir_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  while (have_row)
+    {
+      struct svn_wc__db_info_t *child;
+      const char *child_relpath = svn_sqlite__column_text(stmt, 7, NULL);
+      const char *name = svn_relpath_basename(child_relpath, NULL);
+      svn_error_t *err;
+
+      child = apr_hash_get(*nodes, name, APR_HASH_KEY_STRING);
+      if (!child)
+        {
+          err = svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
+                                  _("Corrupt data for '%s'"),
+                                  svn_dirent_local_style(child_relpath,
+                                                         scratch_pool));
+          SVN_ERR(svn_error_compose_create(err,
+                                           svn_sqlite__step(&have_row, stmt)));
+        }
+
+      child->changelist = svn_sqlite__column_text(stmt, 1, result_pool);
+
+      child->props_mod = !svn_sqlite__column_is_null(stmt, 6);
+      if (child->props_mod)
+        {
+          apr_hash_t *properties;
+
+          err = svn_sqlite__column_properties(&properties, stmt, 6,
+                                              scratch_pool, scratch_pool);
+          if (err)
+            SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+          child->has_props = properties && !!apr_hash_count(properties);
+#ifdef HAVE_SYMLINK
+          child->special = (child->has_props
+                            && apr_hash_get(properties, SVN_PROP_SPECIAL,
+                                            APR_HASH_KEY_STRING));
+#endif
+        }
+
+
+      child->conflicted = (svn_sqlite__column_text(stmt, 2, NULL)     /* old */
+                           || svn_sqlite__column_text(stmt, 3, NULL)  /* new */
+                           || svn_sqlite__column_text(stmt, 4, NULL)  /* work */
+                           || svn_sqlite__column_text(stmt, 0, NULL));/* prop */
+
+      err = svn_sqlite__step(&have_row, stmt);
+      if (err)
+        SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+    }
+
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  SVN_ERR(svn_wc__db_op_read_all_tree_conflicts(&tree_conflicts, db,
+                                                dir_abspath,
+                                                scratch_pool, scratch_pool));
+  *conflicts = apr_hash_make(result_pool);
+  if (tree_conflicts)
+    {
+      apr_hash_index_t *hi;
+
+      for (hi = apr_hash_first(scratch_pool, tree_conflicts);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *name = svn__apr_hash_index_key(hi);
+          struct svn_wc__db_info_t *child
+            = apr_hash_get(*nodes, name, APR_HASH_KEY_STRING);
+
+          if (child)
+            child->conflicted = TRUE;
+
+          apr_hash_set(*conflicts, apr_pstrdup(result_pool, name),
+                       APR_HASH_KEY_STRING, "");
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 svn_error_t *
 svn_wc__db_read_prop(const svn_string_t **propval,
@@ -4754,19 +5040,20 @@ svn_wc__db_read_props(apr_hash_t **props
 }
 
 
-svn_error_t *
-svn_wc__db_read_pristine_props(apr_hash_t **props,
-                               svn_wc__db_t *db,
-                               const char *local_abspath,
-                               apr_pool_t *result_pool,
-                               apr_pool_t *scratch_pool)
+static svn_error_t *
+db_read_pristine_props(apr_hash_t **props,
+                       svn_wc__db_pdh_t *pdh,
+                       const char *local_relpath,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   svn_wc__db_status_t presence;
 
-  SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
-                                 STMT_SELECT_NODE_PROPS, scratch_pool));
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb, STMT_SELECT_NODE_PROPS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
 
   if (!have_row)
@@ -4774,7 +5061,8 @@ svn_wc__db_read_pristine_props(apr_hash_
       return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
                                svn_sqlite__reset(stmt),
                                _("The node '%s' was not found."),
-                               svn_dirent_local_style(local_abspath,
+                               path_for_error_message(pdh->wcroot,
+                                                      local_relpath,
                                                       scratch_pool));
     }
 
@@ -4794,8 +5082,10 @@ svn_wc__db_read_pristine_props(apr_hash_
       presence = svn_sqlite__column_token(stmt, 1, presence_map);
     }
 
-  /* normal or copied: Fetch properties */
-  if (presence == svn_wc__db_status_normal)
+  /* normal or copied: Fetch properties (during update we want
+     properties for incomplete as well) */
+  if (presence == svn_wc__db_status_normal
+      || presence == svn_wc__db_status_incomplete)
     {
       svn_error_t *err;
 
@@ -4815,6 +5105,29 @@ svn_wc__db_read_pristine_props(apr_hash_
 
 
 svn_error_t *
+svn_wc__db_read_pristine_props(apr_hash_t **props,
+                               svn_wc__db_t *db,
+                               const char *local_abspath,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  svn_wc__db_pdh_t *pdh;
+  const char *local_relpath;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&pdh, &local_relpath, db,
+                              local_abspath, svn_sqlite__mode_readwrite,
+                              scratch_pool, scratch_pool));
+  VERIFY_USABLE_PDH(pdh);
+
+  SVN_ERR(db_read_pristine_props(props, pdh, local_relpath,
+                                 result_pool, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
 svn_wc__db_read_children(const apr_array_header_t **children,
                          svn_wc__db_t *db,
                          const char *local_abspath,
@@ -4868,8 +5181,6 @@ relocate_txn(void *baton, svn_sqlite__db
                             new_repos_id));
   SVN_ERR(svn_sqlite__step_done(stmt));
 
-  /* Do a bunch of stuff which is conditional on us actually having a
-     base_node in the first place. */
   if (rb->have_base_node)
     {
       /* Update any locks for the root or its children. */
@@ -5226,20 +5537,24 @@ commit_node(void *baton, svn_sqlite__db_
 }
 
 
-/* */
+/* Set *REPOS_ID and *REPOS_RELPATH to the BASE repository location of
+ * (PDH, LOCAL_RELPATH), scanning upwards through parents if no BASE row
+ * exists for this node or if it inherits the info.
+ *
+ * Similar to scan_upwards_for_repos() except that the node need not exist
+ * in BASE. */
 static svn_error_t *
 determine_repos_info(apr_int64_t *repos_id,
                      const char **repos_relpath,
-                     svn_wc__db_t *db,
                      svn_wc__db_pdh_t *pdh,
                      const char *local_relpath,
-                     const char *name,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   const char *repos_parent_relpath;
+  const char *local_parent_relpath, *name;
 
   /* ### is it faster to fetch fewer columns? */
 
@@ -5264,12 +5579,11 @@ determine_repos_info(apr_int64_t *repos_
 
   /* This was a child node within this wcroot. We want to look at the
      BASE node of the directory.  */
-  local_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
+  svn_relpath_split(&local_parent_relpath, &name, local_relpath, scratch_pool);
 
   /* The REPOS_ID will be the same (### until we support mixed-repos)  */
   SVN_ERR(scan_upwards_for_repos(repos_id, &repos_parent_relpath,
-                                 pdh->wcroot, pdh->local_abspath,
-                                 local_relpath,
+                                 pdh->wcroot, local_parent_relpath,
                                  scratch_pool, scratch_pool));
 
   *repos_relpath = svn_relpath_join(repos_parent_relpath, name, result_pool);
@@ -5335,9 +5649,7 @@ svn_wc__db_global_commit(svn_wc__db_t *d
      ### this always returns values. we should switch to null if/when
      ### possible.  */
   SVN_ERR(determine_repos_info(&cb.repos_id, &cb.repos_relpath,
-                               db, pdh, local_relpath,
-                               svn_dirent_basename(local_abspath,
-                                                   scratch_pool),
+                               pdh, local_relpath,
                                scratch_pool, scratch_pool));
 
   SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb, commit_node, &cb,
@@ -5442,14 +5754,11 @@ svn_wc__db_global_update(svn_wc__db_t *d
 
 
 struct record_baton {
-  apr_int64_t wc_id;
+  svn_wc__db_wcroot_t *wcroot;
   const char *local_relpath;
 
   svn_filesize_t translated_size;
   apr_time_t last_mod_time;
-
-  /* For error reporting.  */
-  const char *local_abspath;
 };
 
 
@@ -5466,12 +5775,13 @@ record_fileinfo(void *baton, svn_sqlite_
   int affected_rows;
 
   SVN_ERR(which_trees_exist(&base_exists, &working_exists,
-                            sdb, rb->wc_id, rb->local_relpath));
+                            sdb, rb->wcroot->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,
+                             path_for_error_message(rb->wcroot,
+                                                    rb->local_relpath,
                                                     scratch_pool));
 
   /* ### Instead of doing it this way, we just ought to update the highest
@@ -5482,7 +5792,7 @@ record_fileinfo(void *baton, svn_sqlite_
                                       ? STMT_UPDATE_WORKING_NODE_FILEINFO
                                       : STMT_UPDATE_BASE_NODE_FILEINFO));
   SVN_ERR(svn_sqlite__bindf(stmt, "isii",
-                            rb->wc_id, rb->local_relpath,
+                            rb->wcroot->wc_id, rb->local_relpath,
                             rb->translated_size, rb->last_mod_time));
   SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
 
@@ -5510,14 +5820,12 @@ svn_wc__db_global_record_fileinfo(svn_wc
                               scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
-  rb.wc_id = pdh->wcroot->wc_id;
+  rb.wcroot = pdh->wcroot;
   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));
 
@@ -5549,7 +5857,7 @@ svn_wc__db_lock_add(svn_wc__db_t *db,
   VERIFY_USABLE_PDH(pdh);
 
   SVN_ERR(scan_upwards_for_repos(&repos_id, &repos_relpath,
-                                 pdh->wcroot, local_abspath, local_relpath,
+                                 pdh->wcroot, local_relpath,
                                  scratch_pool, scratch_pool));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
@@ -5594,7 +5902,7 @@ svn_wc__db_lock_remove(svn_wc__db_t *db,
   VERIFY_USABLE_PDH(pdh);
 
   SVN_ERR(scan_upwards_for_repos(&repos_id, &repos_relpath,
-                                 pdh->wcroot, local_abspath, local_relpath,
+                                 pdh->wcroot, local_relpath,
                                  scratch_pool, scratch_pool));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
@@ -5631,7 +5939,7 @@ svn_wc__db_scan_base_repos(const char **
   VERIFY_USABLE_PDH(pdh);
 
   SVN_ERR(scan_upwards_for_repos(&repos_id, repos_relpath,
-                                 pdh->wcroot, local_abspath, local_relpath,
+                                 pdh->wcroot, local_relpath,
                                  result_pool, scratch_pool));
 
   if (repos_root_url || repos_uuid)
@@ -5797,7 +6105,7 @@ svn_wc__db_scan_addition(svn_wc__db_stat
       if (repos_relpath)
         {
           build_relpath = svn_relpath_join(svn_dirent_basename(current_abspath,
-                                                              scratch_pool),
+                                                               NULL),
                                            build_relpath,
                                            scratch_pool);
         }
@@ -6239,13 +6547,8 @@ svn_wc__db_upgrade_apply_props(svn_sqlit
 
   if (working_props != NULL)
     {
-      struct set_props_baton spb = { 0 };
-
-      spb.props = working_props;
-      spb.wc_id = wc_id;
-      spb.local_relpath = local_relpath;
-      /* NULL for .conflict and .work_items  */
-      SVN_ERR(set_props_txn(&spb, sdb, scratch_pool));
+      SVN_ERR(set_actual_props(wc_id, local_relpath, working_props,
+                               sdb, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -6996,7 +7299,6 @@ struct wclock_obtain_baton
   svn_wc__db_t *db;
   svn_wc__db_pdh_t *pdh;
   const char *local_relpath;
-  const char *local_abspath;
   int levels_to_lock;
   svn_boolean_t steal_lock;
 };
@@ -7050,7 +7352,8 @@ wclock_obtain_cb(void *baton,
         return svn_error_createf(
                                  SVN_ERR_WC_PATH_NOT_FOUND, NULL,
                                  _("The node '%s' was not found."),
-                                 svn_dirent_local_style(bt->local_abspath,
+                                 path_for_error_message(bt->pdh->wcroot,
+                                                        bt->local_relpath,
                                                         scratch_pool));
     }
 
@@ -7107,7 +7410,8 @@ wclock_obtain_cb(void *baton,
                                                           scratch_pool));
           return svn_error_createf(SVN_ERR_WC_LOCKED, err,
                                    _("Working copy '%s' locked."),
-                                   svn_dirent_local_style(bt->local_abspath,
+                                   path_for_error_message(bt->pdh->wcroot,
+                                                          bt->local_relpath,
                                                           scratch_pool));
         }
       else if (!own_lock)
@@ -7157,7 +7461,8 @@ wclock_obtain_cb(void *baton,
               return svn_error_createf(
                               SVN_ERR_WC_LOCKED, err,
                               _("Working copy '%s' locked."),
-                              svn_dirent_local_style(bt->local_abspath,
+                              path_for_error_message(bt->pdh->wcroot,
+                                                     bt->local_relpath,
                                                      scratch_pool));
             }
 
@@ -7181,7 +7486,8 @@ wclock_obtain_cb(void *baton,
   if (err)
     return svn_error_createf(SVN_ERR_WC_LOCKED, err,
                              _("Working copy '%s' locked"),
-                             svn_dirent_local_style(bt->local_abspath,
+                             path_for_error_message(bt->pdh->wcroot,
+                                                    bt->local_relpath,
                                                     scratch_pool));
 
   /* And finally store that we obtained the lock */
@@ -7243,7 +7549,6 @@ svn_wc__db_wclock_obtain(svn_wc__db_t *d
     }
 
   baton.db = db;
-  baton.local_abspath = local_abspath;
   baton.steal_lock = steal_lock;
   baton.levels_to_lock = levels_to_lock;
 
@@ -7486,42 +7791,22 @@ start_directory_update_txn(void *baton,
                            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_NODE_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));
-      SVN_ERR(svn_sqlite__step_done(stmt));
-    }
-  else
-    {
-      /* ### TODO: Maybe check if we can make repos_relpath NULL. */
-      SVN_ERR(svn_sqlite__get_statement(
-                   &stmt, db,
-                   STMT_UPDATE_BASE_NODE_PRESENCE_REVNUM_AND_REPOS_PATH));
+  /* Note: In the majority of calls, the repos_relpath is unchanged. */
+  /* ### TODO: Maybe check if we can make repos_relpath NULL. */
+  SVN_ERR(svn_sqlite__get_statement(
+               &stmt, db,
+               STMT_UPDATE_BASE_NODE_PRESENCE_REVNUM_AND_REPOS_PATH));
+
+  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));
+  SVN_ERR(svn_sqlite__step_done(stmt));
 
-      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));
-      SVN_ERR(svn_sqlite__step_done(stmt));
-    }
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/object-model/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_wc/wc_db.h?rev=1025655&r1=1025654&r2=1025655&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/object-model/subversion/libsvn_wc/wc_db.h Wed Oct 20 17:57:41 2010
@@ -46,6 +46,8 @@
 #include "private/svn_skel.h"
 #include "private/svn_sqlite.h"
 
+#include "svn_private_config.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
@@ -1004,28 +1006,6 @@ svn_wc__db_pristine_repair(svn_wc__db_t 
 /* @} */
 
 
-/* @defgroup svn_wc__db_repos  Repository information management
-   @{
-*/
-
-/* Ensure an entry for the repository at REPOS_ROOT_URL with UUID exists
-   in DB for LOCAL_ABSPATH, either by finding the correct row, or inserting
-   a new row.  In either case return the id in *REPOS_ID.
-
-   Use SCRATCH_POOL for temporary allocations.
-*/
-svn_error_t *
-svn_wc__db_repos_ensure(apr_int64_t *repos_id,
-                        svn_wc__db_t *db,
-                        const char *local_abspath,
-                        const char *repos_root_url,
-                        const char *repos_uuid,
-                        apr_pool_t *scratch_pool);
-
-
-/* @} */
-
-
 /* @defgroup svn_wc__db_op  Operations on WORKING tree
    @{
 */
@@ -1142,10 +1122,8 @@ svn_wc__db_op_add_symlink(svn_wc__db_t *
    To specify no properties, PROPS must be an empty hash, not NULL.
    If the node is not present, return an error.
 
-   ### All the callers are doing a comparison against the current 'pristine'
-       props before calling this, and are passing NULL if the actual props
-       are to be the same as the pristine props. This behaviour should be
-       encapsulated.
+   If PROPS is NULL, set the properties to be the same as the pristine
+   properties.
 
    CONFLICT is used to register a conflict on this node at the same time
    the properties are changed.
@@ -1509,6 +1487,41 @@ svn_wc__db_read_info(svn_wc__db_status_t
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool);
 
+/* Structure returned by svn_wc__db_read_children_info.  Only has the
+   fields needed by status. */
+struct svn_wc__db_info_t {
+  svn_wc__db_status_t status;
+  svn_wc__db_kind_t kind;
+  svn_revnum_t revnum;
+  const char *repos_relpath;
+  const char *repos_root_url;
+  svn_revnum_t changed_rev;
+  const char *changed_author;
+  apr_time_t changed_date;
+  apr_time_t last_mod_time;
+  svn_depth_t depth;
+  svn_filesize_t translated_size;
+  const char *changelist;
+  svn_boolean_t has_props;
+#ifdef HAVE_SYMLINK
+  svn_boolean_t special;
+#endif
+  svn_boolean_t props_mod;
+  svn_boolean_t have_base;
+  svn_boolean_t conflicted;
+  svn_wc__db_lock_t *lock;
+};
+
+/* Return in *NODES a hash mapping name->struct svn_wc__db_info_t for
+   the children of DIR_ABSPATH, and in *CONFLICTS a hash of names in
+   conflict.  */
+svn_error_t *
+svn_wc__db_read_children_info(apr_hash_t **nodes,
+                              apr_hash_t **conflicts,
+                              svn_wc__db_t *db,
+                              const char *dir_abspath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool);
 
 /* Set *PROPVAL to the value of the property named PROPNAME of the node
    LOCAL_ABSPATH in the ACTUAL tree (looking through to the WORKING or BASE

Modified: subversion/branches/object-model/subversion/libsvn_wc/workqueue.c
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_wc/workqueue.c?rev=1025655&r1=1025654&r2=1025655&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_wc/workqueue.c (original)
+++ subversion/branches/object-model/subversion/libsvn_wc/workqueue.c Wed Oct 20 17:57:41 2010
@@ -181,18 +181,23 @@ run_revert(svn_wc__db_t *db,
 {
   const svn_skel_t *arg1 = work_item->children->next;
   const char *local_abspath;
-  svn_boolean_t replaced;
   svn_wc__db_kind_t kind;
   svn_wc__db_status_t status;
   const char *parent_abspath;
   svn_boolean_t conflicted;
   apr_int64_t val;
+  svn_boolean_t reinstall_working;
+  svn_boolean_t remove_working;
 
   /* We need a NUL-terminated path, so copy it out of the skel.  */
   local_abspath = apr_pstrmemdup(scratch_pool, arg1->data, arg1->len);
+
   SVN_ERR(svn_skel__parse_int(&val, arg1->next, scratch_pool));
-  replaced = (val != 0);
-  /* magic_changed is extracted further below.  */
+  remove_working = (val != 0);
+
+  SVN_ERR(svn_skel__parse_int(&val, arg1->next->next, scratch_pool));
+  reinstall_working = (val != 0);
+
   /* use_commit_times is extracted further below.  */
 
   /* NOTE: we can read KIND here since uncommitted kind changes are not
@@ -207,10 +212,13 @@ run_revert(svn_wc__db_t *db,
             scratch_pool, scratch_pool));
 
   if (kind == svn_wc__db_kind_dir)
-    parent_abspath = local_abspath;
+    {
+      parent_abspath = local_abspath;
+    }
   else
-    parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
-
+    {
+      parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
+    }
 
   if (conflicted)
     {
@@ -247,57 +255,6 @@ run_revert(svn_wc__db_t *db,
   /* Deal with the working file, as needed.  */
   if (kind == svn_wc__db_kind_file)
     {
-      svn_boolean_t magic_changed;
-      svn_boolean_t reinstall_working;
-
-      SVN_ERR(svn_skel__parse_int(&val, arg1->next->next, scratch_pool));
-      magic_changed = (val != 0);
-
-      /* If there was a magic property change, then we'll reinstall the
-         working-file to pick up any/all appropriate changes. If there was
-         a replacement, then we definitely want to reinstall the working-file
-         using the original base.  */
-      reinstall_working = magic_changed || replaced;
-
-      if (!replaced && !reinstall_working)
-        /* check for additional scenarios which need the actual re-installed */
-        {
-          svn_node_kind_t check_kind;
-
-          /* If the working file is missing, we need to reinstall it.  */
-          SVN_ERR(svn_io_check_path(local_abspath, &check_kind,
-                                    scratch_pool));
-          reinstall_working = (check_kind == svn_node_none);
-
-          if (!reinstall_working)
-            {
-              /* ### can we optimize this call? we already fetched some
-                 ### info about the node. and *definitely* never want a
-                 ### full file-scan.  */
-
-              /* ### for now, just always reinstall. without some extra work,
-                 ### we could end up in a situation where the file is copied
-                 ### from the base, but then something fails immediately
-                 ### after that. on the second time through here, we would
-                 ### see the file is "the same" and fail to complete those
-                 ### follow-on actions. in some future work, examine the
-                 ### points of failure, and possibly precompue the
-                 ### "reinstall_working" flag, or maybe do some follow-on
-                 ### actions unconditionally.  */
-#if 1
-              reinstall_working = TRUE;
-#endif
-#if 0
-              /* ### try to avoid altering the timestamp if the intended
-                 ### contents are the same as current-contents.  */
-              SVN_ERR(svn_wc__text_modified_internal_p(&reinstall_working,
-                                                       db, local_abspath,
-                                                       FALSE, FALSE,
-                                                       scratch_pool));
-#endif
-            }
-        }
-
       if (reinstall_working)
         {
           svn_boolean_t use_commit_times;
@@ -321,43 +278,24 @@ run_revert(svn_wc__db_t *db,
     {
       SVN__NOT_IMPLEMENTED();
     }
-  else if (kind == svn_wc__db_kind_dir)
+  else if (reinstall_working && kind == svn_wc__db_kind_dir)
     {
-      svn_node_kind_t disk_kind;
-      SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
+      svn_node_kind_t on_disk;
 
-      if (disk_kind == svn_node_none)
+      /* Unfortunately we need another stat(), because I don't want
+         to resort to APR error macros to see if we're creating a
+         directory on top of an existing path */
+      SVN_ERR(svn_io_check_path(local_abspath, &on_disk, scratch_pool));
+      if (on_disk == svn_node_none)
         SVN_ERR(svn_io_dir_make(local_abspath, APR_OS_DEFAULT, scratch_pool));
     }
 
 
-  {
-    svn_boolean_t is_wc_root;
-
-    SVN_ERR(svn_wc__check_wc_root(&is_wc_root, NULL, NULL,
-                                  db, local_abspath, scratch_pool));
-
-    /* Remove the WORKING_NODE from the node and (if there) its parent stub */
-    /* ### A working copy root can't have a working node and trying
-       ### to delete it fails because the root doesn't have a stub. */
-    if (!is_wc_root)
-      {
-        const char *op_root_abspath = NULL;
-
-        /* If the node is not the operation root, we should not delete
-           the working node */
-        if (status == svn_wc__db_status_added)
-          SVN_ERR(svn_wc__db_scan_addition(NULL, &op_root_abspath, NULL, NULL,
-                                           NULL, NULL, NULL, NULL, NULL,
-                                           db, local_abspath,
-                                           scratch_pool, scratch_pool));
-
-        if (!op_root_abspath
-            || (strcmp(op_root_abspath, local_abspath) == 0))
-          SVN_ERR(svn_wc__db_temp_op_remove_working(db, local_abspath,
-                                                    scratch_pool));
-      }
-  }
+  if (remove_working)
+    {
+      SVN_ERR(svn_wc__db_temp_op_remove_working(db, local_abspath,
+                                                scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -407,6 +345,7 @@ verify_pristine_present(svn_wc__db_t *db
 svn_error_t *
 svn_wc__wq_add_revert(svn_boolean_t *will_revert,
                       svn_wc__db_t *db,
+                      const char *revert_root,
                       const char *local_abspath,
                       svn_boolean_t use_commit_times,
                       apr_pool_t *scratch_pool)
@@ -414,7 +353,8 @@ svn_wc__wq_add_revert(svn_boolean_t *wil
   svn_wc__db_status_t status;
   svn_wc__db_kind_t kind;
   svn_boolean_t replaced;
-  svn_boolean_t magic_changed = FALSE;
+  svn_boolean_t remove_working = FALSE;
+  svn_boolean_t reinstall_working;
 
   SVN_ERR(svn_wc__db_read_info(
             &status, &kind, NULL, NULL, NULL, NULL,
@@ -424,8 +364,11 @@ svn_wc__wq_add_revert(svn_boolean_t *wil
             db, local_abspath,
             scratch_pool, scratch_pool));
 
-  /* Special handling for issue #2101.  */
-  if (kind == svn_wc__db_kind_file)
+  /* Special handling for issue #2101, which is specifically
+     about reverting copies of 'deleted' files and dirs, being inserted
+     in the copy as a schedule-delete files, yet can't be reverted. */
+  if (kind == svn_wc__db_kind_file
+      && status == svn_wc__db_status_deleted)
     SVN_ERR(verify_pristine_present(db, local_abspath, scratch_pool));
 
   /* Gather a few items *before* the revert work-item has a chance to run.
@@ -436,9 +379,9 @@ svn_wc__wq_add_revert(svn_boolean_t *wil
                                        scratch_pool));
 
   /* If a replacement has occurred, then a revert definitely happens.  */
-  *will_revert = replaced;
+  *will_revert = reinstall_working = replaced;
 
-  if (!replaced)
+  if (status == svn_wc__db_status_normal)
     {
       apr_hash_t *base_props;
       apr_hash_t *working_props;
@@ -452,51 +395,65 @@ svn_wc__wq_add_revert(svn_boolean_t *wil
                                        scratch_pool, scratch_pool));
       SVN_ERR(svn_prop_diffs(&prop_diffs, working_props, base_props,
                              scratch_pool));
-      magic_changed = svn_wc__has_magic_property(prop_diffs);
+      if (svn_wc__has_magic_property(prop_diffs))
+        reinstall_working = TRUE;
 
       if (prop_diffs->nelts > 0)
         {
           /* Property changes cause a revert to occur.  */
           *will_revert = TRUE;
         }
-      else
-        {
-          /* There is nothing to do for NORMAL or ADDED nodes. Typically,
-             we won't even be called for added nodes (since a revert
-             simply removes it from version control), but it is possible
-             that a parent replacement was turned from a replaced copy
-             into a normal node, and the (broken) old ENTRY->COPIED logic
-             then turns the copied children into typical ADDED nodes.
-             Since the recursion has already started, these children are
-             visited (unlike most added nodes).  */
-          if (status != svn_wc__db_status_normal
-              && status != svn_wc__db_status_added)
-            {
-              *will_revert = TRUE;
-            }
+    }
+  else
+    {
+      *will_revert = TRUE;
+      if (status != svn_wc__db_status_added)
+        reinstall_working = TRUE;
+    }
 
-          /* We may need to restore a missing working file.  */
-          if (! *will_revert)
-            {
-              svn_node_kind_t on_disk;
+  /* We may need to restore a missing working file.  */
+  if (! reinstall_working
+      && status != svn_wc__db_status_added)
+    {
+      svn_node_kind_t on_disk;
 
-              SVN_ERR(svn_io_check_path(local_abspath, &on_disk,
-                                        scratch_pool));
-              *will_revert = on_disk == svn_node_none;
-            }
+      SVN_ERR(svn_io_check_path(local_abspath, &on_disk, scratch_pool));
+      reinstall_working = on_disk == svn_node_none;
+      *will_revert = *will_revert || reinstall_working;
+    }
 
-          if (! *will_revert)
-            {
-              /* ### there may be ways to simplify this test, rather than
-                 ### doing file comparisons and junk... */
-              SVN_ERR(svn_wc__internal_text_modified_p(will_revert,
-                                                       db, local_abspath,
-                                                       FALSE, FALSE,
-                                                       scratch_pool));
-            }
-        }
+  if (! reinstall_working
+      && status == svn_wc__db_status_normal)
+    {
+      /* ### there may be ways to simplify this test, rather than
+         ### doing file comparisons and junk... */
+      SVN_ERR(svn_wc__internal_text_modified_p(&reinstall_working,
+                                               db, local_abspath,
+                                               FALSE, FALSE,
+                                               scratch_pool));
+      *will_revert = *will_revert || reinstall_working;
     }
 
+
+  if (status == svn_wc__db_status_added)
+    {
+      /* When looking at an added, non-replacing node, it's entry
+         will have to be removed after revert: if not, it'll look
+         like it's still under version control. */
+      const char *op_root_abspath;
+
+      SVN_ERR(svn_wc__db_scan_addition(NULL, &op_root_abspath, NULL, NULL,
+                                       NULL, NULL, NULL, NULL, NULL,
+                                       db, local_abspath,
+                                       scratch_pool, scratch_pool));
+
+      if (svn_dirent_is_ancestor(revert_root, op_root_abspath))
+        remove_working = TRUE;
+    }
+  else
+    remove_working = TRUE;
+
+
   /* Don't even bother to queue a work item if there is nothing to do.  */
   if (*will_revert)
     {
@@ -507,8 +464,8 @@ svn_wc__wq_add_revert(svn_boolean_t *wil
       /* These skel atoms hold references to very transitory state, but
          we only need the work_item to survive for the duration of wq_add.  */
       svn_skel__prepend_int(use_commit_times, work_item, scratch_pool);
-      svn_skel__prepend_int(magic_changed, work_item, scratch_pool);
-      svn_skel__prepend_int(replaced, work_item, scratch_pool);
+      svn_skel__prepend_int(reinstall_working, work_item, scratch_pool);
+      svn_skel__prepend_int(remove_working, work_item, scratch_pool);
       svn_skel__prepend_str(local_abspath, work_item, scratch_pool);
       svn_skel__prepend_str(OP_REVERT, work_item, scratch_pool);
 

Modified: subversion/branches/object-model/subversion/libsvn_wc/workqueue.h
URL: http://svn.apache.org/viewvc/subversion/branches/object-model/subversion/libsvn_wc/workqueue.h?rev=1025655&r1=1025654&r2=1025655&view=diff
==============================================================================
--- subversion/branches/object-model/subversion/libsvn_wc/workqueue.h (original)
+++ subversion/branches/object-model/subversion/libsvn_wc/workqueue.h Wed Oct 20 17:57:41 2010
@@ -188,10 +188,12 @@ svn_wc__wq_build_record_fileinfo(svn_ske
                                  apr_pool_t *result_pool);
 
 
-/* Record a work item to revert LOCAL_ABSPATH.  */
+/* Record a work item to revert LOCAL_ABSPATH;
+   REVERT_ROOT designates the root of the entire revert operation. */
 svn_error_t *
 svn_wc__wq_add_revert(svn_boolean_t *will_revert,
                       svn_wc__db_t *db,
+                      const char *revert_root,
                       const char *local_abspath,
                       svn_boolean_t use_commit_times,
                       apr_pool_t *scratch_pool);