On the explore-wc branch:

Bring up to date with trunk.

Resolved conflicts in entries.c with an #ifdef FROM_TRUNK around the code
sitting on trunk, which we aren't using in this branch (calls to the old
functions to read/write 'entries').


git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/explore-wc@875995 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/BRANCH-README b/BRANCH-README
new file mode 100644
index 0000000..7f08ace
--- /dev/null
+++ b/BRANCH-README
@@ -0,0 +1,6 @@
+This branch exists as a place to stash patches and get review on WC-NG work
+prior to the 1.6.x branch.  Shortly after that branch is created, this branch
+will be merged back to trunk and disappear.
+
+For more information about WC-NG, including a proposed implementation plan,
+see: http://svn.collab.net/repos/svn/trunk/notes/wc-ng-design
diff --git a/Makefile.in b/Makefile.in
index db3ed9d..42a8829 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -329,7 +329,9 @@
             (cd $$i && rm -f *.o *.lo *.la *.la-a *.spo *.mo && \
              rm -rf .libs) ; \
         done
-	rm -f $(CLEAN_FILES) $(abs_srcdir)/subversion/libsvn_fs_fs/rep-cache-db.h
+	rm -f $(CLEAN_FILES) \
+            $(abs_srcdir)/subversion/libsvn_fs_fs/rep-cache-db.h \
+	        $(abs_srcdir)/subversion/libsvn_wc/wc-metadata.h
 	find $(abs_srcdir) -name "*.pyc" -exec rm {} ';'
 
 # clean all but bulky test output, returning to before './configure' was run.
diff --git a/build.conf b/build.conf
index d938595..7da6cc3 100644
--- a/build.conf
+++ b/build.conf
@@ -34,6 +34,7 @@
 private-built-includes =
         subversion/svn_private_config.h
         subversion/libsvn_fs_fs/rep-cache-db.h
+        subversion/libsvn_wc/wc-metadata.h
         subversion/bindings/swig/proxy/swig_python_external_runtime.swg
         subversion/bindings/swig/proxy/swig_perl_external_runtime.swg
         subversion/bindings/swig/proxy/swig_ruby_external_runtime.swg
diff --git a/build/generator/gen_win.py b/build/generator/gen_win.py
index 206a519..b42246e 100644
--- a/build/generator/gen_win.py
+++ b/build/generator/gen_win.py
@@ -1387,6 +1387,7 @@
     import transform_sql
     sql_sources = [
       os.path.join('subversion', 'libsvn_fs_fs', 'rep-cache-db'),
+      os.path.join('subversion', 'libsvn_wc', 'wc-metadata'),
       ]
     for sql in sql_sources:
       transform_sql.main(open(sql + '.sql', 'r'),
diff --git a/subversion/include/svn_error_codes.h b/subversion/include/svn_error_codes.h
index a4aa17c..7bdbb71 100644
--- a/subversion/include/svn_error_codes.h
+++ b/subversion/include/svn_error_codes.h
@@ -458,6 +458,16 @@
              SVN_ERR_WC_CATEGORY_START + 31,
              "Cannot move a file external")
 
+  /** @since New in 1.7. */
+  SVN_ERRDEF(SVN_ERR_WC_DB_ERROR,
+             SVN_ERR_WC_CATEGORY_START + 32,
+             "Something's amiss with the wc sqlite database")
+
+  /** @since New in 1.7. */
+  SVN_ERRDEF(SVN_ERR_WC_MISSING,
+             SVN_ERR_WC_CATEGORY_START + 33,
+             "The working copy is missing")
+
   /* fs errors */
 
   SVN_ERRDEF(SVN_ERR_FS_GENERAL,
diff --git a/subversion/libsvn_wc/README b/subversion/libsvn_wc/README
index a7c6de0..abdd9d0 100644
--- a/subversion/libsvn_wc/README
+++ b/subversion/libsvn_wc/README
@@ -107,6 +107,8 @@
             props/              /* tmp area for props */
        empty-file               /* Obsolete, no longer used, not present in
                                    post-1.3 working copies */
+       wc.db                    /* A SQLite database which contains *all* the
+                                   administrative information for a wc-ng. */
 
 `format':
    Says what version of the working copy adm format this is (so future
diff --git a/subversion/libsvn_wc/adm_ops.c b/subversion/libsvn_wc/adm_ops.c
index 0875359..d9280d0 100644
--- a/subversion/libsvn_wc/adm_ops.c
+++ b/subversion/libsvn_wc/adm_ops.c
@@ -182,7 +182,9 @@
                   if (current_entry->schedule != svn_wc_schedule_add
                       && !excluded)
                     {
-                      svn_wc__entry_remove(entries, name);
+                      SVN_ERR(svn_wc__entry_remove(
+                                     entries, svn_wc_adm_access_path(dirpath),
+                                     name, subpool));
                       if (notify_func)
                         {
                           notify = svn_wc_create_notify(child_path,
@@ -1222,7 +1224,9 @@
                  with!  this means we're dealing with a missing item
                  that's scheduled for addition.  Easiest to just
                  remove the entry.  */
-              svn_wc__entry_remove(entries, base_name);
+              SVN_ERR(svn_wc__entry_remove(
+                            entries, svn_wc_adm_access_path(parent_access),
+                            base_name, pool));
               SVN_ERR(svn_wc__entries_write(entries, parent_access, pool));
             }
         }
@@ -2068,7 +2072,9 @@
                  adm_access, for which we definitely can't use the 'else'
                  code path (as it will remove the parent from version
                  control... (See issue 2425) */
-              svn_wc__entry_remove(entries, basey);
+              SVN_ERR(svn_wc__entry_remove(
+                            entries, svn_wc_adm_access_path(parent_access),
+                            basey, pool));
               SVN_ERR(svn_wc__entries_write(entries, parent_access, pool));
             }
           else
@@ -2461,7 +2467,8 @@
 
       /* Remove NAME from PATH's entries file: */
       SVN_ERR(svn_wc_entries_read(&entries, adm_access, TRUE, pool));
-      svn_wc__entry_remove(entries, name);
+      SVN_ERR(svn_wc__entry_remove(entries, svn_wc_adm_access_path(adm_access),
+                                   name, pool));
       SVN_ERR(svn_wc__entries_write(entries, adm_access, pool));
 
       /* Remove text-base/NAME.svn-base */
@@ -2561,7 +2568,9 @@
                   /* The directory is either missing or excluded,
                      so don't try to recurse, just delete the
                      entry in the parent directory. */
-                  svn_wc__entry_remove(entries, current_entry_name);
+                  SVN_ERR(svn_wc__entry_remove(
+                                entries, svn_wc_adm_access_path(adm_access),
+                                current_entry_name, subpool));
                 }
               else
                 {
@@ -2625,7 +2634,9 @@
                                      APR_HASH_KEY_STRING);
             if (dir_entry->depth != svn_depth_exclude)
               {
-                svn_wc__entry_remove(parent_entries, base_name);
+                SVN_ERR(svn_wc__entry_remove(
+                        parent_entries, svn_wc_adm_access_path(parent_access),
+                        base_name, pool));
                 SVN_ERR(svn_wc__entries_write(parent_entries, parent_access, pool));
 
               }
diff --git a/subversion/libsvn_wc/crop.c b/subversion/libsvn_wc/crop.c
index a26cb6c..f46f758 100644
--- a/subversion/libsvn_wc/crop.c
+++ b/subversion/libsvn_wc/crop.c
@@ -129,7 +129,9 @@
                  logically not exist. */
               if (depth < svn_depth_immediates)
                 {
-                  svn_wc__entry_remove(entries, current_entry->name);
+                  SVN_ERR(svn_wc__entry_remove(
+                                entries, svn_wc_adm_access_path(dir_access),
+                                current_entry->name, iterpool));
                   SVN_ERR(svn_wc__entries_write(entries, dir_access, iterpool));
                 }
               continue;
diff --git a/subversion/libsvn_wc/entries.c b/subversion/libsvn_wc/entries.c
index fc4e66b..2237c94 100644
--- a/subversion/libsvn_wc/entries.c
+++ b/subversion/libsvn_wc/entries.c
@@ -27,6 +27,7 @@
 #include "svn_pools.h"
 #include "svn_path.h"
 #include "svn_ctype.h"
+#include "svn_string.h"
 
 #include "wc.h"
 #include "adm_files.h"
@@ -37,6 +38,173 @@
 
 #include "svn_private_config.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_sqlite.h"
+#include "private/svn_skel.h"
+
+#include "wc-metadata.h"
+
+#define MAYBE_ALLOC(x,p) ((x) ? (x) : apr_pcalloc((p), sizeof(*(x))))
+
+static const char * const upgrade_sql[] = { NULL, NULL, NULL, NULL, NULL,
+  NULL, NULL, NULL, NULL, NULL, NULL, WC_METADATA_SQL };
+
+/* This values map to the members of STATEMENTS below, and should be added
+   and removed at the same time. */
+enum statement_keys {
+  STMT_INSERT_REPOSITORY,
+  STMT_INSERT_WCROOT,
+  STMT_INSERT_BASE_NODE,
+  STMT_INSERT_WORKING_NODE,
+  STMT_INSERT_ACTUAL_NODE,
+  STMT_INSERT_CHANGELIST,
+  STMT_SELECT_REPOSITORY,
+  STMT_SELECT_WCROOT_NULL,
+  STMT_SELECT_REPOSITORY_BY_ID,
+  STMT_SELECT_BASE_NODE,
+  STMT_SELECT_WORKING_NODE,
+  STMT_SELECT_ACTUAL_NODE,
+  STMT_DELETE_BASE_NODE,
+  STMT_DELETE_WORKING_NODE,
+  STMT_DELETE_ACTUAL_NODE,
+  STMT_SELECT_BASE_NODE_BY_RELPATH
+};
+
+static const char * const statements[] = {
+  "insert into repository (root, uuid) "
+  "values (?1, ?2);",
+
+  "insert into wcroot (local_abspath) "
+  "values (?1);",
+
+  "insert or replace into base_node "
+    "(wc_id, local_relpath, repos_id, repos_relpath, parent_id, revnum, "
+     "kind, checksum, translated_size, changed_rev, changed_date, "
+     "changed_author, depth, last_mod_time, properties, incomplete_children)"
+  "values (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, "
+          "?15, ?16);",
+
+  "insert or replace into working_node "
+    "(wc_id, local_relpath, parent_relpath, kind, copyfrom_repos_id, "
+     "copyfrom_repos_path, copyfrom_revnum, moved_from, moved_to, checksum, "
+     "translated_size, changed_rev, changed_date, changed_author, depth, "
+     "last_mod_time, properties, changelist_id, tree_conflict_data) "
+  "values (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, "
+          "?15, ?16, ?17, ?18, ?19);",
+
+  "insert or replace into actual_node "
+    "(wc_id, local_relpath, properties, conflict_old, conflict_new, "
+     "conflict_working, prop_reject, changelist_id) "
+  "values (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);",
+
+  "insert or replace into changelist "
+    "(wc_id, name) "
+  "values (?1, ?2);",
+
+  "select id, root from repository where uuid = ?1;",
+
+  "select id from wcroot where local_abspath is null;",
+
+  "select root, uuid from repository where id = ?1;",
+
+  "select id, wc_id, local_relpath, repos_id, repos_relpath, parent_id, "
+    "revnum, kind, checksum, translated_size, changed_rev, changed_date, "
+    "changed_author, depth, last_mod_time, properties, incomplete_children "
+  "from base_node;",
+
+  "select id, wc_id, local_relpath, parent_relpath, kind, copyfrom_repos_id, "
+    "copyfrom_repos_path, copyfrom_revnum, moved_from, moved_to, checksum, "
+    "translated_size, changed_rev, changed_date, changed_author, depth, "
+    "last_mod_time, properties, changelist_id, tree_conflict_data "
+  "from working_node;",
+
+  "select id, wc_id, local_relpath, properties, conflict_old, conflict_new, "
+     "conflict_working, prop_reject, changelist_id "
+  "from actual_node;",
+
+  "delete from base_node where wc_id = ?1 and local_relpath = ?2;",
+
+  "delete from working_node where wc_id = ?1 and local_relpath = ?2;",
+
+  "delete from actual_node where wc_id = ?1 and local_relpath = ?2;",
+
+  "select repos_relpath, root, uuid "
+  "from base_node, repository "
+  "where local_relpath = ?1 and repository.id = base_node.repos_id;",
+
+  NULL
+  };
+
+/* Temporary structures which mirror the tables in wc-metadata.sql.
+   For detailed descriptions of each field, see that file. */
+typedef struct {
+  apr_int64_t id;
+  apr_int64_t wc_id;
+  const char *local_relpath;
+  apr_int64_t repos_id;
+  const char *repos_relpath;
+  apr_int64_t parent_id;
+  svn_revnum_t revision;
+  svn_node_kind_t kind;
+  svn_checksum_t *checksum;
+  apr_size_t translated_size;
+  svn_revnum_t changed_rev;
+  apr_time_t changed_date;
+  const char *changed_author;
+  svn_depth_t depth;
+  apr_time_t last_mod_time;
+  apr_hash_t *properties;
+  svn_boolean_t incomplete_children;
+} db_base_node_t;
+
+typedef struct {
+  apr_int64_t id;
+  apr_int64_t wc_id;
+  const char *local_relpath;
+  const char *parent_relpath;
+  svn_node_kind_t kind;
+  apr_int64_t copyfrom_repos_id;
+  const char *copyfrom_repos_path;
+  svn_revnum_t copyfrom_revnum;
+  const char *moved_from;
+  const char *moved_to;
+  svn_checksum_t *checksum;
+  apr_size_t translated_size;
+  svn_revnum_t changed_rev;
+  apr_time_t changed_date;
+  const char *changed_author;
+  svn_depth_t depth;
+  apr_time_t last_mod_time;
+  apr_hash_t *properties;
+  apr_int64_t changelist_id;
+  const char *tree_conflict_data;
+} db_working_node_t;
+
+typedef struct {
+  apr_int64_t id;
+  apr_int64_t wc_id;
+  const char *local_relpath;
+  apr_hash_t *properties;
+  const char *conflict_old;
+  const char *conflict_new;
+  const char *conflict_working;
+  const char *prop_reject;
+  apr_int64_t changelist_id;
+} db_actual_node_t;
+
+typedef struct {
+  apr_int64_t id;
+  apr_int64_t wc_id;
+  const char *name;
+} db_changelist_t;
+
+typedef struct {
+  const char *url;
+  const char *lock_token;
+  const char *lock_owner;
+  const char *lock_comment;
+  apr_time_t lock_date;
+} db_lock_t;
+
 
 
 /** Overview **/
@@ -52,6 +220,18 @@
 /*--------------------------------------------------------------- */
 
 
+/*** Working with the entries sqlite database ***/
+
+/* Return the location of the sqlite database containing the entry information
+   for PATH in the filesystem.  Allocate in RESULT_POOL. ***/
+static const char *
+db_path(const char *path,
+        apr_pool_t *result_pool)
+{
+  return svn_wc__adm_child(path, "wc.db", result_pool);
+}
+
+
 /*** reading and writing the entries file ***/
 
 
@@ -102,7 +282,6 @@
 }
 
 
-
 svn_error_t *
 svn_wc__atts_to_entry(svn_wc_entry_t **new_entry,
                       apr_uint64_t *modify_flags,
@@ -500,15 +679,488 @@
 }
 
 
+/* Select all the rows from base_node table in WC_DB and put them into *NODES,
+   allocated in RESULT_POOL. */
+static svn_error_t *
+fetch_base_nodes(apr_hash_t **nodes,
+                 svn_sqlite__db_t *wc_db,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  *nodes = apr_hash_make(result_pool);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_SELECT_BASE_NODE));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  while (have_row)
+    {
+      apr_size_t len;
+      const void *val;
+      db_base_node_t *base_node = apr_pcalloc(result_pool,
+                                              sizeof(*base_node));
+
+      base_node->wc_id = svn_sqlite__column_int(stmt, 1);
+      base_node->local_relpath = svn_sqlite__column_text(stmt, 2, result_pool);
+
+      if (!svn_sqlite__column_is_null(stmt, 3))
+        {
+          base_node->repos_id = svn_sqlite__column_int(stmt, 3);
+          base_node->repos_relpath = svn_sqlite__column_text(stmt, 4,
+                                                             result_pool);
+        }
+
+      if (!svn_sqlite__column_is_null(stmt, 5))
+        base_node->parent_id = svn_sqlite__column_int(stmt, 5);
+
+      base_node->revision = svn_sqlite__column_int(stmt, 6);
+      base_node->kind = svn_node_kind_from_word(
+                                    svn_sqlite__column_text(stmt, 7, NULL));
+
+      if (!svn_sqlite__column_is_null(stmt, 8))
+        {
+          const char *digest = svn_sqlite__column_text(stmt, 8, NULL);
+          svn_checksum_kind_t kind = (digest[1] == 'm'
+                                      ? svn_checksum_md5 : svn_checksum_sha1);
+          SVN_ERR(svn_checksum_parse_hex(&base_node->checksum, kind,
+                                         digest + 6, result_pool));
+        }
+
+      base_node->translated_size = svn_sqlite__column_int(stmt, 9);
+
+      base_node->changed_rev = svn_sqlite__column_int(stmt, 10);
+      base_node->changed_date = svn_sqlite__column_int(stmt, 11);
+      base_node->changed_author = svn_sqlite__column_text(stmt, 12,
+                                                          result_pool);
+
+      base_node->depth = svn_depth_from_word(
+                                    svn_sqlite__column_text(stmt, 13, NULL));
+      base_node->last_mod_time = svn_sqlite__column_int(stmt, 14);
+
+      val = svn_sqlite__column_blob(stmt, 15, &len);
+      SVN_ERR(svn_skel__parse_proplist(&base_node->properties,
+                                       svn_skel__parse(val, len, scratch_pool),
+                                       result_pool));
+
+      base_node->incomplete_children = svn_sqlite__column_boolean(stmt, 16);
+
+      apr_hash_set(*nodes, base_node->local_relpath, APR_HASH_KEY_STRING,
+                   base_node);
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Select all the rows from working_node table in WC_DB and put them into
+   *NODES allocated in RESULT_POOL. */
+static svn_error_t *
+fetch_working_nodes(apr_hash_t **nodes,
+                    svn_sqlite__db_t *wc_db,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  *nodes = apr_hash_make(result_pool);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_SELECT_WORKING_NODE));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  while (have_row)
+    {
+      apr_size_t len;
+      const void *val;
+      db_working_node_t *working_node = apr_pcalloc(result_pool,
+                                                    sizeof(*working_node));
+
+      working_node->wc_id = svn_sqlite__column_int(stmt, 1);
+      working_node->local_relpath = svn_sqlite__column_text(stmt, 2,
+                                                            result_pool);
+      working_node->parent_relpath = svn_sqlite__column_text(stmt, 3,
+                                                             result_pool);
+      working_node->kind = svn_node_kind_from_word(
+                                     svn_sqlite__column_text(stmt, 4, NULL));
+
+      if (!svn_sqlite__column_is_null(stmt, 5))
+        {
+          working_node->copyfrom_repos_id = svn_sqlite__column_int(stmt, 5);
+          working_node->copyfrom_repos_path = svn_sqlite__column_text(stmt, 6,
+                                                                result_pool);
+          working_node->copyfrom_revnum = svn_sqlite__column_revnum(stmt, 7);
+        }
+
+      if (!svn_sqlite__column_is_null(stmt, 8))
+        working_node->moved_from = svn_sqlite__column_text(stmt, 8,
+                                                           result_pool);
+
+      if (!svn_sqlite__column_is_null(stmt, 9))
+        working_node->moved_to = svn_sqlite__column_text(stmt, 9, result_pool);
+
+      if (!svn_sqlite__column_is_null(stmt, 10))
+        {
+          const char *digest = svn_sqlite__column_text(stmt, 10, NULL);
+          svn_checksum_kind_t kind = (digest[1] == 'm'
+                                      ? svn_checksum_md5 : svn_checksum_sha1);
+          SVN_ERR(svn_checksum_parse_hex(&working_node->checksum, kind,
+                                         digest + 6, result_pool));
+          working_node->translated_size = svn_sqlite__column_int(stmt, 11);
+        }
+
+      if (!svn_sqlite__column_is_null(stmt, 12))
+        {
+          working_node->changed_rev = svn_sqlite__column_revnum(stmt, 12);
+          working_node->changed_date = svn_sqlite__column_int(stmt, 13);
+          working_node->changed_author = svn_sqlite__column_text(stmt, 14,
+                                                                 result_pool);
+        }
+
+      working_node->depth = svn_depth_from_word(
+                                    svn_sqlite__column_text(stmt, 15, NULL));
+      working_node->last_mod_time = svn_sqlite__column_int(stmt, 16);
+
+      val = svn_sqlite__column_blob(stmt, 17, &len);
+      SVN_ERR(svn_skel__parse_proplist(&working_node->properties,
+                                       svn_skel__parse(val, len, scratch_pool),
+                                       result_pool));
+
+      if (!svn_sqlite__column_is_null(stmt, 18))
+        working_node->changelist_id = svn_sqlite__column_int(stmt, 18);
+
+      if (!svn_sqlite__column_is_null(stmt, 19))
+        working_node->tree_conflict_data = svn_sqlite__column_text(stmt, 19,
+                                                                result_pool);
+
+      apr_hash_set(*nodes, working_node->local_relpath, APR_HASH_KEY_STRING,
+                   working_node);
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Select all the rows from actual_node table in WC_DB and put them into
+   *NODES allocated in RESULT_POOL. */
+static svn_error_t *
+fetch_actual_nodes(apr_hash_t **nodes,
+                   svn_sqlite__db_t *wc_db,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  *nodes = apr_hash_make(result_pool);
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_SELECT_ACTUAL_NODE));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  while (have_row)
+    {
+      db_actual_node_t *actual_node = apr_pcalloc(result_pool,
+                                                  sizeof(*actual_node));
+
+      actual_node->wc_id = svn_sqlite__column_int(stmt, 1);
+      actual_node->local_relpath = svn_sqlite__column_text(stmt, 2,
+                                                           result_pool);
+
+      if (!svn_sqlite__column_is_null(stmt, 3))
+        {
+          apr_size_t len;
+          const void *val;
+
+          val = svn_sqlite__column_blob(stmt, 3, &len);
+          SVN_ERR(svn_skel__parse_proplist(&actual_node->properties,
+                                           svn_skel__parse(val, len,
+                                                           scratch_pool),
+                                           result_pool));
+        }
+
+      if (!svn_sqlite__column_is_null(stmt, 4))
+        {
+          actual_node->conflict_old = svn_sqlite__column_text(stmt, 4,
+                                                              result_pool);
+          actual_node->conflict_new = svn_sqlite__column_text(stmt, 5,
+                                                              result_pool);
+          actual_node->conflict_working = svn_sqlite__column_text(stmt, 6,
+                                                                  result_pool);
+        }
+
+      if (!svn_sqlite__column_is_null(stmt, 7))
+        actual_node->prop_reject = svn_sqlite__column_text(stmt, 7,
+                                                           result_pool);
+
+      if (!svn_sqlite__column_is_null(stmt, 8))
+        actual_node->changelist_id = svn_sqlite__column_int(stmt, 8);
+
+      apr_hash_set(*nodes, actual_node->local_relpath, APR_HASH_KEY_STRING,
+                   actual_node);
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_wc_id(apr_int64_t *wc_id, svn_sqlite__db_t *wc_db)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_SELECT_WCROOT_NULL));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (!have_row)
+    return svn_error_create(SVN_ERR_WC_DB_ERROR, NULL, _("No WC table entry"));
+  *wc_id = svn_sqlite__column_int(stmt, 0);
+  return svn_sqlite__reset(stmt);
+}
+
+static svn_error_t *
+get_repos_info(const char **repos_root,
+               const char **repos_uuid,
+               svn_sqlite__db_t *wc_db,
+               apr_int64_t repos_id,
+               apr_pool_t *result_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db,
+                                    STMT_SELECT_REPOSITORY_BY_ID));
+  SVN_ERR(svn_sqlite__bindf(stmt, "i", repos_id));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (!have_row)
+    return svn_error_createf(SVN_ERR_WC_DB_ERROR, NULL,
+                             _("No REPOSITORY table entry for id '%ld'"),
+                             (long int)repos_id);
+
+  *repos_root = svn_sqlite__column_text(stmt, 0, result_pool);
+  *repos_uuid = svn_sqlite__column_text(stmt, 1, result_pool);
+
+  return svn_sqlite__reset(stmt);
+}
+
+/* This function exists for one purpose: to find the expected future url of
+   an entry which is schedule-add.  In a centralized metadata storage
+   situation, this is pretty easy, but in the current one-db-per-.svn scenario,
+   we need to jump through some hoops, so here it is. */
+static svn_error_t *
+find_working_add_entry_url_stuffs(const char *adm_access_path,
+                                  svn_wc_entry_t *entry,
+                                  const char *relative_path,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool)
+{
+  const char *wc_db_path = db_path(adm_access_path, scratch_pool);
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  svn_sqlite__db_t *wc_db;
+
+  /* Open parent database. */
+  /*fprintf(stderr, "%d: access path: '%s'; relative path: '%s'; db path: '%s'\n",
+            __LINE__, adm_access_path, relative_path, wc_db_path);*/
+  SVN_ERR(svn_sqlite__open(&wc_db, wc_db_path,
+                           svn_sqlite__mode_readwrite, statements,
+                           SVN_WC__VERSION, upgrade_sql, scratch_pool,
+                           scratch_pool));
+
+  /* Check to see if a base_node exists for the directory. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db,
+                                    STMT_SELECT_BASE_NODE_BY_RELPATH));
+  SVN_ERR(svn_sqlite__bindf(stmt, "s", SVN_WC_ENTRY_THIS_DIR));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+  /* If so, cat the url with the existing relative path, put that in
+     entry->url and return. */
+  if (have_row)
+    {
+      const char *base = svn_sqlite__column_text(stmt, 0, NULL);
+
+      entry->repos = svn_sqlite__column_text(stmt, 1, result_pool);
+      entry->uuid = svn_sqlite__column_text(stmt, 2, result_pool);
+      entry->url = svn_path_join_many(result_pool, entry->repos, base,
+                                      relative_path, NULL);
+      return svn_sqlite__reset(stmt);
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  /* If not, move a path segement from adm_access_path to relative_path and
+     recurse. */
+  return find_working_add_entry_url_stuffs(
+                    svn_path_dirname(adm_access_path, scratch_pool),
+                    entry,
+                    svn_path_join(svn_path_basename(adm_access_path,
+                                                    scratch_pool),
+                                  relative_path, scratch_pool),
+                    result_pool, scratch_pool);
+}
 
 /* Fill the entries cache in ADM_ACCESS. The full hash cache will be
-   populated.  POOL is used for local memory allocation, the access baton
-   pool is used for the cache. */
+   populated.  SCRATCH_POOL is used for local memory allocation, the access
+   baton pool is used for the cache. */
 static svn_error_t *
 read_entries(svn_wc_adm_access_t *adm_access,
              apr_pool_t *scratch_pool)
 {
+  apr_hash_t *base_nodes;
+  apr_hash_t *working_nodes;
+  apr_hash_t *actual_nodes;
+  svn_sqlite__db_t *wc_db;
+  apr_hash_index_t *hi;
+  const char *repos_root = NULL;
+  const char *repos_uuid = NULL;
+  apr_pool_t *result_pool = svn_wc_adm_access_pool(adm_access);
+  apr_hash_t *entries = apr_hash_make(result_pool);
+  const char *wc_db_path = db_path(svn_wc_adm_access_path(adm_access),
+                                   scratch_pool);
+  
+  /* Open the wc.db sqlite database. */
+  SVN_ERR(svn_sqlite__open(&wc_db, wc_db_path, svn_sqlite__mode_readwrite,
+                           statements, SVN_WC__VERSION, upgrade_sql,
+                           scratch_pool, scratch_pool));
+
+  /* The basic strategy here is to get all the node information from the
+     database for the directory in question and convert that to
+     svn_wc_entry_t structs.  To do that, we fetch each of the nodes from
+     the three node tables into a hash, then iterate over them, linking them
+     together as required.
+
+     TODO: A smarter way would be to craft a query using the correct type of
+     outer join so that we can get all the nodes in one fell swoop.  However,
+     that takes more thought and effort than I'm willing to invest right now.
+     We can put it on the stack of future optimizations. */
+
+  SVN_ERR(fetch_base_nodes(&base_nodes, wc_db, scratch_pool, scratch_pool));
+  SVN_ERR(fetch_working_nodes(&working_nodes, wc_db, scratch_pool,
+                              scratch_pool));
+  SVN_ERR(fetch_actual_nodes(&actual_nodes, wc_db, scratch_pool, scratch_pool));
+
+  for (hi = apr_hash_first(scratch_pool, base_nodes); hi;
+        hi = apr_hash_next(hi))
+    {
+      const db_base_node_t *base_node;
+      const db_working_node_t *working_node;
+      const db_actual_node_t *actual_node;
+      const char *rel_path;
+      svn_wc_entry_t *entry = alloc_entry(result_pool);
+
+      apr_hash_this(hi, (const void **) &rel_path, NULL, (void **) &base_node);
+
+      /* Get any corresponding working and actual nodes, removing them from
+         their respective hashs to indicate we've seen them. */
+      working_node = apr_hash_get(working_nodes, rel_path, APR_HASH_KEY_STRING);
+      apr_hash_set(working_nodes, rel_path, APR_HASH_KEY_STRING, NULL);
+      actual_node = apr_hash_get(actual_nodes, rel_path, APR_HASH_KEY_STRING);
+      apr_hash_set(actual_nodes, rel_path, APR_HASH_KEY_STRING, NULL);
+
+      entry->name = apr_pstrdup(result_pool, base_node->local_relpath);
+
+      if (working_node)
+        {
+          if (working_node->kind == svn_node_none)
+            entry->schedule = svn_wc_schedule_delete;
+          else
+            entry->schedule = svn_wc_schedule_replace;
+        }
+      else
+        {
+          entry->schedule = svn_wc_schedule_normal;
+        }
+
+      if (base_node->repos_id)
+        {
+          if (repos_root == NULL)
+            SVN_ERR(get_repos_info(&repos_root, &repos_uuid, wc_db,
+                                   base_node->repos_id, result_pool));
+
+          entry->uuid = repos_uuid;
+          entry->url = svn_path_join(repos_root, base_node->repos_relpath,
+                                     result_pool);
+          entry->repos = repos_root;
+        }
+
+      if (working_node && (working_node->copyfrom_repos_path != NULL))
+        entry->copied = TRUE;
+
+      if (working_node && (working_node->tree_conflict_data != NULL))
+        entry->tree_conflict_data = apr_pstrdup(result_pool,
+                                             working_node->tree_conflict_data);
+
+
+      if (base_node->checksum)
+        entry->checksum = svn_checksum_to_cstring(base_node->checksum,
+                                                  result_pool);
+
+      if (actual_node && (actual_node->conflict_old != NULL))
+        {
+          entry->conflict_old = apr_pstrdup(result_pool,
+                                            actual_node->conflict_old);
+          entry->conflict_new = apr_pstrdup(result_pool,
+                                            actual_node->conflict_new);
+          entry->conflict_wrk = apr_pstrdup(result_pool,
+                                            actual_node->conflict_working);
+        }
+
+      if (actual_node && (actual_node->prop_reject != NULL))
+        entry->prejfile = apr_pstrdup(result_pool, actual_node->prop_reject);
+
+      entry->depth = base_node->depth;
+      entry->revision = base_node->revision;
+      entry->kind = base_node->kind;
+
+      entry->incomplete = base_node->incomplete_children;
+
+      apr_hash_set(entries, entry->name, APR_HASH_KEY_STRING, entry);
+    }
+
+  /* Loop over any additional working nodes. */
+  for (hi = apr_hash_first(scratch_pool, working_nodes); hi;
+        hi = apr_hash_next(hi))
+    {
+      const db_working_node_t *working_node;
+      const char *rel_path;
+      svn_wc_entry_t *entry = alloc_entry(result_pool);
+
+      apr_hash_this(hi, (const void **) &rel_path, NULL,
+                    (void **) &working_node);
+      entry->name = apr_pstrdup(result_pool, working_node->local_relpath);
+
+      /* This node is in WORKING, but not in BASE, so it must be an add. */
+      entry->schedule = svn_wc_schedule_add;
+
+      if (working_node->copyfrom_repos_path != NULL)
+        entry->copied = TRUE;
+
+      if (working_node->checksum)
+        entry->checksum = svn_checksum_to_cstring(working_node->checksum,
+                                                  result_pool);
+
+      SVN_ERR(find_working_add_entry_url_stuffs(
+                        entry->name[0] == 0
+                            ? svn_path_dirname(svn_wc_adm_access_path(
+                                            adm_access), scratch_pool)
+                            : svn_wc_adm_access_path(adm_access),
+                        entry,
+                        entry->name[0] == 0
+                            ? svn_path_basename(svn_wc_adm_access_path(
+                                                   adm_access), scratch_pool)
+                            : entry->name,
+                        result_pool, scratch_pool));
+      entry->kind = working_node->kind;
+      entry->revision = 0;
+
+      apr_hash_set(entries, entry->name, APR_HASH_KEY_STRING, entry);
+    }
+
+  /* Fill in any implied fields. */
+  SVN_ERR(resolve_to_defaults(entries, result_pool));
+  svn_wc__adm_access_set_entries(adm_access, TRUE, entries);
+
+  return SVN_NO_ERROR;
+
+#ifdef FROM_TRUNK
   return svn_wc__read_entries_old(adm_access, scratch_pool);
+#endif
 }
 
 /* For non-directory PATHs full entry information is obtained by reading
@@ -609,12 +1261,513 @@
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+insert_base_node(svn_sqlite__db_t *wc_db,
+                 const db_base_node_t *base_node,
+                 apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  const svn_stringbuf_t *properties;
+  svn_skel_t *skel;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_INSERT_BASE_NODE));
+
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 1, base_node->wc_id));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 2, base_node->local_relpath));
+
+  if (base_node->repos_id)
+    {
+      SVN_ERR(svn_sqlite__bind_int64(stmt, 3, base_node->repos_id));
+      SVN_ERR(svn_sqlite__bind_text(stmt, 4, base_node->repos_relpath));
+    }
+
+  if (base_node->parent_id)
+    SVN_ERR(svn_sqlite__bind_int64(stmt, 5, base_node->parent_id));
+
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 6, base_node->revision));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 7,
+                                svn_node_kind_to_word(base_node->kind)));
+
+  if (base_node->checksum)
+    {
+      const char *kind_str = (base_node->checksum->kind == svn_checksum_md5
+                              ? "$md5 $" : "$sha1$");
+      SVN_ERR(svn_sqlite__bind_text(stmt, 8, apr_pstrcat(scratch_pool,
+                    kind_str, svn_checksum_to_cstring(base_node->checksum,
+                                                      scratch_pool), NULL)));
+    }
+
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 9, base_node->translated_size));
+
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 10, base_node->changed_rev));
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 11, base_node->changed_date));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 12, base_node->changed_author));
+
+  SVN_ERR(svn_sqlite__bind_text(stmt, 13, svn_depth_to_word(base_node->depth)));
+
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 14, base_node->last_mod_time));
+
+  if (base_node->properties)
+    SVN_ERR(svn_skel__unparse_proplist(&skel, base_node->properties,
+                                       scratch_pool));
+  else
+    skel = svn_skel__make_empty_list(scratch_pool);
+
+  properties = svn_skel__unparse(skel, scratch_pool);
+  SVN_ERR(svn_sqlite__bind_blob(stmt, 15, properties->data, properties->len));
+
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 16, base_node->incomplete_children));
+
+  /* Execute and reset the insert clause. */
+  return svn_sqlite__insert(NULL, stmt);
+}
+
+static svn_error_t *
+insert_working_node(svn_sqlite__db_t *wc_db,
+                    const db_working_node_t *working_node,
+                    apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_stringbuf_t *properties;
+  svn_skel_t *skel;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_INSERT_WORKING_NODE));
+
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 1, working_node->wc_id));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 2, working_node->local_relpath));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 3, working_node->parent_relpath));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 4,
+                                svn_node_kind_to_word(working_node->kind)));
+
+  if (working_node->copyfrom_repos_id > 0)
+    {
+      SVN_ERR(svn_sqlite__bind_int64(stmt, 5,
+                                     working_node->copyfrom_repos_id));
+      SVN_ERR(svn_sqlite__bind_text(stmt, 6,
+                                    working_node->copyfrom_repos_path));
+      SVN_ERR(svn_sqlite__bind_int64(stmt, 7, working_node->copyfrom_revnum));
+    }
+
+  if (working_node->moved_from)
+    SVN_ERR(svn_sqlite__bind_text(stmt, 8, working_node->moved_from));
+
+  if (working_node->moved_to)
+    SVN_ERR(svn_sqlite__bind_text(stmt, 9, working_node->moved_to));
+
+  if (working_node->checksum)
+    {
+      const char *kind_str = (working_node->checksum->kind == svn_checksum_md5
+                              ? "$md5 $" : "$sha1$");
+      SVN_ERR(svn_sqlite__bind_text(stmt, 10, apr_pstrcat(scratch_pool,
+                    kind_str, svn_checksum_to_cstring(working_node->checksum,
+                                                      scratch_pool), NULL)));
+      SVN_ERR(svn_sqlite__bind_int64(stmt, 11, working_node->translated_size));
+    }
+
+  if (working_node->changed_rev != SVN_INVALID_REVNUM)
+    {
+      SVN_ERR(svn_sqlite__bind_int64(stmt, 12, working_node->changed_rev));
+      SVN_ERR(svn_sqlite__bind_int64(stmt, 13, working_node->changed_date));
+      SVN_ERR(svn_sqlite__bind_text(stmt, 14, working_node->changed_author));
+    }
+
+  SVN_ERR(svn_sqlite__bind_text(stmt, 15,
+                                svn_depth_to_word(working_node->depth)));
+
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 16, working_node->last_mod_time));
+
+  if (working_node->properties)
+    SVN_ERR(svn_skel__unparse_proplist(&skel, working_node->properties,
+                                       scratch_pool));
+  else
+    skel = svn_skel__make_empty_list(scratch_pool);
+
+  properties = svn_skel__unparse(skel, scratch_pool);
+  SVN_ERR(svn_sqlite__bind_blob(stmt, 17, properties->data, properties->len));
+
+  if (working_node->changelist_id > 0)
+    SVN_ERR(svn_sqlite__bind_int64(stmt, 18, working_node->changelist_id));
+
+  if (working_node->tree_conflict_data)
+    SVN_ERR(svn_sqlite__bind_text(stmt, 19, working_node->tree_conflict_data));
+
+  /* Execute and reset the insert clause. */
+  return svn_sqlite__insert(NULL, stmt);
+}
+
+static svn_error_t *
+insert_actual_node(svn_sqlite__db_t *wc_db,
+                   const db_actual_node_t *actual_node,
+                   apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_stringbuf_t *properties;
+  svn_skel_t *skel;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_INSERT_ACTUAL_NODE));
+
+  SVN_ERR(svn_sqlite__bind_int64(stmt, 1, actual_node->wc_id));
+  SVN_ERR(svn_sqlite__bind_text(stmt, 2, actual_node->local_relpath));
+
+  if (actual_node->properties)
+    SVN_ERR(svn_skel__unparse_proplist(&skel, actual_node->properties,
+                                       scratch_pool));
+  else
+    skel = svn_skel__make_empty_list(scratch_pool);
+
+  properties = svn_skel__unparse(skel, scratch_pool);
+  SVN_ERR(svn_sqlite__bind_blob(stmt, 3, properties->data, properties->len));
+
+  if (actual_node->conflict_old)
+    {
+      SVN_ERR(svn_sqlite__bind_text(stmt, 4, actual_node->conflict_old));
+      SVN_ERR(svn_sqlite__bind_text(stmt, 5, actual_node->conflict_new));
+      SVN_ERR(svn_sqlite__bind_text(stmt, 6, actual_node->conflict_working));
+    }
+
+  if (actual_node->prop_reject)
+    SVN_ERR(svn_sqlite__bind_text(stmt, 7, actual_node->prop_reject));
+
+  if (actual_node->changelist_id > 0)
+    SVN_ERR(svn_sqlite__bind_int64(stmt, 8, actual_node->changelist_id));
+
+  /* Execute and reset the insert clause. */
+  return svn_sqlite__insert(NULL, stmt);
+}
+
+static svn_error_t *
+insert_changelist(svn_sqlite__db_t *wc_db,
+                  db_changelist_t *changelist,
+                  apr_int64_t *changelist_id,
+                  apr_pool_t *scratch_pool)
+{
+  svn_sqlite__stmt_t *stmt;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_INSERT_CHANGELIST));
+
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", (apr_int64_t) changelist->wc_id,
+                            changelist->name));
+
+  /* Execute and reset the insert clause. */
+  return svn_sqlite__insert(changelist_id, stmt);
+}
+
+/* Write the information for ENTRY to WC_DB.  The WC_ID, REPOS_ID and
+   REPOS_ROOT will all be used for writing ENTRY. */
+static svn_error_t *
+write_entry(svn_sqlite__db_t *wc_db,
+            apr_int64_t wc_id,
+            apr_int64_t repos_id,
+            const char *repos_root,
+            const svn_wc_entry_t *entry,
+            const char *name,
+            const svn_wc_entry_t *this_dir,
+            apr_pool_t *pool)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t got_row;
+  apr_pool_t *scratch_pool = svn_pool_create(pool);
+  db_base_node_t *base_node = NULL;
+  db_working_node_t *working_node = NULL;
+  db_actual_node_t *actual_node = NULL;
+
+  switch (entry->schedule)
+    {
+      case svn_wc_schedule_normal:
+        base_node = MAYBE_ALLOC(base_node, scratch_pool);
+
+        /* We also need to chuck any existing working node. */
+        SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db,
+                                          STMT_DELETE_WORKING_NODE));
+        SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, name));
+        SVN_ERR(svn_sqlite__step(&got_row, stmt));
+        SVN_ERR(svn_sqlite__reset(stmt));
+        break;
+
+      case svn_wc_schedule_add:
+        working_node = MAYBE_ALLOC(working_node, scratch_pool);
+
+        /* We also need to chuck any existing base node. */
+        SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db,
+                                          STMT_DELETE_BASE_NODE));
+        SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, name));
+        SVN_ERR(svn_sqlite__step(&got_row, stmt));
+        SVN_ERR(svn_sqlite__reset(stmt));
+        break;
+
+      case svn_wc_schedule_delete:
+      case svn_wc_schedule_replace:
+        working_node = MAYBE_ALLOC(working_node, scratch_pool);
+        base_node = MAYBE_ALLOC(base_node, scratch_pool);
+        break;
+    }
+
+  if (entry->copied)
+    {
+      working_node = MAYBE_ALLOC(working_node, scratch_pool);
+      working_node->copyfrom_repos_path = entry->copyfrom_url;
+      working_node->copyfrom_revnum = entry->copyfrom_rev;
+    }
+
+  if (entry->deleted)
+    working_node = MAYBE_ALLOC(working_node, scratch_pool);
+
+  if (entry->absent)
+    {
+      /* TODO: Adjust kinds to absent kinds. */
+    }
+
+  if (entry->incomplete)
+    {
+      base_node = MAYBE_ALLOC(base_node, scratch_pool);
+      base_node->incomplete_children = TRUE;
+    }
+
+  if (entry->conflict_old)
+    {
+      actual_node = MAYBE_ALLOC(actual_node, scratch_pool);
+      actual_node->conflict_old = entry->conflict_old;
+      actual_node->conflict_new = entry->conflict_new;
+      actual_node->conflict_working = entry->conflict_wrk;
+    }
+
+  if (entry->prejfile)
+    {
+      actual_node = MAYBE_ALLOC(actual_node, scratch_pool);
+      actual_node->prop_reject = entry->prejfile;
+    }
+
+  if (entry->changelist)
+    {
+      db_changelist_t changelist;
+      apr_int64_t changelist_id;
+
+      changelist.wc_id = wc_id;
+      changelist.name = entry->changelist;
+
+      SVN_ERR(insert_changelist(wc_db, &changelist, &changelist_id,
+                                scratch_pool));
+
+      if (working_node)
+        working_node->changelist_id = changelist_id;
+      if (actual_node)
+        actual_node->changelist_id = changelist_id;
+    }
+
+  if (entry->tree_conflict_data)
+    {
+      working_node = MAYBE_ALLOC(working_node, scratch_pool);
+      working_node->tree_conflict_data = entry->tree_conflict_data;
+    }
+
+  /* Insert the base node. */
+  if (base_node)
+    {
+      base_node->wc_id = wc_id;
+      base_node->local_relpath = name;
+      base_node->kind = entry->kind;
+      base_node->revision = entry->revision;
+      base_node->depth = entry->depth;
+
+      if (entry->kind == svn_node_dir)
+        base_node->checksum = NULL;
+      else
+        SVN_ERR(svn_checksum_parse_hex(&base_node->checksum, svn_checksum_md5,
+                                       entry->checksum, scratch_pool));
+
+      if (repos_root)
+        {
+          base_node->repos_id = repos_id;
+          if (entry->url != NULL)
+            {
+              base_node->repos_relpath = svn_path_is_child(repos_root,
+                                                           entry->url,
+                                                           scratch_pool);
+
+              if (base_node->repos_relpath == NULL)
+                base_node->repos_relpath = "";
+            }
+          else
+            {
+              const char *base_path = svn_path_is_child(repos_root,
+                                                        this_dir->url,
+                                                        scratch_pool);
+              if (base_path == NULL)
+                base_path = repos_root;
+
+              base_node->repos_relpath = svn_path_join(base_path, entry->name,
+                                                       scratch_pool);
+            }
+        }
+
+      /* TODO: These values should always be present, if they are missing
+         during an upgrade, set a flag, and then ask the user to talk to the
+         server. */
+      base_node->changed_rev = entry->cmt_rev;
+      base_node->changed_date = entry->cmt_date;
+      base_node->changed_author = entry->cmt_author == NULL
+                                        ? "<unknown author>"
+                                        : entry->cmt_author;
+
+      SVN_ERR(insert_base_node(wc_db, base_node, scratch_pool));
+    }
+
+  /* Insert the working node. */
+  if (working_node)
+    {
+      working_node->wc_id = wc_id;
+      working_node->local_relpath = name;
+      working_node->parent_relpath = "";
+      working_node->depth = entry->depth;
+
+      if (entry->kind == svn_node_dir)
+        working_node->checksum = NULL;
+      else
+        SVN_ERR(svn_checksum_parse_hex(&working_node->checksum,
+                                       svn_checksum_md5,
+                                       entry->checksum, scratch_pool));
+
+      if (entry->schedule == svn_wc_schedule_delete)
+        working_node->kind = svn_node_none;
+      else
+        working_node->kind = entry->kind;
+
+      SVN_ERR(insert_working_node(wc_db, working_node, scratch_pool));
+    }
+
+  /* Insert the actual node. */
+  if (actual_node)
+    {
+      actual_node->wc_id = wc_id;
+      actual_node->local_relpath = name;
+
+      SVN_ERR(insert_actual_node(wc_db, actual_node, scratch_pool));
+    }
+
+  svn_pool_destroy(scratch_pool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Baton for use with entries_write_body(). */
+struct entries_write_txn_baton
+{
+  apr_hash_t *entries;
+  const svn_wc_entry_t *this_dir;
+  apr_pool_t *scratch_pool;
+};
+
+/* Actually do the sqlite work within a transaction.
+   This implements svn_sqlite__transaction_callback_t */
+static svn_error_t *
+entries_write_body(void *baton,
+                   svn_sqlite__db_t *wc_db)
+{
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  apr_hash_index_t *hi;
+  struct entries_write_txn_baton *ewtb = baton;
+  apr_pool_t *iterpool = svn_pool_create(ewtb->scratch_pool);
+  const char *repos_root;
+  apr_int64_t repos_id;
+  apr_int64_t wc_id;
+
+  /* Get the repos ID. */
+  if (ewtb->this_dir->uuid != NULL)
+    {
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_SELECT_REPOSITORY));
+      SVN_ERR(svn_sqlite__bindf(stmt, "s", ewtb->this_dir->uuid));
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+      if (!have_row)
+        return svn_error_createf(SVN_ERR_WC_DB_ERROR, NULL,
+                                 _("No REPOSITORY table entry for uuid '%s'"),
+                                 ewtb->this_dir->uuid);
+
+      repos_id = svn_sqlite__column_int(stmt, 0);
+      repos_root = svn_sqlite__column_text(stmt, 1, ewtb->scratch_pool);
+      SVN_ERR(svn_sqlite__reset(stmt));
+    }
+  else
+    {
+      repos_id = 0;
+      repos_root = NULL;
+    }
+
+  /* Write out "this dir" */
+  SVN_ERR(fetch_wc_id(&wc_id, wc_db));
+  SVN_ERR(write_entry(wc_db, wc_id, repos_id, repos_root, ewtb->this_dir,
+                      SVN_WC_ENTRY_THIS_DIR, ewtb->this_dir,
+                      ewtb->scratch_pool));
+
+  for (hi = apr_hash_first(ewtb->scratch_pool, ewtb->entries); hi;
+        hi = apr_hash_next(hi))
+    {
+      const void *key;
+      void *val;
+      const svn_wc_entry_t *this_entry;
+
+      svn_pool_clear(iterpool);
+
+      /* Get the entry and make sure its attributes are up-to-date. */
+      apr_hash_this(hi, &key, NULL, &val);
+      this_entry = val;
+
+      /* Don't rewrite the "this dir" entry! */
+      if (strcmp(key, SVN_WC_ENTRY_THIS_DIR) == 0)
+        continue;
+
+      /* Write the entry. */
+      SVN_ERR(write_entry(wc_db, wc_id, repos_id, repos_root,
+                          this_entry, key, ewtb->this_dir, iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_wc__entries_write(apr_hash_t *entries,
                       svn_wc_adm_access_t *adm_access,
                       apr_pool_t *pool)
 {
+  svn_sqlite__db_t *wc_db;
+  const svn_wc_entry_t *this_dir;
+  struct entries_write_txn_baton ewtb;
+
+  SVN_ERR(svn_wc__adm_write_check(adm_access, pool));
+
+  /* Get a copy of the "this dir" entry for comparison purposes. */
+  this_dir = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR,
+                          APR_HASH_KEY_STRING);
+
+  /* If there is no "this dir" entry, something is wrong. */
+  if (! this_dir)
+    return svn_error_createf(SVN_ERR_ENTRY_NOT_FOUND, NULL,
+                             _("No default entry in directory '%s'"),
+                             svn_path_local_style
+                             (svn_wc_adm_access_path(adm_access), pool));
+
+  /* Open the wc.db sqlite database. */
+  SVN_ERR(svn_sqlite__open(&wc_db,
+                           db_path(svn_wc_adm_access_path(adm_access), pool),
+                           svn_sqlite__mode_readwrite, statements,
+                           SVN_WC__VERSION, upgrade_sql, pool, pool));
+
+  /* Do the work in a transaction. */
+  ewtb.entries = entries;
+  ewtb.this_dir = this_dir;
+  ewtb.scratch_pool = pool;
+  SVN_ERR(svn_sqlite__with_transaction(wc_db, entries_write_body, &ewtb));
+
+  svn_wc__adm_access_set_entries(adm_access, TRUE, entries);
+  svn_wc__adm_access_set_entries(adm_access, FALSE, NULL);
+
+  return SVN_NO_ERROR;
+
+#ifdef FROM_TRUNK
   return svn_wc__entries_write_old(entries, adm_access, pool);
+#endif
 }
 
 
@@ -843,11 +1996,63 @@
   return SVN_NO_ERROR;
 }
 
-
-void
-svn_wc__entry_remove(apr_hash_t *entries, const char *name)
+/* Actually do the sqlite removal work within a transaction.
+   This implements svn_sqlite__transaction_callback_t */
+static svn_error_t *
+entry_remove_body(void *baton,
+                  svn_sqlite__db_t *wc_db)
 {
+  const char *local_relpath = baton;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t got_row;  /* Meaningless when doing a delete. */
+  apr_int64_t wc_id;
+
+  SVN_ERR(fetch_wc_id(&wc_id, wc_db));
+
+  /* Remove the base node. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_DELETE_BASE_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&got_row, stmt));
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  /* Remove the working node. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_DELETE_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&got_row, stmt));
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  /* Remove the actual node. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_DELETE_ACTUAL_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+  SVN_ERR(svn_sqlite__step(&got_row, stmt));
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__entry_remove(apr_hash_t *entries,
+                     const char *parent_dir,
+                     const char *name,
+                     apr_pool_t *scratch_pool)
+{
+  svn_sqlite__db_t *wc_db;
+
   apr_hash_set(entries, name, APR_HASH_KEY_STRING, NULL);
+
+  /* Also remove from the sqlite database. */
+  /* Open the wc.db sqlite database. */
+  SVN_ERR(svn_sqlite__open(&wc_db, db_path(parent_dir, scratch_pool),
+                           svn_sqlite__mode_readwrite, statements,
+                           SVN_WC__VERSION, upgrade_sql,
+                           scratch_pool, scratch_pool));
+
+  /* Do the work in a transaction, for consistency. */
+  SVN_ERR(svn_sqlite__with_transaction(wc_db, entry_remove_body,
+                                       (void *) name));
+
+  return SVN_NO_ERROR;
 }
 
 
@@ -1316,6 +2521,57 @@
 
 /*** Initialization of the entries file. ***/
 
+/* Baton for use with init_body() */
+struct init_txn_baton
+{
+  const char *uuid;
+  const char *url;
+  const char *repos;
+  svn_revnum_t initial_rev;
+  svn_depth_t depth;
+  apr_pool_t *scratch_pool;
+};
+
+/* Actually do the sqlite work within a transaction.
+   This implements svn_sqlite__transaction_callback_t */
+static svn_error_t *
+init_body(void *baton,
+          svn_sqlite__db_t *wc_db)
+{
+  struct init_txn_baton *itb = baton;
+  svn_sqlite__stmt_t *stmt;
+  apr_int64_t wc_id;
+  apr_int64_t repos_id;
+  svn_wc_entry_t *entry = alloc_entry(itb->scratch_pool);
+
+  /* Insert the repository. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_INSERT_REPOSITORY));
+  SVN_ERR(svn_sqlite__bindf(stmt, "ss", itb->repos, itb->uuid));
+  SVN_ERR(svn_sqlite__insert(&repos_id, stmt));
+
+  /* Insert the wcroot. */
+  /* TODO: Right now, this just assumes wc metadata is being stored locally. */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wc_db, STMT_INSERT_WCROOT));
+  SVN_ERR(svn_sqlite__insert(&wc_id, stmt));
+
+  /* Add an entry for the dir itself.  The directory has no name.  It
+     might have a UUID, but otherwise only the revision and default
+     ancestry are present as XML attributes, and possibly an
+     'incomplete' flag if the revnum is > 0. */
+
+  entry->kind = svn_node_dir;
+  entry->url = itb->url;
+  entry->revision = itb->initial_rev;
+  entry->uuid = itb->uuid;
+  entry->repos = itb->repos;
+  entry->depth = itb->depth;
+  if (itb->initial_rev > 0)
+    entry->incomplete = TRUE;
+
+  return write_entry(wc_db, wc_id, repos_id, itb->repos, entry,
+                     SVN_WC_ENTRY_THIS_DIR, entry, itb->scratch_pool);
+}
+
 svn_error_t *
 svn_wc__entries_init(const char *path,
                      const char *uuid,
@@ -1325,12 +2581,10 @@
                      svn_depth_t depth,
                      apr_pool_t *pool)
 {
-  svn_stream_t *stream;
-  const char *temp_file_path;
-  svn_stringbuf_t *accum = svn_stringbuf_createf(pool, "%d\n",
-                                                 SVN_WC__VERSION);
-  svn_wc_entry_t *entry = alloc_entry(pool);
-  apr_size_t len;
+  svn_node_kind_t kind;
+  svn_sqlite__db_t *wc_db;
+  const char *wc_db_path = db_path(path, pool);
+  struct init_txn_baton itb;
 
   SVN_ERR_ASSERT(! repos || svn_path_is_ancestor(repos, url));
   SVN_ERR_ASSERT(depth == svn_depth_empty
@@ -1338,37 +2592,26 @@
                  || depth == svn_depth_immediates
                  || depth == svn_depth_infinity);
 
-  /* Create the entries file, which must not exist prior to this. */
-  SVN_ERR(svn_wc__open_adm_writable(&stream, &temp_file_path,
-                                    path, SVN_WC__ADM_ENTRIES, pool, pool));
+  /* Check that the entries sqlite database does not yet exist. */
+  SVN_ERR(svn_io_check_path(wc_db_path, &kind, pool));
+  if (kind != svn_node_none)
+    return svn_error_createf(SVN_ERR_WC_DB_ERROR, NULL,
+                             _("Existing sqlite database found at '%s'"),
+                             svn_path_local_style(wc_db_path, pool));
 
-  /* Add an entry for the dir itself.  The directory has no name.  It
-     might have a UUID, but otherwise only the revision and default
-     ancestry are present as XML attributes, and possibly an
-     'incomplete' flag if the revnum is > 0. */
+  /* Create the entries database, and start a transaction. */
+  SVN_ERR(svn_sqlite__open(&wc_db, wc_db_path, svn_sqlite__mode_rwcreate,
+                           statements, SVN_WC__VERSION, upgrade_sql, pool,
+                           pool));
 
-  entry->kind = svn_node_dir;
-  entry->url = url;
-  entry->revision = initial_rev;
-  entry->uuid = uuid;
-  entry->repos = repos;
-  entry->depth = depth;
-  if (initial_rev > 0)
-    entry->incomplete = TRUE;
-
-  SVN_ERR(svn_wc__write_entry_old(accum, entry, SVN_WC_ENTRY_THIS_DIR, entry,
-                                  pool));
-
-  len = accum->len;
-  SVN_ERR_W(svn_stream_write(stream, accum->data, &len),
-            apr_psprintf(pool,
-                         _("Error writing entries file for '%s'"),
-                         svn_path_local_style(path, pool)));
-
-  /* Now we have a `entries' file with exactly one entry, an entry
-     for this dir.  Close the file and sync it up. */
-  return svn_wc__close_adm_stream(stream, temp_file_path, path,
-                                  SVN_WC__ADM_ENTRIES, pool);
+  /* Do the body of the work within an sqlite transaction. */
+  itb.uuid = uuid;
+  itb.url = url;
+  itb.repos = repos;
+  itb.initial_rev = initial_rev;
+  itb.depth = depth;
+  itb.scratch_pool = pool;
+  return svn_sqlite__with_transaction(wc_db, init_body, &itb);
 }
 
 
diff --git a/subversion/libsvn_wc/entries.h b/subversion/libsvn_wc/entries.h
index d25b278..c8ca635 100644
--- a/subversion/libsvn_wc/entries.h
+++ b/subversion/libsvn_wc/entries.h
@@ -198,8 +198,15 @@
                                   svn_boolean_t do_sync,
                                   apr_pool_t *pool);
 
-/* Remove entry NAME from ENTRIES, unconditionally. */
-void svn_wc__entry_remove(apr_hash_t *entries, const char *name);
+/* Remove entry NAME from ENTRIES, unconditionally.  PARENT_DIR should be
+   the directory which contains the .svn administrative directory for PATH
+   (in most cases, this will be svn_wc_adm_access_path() applied to the
+   access baton which ENTRIES is or will eventually be a part of. */
+svn_error_t *
+svn_wc__entry_remove(apr_hash_t *entries,
+                     const char *parent_dir,
+                     const char *name,
+                     apr_pool_t *scratch_pool);
 
 
 /* Tweak the entry NAME within hash ENTRIES.  If NEW_URL is non-null,
@@ -245,7 +252,6 @@
                         const svn_wc_entry_t *this_dir,
                         apr_pool_t *pool);
 
-
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/subversion/libsvn_wc/log.c b/subversion/libsvn_wc/log.c
index 2751b06..8eaa955 100644
--- a/subversion/libsvn_wc/log.c
+++ b/subversion/libsvn_wc/log.c
@@ -946,7 +946,9 @@
                 {
                   SVN_ERR(svn_wc_entries_read(&entries, loggy->adm_access,
                                               TRUE, loggy->pool));
-                  svn_wc__entry_remove(entries, name);
+                  SVN_ERR(svn_wc__entry_remove(
+                            entries, svn_wc_adm_access_path(loggy->adm_access),
+                            name, loggy->pool));
                   SVN_ERR(svn_wc__entries_write(entries, loggy->adm_access,
                                                 loggy->pool));
                 }
diff --git a/subversion/libsvn_wc/questions.c b/subversion/libsvn_wc/questions.c
index f8eb59e..7639264 100644
--- a/subversion/libsvn_wc/questions.c
+++ b/subversion/libsvn_wc/questions.c
@@ -38,6 +38,7 @@
 #include "entries.h"
 #include "props.h"
 #include "translate.h"
+#include "wc_db.h"
 
 #include "svn_private_config.h"
 #include "private/svn_wc_private.h"
@@ -51,32 +52,15 @@
                 apr_pool_t *pool)
 {
   svn_error_t *err;
-  const char *format_file_path = svn_wc__adm_child(path, SVN_WC__ADM_ENTRIES,
-                                                   pool);
+  svn_node_kind_t kind;
 
-  /* First try to read the format number from the entries file. */
-  err = svn_io_read_version_file(wc_format, format_file_path, pool);
+  err = svn_wc__db_version(wc_format, path, pool);
+  if (err && err->apr_err != SVN_ERR_WC_MISSING)
+    return err;
 
-  /* If that didn't work and the first line of the entries file contains
-     something other than a number, then it is probably in XML format. */
-  if (err && err->apr_err == SVN_ERR_BAD_VERSION_FILE_FORMAT)
+  if (err)
     {
       svn_error_clear(err);
-      /* Fall back on reading the format file instead.
-         Note that the format file might not exist in newer working copies
-         (format 7 and higher), but in that case, the entries file should
-         have contained the format number. */
-      format_file_path = svn_wc__adm_child(path, SVN_WC__ADM_FORMAT, pool);
-
-      err = svn_io_read_version_file(wc_format, format_file_path, pool);
-    }
-
-  if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
-              || APR_STATUS_IS_ENOTDIR(err->apr_err)))
-    {
-      svn_node_kind_t kind;
-
-      svn_error_clear(err);
 
       /* Check path itself exists. */
       SVN_ERR(svn_io_check_path(path, &kind, pool));
@@ -88,50 +72,34 @@
             svn_path_local_style(path, pool));
         }
 
-      /* If the format file does not exist or path not directory, then for
+      /* If the metadata does not exist or path not directory, then for
          our purposes this is not a working copy, so return 0. */
       *wc_format = 0;
+      return SVN_NO_ERROR;
     }
-  else if (err)
-    return err;
   else
     {
-      /* If we managed to read the format file we assume that we
+      /* If we managed to read the format we assume that we
           are dealing with a real wc so we can return a nice
           error. */
-      SVN_ERR(svn_wc__check_format(*wc_format, path, pool));
+      return svn_wc__check_format(*wc_format, path, pool);
     }
-
-  return SVN_NO_ERROR;
 }
 
 
 svn_error_t *
 svn_wc__check_format(int wc_format, const char *path, apr_pool_t *pool)
 {
-  if (wc_format < 2)
+  if (wc_format < SVN_WC__WC_NG_VERSION)
     {
       return svn_error_createf
         (SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
          _("Working copy format of '%s' is too old (%d); "
-           "please check out your working copy again"),
-         svn_path_local_style(path, pool), wc_format);
-    }
-  else if (wc_format > SVN_WC__VERSION)
-    {
-      /* This won't do us much good for the 1.4<->1.5 crossgrade,
-         since 1.4.x clients don't refer to this FAQ entry, but at
-         least post-1.5 crossgrades will be somewhat less painful. */
-      return svn_error_createf
-        (SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
-         _("This client is too old to work with working copy '%s'.  You need\n"
-           "to get a newer Subversion client, or to downgrade this working "
-           "copy.\n"
+           "please run 'svn cleanup' to upgrade your working copy\n"
            "See "
            "http://subversion.tigris.org/faq.html#working-copy-format-change\n"
-           "for details."
-           ),
-         svn_path_local_style(path, pool));
+           "for details."),
+         svn_path_local_style(path, pool), wc_format);
     }
 
   return SVN_NO_ERROR;
diff --git a/subversion/libsvn_wc/update_editor.c b/subversion/libsvn_wc/update_editor.c
index 04de446..abc2244 100644
--- a/subversion/libsvn_wc/update_editor.c
+++ b/subversion/libsvn_wc/update_editor.c
@@ -191,6 +191,9 @@
   /* The URL to the root of the repository, or NULL. */
   const char *repos;
 
+  /* The UUID of the repos, or NULL. */
+  const char *uuid;
+
   /* External diff3 to use for merges (can be null, in which case
      internal merge code is used). */
   const char *diff3_cmd;
@@ -724,7 +727,9 @@
       if (current_entry->deleted)
         {
           if (current_entry->schedule != svn_wc_schedule_add)
-            svn_wc__entry_remove(entries, name);
+            SVN_ERR(svn_wc__entry_remove(
+                             entries, svn_wc_adm_access_path(adm_access),
+                             name, subpool));
           else
             {
               svn_wc_entry_t tmpentry;
@@ -743,7 +748,9 @@
       else if (current_entry->absent
                && (current_entry->revision != *(eb->target_revision)))
         {
-          svn_wc__entry_remove(entries, name);
+          SVN_ERR(svn_wc__entry_remove(
+                                entries, svn_wc_adm_access_path(adm_access),
+                                name, subpool));
         }
       else if (current_entry->kind == svn_node_dir)
         {
@@ -759,7 +766,9 @@
                        && (! current_entry->absent)
                        && (current_entry->schedule != svn_wc_schedule_add))
               {
-                svn_wc__entry_remove(entries, name);
+                SVN_ERR(svn_wc__entry_remove(
+                             entries, svn_wc_adm_access_path(adm_access),
+                             name, subpool));
                 if (eb->notify_func)
                   {
                     svn_wc_notify_t *notify
@@ -1019,7 +1028,7 @@
 
   /* Make sure it's the right working copy, either by creating it so,
      or by checking that it is so already. */
-  SVN_ERR(svn_wc_ensure_adm3(db->path, NULL,
+  SVN_ERR(svn_wc_ensure_adm3(db->path, db->edit_baton->uuid,
                              ancestor_url, repos,
                              ancestor_revision, db->ambient_depth, pool));
 
@@ -1956,7 +1965,9 @@
       apr_hash_t *entries;
       const char *base_name = svn_path_basename(full_path, pool);
       SVN_ERR(svn_wc_entries_read(&entries, parent_adm_access, TRUE, pool));
-      svn_wc__entry_remove(entries, base_name);
+      SVN_ERR(svn_wc__entry_remove(
+                        entries, svn_wc_adm_access_path(parent_adm_access),
+                        base_name, pool));
       SVN_ERR(svn_wc__entries_write(entries, parent_adm_access, pool));
       if (strcmp(path, eb->target) == 0)
         eb->target_deleted = TRUE;
@@ -4664,6 +4675,7 @@
   eb->target_revision          = target_revision;
   eb->switch_url               = switch_url;
   eb->repos                    = entry ? entry->repos : NULL;
+  eb->uuid                     = entry ? entry->uuid : NULL;
   eb->adm_access               = adm_access;
   eb->anchor                   = anchor;
   eb->target                   = target;
diff --git a/subversion/libsvn_wc/wc.h b/subversion/libsvn_wc/wc.h
index 701d494..faf124b 100644
--- a/subversion/libsvn_wc/wc.h
+++ b/subversion/libsvn_wc/wc.h
@@ -72,9 +72,13 @@
  * The change from 9 to 10 was the addition of tree-conflicts, file
  * externals and a different canonicalization of urls.
  *
+ * The change from 10 to 11 was a complete rewrite of the wc datastore,
+ * which resulted in centralization and migration of data to an sqlite
+ * datebase.
+ *
  * Please document any further format changes here.
  */
-#define SVN_WC__VERSION       10
+#define SVN_WC__VERSION       11
 
 /* A version <= this doesn't have property caching in the entries file. */
 #define SVN_WC__NO_PROPCACHING_VERSION 5
@@ -88,6 +92,9 @@
 /* A version < this can have urls that aren't canonical according to the new
    rules. See issue #2475. */
 #define SVN_WC__CHANGED_CANONICAL_URLS 10
+
+/* A version < this is pre-wc-ng. */
+#define SVN_WC__WC_NG_VERSION 11
 
 /*** Update traversals. ***/
 
diff --git a/subversion/libsvn_wc/wc_db.c b/subversion/libsvn_wc/wc_db.c
index e94de21..71036fd 100644
--- a/subversion/libsvn_wc/wc_db.c
+++ b/subversion/libsvn_wc/wc_db.c
@@ -23,10 +23,14 @@
 #include "svn_types.h"
 #include "svn_error.h"
 #include "svn_path.h"
+#include "svn_wc.h"
 
+#include "wc.h"
 #include "wc_db.h"
+#include "adm_files.h"
 
 #include "svn_private_config.h"
+#include "private/svn_sqlite.h"
 
 
 struct svn_wc__db_t {
@@ -214,6 +218,61 @@
 
 
 svn_error_t *
+svn_wc__db_version(int *version,
+                   const char *path,
+                   apr_pool_t *scratch_pool)
+{
+  svn_error_t *err;
+  const char *format_file_path;
+
+  /* First, try reading the wc.db file.  Instead of stat'ing the file to
+     see if it exists, and then opening it, we just try opening it.  If we
+     get any kind of an error, wrap that eith an ENOENT error and return. */
+  err = svn_sqlite__get_schema_version(version,
+                                       svn_wc__adm_child(path, "wc.db",
+                                                         scratch_pool),
+                                       scratch_pool);
+  if (err && err->apr_err != SVN_ERR_SQLITE_ERROR)
+    return err;
+  else if (!err)
+    return SVN_NO_ERROR;
+
+  /* Hmm, that didn't work.  Now try reading the format number from the
+     entries file. */
+  svn_error_clear(err);
+  format_file_path = svn_wc__adm_child(path, SVN_WC__ADM_ENTRIES, scratch_pool);
+  err = svn_io_read_version_file(version, format_file_path, scratch_pool);
+  if (err && err->apr_err != SVN_ERR_BAD_VERSION_FILE_FORMAT)
+    return svn_error_createf(SVN_ERR_WC_MISSING, err, _("'%s' does not exist"),
+                             svn_path_local_style(path, scratch_pool));
+  else if (!err)
+    return SVN_NO_ERROR;
+
+  /* Wow, another error; this must be a really old working copy!  Fall back
+     to reading the format file. */
+  svn_error_clear(err);
+  /* Note that the format file might not exist in newer working copies
+     (format 7 and higher), but in that case, the entries file should
+     have contained the format number. */
+  format_file_path = svn_wc__adm_child(path, SVN_WC__ADM_FORMAT, scratch_pool);
+  err = svn_io_read_version_file(version, format_file_path, scratch_pool);
+
+  if (err && (APR_STATUS_IS_ENOENT(err->apr_err)
+              || APR_STATUS_IS_ENOTDIR(err->apr_err)))
+    return svn_error_createf(SVN_ERR_WC_MISSING, err, _("'%s' does not exist"),
+                             svn_path_local_style(path, scratch_pool));
+  else if (!err)
+    return SVN_NO_ERROR;
+
+  /* If we've gotten this far, all of the above checks have failed, so just
+     bail. */
+  return svn_error_createf(SVN_ERR_WC_MISSING, NULL,
+                           _("'%s' is not a working copy"),
+                           svn_path_local_style(path, scratch_pool));
+}
+
+
+svn_error_t *
 svn_wc__db_txn_begin(svn_wc__db_t *db,
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
diff --git a/subversion/libsvn_wc/wc_db.h b/subversion/libsvn_wc/wc_db.h
index f9f150d..de88733 100644
--- a/subversion/libsvn_wc/wc_db.h
+++ b/subversion/libsvn_wc/wc_db.h
@@ -185,6 +185,18 @@
                      apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool);
 
+/* This function answers at simple question: what format version of the wc
+   exists at PATH.  The reason it takes a PATH instead of an existing db
+   handle is because it may need to use legacy, pre-wc-ng methods to determine
+   what that version is, and such versions don't have any db to open. 
+   
+   If no working copy exists at PATH, return SVN_ERR_WC_MISSING. */
+svn_error_t *
+svn_wc__db_version(int *version,
+                   const char *path,
+                   apr_pool_t *scratch_pool);
+                   
+
 /**
  * Start a transaction for the database(s) which are part of @a db.
  *