You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/02/04 21:48:13 UTC
svn commit: r1442344 [22/39] - in /subversion/branches/fsfs-format7: ./
build/ build/ac-macros/ build/generator/ build/generator/templates/
build/win32/ contrib/client-side/emacs/
contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ doc/...
Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/wc_db.c Mon Feb 4 20:48:05 2013
@@ -46,6 +46,7 @@
#include "conflicts.h"
#include "wc_db_private.h"
#include "workqueue.h"
+#include "token-map.h"
#include "svn_private_config.h"
#include "private/svn_sqlite.h"
@@ -104,9 +105,9 @@
#define UNKNOWN_WC_ID ((apr_int64_t) -1)
#define FORMAT_FROM_SDB (-1)
-/* Check if the column contains actual properties. The empty set of properties
- is stored as "()", so we have properties if the size of the column is
- larger than 2. */
+/* Check if column number I, a property-skel column, contains a non-empty
+ set of properties. The empty set of properties is stored as "()", so we
+ have properties if the size of the column is larger than 2. */
#define SQLITE_PROPERTIES_AVAILABLE(stmt, i) \
(svn_sqlite__column_bytes(stmt, i) > 2)
@@ -117,6 +118,7 @@ svn_wc__db_op_depth_for_upgrade(const ch
}
+/* Representation of a new base row for the NODES table */
typedef struct insert_base_baton_t {
/* common to all insertions into BASE */
svn_wc__db_status_t status;
@@ -175,6 +177,7 @@ typedef struct insert_base_baton_t {
} insert_base_baton_t;
+/* Representation of a new working row for the NODES table */
typedef struct insert_working_baton_t {
/* common to all insertions into WORKING (including NODE_DATA) */
svn_wc__db_status_t presence;
@@ -216,6 +219,7 @@ typedef struct insert_working_baton_t {
} insert_working_baton_t;
+/* Representation of a new row for the EXTERNALS table */
typedef struct insert_external_baton_t {
/* common to all insertions into EXTERNALS */
svn_kind_t kind;
@@ -266,27 +270,6 @@ typedef struct insert_external_baton_t {
} insert_external_baton_t;
-static const svn_token_map_t kind_map[] = {
- { "file", svn_kind_file },
- { "dir", svn_kind_dir },
- { "symlink", svn_kind_symlink },
- { "unknown", svn_kind_unknown },
- { NULL }
-};
-
-/* Note: we only decode presence values from the database. These are a subset
- of all the status values. */
-static const svn_token_map_t presence_map[] = {
- { "normal", svn_wc__db_status_normal },
- { "server-excluded", svn_wc__db_status_server_excluded },
- { "excluded", svn_wc__db_status_excluded },
- { "not-present", svn_wc__db_status_not_present },
- { "incomplete", svn_wc__db_status_incomplete },
- { "base-deleted", svn_wc__db_status_base_deleted },
- { NULL }
-};
-
-
/* Forward declarations */
static svn_error_t *
add_work_items(svn_sqlite__db_t *sdb,
@@ -301,12 +284,6 @@ set_actual_props(apr_int64_t wc_id,
apr_pool_t *scratch_pool);
static svn_error_t *
-mark_conflict(svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath,
- const svn_skel_t *conflict_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,
@@ -321,6 +298,7 @@ static svn_error_t *
db_read_pristine_props(apr_hash_t **props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
+ svn_boolean_t deleted_ok,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
@@ -341,7 +319,7 @@ read_info(svn_wc__db_status_t *status,
svn_revnum_t *original_revision,
svn_wc__db_lock_t **lock,
svn_filesize_t *recorded_size,
- apr_time_t *recorded_mod_time,
+ apr_time_t *recorded_time,
const char **changelist,
svn_boolean_t *conflicted,
svn_boolean_t *op_root,
@@ -382,19 +360,14 @@ wclock_owns_lock(svn_boolean_t *own_lock
svn_boolean_t exact,
apr_pool_t *scratch_pool);
-/* Baton for db_is_switched */
-struct db_is_switched_baton_t
-{
- svn_boolean_t *is_switched;
- svn_kind_t *kind;
-};
-
static svn_error_t *
-db_is_switched(void *baton,
+db_is_switched(svn_boolean_t *is_switched,
+ svn_kind_t *kind,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *scratch_pool);
-
+
+
/* Return the absolute path, in local path style, of LOCAL_RELPATH
in WCROOT. */
static const char *
@@ -492,11 +465,11 @@ fetch_repos_info(const char **repos_root
}
-/* Set *REPOS_ID, *REVISION and *REPOS_RELPATH from the
- given columns of the SQLITE statement STMT, or to NULL if the respective
+/* Set *REPOS_ID, *REVISION and *REPOS_RELPATH from the given columns of the
+ SQLITE statement STMT, or to NULL/SVN_INVALID_REVNUM if the respective
column value is null. Any of the output parameters may be NULL if not
required. */
-static svn_error_t *
+static void
repos_location_from_columns(apr_int64_t *repos_id,
svn_revnum_t *revision,
const char **repos_relpath,
@@ -506,8 +479,6 @@ repos_location_from_columns(apr_int64_t
int col_repos_relpath,
apr_pool_t *result_pool)
{
- svn_error_t *err = SVN_NO_ERROR;
-
if (repos_id)
{
/* Fetch repository information via REPOS_ID. */
@@ -525,8 +496,6 @@ repos_location_from_columns(apr_int64_t
*repos_relpath = svn_sqlite__column_text(stmt, col_repos_relpath,
result_pool);
}
-
- return err;
}
@@ -611,42 +580,12 @@ blank_ibb(insert_base_baton_t *pibb)
}
-/* Extend any delete of the parent of LOCAL_RELPATH to LOCAL_RELPATH.
-
- Given a wc:
-
- 0 1 2 3 4
- normal
- A normal
- A/B normal normal
- A/B/C not-pres normal
- A/B/C/D normal
-
- That is checkout, delete A/B, copy a replacement A/B, delete copied
- child A/B/C, add replacement A/B/C, add A/B/C/D.
-
- Now an update that adds base nodes for A/B/C, A/B/C/D and A/B/C/D/E
- must extend the A/B deletion:
-
- 0 1 2 3 4
- normal
- A normal
- A/B normal normal
- A/B/C normal not-pres normal
- A/B/C/D normal base-del normal
- A/B/C/D/E normal base-del
-
- When adding a base node if the parent has a working node then the
- parent base is deleted and this must be extended to cover new base
- node.
-
- In the example above A/B/C/D and A/B/C/D/E are the nodes that get
- the extended delete, A/B/C is already deleted.
- */
-static svn_error_t *
-extend_parent_delete(svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath,
- apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_extend_parent_delete(svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ svn_kind_t kind,
+ int op_depth,
+ apr_pool_t *scratch_pool)
{
svn_boolean_t have_row;
svn_sqlite__stmt_t *stmt;
@@ -657,28 +596,29 @@ extend_parent_delete(svn_wc__db_wcroot_t
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_LOWEST_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, parent_relpath,
+ op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
parent_op_depth = svn_sqlite__column_int(stmt, 0);
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
{
- int op_depth;
+ int existing_op_depth;
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+ op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (have_row)
- op_depth = svn_sqlite__column_int(stmt, 0);
+ existing_op_depth = svn_sqlite__column_int(stmt, 0);
SVN_ERR(svn_sqlite__reset(stmt));
- if (!have_row || parent_op_depth < op_depth)
+ if (!have_row || parent_op_depth < existing_op_depth)
{
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_INSTALL_WORKING_NODE_FOR_DELETE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isdt", wcroot->wc_id,
+ STMT_INSTALL_WORKING_NODE_FOR_DELETE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isdst", wcroot->wc_id,
local_relpath, parent_op_depth,
- presence_map,
- svn_wc__db_status_base_deleted));
+ parent_relpath, kind_map, kind));
SVN_ERR(svn_sqlite__update(NULL, stmt));
}
}
@@ -687,22 +627,24 @@ extend_parent_delete(svn_wc__db_wcroot_t
}
-/* This is the reverse of extend_parent_delete.
+/* This is the reverse of svn_wc__db_extend_parent_delete.
- When removing a base node if the parent has a working node then the
- parent base and this node are both deleted and so the delete of
- this node must be removed.
+ When removing a node if the parent has a higher working node then
+ the parent node and this node are both deleted or replaced and any
+ delete over this node must be removed.
*/
-static svn_error_t *
-retract_parent_delete(svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath,
- apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_retract_parent_delete(svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ int op_depth,
+ apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_LOWEST_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+ op_depth));
SVN_ERR(svn_sqlite__step_done(stmt));
return SVN_NO_ERROR;
@@ -710,7 +652,9 @@ retract_parent_delete(svn_wc__db_wcroot_
-/* */
+/* Insert the base row represented by (insert_base_baton_t *) BATON.
+ *
+ * Implements svn_wc__db_txn_callback_t. */
static svn_error_t *
insert_base_node(void *baton,
svn_wc__db_wcroot_t *wcroot,
@@ -721,7 +665,7 @@ insert_base_node(void *baton,
apr_int64_t repos_id = pibb->repos_id;
svn_sqlite__stmt_t *stmt;
svn_filesize_t recorded_size = SVN_INVALID_FILESIZE;
- apr_int64_t recorded_mod_time;
+ apr_int64_t recorded_time;
/* The directory at the WCROOT has a NULL parent_relpath. Otherwise,
bind the appropriate parent_relpath. */
@@ -747,7 +691,7 @@ insert_base_node(void *baton,
{
/* Preserve size and modification time if caller asked us to. */
recorded_size = get_recorded_size(stmt, 6);
- recorded_mod_time = svn_sqlite__column_int64(stmt, 12);
+ recorded_time = svn_sqlite__column_int64(stmt, 12);
}
SVN_ERR(svn_sqlite__reset(stmt));
}
@@ -765,7 +709,7 @@ insert_base_node(void *baton,
pibb->revision,
presence_map, pibb->status, /* 8 */
(pibb->kind == svn_kind_dir) ? /* 9 */
- svn_depth_to_word(pibb->depth) : NULL,
+ svn_token__to_word(depth_map, pibb->depth) : NULL,
kind_map, pibb->kind, /* 10 */
pibb->changed_rev, /* 11 */
pibb->changed_date, /* 12 */
@@ -789,10 +733,14 @@ insert_base_node(void *baton,
if (recorded_size != SVN_INVALID_FILESIZE)
{
SVN_ERR(svn_sqlite__bind_int64(stmt, 16, recorded_size));
- SVN_ERR(svn_sqlite__bind_int64(stmt, 17, recorded_mod_time));
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 17, recorded_time));
}
}
+ /* Set properties. Must be null if presence not normal or incomplete. */
+ assert(pibb->status == svn_wc__db_status_normal
+ || pibb->status == svn_wc__db_status_incomplete
+ || pibb->props == NULL);
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props,
scratch_pool));
@@ -849,13 +797,16 @@ insert_base_node(void *baton,
|| (pibb->status == svn_wc__db_status_incomplete))
&& ! pibb->file_external)
{
- SVN_ERR(extend_parent_delete(wcroot, local_relpath, scratch_pool));
+ SVN_ERR(svn_wc__db_extend_parent_delete(wcroot, local_relpath,
+ pibb->kind, 0,
+ scratch_pool));
}
else if (pibb->status == svn_wc__db_status_not_present
|| pibb->status == svn_wc__db_status_server_excluded
|| pibb->status == svn_wc__db_status_excluded)
{
- SVN_ERR(retract_parent_delete(wcroot, local_relpath, scratch_pool));
+ SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, 0,
+ scratch_pool));
}
}
@@ -878,12 +829,15 @@ insert_base_node(void *baton,
SVN_ERR(add_work_items(wcroot->sdb, pibb->work_items, scratch_pool));
if (pibb->conflict)
- SVN_ERR(mark_conflict(wcroot, local_relpath, pibb->conflict, scratch_pool));
+ SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
+ pibb->conflict, scratch_pool));
return SVN_NO_ERROR;
}
+/* Initialize the baton with appropriate "blank" values. This allows the
+ insertion function to leave certain columns null. */
static void
blank_iwb(insert_working_baton_t *piwb)
{
@@ -986,7 +940,9 @@ insert_incomplete_children(svn_sqlite__d
}
-/* */
+/* Insert the working row represented by (insert_working_baton_t *) BATON.
+ *
+ * Implements svn_wc__db_txn_callback_t. */
static svn_error_t *
insert_working_node(void *baton,
svn_wc__db_wcroot_t *wcroot,
@@ -995,7 +951,9 @@ insert_working_node(void *baton,
{
const insert_working_baton_t *piwb = baton;
const char *parent_relpath;
+ const char *moved_to_relpath = NULL;
svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
SVN_ERR_ASSERT(piwb->op_depth > 0);
@@ -1003,16 +961,27 @@ insert_working_node(void *baton,
SVN_ERR_ASSERT(*local_relpath != '\0');
parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
+ /* Preserve existing moved-to information for this relpath,
+ * which might exist in case we're replacing an existing base-deleted
+ * node. */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_TO));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+ piwb->op_depth));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ moved_to_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+ SVN_ERR(svn_sqlite__reset(stmt));
+
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnntstrisn"
"nnnn" /* properties translated_size last_mod_time dav_cache */
- "snnd", /* symlink_target, file_external, moved_to, moved_here */
+ "snsd", /* symlink_target, file_external, moved_to, moved_here */
wcroot->wc_id, local_relpath,
piwb->op_depth,
parent_relpath,
presence_map, piwb->presence,
(piwb->kind == svn_kind_dir)
- ? svn_depth_to_word(piwb->depth) : NULL,
+ ? svn_token__to_word(depth_map, piwb->depth) : NULL,
kind_map, piwb->kind,
piwb->changed_rev,
piwb->changed_date,
@@ -1020,6 +989,7 @@ insert_working_node(void *baton,
/* Note: incomplete nodes may have a NULL target. */
(piwb->kind == svn_kind_symlink)
? piwb->target : NULL,
+ moved_to_relpath,
piwb->moved_here));
if (piwb->kind == svn_kind_file)
@@ -1035,6 +1005,10 @@ insert_working_node(void *baton,
SVN_ERR(svn_sqlite__bind_revnum(stmt, 7, piwb->original_revnum));
}
+ /* Set properties. Must be null if presence not normal or incomplete. */
+ assert(piwb->presence == svn_wc__db_status_normal
+ || piwb->presence == svn_wc__db_status_incomplete
+ || piwb->props == NULL);
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
@@ -1112,8 +1086,8 @@ insert_working_node(void *baton,
SVN_ERR(add_work_items(wcroot->sdb, piwb->work_items, scratch_pool));
if (piwb->conflict)
- SVN_ERR(mark_conflict(wcroot, local_relpath, piwb->conflict,
- scratch_pool));
+ SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
+ piwb->conflict, scratch_pool));
return SVN_NO_ERROR;
}
@@ -1236,6 +1210,41 @@ gather_repo_children(const apr_array_hea
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_wc__db_get_children_op_depth(apr_hash_t **children,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ int op_depth,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ *children = apr_hash_make(result_pool);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_OP_DEPTH_CHILDREN));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+ op_depth));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ while (have_row)
+ {
+ const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+ svn_kind_t *child_kind = apr_palloc(result_pool, sizeof(svn_kind_t));
+
+ *child_kind = svn_sqlite__column_token(stmt, 1, kind_map);
+ apr_hash_set(*children,
+ svn_relpath_basename(child_relpath, result_pool),
+ APR_HASH_KEY_STRING, child_kind);
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ return SVN_NO_ERROR;
+}
+
/* Return TRUE if CHILD_ABSPATH is an immediate child of PARENT_ABSPATH.
* Else, return FALSE. */
@@ -1389,25 +1398,21 @@ does_node_exist(svn_boolean_t *exists,
return svn_error_trace(svn_sqlite__reset(stmt));
}
-/* baton for init_db */
-struct init_db_baton
-{
- /* output values */
- apr_int64_t wc_id;
- apr_int64_t repos_id;
- /* input values */
- const char *repos_root_url;
- const char *repos_uuid;
- const char *root_node_repos_relpath;
- svn_revnum_t root_node_revision;
- svn_depth_t root_node_depth;
-};
-
-/* Helper for create_db(). Initializes our wc.db schema */
+/* Helper for create_db(). Initializes our wc.db schema.
+ */
static svn_error_t *
-init_db( void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool)
+init_db(/* output values */
+ apr_int64_t *repos_id,
+ apr_int64_t *wc_id,
+ /* input values */
+ svn_sqlite__db_t *db,
+ const char *repos_root_url,
+ const char *repos_uuid,
+ const char *root_node_repos_relpath,
+ svn_revnum_t root_node_revision,
+ svn_depth_t root_node_depth,
+ apr_pool_t *scratch_pool)
{
- struct init_db_baton *idb = baton;
svn_sqlite__stmt_t *stmt;
/* Create the database's schema. */
@@ -1417,32 +1422,33 @@ init_db( void *baton, svn_sqlite__db_t *
SVN_ERR(svn_sqlite__exec_statements(db, STMT_CREATE_EXTERNALS));
/* Insert the repository. */
- SVN_ERR(create_repos_id(&idb->repos_id, idb->repos_root_url, idb->repos_uuid,
+ SVN_ERR(create_repos_id(repos_id, repos_root_url, repos_uuid,
db, scratch_pool));
/* Insert the wcroot. */
/* ### Right now, this just assumes wc metadata is being stored locally. */
SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_WCROOT));
- SVN_ERR(svn_sqlite__insert(&idb->wc_id, stmt));
+ SVN_ERR(svn_sqlite__insert(wc_id, stmt));
- if (idb->root_node_repos_relpath)
+ if (root_node_repos_relpath)
{
svn_wc__db_status_t status = svn_wc__db_status_normal;
- if (idb->root_node_revision > 0)
+ if (root_node_revision > 0)
status = svn_wc__db_status_incomplete; /* Will be filled by update */
SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "isdsisrtst",
- idb->wc_id, /* 1 */
+ *wc_id, /* 1 */
"", /* 2 */
0, /* op_depth is 0 for base */
NULL, /* 4 */
- idb->repos_id,
- idb->root_node_repos_relpath,
- idb->root_node_revision,
+ *repos_id,
+ root_node_repos_relpath,
+ root_node_revision,
presence_map, status, /* 8 */
- svn_depth_to_word(idb->root_node_depth),
+ svn_token__to_word(depth_map,
+ root_node_depth),
kind_map, svn_kind_dir /* 10 */));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
@@ -1475,23 +1481,16 @@ create_db(svn_sqlite__db_t **sdb,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- struct init_db_baton idb;
-
SVN_ERR(svn_wc__db_util_open_db(sdb, dir_abspath, sdb_fname,
svn_sqlite__mode_rwcreate, exclusive,
NULL /* my_statements */,
result_pool, scratch_pool));
- idb.repos_root_url = repos_root_url;
- idb.repos_uuid = repos_uuid;
- idb.root_node_repos_relpath = root_node_repos_relpath;
- idb.root_node_revision = root_node_revision;
- idb.root_node_depth = root_node_depth;
-
- SVN_ERR(svn_sqlite__with_lock(*sdb, init_db, &idb, scratch_pool));
-
- *repos_id = idb.repos_id;
- *wc_id = idb.wc_id;
+ SVN_SQLITE__WITH_LOCK(init_db(repos_id, wc_id,
+ *sdb, repos_root_url, repos_uuid,
+ root_node_repos_relpath, root_node_revision,
+ root_node_depth, scratch_pool),
+ *sdb);
return SVN_NO_ERROR;
}
@@ -1566,7 +1565,7 @@ svn_wc__db_to_relpath(const char **local
/* This function is indirectly called from the upgrade code, so we
can't verify the wcroot here. Just check that it is not NULL */
- SVN_ERR_ASSERT(wcroot != NULL);
+ CHECK_MINIMAL_WCROOT(wcroot, wri_abspath, scratch_pool);
if (svn_dirent_is_ancestor(wcroot->abspath, local_abspath))
{
@@ -1598,7 +1597,11 @@ svn_wc__db_from_relpath(const char **loc
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &unused_relpath, db,
wri_abspath, scratch_pool, scratch_pool));
- VERIFY_USABLE_WCROOT(wcroot);
+
+ /* This function is indirectly called from the upgrade code, so we
+ can't verify the wcroot here. Just check that it is not NULL */
+ CHECK_MINIMAL_WCROOT(wcroot, wri_abspath, scratch_pool);
+
*local_abspath = svn_dirent_join(wcroot->abspath,
local_relpath,
@@ -1622,12 +1625,7 @@ svn_wc__db_get_wcroot(const char **wcroo
/* Can't use VERIFY_USABLE_WCROOT, as this should be usable to detect
where call upgrade */
-
- if (wcroot == NULL)
- return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
- _("The node '%s' is not in a working copy."),
- svn_dirent_local_style(wri_abspath,
- scratch_pool));
+ CHECK_MINIMAL_WCROOT(wcroot, wri_abspath, scratch_pool);
*wcroot_abspath = apr_pstrdup(result_pool, wcroot->abspath);
@@ -2057,26 +2055,21 @@ svn_wc__db_base_add_not_present_node(svn
kind, svn_wc__db_status_not_present, conflict, work_items, scratch_pool);
}
-/* Baton for db_base_remove */
-struct base_remove_baton
-{
- svn_wc__db_t *db; /* For checking conflicts */
- svn_boolean_t keep_as_working;
- svn_revnum_t not_present_revision;
- svn_skel_t *conflict;
- svn_skel_t *work_items;
-};
-
-/* This implements svn_wc__db_txn_callback_t */
+/* The body of svn_wc__db_base_remove().
+ */
static svn_error_t *
-db_base_remove(void *baton,
- svn_wc__db_wcroot_t *wcroot,
+db_base_remove(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
+ svn_wc__db_t *db, /* For checking conflicts */
+ svn_boolean_t keep_as_working,
+ svn_boolean_t queue_deletes,
+ svn_revnum_t not_present_revision,
+ svn_skel_t *conflict,
+ svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
- struct base_remove_baton *rb = baton;
svn_wc__db_status_t status;
apr_int64_t repos_id;
const char *repos_relpath;
@@ -2086,14 +2079,14 @@ db_base_remove(void *baton,
SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, NULL,
&repos_relpath, &repos_id,
NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
wcroot, local_relpath,
scratch_pool, scratch_pool));
if (status == svn_wc__db_status_normal
- && rb->keep_as_working)
+ && keep_as_working)
{
- SVN_ERR(svn_wc__db_op_make_copy(rb->db,
+ SVN_ERR(svn_wc__db_op_make_copy(db,
svn_dirent_join(wcroot->abspath,
local_relpath,
scratch_pool),
@@ -2114,6 +2107,7 @@ db_base_remove(void *baton,
/* Step 1: Create workqueue operations to remove files and dirs in the
local-wc */
if (!keep_working
+ && queue_deletes
&& (status == svn_wc__db_status_normal
|| status == svn_wc__db_status_incomplete))
{
@@ -2139,6 +2133,7 @@ db_base_remove(void *baton,
svn_kind_t node_kind = svn_sqlite__column_token(stmt, 1,
kind_map);
const char *node_abspath;
+ svn_error_t *err;
svn_pool_clear(iterpool);
@@ -2146,18 +2141,21 @@ db_base_remove(void *baton,
iterpool);
if (node_kind == svn_kind_dir)
- SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
- rb->db, wcroot->abspath,
- node_abspath, FALSE,
- iterpool, iterpool));
+ err = svn_wc__wq_build_dir_remove(&work_item,
+ db, wcroot->abspath,
+ node_abspath, FALSE,
+ iterpool, iterpool);
else
- SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
- rb->db,
- wcroot->abspath,
- node_abspath,
- iterpool, iterpool));
+ err = svn_wc__wq_build_file_remove(&work_item,
+ db,
+ wcroot->abspath,
+ node_abspath,
+ iterpool, iterpool);
- SVN_ERR(add_work_items(wcroot->sdb, work_item, iterpool));
+ if (!err)
+ err = add_work_items(wcroot->sdb, work_item, iterpool);
+ if (err)
+ return svn_error_compose_create(err, svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
@@ -2165,14 +2163,14 @@ db_base_remove(void *baton,
SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_wc__wq_build_dir_remove(&work_item,
- rb->db, wcroot->abspath,
+ db, wcroot->abspath,
local_abspath, FALSE,
scratch_pool, iterpool));
svn_pool_destroy(iterpool);
}
else
SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
- rb->db, wcroot->abspath,
+ db, wcroot->abspath,
local_abspath,
scratch_pool, scratch_pool));
@@ -2189,7 +2187,7 @@ db_base_remove(void *baton,
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
}
- else if (! rb->keep_as_working)
+ else if (! keep_as_working)
{
/* Delete only the ACTUAL nodes that apply to a delete of a BASE node */
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -2228,7 +2226,8 @@ db_base_remove(void *baton,
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
- SVN_ERR(retract_parent_delete(wcroot, local_relpath, scratch_pool));
+ SVN_ERR(svn_wc__db_retract_parent_delete(wcroot, local_relpath, 0,
+ scratch_pool));
/* Step 6: Delete actual node if we don't keep working */
if (! keep_working)
@@ -2239,7 +2238,7 @@ db_base_remove(void *baton,
SVN_ERR(svn_sqlite__step_done(stmt));
}
- if (SVN_IS_VALID_REVNUM(rb->not_present_revision))
+ if (SVN_IS_VALID_REVNUM(not_present_revision))
{
struct insert_base_baton_t ibb;
blank_ibb(&ibb);
@@ -2248,7 +2247,7 @@ db_base_remove(void *baton,
ibb.status = svn_wc__db_status_not_present;
ibb.kind = kind;
ibb.repos_relpath = repos_relpath;
- ibb.revision = rb->not_present_revision;
+ ibb.revision = not_present_revision;
/* Depending upon KIND, any of these might get used. */
ibb.children = NULL;
@@ -2259,9 +2258,10 @@ db_base_remove(void *baton,
SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool));
}
- SVN_ERR(add_work_items(wcroot->sdb, rb->work_items, scratch_pool));
- if (rb->conflict)
- SVN_ERR(mark_conflict(wcroot, local_relpath, rb->conflict, scratch_pool));
+ SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
+ if (conflict)
+ SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
+ conflict, scratch_pool));
return SVN_NO_ERROR;
}
@@ -2271,6 +2271,7 @@ svn_error_t *
svn_wc__db_base_remove(svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t keep_as_working,
+ svn_boolean_t queue_deletes,
svn_revnum_t not_present_revision,
svn_skel_t *conflict,
svn_skel_t *work_items,
@@ -2278,7 +2279,6 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
- struct base_remove_baton rb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
@@ -2286,14 +2286,11 @@ svn_wc__db_base_remove(svn_wc__db_t *db,
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- rb.db = db;
- rb.keep_as_working = keep_as_working;
- rb.not_present_revision = not_present_revision;
- rb.conflict = conflict;
- rb.work_items = work_items;
-
- SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, db_base_remove, &rb,
- scratch_pool));
+ SVN_WC__DB_WITH_TXN(db_base_remove(wcroot, local_relpath,
+ db, keep_as_working, queue_deletes,
+ not_present_revision,
+ conflict, work_items, scratch_pool),
+ wcroot);
/* If this used to be a directory we should remove children so pass
* depth infinity. */
@@ -2318,6 +2315,7 @@ svn_wc__db_base_get_info_internal(svn_wc
const char **target,
svn_wc__db_lock_t **lock,
svn_boolean_t *had_props,
+ apr_hash_t **props,
svn_boolean_t *update_root,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
@@ -2336,8 +2334,9 @@ svn_wc__db_base_get_info_internal(svn_wc
if (have_row)
{
- svn_kind_t node_kind = svn_sqlite__column_token(stmt, 3,
- kind_map);
+ svn_wc__db_status_t node_status = svn_sqlite__column_token(stmt, 2,
+ presence_map);
+ svn_kind_t node_kind = svn_sqlite__column_token(stmt, 3, kind_map);
if (kind)
{
@@ -2345,10 +2344,10 @@ svn_wc__db_base_get_info_internal(svn_wc
}
if (status)
{
- *status = svn_sqlite__column_token(stmt, 2, presence_map);
+ *status = node_status;
}
- err = repos_location_from_columns(repos_id, revision, repos_relpath,
- stmt, 0, 4, 1, result_pool);
+ repos_location_from_columns(repos_id, revision, repos_relpath,
+ stmt, 0, 4, 1, result_pool);
SVN_ERR_ASSERT(!repos_id || *repos_id != INVALID_REPOS_ID);
SVN_ERR_ASSERT(!repos_relpath || *repos_relpath);
if (lock)
@@ -2376,12 +2375,8 @@ svn_wc__db_base_get_info_internal(svn_wc
}
else
{
- const char *depth_str = svn_sqlite__column_text(stmt, 10, NULL);
-
- if (depth_str == NULL)
- *depth = svn_depth_unknown;
- else
- *depth = svn_depth_from_word(depth_str);
+ *depth = svn_sqlite__column_token_null(stmt, 10, depth_map,
+ svn_depth_unknown);
}
}
if (checksum)
@@ -2413,8 +2408,25 @@ svn_wc__db_base_get_info_internal(svn_wc
{
*had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 13);
}
+ if (props)
+ {
+ if (node_status == svn_wc__db_status_normal
+ || node_status == svn_wc__db_status_incomplete)
+ {
+ SVN_ERR(svn_sqlite__column_properties(props, stmt, 13,
+ result_pool, scratch_pool));
+ if (*props == NULL)
+ *props = apr_hash_make(result_pool);
+ }
+ else
+ {
+ assert(svn_sqlite__column_is_null(stmt, 13));
+ *props = NULL;
+ }
+ }
if (update_root)
{
+ /* It's an update root iff it's a file external. */
*update_root = svn_sqlite__column_boolean(stmt, 14);
}
}
@@ -2446,6 +2458,7 @@ svn_wc__db_base_get_info(svn_wc__db_stat
const char **target,
svn_wc__db_lock_t **lock,
svn_boolean_t *had_props,
+ apr_hash_t **props,
svn_boolean_t *update_root,
svn_wc__db_t *db,
const char *local_abspath,
@@ -2467,7 +2480,7 @@ svn_wc__db_base_get_info(svn_wc__db_stat
changed_rev, changed_date,
changed_author, depth,
checksum, target, lock,
- had_props, update_root,
+ had_props, props, update_root,
wcroot, local_relpath,
result_pool, scratch_pool));
SVN_ERR_ASSERT(repos_id != INVALID_REPOS_ID);
@@ -2508,7 +2521,6 @@ svn_wc__db_base_get_children_info(apr_ha
struct svn_wc__db_base_info_t *info;
svn_error_t *err;
apr_int64_t repos_id;
- const char *depth_str;
const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
const char *name = svn_relpath_basename(child_relpath, result_pool);
@@ -2520,10 +2532,8 @@ svn_wc__db_base_get_children_info(apr_ha
info->kind = svn_sqlite__column_token(stmt, 4, kind_map);
info->revnum = svn_sqlite__column_revnum(stmt, 5);
- depth_str = svn_sqlite__column_text(stmt, 6, NULL);
-
- info->depth = (depth_str != NULL) ? svn_depth_from_word(depth_str)
- : svn_depth_unknown;
+ info->depth = svn_sqlite__column_token_null(stmt, 6, depth_map,
+ svn_depth_unknown);
info->update_root = svn_sqlite__column_boolean(stmt, 7);
@@ -2556,32 +2566,24 @@ svn_wc__db_base_get_props(apr_hash_t **p
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
- svn_error_t *err;
+ svn_wc__db_status_t presence;
- SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
- STMT_SELECT_BASE_PROPS, scratch_pool));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (!have_row)
+ SVN_ERR(svn_wc__db_base_get_info(&presence, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, props, NULL,
+ db, local_abspath,
+ result_pool, scratch_pool));
+ if (presence != svn_wc__db_status_normal
+ && presence != svn_wc__db_status_incomplete)
{
- err = svn_sqlite__reset(stmt);
- return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, err,
- _("The node '%s' was not found."),
+ return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
+ _("The node '%s' has a BASE status that"
+ " has no properties."),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
- err = svn_sqlite__column_properties(props, stmt, 0, result_pool,
- scratch_pool);
- if (err == NULL && *props == NULL)
- {
- /* ### is this a DB constraint violation? the column "probably" should
- ### never be null. */
- *props = apr_hash_make(result_pool);
- }
-
- return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+ return SVN_NO_ERROR;
}
@@ -2696,6 +2698,7 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
const svn_checksum_t **checksum,
const char **target,
svn_boolean_t *had_props,
+ apr_hash_t **props,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int op_depth,
@@ -2714,8 +2717,9 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
if (have_row)
{
- svn_kind_t node_kind = svn_sqlite__column_token(stmt, 3,
- kind_map);
+ svn_wc__db_status_t node_status = svn_sqlite__column_token(stmt, 2,
+ presence_map);
+ svn_kind_t node_kind = svn_sqlite__column_token(stmt, 3, kind_map);
if (kind)
{
@@ -2723,13 +2727,13 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
}
if (status)
{
- *status = svn_sqlite__column_token(stmt, 2, presence_map);
+ *status = node_status;
if (op_depth > 0)
SVN_ERR(convert_to_working_status(status, *status));
}
- err = repos_location_from_columns(repos_id, revision, repos_relpath,
- stmt, 0, 4, 1, result_pool);
+ repos_location_from_columns(repos_id, revision, repos_relpath,
+ stmt, 0, 4, 1, result_pool);
if (changed_rev)
{
@@ -2752,12 +2756,8 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
}
else
{
- const char *depth_str = svn_sqlite__column_text(stmt, 10, NULL);
-
- if (depth_str == NULL)
- *depth = svn_depth_unknown;
- else
- *depth = svn_depth_from_word(depth_str);
+ *depth = svn_sqlite__column_token_null(stmt, 10, depth_map,
+ svn_depth_unknown);
}
}
if (checksum)
@@ -2789,6 +2789,22 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
{
*had_props = SQLITE_PROPERTIES_AVAILABLE(stmt, 13);
}
+ if (props)
+ {
+ if (node_status == svn_wc__db_status_normal
+ || node_status == svn_wc__db_status_incomplete)
+ {
+ SVN_ERR(svn_sqlite__column_properties(props, stmt, 13,
+ result_pool, scratch_pool));
+ if (*props == NULL)
+ *props = apr_hash_make(result_pool);
+ }
+ else
+ {
+ assert(svn_sqlite__column_is_null(stmt, 13));
+ *props = NULL;
+ }
+ }
}
else
{
@@ -2803,11 +2819,7 @@ svn_wc__db_depth_get_info(svn_wc__db_sta
}
-/* Helper for creating SQLite triggers, running the main transaction
- callback, and then dropping the triggers. It guarantees that the
- triggers will not survive the transaction. This could be used for
- any general prefix/postscript statements where the postscript
- *must* be executed if the transaction completes. */
+/* Baton for passing args to with_triggers(). */
struct with_triggers_baton_t {
int create_trigger;
int drop_trigger;
@@ -2815,7 +2827,13 @@ struct with_triggers_baton_t {
void *cb_baton;
};
-/* conforms to svn_wc__db_txn_callback_t */
+/* Helper for creating SQLite triggers, running the main transaction
+ callback, and then dropping the triggers. It guarantees that the
+ triggers will not survive the transaction. This could be used for
+ any general prefix/postscript statements where the postscript
+ *must* be executed if the transaction completes.
+
+ Implements svn_wc__db_txn_callback_t. */
static svn_error_t *
with_triggers(void *baton,
svn_wc__db_wcroot_t *wcroot,
@@ -2894,6 +2912,8 @@ with_finalization(svn_wc__db_wcroot_t *w
}
+/* Initialize the baton with appropriate "blank" values. This allows the
+ insertion function to leave certain columns null. */
static void
blank_ieb(insert_external_baton_t *ieb)
{
@@ -2906,6 +2926,9 @@ blank_ieb(insert_external_baton_t *ieb)
ieb->recorded_revision = SVN_INVALID_REVNUM;
}
+/* Insert the externals row represented by (insert_external_baton_t *) BATON.
+ *
+ * Implements svn_wc__db_txn_callback_t. */
static svn_error_t *
insert_external_node(void *baton,
svn_wc__db_wcroot_t *wcroot,
@@ -2928,7 +2951,7 @@ insert_external_node(void *baton,
/* And there must be no existing BASE node or it must be a file external */
err = svn_wc__db_base_get_info_internal(&status, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, &update_root,
+ NULL, NULL, NULL, NULL, &update_root,
wcroot, local_relpath,
scratch_pool, scratch_pool);
if (err)
@@ -3245,25 +3268,21 @@ svn_wc__db_external_add_dir(svn_wc__db_t
&ieb, scratch_pool));
}
-/* Baton for db_external_remove */
-struct external_remove_baton
-{
- const svn_skel_t *work_items;
-};
-
+/* The body of svn_wc__db_external_remove(). */
static svn_error_t *
-db_external_remove(void *baton, svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath, apr_pool_t *scratch_pool)
+db_external_remove(const svn_skel_t *work_items,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
- struct external_remove_baton *rb = baton;
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_DELETE_EXTERNAL));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
- SVN_ERR(add_work_items(wcroot->sdb, rb->work_items, scratch_pool));
+ SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
/* ### What about actual? */
return SVN_NO_ERROR;
@@ -3278,7 +3297,6 @@ svn_wc__db_external_remove(svn_wc__db_t
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
- struct external_remove_baton rb;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
@@ -3293,9 +3311,9 @@ svn_wc__db_external_remove(svn_wc__db_t
local_relpath = svn_dirent_skip_ancestor(wcroot->abspath, local_abspath);
- rb.work_items = work_items;
- SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, db_external_remove,
- &rb, scratch_pool));
+ SVN_WC__DB_WITH_TXN(db_external_remove(work_items, wcroot, local_relpath,
+ scratch_pool),
+ wcroot);
return SVN_NO_ERROR;
}
@@ -3410,11 +3428,13 @@ svn_wc__db_committable_externals_below(a
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_COMMITTABLE_EXTERNALS_BELOW));
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, wcroot->sdb,
+ immediates_only
+ ? STMT_SELECT_COMMITTABLE_EXTERNALS_IMMEDIATELY_BELOW
+ : STMT_SELECT_COMMITTABLE_EXTERNALS_BELOW));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
- (immediates_only ? 1 : 0)));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
@@ -3551,15 +3571,14 @@ svn_wc__db_externals_gather_definitions(
if (depths)
{
- const char *depth_word = svn_sqlite__column_text(stmt, 2, NULL);
- svn_depth_t depth = svn_depth_unknown;
-
- if (depth_word)
- depth = svn_depth_from_word(depth_word);
+ svn_depth_t depth
+ = svn_sqlite__column_token_null(stmt, 2, depth_map,
+ svn_depth_unknown);
apr_hash_set(*depths, node_abspath,
APR_HASH_KEY_STRING,
- svn_depth_to_word(depth)); /* Use static string */
+ svn_token__to_word(depth_map,
+ depth)); /* Use static string */
}
}
@@ -3652,7 +3671,7 @@ cross_db_copy(svn_wc__db_wcroot_t *src_w
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
src_wcroot, src_relpath, scratch_pool, scratch_pool));
- SVN_ERR(db_read_pristine_props(&props, src_wcroot, src_relpath,
+ SVN_ERR(db_read_pristine_props(&props, src_wcroot, src_relpath, FALSE,
scratch_pool, scratch_pool));
blank_iwb(&iwb);
@@ -3684,46 +3703,313 @@ cross_db_copy(svn_wc__db_wcroot_t *src_w
return SVN_NO_ERROR;
}
+/* Helper for scan_deletion_txn. Extracts the moved-to information, if
+ any, from STMT. Sets *SCAN to FALSE if moved-to was available. */
+static svn_error_t *
+get_moved_to(const char **moved_to_relpath_p,
+ const char **moved_to_op_root_relpath_p,
+ svn_boolean_t *scan,
+ svn_sqlite__stmt_t *stmt,
+ const char *current_relpath,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *moved_to_relpath = svn_sqlite__column_text(stmt, 3, NULL);
-/* Set *COPYFROM_ID, *COPYFROM_RELPATH, *COPYFROM_REV to the values
- appropriate for the copy. Also return *STATUS, *KIND and *HAVE_WORK, *OP_ROOT
- since they are available. This is a helper for
- svn_wc__db_op_copy. */
+ if (moved_to_relpath)
+ {
+ const char *moved_to_op_root_relpath = moved_to_relpath;
+
+ if (strcmp(current_relpath, local_relpath))
+ {
+ /* LOCAL_RELPATH is a child inside the move op-root. */
+ const char *moved_child_relpath;
+
+ /* The CURRENT_RELPATH is the op_root of the delete-half of
+ * the move. LOCAL_RELPATH is a child that was moved along.
+ * Compute the child's new location within the move target. */
+ moved_child_relpath = svn_relpath_skip_ancestor(current_relpath,
+ local_relpath);
+ SVN_ERR_ASSERT(moved_child_relpath &&
+ strlen(moved_child_relpath) > 0);
+ moved_to_relpath = svn_relpath_join(moved_to_op_root_relpath,
+ moved_child_relpath,
+ result_pool);
+ }
+
+ if (moved_to_op_root_relpath && moved_to_op_root_relpath_p)
+ *moved_to_op_root_relpath_p
+ = apr_pstrdup(result_pool, moved_to_op_root_relpath);
+
+ if (moved_to_relpath && moved_to_relpath_p)
+ *moved_to_relpath_p
+ = apr_pstrdup(result_pool, moved_to_relpath);
+
+ *scan = FALSE;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* The body of svn_wc__db_scan_deletion().
+ */
static svn_error_t *
-get_info_for_copy(apr_int64_t *copyfrom_id,
- const char **copyfrom_relpath,
- svn_revnum_t *copyfrom_rev,
- svn_wc__db_status_t *status,
- svn_kind_t *kind,
- svn_boolean_t *op_root,
+scan_deletion_txn(const char **base_del_relpath,
+ const char **moved_to_relpath,
+ const char **work_del_relpath,
+ const char **moved_to_op_root_relpath,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- const char *repos_relpath;
- svn_revnum_t revision;
- svn_wc__db_status_t node_status;
+ const char *current_relpath = local_relpath;
+ svn_sqlite__stmt_t *stmt;
+ svn_wc__db_status_t work_presence;
+ svn_boolean_t have_row, scan, have_base;
+ int op_depth;
- SVN_ERR(read_info(&node_status, kind, &revision, &repos_relpath, copyfrom_id,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, op_root, NULL, NULL,
- NULL /* have_base */,
- NULL /* have_more_work */,
- NULL /* have_work */,
- wcroot, local_relpath, result_pool, scratch_pool));
+ /* Initialize all the OUT parameters. */
+ if (base_del_relpath != NULL)
+ *base_del_relpath = NULL;
+ if (moved_to_relpath != NULL)
+ *moved_to_relpath = NULL;
+ if (work_del_relpath != NULL)
+ *work_del_relpath = NULL;
+ if (moved_to_op_root_relpath != NULL)
+ *moved_to_op_root_relpath = NULL;
- if (node_status == svn_wc__db_status_excluded)
- {
- /* The parent cannot be excluded, so look at the parent and then
- adjust the relpath */
- const char *parent_relpath, *base_name;
+ /* If looking for moved-to info then we need to scan every path
+ until we find it. If not looking for moved-to we only need to
+ check op-roots and parents of op-roots. */
+ scan = (moved_to_op_root_relpath || moved_to_relpath);
- svn_dirent_split(&parent_relpath, &base_name, local_relpath,
- scratch_pool);
- SVN_ERR(get_info_for_copy(copyfrom_id, copyfrom_relpath, copyfrom_rev,
- NULL, NULL, NULL,
- wcroot, parent_relpath,
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, wcroot->sdb,
+ scan ? STMT_SELECT_DELETION_INFO_SCAN
+ : STMT_SELECT_DELETION_INFO));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (!have_row)
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, svn_sqlite__reset(stmt),
+ _("The node '%s' was not found."),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+
+ work_presence = svn_sqlite__column_token(stmt, 1, presence_map);
+ have_base = !svn_sqlite__column_is_null(stmt, 0);
+ if (work_presence != svn_wc__db_status_not_present
+ && work_presence != svn_wc__db_status_base_deleted)
+ return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS,
+ svn_sqlite__reset(stmt),
+ _("Expected node '%s' to be deleted."),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+
+ op_depth = svn_sqlite__column_int(stmt, 2);
+
+ /* Special case: LOCAL_RELPATH not-present within a WORKING tree, we
+ treat this as an op-root. At commit time we need to explicitly
+ delete such nodes otherwise they will be present in the
+ repository copy. */
+ if (work_presence == svn_wc__db_status_not_present
+ && work_del_relpath && !*work_del_relpath)
+ {
+ *work_del_relpath = apr_pstrdup(result_pool, current_relpath);
+
+ if (!scan && !base_del_relpath)
+ {
+ /* We have all we need, exit early */
+ SVN_ERR(svn_sqlite__reset(stmt));
+ return SVN_NO_ERROR;
+ }
+ }
+
+
+ while(TRUE)
+ {
+ svn_error_t *err;
+ const char *parent_relpath;
+ int current_depth = relpath_depth(current_relpath);
+
+ /* Step CURRENT_RELPATH to op-root */
+
+ while(TRUE)
+ {
+ if (scan)
+ {
+ err = get_moved_to(moved_to_relpath, moved_to_op_root_relpath,
+ &scan, stmt, current_relpath,
+ wcroot, local_relpath,
+ result_pool, scratch_pool);
+ if (err || (!scan
+ && !base_del_relpath
+ && !work_del_relpath))
+ {
+ /* We have all we need (or an error occurred) */
+ SVN_ERR(svn_sqlite__reset(stmt));
+ return svn_error_trace(err);
+ }
+ }
+
+ if(current_depth <= op_depth)
+ break;
+
+ current_relpath = svn_relpath_dirname(current_relpath, scratch_pool);
+ --current_depth;
+
+ if (scan || current_depth == op_depth)
+ {
+ SVN_ERR(svn_sqlite__reset(stmt));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
+ current_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ SVN_ERR_ASSERT(have_row);
+ have_base = !svn_sqlite__column_is_null(stmt, 0);
+ }
+ }
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ /* Now CURRENT_RELPATH is an op-root, have a look at the parent. */
+
+ SVN_ERR_ASSERT(current_relpath[0] != '\0'); /* Catch invalid data */
+ parent_relpath = svn_relpath_dirname(current_relpath, scratch_pool);
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (!have_row)
+ {
+ /* No row means no WORKING node which mean we just fell off
+ the WORKING tree, so CURRENT_RELPATH is the op-root
+ closest to the wc root. */
+ if (have_base && base_del_relpath)
+ *base_del_relpath = apr_pstrdup(result_pool, current_relpath);
+ break;
+ }
+
+ /* Still in the WORKING tree so the first time we get here
+ CURRENT_RELPATH is a delete op-root in the WORKING tree. */
+ if (work_del_relpath && !*work_del_relpath)
+ {
+ *work_del_relpath = apr_pstrdup(result_pool, current_relpath);
+
+ if (!scan && !base_del_relpath)
+ break; /* We have all we need */
+ }
+
+ current_relpath = parent_relpath;
+ op_depth = svn_sqlite__column_int(stmt, 2);
+ have_base = !svn_sqlite__column_is_null(stmt, 0);
+ }
+
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_scan_deletion(const char **base_del_abspath,
+ const char **moved_to_abspath,
+ const char **work_del_abspath,
+ const char **moved_to_op_root_abspath,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_wcroot_t *wcroot;
+ const char *local_relpath;
+ const char *base_del_relpath, *moved_to_relpath, *work_del_relpath;
+ const char *moved_to_op_root_relpath;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
+ local_abspath, scratch_pool, scratch_pool));
+ VERIFY_USABLE_WCROOT(wcroot);
+
+ SVN_WC__DB_WITH_TXN(
+ scan_deletion_txn(&base_del_relpath, &moved_to_relpath,
+ &work_del_relpath, &moved_to_op_root_relpath,
+ wcroot, local_relpath, result_pool, scratch_pool),
+ wcroot);
+
+ if (base_del_abspath)
+ {
+ *base_del_abspath = (base_del_relpath
+ ? svn_dirent_join(wcroot->abspath,
+ base_del_relpath, result_pool)
+ : NULL);
+ }
+ if (moved_to_abspath)
+ {
+ *moved_to_abspath = (moved_to_relpath
+ ? svn_dirent_join(wcroot->abspath,
+ moved_to_relpath, result_pool)
+ : NULL);
+ }
+ if (work_del_abspath)
+ {
+ *work_del_abspath = (work_del_relpath
+ ? svn_dirent_join(wcroot->abspath,
+ work_del_relpath, result_pool)
+ : NULL);
+ }
+ if (moved_to_op_root_abspath)
+ {
+ *moved_to_op_root_abspath = (moved_to_op_root_relpath
+ ? svn_dirent_join(wcroot->abspath,
+ moved_to_op_root_relpath,
+ result_pool)
+ : NULL);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Set *COPYFROM_ID, *COPYFROM_RELPATH, *COPYFROM_REV to the values
+ appropriate for the copy. Also return *STATUS, *KIND and *HAVE_WORK, *OP_ROOT
+ since they are available. This is a helper for
+ svn_wc__db_op_copy. */
+static svn_error_t *
+get_info_for_copy(apr_int64_t *copyfrom_id,
+ const char **copyfrom_relpath,
+ svn_revnum_t *copyfrom_rev,
+ svn_wc__db_status_t *status,
+ svn_kind_t *kind,
+ svn_boolean_t *op_root,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *repos_relpath;
+ svn_revnum_t revision;
+ svn_wc__db_status_t node_status;
+
+ SVN_ERR(read_info(&node_status, kind, &revision, &repos_relpath, copyfrom_id,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, op_root, NULL, NULL,
+ NULL /* have_base */,
+ NULL /* have_more_work */,
+ NULL /* have_work */,
+ wcroot, local_relpath, result_pool, scratch_pool));
+
+ if (node_status == svn_wc__db_status_excluded)
+ {
+ /* The parent cannot be excluded, so look at the parent and then
+ adjust the relpath */
+ const char *parent_relpath, *base_name;
+
+ svn_dirent_split(&parent_relpath, &base_name, local_relpath,
+ scratch_pool);
+ SVN_ERR(get_info_for_copy(copyfrom_id, copyfrom_relpath, copyfrom_rev,
+ NULL, NULL, NULL,
+ wcroot, parent_relpath,
scratch_pool, scratch_pool));
if (*copyfrom_relpath)
*copyfrom_relpath = svn_relpath_join(*copyfrom_relpath, base_name,
@@ -3751,10 +4037,10 @@ get_info_for_copy(apr_int64_t *copyfrom_
{
const char *base_del_relpath, *work_del_relpath;
- SVN_ERR(svn_wc__db_scan_deletion_internal(&base_del_relpath, NULL,
- &work_del_relpath,
- NULL, wcroot, local_relpath,
- scratch_pool, scratch_pool));
+ SVN_ERR(scan_deletion_txn(&base_del_relpath, NULL,
+ &work_del_relpath,
+ NULL, wcroot, local_relpath,
+ scratch_pool, scratch_pool));
if (work_del_relpath)
{
const char *op_root_relpath;
@@ -3780,7 +4066,7 @@ get_info_for_copy(apr_int64_t *copyfrom_
copyfrom_relpath,
copyfrom_id, NULL, NULL,
NULL, NULL, NULL, NULL,
- NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
wcroot, local_relpath,
result_pool,
scratch_pool));
@@ -3801,15 +4087,44 @@ get_info_for_copy(apr_int64_t *copyfrom_
}
-/* Forward declarations for db_op_copy() to use.
-
- ### these are just to avoid churn. a future commit should shuffle the
- ### functions around. */
+/* Set *OP_DEPTH to the highest op depth of WCROOT:LOCAL_RELPATH. */
static svn_error_t *
op_depth_of(int *op_depth,
svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath);
+ const char *local_relpath)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_NODE_INFO));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ SVN_ERR_ASSERT(have_row);
+ *op_depth = svn_sqlite__column_int(stmt, 0);
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Determine at which OP_DEPTH a copy of COPYFROM_REPOS_ID, COPYFROM_RELPATH at
+ revision COPYFROM_REVISION should be inserted as LOCAL_RELPATH. Do this
+ by checking if this would be a direct child of a copy of its parent
+ directory. If it is then set *OP_DEPTH to the op_depth of its parent.
+
+ If the node is not a direct copy at the same revision of the parent
+ *NP_OP_DEPTH will be set to the op_depth of the parent when a not-present
+ node should be inserted at this op_depth. This will be the case when the
+ parent already defined an incomplete child with the same name. Otherwise
+ *NP_OP_DEPTH will be set to -1.
+ If the parent node is not the parent of the to be copied node, then
+ *OP_DEPTH will be set to the proper op_depth for a new operation root.
+
+ Set *PARENT_OP_DEPTH to the op_depth of the parent.
+
+ */
static svn_error_t *
op_depth_for_copy(int *op_depth,
int *np_op_depth,
@@ -3819,7 +4134,86 @@ op_depth_for_copy(int *op_depth,
svn_revnum_t copyfrom_revision,
svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
- apr_pool_t *scratch_pool);
+ apr_pool_t *scratch_pool)
+{
+ const char *parent_relpath, *name;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ int incomplete_op_depth = -1;
+ int min_op_depth = 1; /* Never touch BASE */
+
+ *op_depth = relpath_depth(local_relpath);
+ *np_op_depth = -1;
+
+ svn_relpath_split(&parent_relpath, &name, local_relpath, scratch_pool);
+ *parent_op_depth = relpath_depth(parent_relpath);
+
+ if (!copyfrom_relpath)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ {
+ svn_wc__db_status_t status = svn_sqlite__column_token(stmt, 1,
+ presence_map);
+
+ min_op_depth = svn_sqlite__column_int(stmt, 0);
+ if (status == svn_wc__db_status_incomplete)
+ incomplete_op_depth = min_op_depth;
+ }
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ {
+ svn_wc__db_status_t presence = svn_sqlite__column_token(stmt, 1,
+ presence_map);
+
+ *parent_op_depth = svn_sqlite__column_int(stmt, 0);
+ if (*parent_op_depth < min_op_depth)
+ {
+ /* We want to create a copy; not overwrite the lower layers */
+ SVN_ERR(svn_sqlite__reset(stmt));
+ return SVN_NO_ERROR;
+ }
+
+ /* You can only add children below a node that exists.
+ In WORKING that must be status added, which is represented
+ as presence normal */
+ SVN_ERR_ASSERT(presence == svn_wc__db_status_normal);
+
+ if ((incomplete_op_depth < 0)
+ || (incomplete_op_depth == *parent_op_depth))
+ {
+ apr_int64_t parent_copyfrom_repos_id
+ = svn_sqlite__column_int64(stmt, 10);
+ const char *parent_copyfrom_relpath
+ = svn_sqlite__column_text(stmt, 11, NULL);
+ svn_revnum_t parent_copyfrom_revision
+ = svn_sqlite__column_revnum(stmt, 12);
+
+ if (parent_copyfrom_repos_id == copyfrom_repos_id)
+ {
+ if (copyfrom_revision == parent_copyfrom_revision
+ && !strcmp(copyfrom_relpath,
+ svn_relpath_join(parent_copyfrom_relpath, name,
+ scratch_pool)))
+ *op_depth = *parent_op_depth;
+ else if (incomplete_op_depth > 0)
+ *np_op_depth = incomplete_op_depth;
+ }
+ }
+ }
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ return SVN_NO_ERROR;
+}
/* Like svn_wc__db_op_copy(), but with WCROOT+LOCAL_RELPATH
@@ -4069,7 +4463,7 @@ db_op_copy(svn_wc__db_wcroot_t *src_wcro
return SVN_NO_ERROR;
}
-/* Baton for op_copy_txn */
+/* Baton for passing args to op_copy_txn(). */
struct op_copy_baton
{
svn_wc__db_wcroot_t *src_wcroot;
@@ -4084,10 +4478,13 @@ struct op_copy_baton
const char *dst_op_root_relpath;
};
-/* Helper for svn_wc__db_op_copy.
- Implements svn_sqlite__transaction_callback_t */
+/* Helper for svn_wc__db_op_copy().
+ *
+ * Implements svn_sqlite__transaction_callback_t. */
static svn_error_t *
-op_copy_txn(void * baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
+op_copy_txn(void * baton,
+ svn_sqlite__db_t *sdb,
+ apr_pool_t *scratch_pool)
{
struct op_copy_baton *ocb = baton;
int move_op_depth;
@@ -4190,7 +4587,8 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
svn_error_t *err;
err = svn_wc__db_depth_get_info(&status, &kind, &node_revision,
&node_repos_relpath, &node_repos_id,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL,
src_wcroot, src_relpath, src_op_depth,
scratch_pool, scratch_pool);
@@ -4360,10 +4758,12 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
return SVN_NO_ERROR;
}
-/* Helper for svn_wc__db_op_copy_shadowed_layer.
- Implements svn_sqlite__transaction_callback_t */
+/* Helper for svn_wc__db_op_copy_shadowed_layer().
+ *
+ * Implements svn_sqlite__transaction_callback_t. */
static svn_error_t *
-op_copy_shadowed_layer_txn(void * baton, svn_sqlite__db_t *sdb,
+op_copy_shadowed_layer_txn(void *baton,
+ svn_sqlite__db_t *sdb,
apr_pool_t *scratch_pool)
{
struct op_copy_baton *ocb = baton;
@@ -4407,7 +4807,8 @@ op_copy_shadowed_layer_txn(void * baton,
/* Get some information from the parent */
SVN_ERR(svn_wc__db_depth_get_info(NULL, NULL, &revision, &repos_relpath,
&repos_id, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, ocb->src_wcroot,
+ NULL, NULL, NULL,
+ ocb->src_wcroot,
src_parent_relpath, src_op_depth,
scratch_pool, scratch_pool));
@@ -4473,27 +4874,6 @@ svn_wc__db_op_copy_shadowed_layer(svn_wc
}
-/* Set *OP_DEPTH to the highest op depth of WCROOT:LOCAL_RELPATH. */
-static svn_error_t *
-op_depth_of(int *op_depth,
- svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath)
-{
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_NODE_INFO));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- SVN_ERR_ASSERT(have_row);
- *op_depth = svn_sqlite__column_int(stmt, 0);
- SVN_ERR(svn_sqlite__reset(stmt));
-
- return SVN_NO_ERROR;
-}
-
-
/* If there are any server-excluded base nodes then the copy must fail
as it's not possible to commit such a copy.
Return an error if there are any server-excluded nodes. */
@@ -4518,117 +4898,9 @@ catch_copy_of_server_excluded(svn_wc__db
if (have_row)
return svn_error_createf(SVN_ERR_AUTHZ_UNREADABLE, NULL,
_("Cannot copy '%s' excluded by server"),
- path_for_error_message(wcroot,
- server_excluded_relpath,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-
-/* Determine at which OP_DEPTH a copy of COPYFROM_REPOS_ID, COPYFROM_RELPATH at
- revision COPYFROM_REVISION should be inserted as LOCAL_RELPATH. Do this
- by checking if this would be a direct child of a copy of its parent
- directory. If it is then set *OP_DEPTH to the op_depth of its parent.
-
- If the node is not a direct copy at the same revision of the parent
- *NP_OP_DEPTH will be set to the op_depth of the parent when a not-present
- node should be inserted at this op_depth. This will be the case when the
- parent already defined an incomplete child with the same name. Otherwise
- *NP_OP_DEPTH will be set to -1.
-
- If the parent node is not the parent of the to be copied node, then
- *OP_DEPTH will be set to the proper op_depth for a new operation root.
-
- Set *PARENT_OP_DEPTH to the op_depth of the parent.
-
- */
-static svn_error_t *
-op_depth_for_copy(int *op_depth,
- int *np_op_depth,
- int *parent_op_depth,
- apr_int64_t copyfrom_repos_id,
- const char *copyfrom_relpath,
- svn_revnum_t copyfrom_revision,
- svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath,
- apr_pool_t *scratch_pool)
-{
- const char *parent_relpath, *name;
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
- int incomplete_op_depth = -1;
- int min_op_depth = 1; /* Never touch BASE */
-
- *op_depth = relpath_depth(local_relpath);
- *np_op_depth = -1;
-
- svn_relpath_split(&parent_relpath, &name, local_relpath, scratch_pool);
- *parent_op_depth = relpath_depth(parent_relpath);
-
- if (!copyfrom_relpath)
- return SVN_NO_ERROR;
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (have_row)
- {
- svn_wc__db_status_t status = svn_sqlite__column_token(stmt, 1,
- presence_map);
-
- min_op_depth = svn_sqlite__column_int(stmt, 0);
- if (status == svn_wc__db_status_incomplete)
- incomplete_op_depth = min_op_depth;
- }
- SVN_ERR(svn_sqlite__reset(stmt));
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (have_row)
- {
- svn_wc__db_status_t presence = svn_sqlite__column_token(stmt, 1,
- presence_map);
-
- *parent_op_depth = svn_sqlite__column_int(stmt, 0);
- if (*parent_op_depth < min_op_depth)
- {
- /* We want to create a copy; not overwrite the lower layers */
- SVN_ERR(svn_sqlite__reset(stmt));
- return SVN_NO_ERROR;
- }
-
- /* You can only add children below a node that exists.
- In WORKING that must be status added, which is represented
- as presence normal */
- SVN_ERR_ASSERT(presence == svn_wc__db_status_normal);
-
- if ((incomplete_op_depth < 0)
- || (incomplete_op_depth == *parent_op_depth))
- {
- apr_int64_t parent_copyfrom_repos_id
- = svn_sqlite__column_int64(stmt, 10);
- const char *parent_copyfrom_relpath
- = svn_sqlite__column_text(stmt, 11, NULL);
- svn_revnum_t parent_copyfrom_revision
- = svn_sqlite__column_revnum(stmt, 12);
-
- if (parent_copyfrom_repos_id == copyfrom_repos_id)
- {
- if (copyfrom_revision == parent_copyfrom_revision
- && !strcmp(copyfrom_relpath,
- svn_relpath_join(parent_copyfrom_relpath, name,
- scratch_pool)))
- *op_depth = *parent_op_depth;
- else if (incomplete_op_depth > 0)
- *np_op_depth = incomplete_op_depth;
- }
- }
- }
- SVN_ERR(svn_sqlite__reset(stmt));
+ path_for_error_message(wcroot,
+ server_excluded_relpath,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -4867,6 +5139,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t
svn_error_t *
svn_wc__db_op_add_directory(svn_wc__db_t *db,
const char *local_abspath,
+ const apr_hash_t *props,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
@@ -4890,6 +5163,11 @@ svn_wc__db_op_add_directory(svn_wc__db_t
iwb.presence = svn_wc__db_status_normal;
iwb.kind = svn_kind_dir;
iwb.op_depth = relpath_depth(local_relpath);
+ if (props && apr_hash_count((apr_hash_t *)props))
+ {
+ iwb.update_actual_props = TRUE;
+ iwb.new_actual_props = props;
+ }
iwb.work_items = work_items;
@@ -4907,6 +5185,7 @@ svn_wc__db_op_add_directory(svn_wc__db_t
svn_error_t *
svn_wc__db_op_add_file(svn_wc__db_t *db,
const char *local_abspath,
+ const apr_hash_t *props,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
@@ -4930,6 +5209,11 @@ svn_wc__db_op_add_file(svn_wc__db_t *db,
iwb.presence = svn_wc__db_status_normal;
iwb.kind = svn_kind_file;
iwb.op_depth = relpath_depth(local_relpath);
+ if (props && apr_hash_count((apr_hash_t *)props))
+ {
+ iwb.update_actual_props = TRUE;
+ iwb.new_actual_props = props;
+ }
iwb.work_items = work_items;
@@ -4945,6 +5229,7 @@ svn_error_t *
svn_wc__db_op_add_symlink(svn_wc__db_t *db,
const char *local_abspath,
const char *target,
+ const apr_hash_t *props,
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
@@ -4971,6 +5256,11 @@ svn_wc__db_op_add_symlink(svn_wc__db_t *
iwb.presence = svn_wc__db_status_normal;
iwb.kind = svn_kind_symlink;
iwb.op_depth = relpath_depth(local_relpath);
+ if (props && apr_hash_count((apr_hash_t *)props))
+ {
+ iwb.update_actual_props = TRUE;
+ iwb.new_actual_props = props;
+ }
iwb.target = target;
@@ -4983,13 +5273,14 @@ svn_wc__db_op_add_symlink(svn_wc__db_t *
return SVN_NO_ERROR;
}
+/* Baton for passing args to db_record_fileinfo(). */
struct record_baton_t {
- svn_filesize_t translated_size;
- apr_time_t last_mod_time;
+ svn_filesize_t recorded_size;
+ apr_time_t recorded_time;
};
-/* Record TRANSLATED_SIZE and LAST_MOD_TIME into top layer in NODES */
+/* Record RECORDED_SIZE and RECORDED_TIME into top layer in NODES */
static svn_error_t *
db_record_fileinfo(void *baton,
svn_wc__db_wcroot_t *wcroot,
@@ -5003,7 +5294,7 @@ db_record_fileinfo(void *baton,
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_UPDATE_NODE_FILEINFO));
SVN_ERR(svn_sqlite__bindf(stmt, "isii", wcroot->wc_id, local_relpath,
- rb->translated_size, rb->last_mod_time));
+ rb->recorded_size, rb->recorded_time));
SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
SVN_ERR_ASSERT(affected_rows == 1);
@@ -5015,8 +5306,8 @@ db_record_fileinfo(void *baton,
svn_error_t *
svn_wc__db_global_record_fileinfo(svn_wc__db_t *db,
const char *local_abspath,
- svn_filesize_t translated_size,
- apr_time_t last_mod_time,
+ svn_filesize_t recorded_size,
+ apr_time_t recorded_time,
apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
@@ -5029,8 +5320,8 @@ svn_wc__db_global_record_fileinfo(svn_wc
local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- rb.translated_size = translated_size;
- rb.last_mod_time = last_mod_time;
+ rb.recorded_size = recorded_size;
+ rb.recorded_time = recorded_time;
SVN_ERR(db_record_fileinfo(&rb, wcroot, local_relpath, scratch_pool));
@@ -5041,18 +5332,12 @@ svn_wc__db_global_record_fileinfo(svn_wc
}
-struct set_props_baton_t
-{
- apr_hash_t *props;
- svn_boolean_t clear_recorded_info;
-
- const svn_skel_t *conflict;
- const svn_skel_t *work_items;
-};
-
-
/* Set the ACTUAL_NODE properties column for (WC_ID, LOCAL_RELPATH) to
- * PROPS. */
+ * PROPS.
+ *
+ * Note: PROPS=NULL means the actual props are the same as the pristine
+ * props; to indicate no properties when the pristine has some props,
+ * PROPS must be an empty hash. */
static svn_error_t *
set_actual_props(apr_int64_t wc_id,
const char *local_relpath,
@@ -5084,50 +5369,56 @@ set_actual_props(apr_int64_t wc_id,
}
-/* Set the 'properties' column in the 'ACTUAL_NODE' table to BATON->props.
+/* The body of svn_wc__db_op_set_props().
+
+ 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.
To specify no properties, BATON->props must be an empty hash, not NULL.
- BATON is of type 'struct set_props_baton_t'. */
+ BATON is of type 'struct set_props_baton_t'.
+*/
static svn_error_t *
-set_props_txn(void *baton,
- svn_wc__db_wcroot_t *wcroot,
+set_props_txn(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
+ apr_hash_t *props,
+ svn_boolean_t clear_recorded_info,
+ const svn_skel_t *conflict,
+ const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
- struct set_props_baton_t *spb = baton;
apr_hash_t *pristine_props;
/* 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, wcroot, local_relpath,
+ SVN_ERR(db_read_pristine_props(&pristine_props, wcroot, local_relpath, FALSE,
scratch_pool, scratch_pool));
- if (spb->props && pristine_props)
+ if (props && pristine_props)
{
apr_array_header_t *prop_diffs;
- SVN_ERR(svn_prop_diffs(&prop_diffs, spb->props, pristine_props,
+ SVN_ERR(svn_prop_diffs(&prop_diffs, props, pristine_props,
scratch_pool));
if (prop_diffs->nelts == 0)
- spb->props = NULL;
+ props = NULL;
}
SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath,
- spb->props, wcroot->sdb, scratch_pool));
+ props, wcroot->sdb, scratch_pool));
- if (spb->clear_recorded_info)
+ if (clear_recorded_info)
{
struct record_baton_t rb;
- rb.translated_size = SVN_INVALID_FILESIZE;
- rb.last_mod_time = 0;
+ rb.recorded_size = SVN_INVALID_FILESIZE;
+ rb.recorded_time = 0;
SVN_ERR(db_record_fileinfo(&rb, wcroot, local_relpath, scratch_pool));
}
/* And finally. */
- SVN_ERR(add_work_items(wcroot->sdb, spb->work_items, scratch_pool));
- if (spb->conflict)
- SVN_ERR(mark_conflict(wcroot, local_relpath, spb->conflict, scratch_pool));
+ SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
+ if (conflict)
+ SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
+ conflict, scratch_pool));
return SVN_NO_ERROR;
}
@@ -5142,7 +5433,6 @@ svn_wc__db_op_set_props(svn_wc__db_t *db
const svn_skel_t *work_items,
apr_pool_t *scratch_pool)
{
- struct set_props_baton_t spb;
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
@@ -5152,77 +5442,13 @@ svn_wc__db_op_set_props(svn_wc__db_t *db
db, local_abspath, scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- spb.props = props;
- spb.clear_recorded_info = clear_recorded_info;
- spb.conflict = conflict;
- spb.work_items = work_items;
-
- return svn_error_trace(svn_wc__db_with_txn(wcroot, local_relpath,
- set_props_txn, &spb,
- scratch_pool));
-}
-
-
-#ifdef SVN__SUPPORT_BASE_MERGE
-
-/* Set properties in a given table. The row must exist. */
-static svn_error_t *
-set_properties(svn_wc__db_t *db,
- const char *local_abspath,
- const apr_hash_t *props,
- int stmt_idx,
- const char *table_name,
- apr_pool_t *scratch_pool)
-{
- svn_sqlite__stmt_t *stmt;
- int affected_rows;
-
- SVN_ERR_ASSERT(props != NULL);
-
- SVN_ERR(get_statement_for_path(&stmt, db, local_abspath, stmt_idx,
- scratch_pool));
-
- SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
- SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
-
- if (affected_rows != 1)
- return svn_error_createf(SVN_ERR_WC_DB_ERROR, NULL,
- _("Can't store properties for '%s' in '%s'."),
- svn_dirent_local_style(local_abspath,
- scratch_pool),
- table_name);
-
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_wc__db_temp_base_set_props(svn_wc__db_t *db,
- const char *local_abspath,
- const apr_hash_t *props,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR(set_properties(db, local_abspath, props,
- STMT_UPDATE_NODE_BASE_PROPS,
- "base node", scratch_pool));
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_wc__db_temp_working_set_props(svn_wc__db_t *db,
- const char *local_abspath,
- const apr_hash_t *props,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR(set_properties(db, local_abspath, props,
- STMT_UPDATE_NODE_WORKING_PROPS,
- "working node", scratch_pool));
+ SVN_WC__DB_WITH_TXN(set_props_txn(wcroot, local_relpath, props,
+ clear_recorded_info, conflict, work_items,
+ scratch_pool),
+ wcroot);
return SVN_NO_ERROR;
}
-#endif /* SVN__SUPPORT_BASE_MERGE */
-
svn_error_t *
svn_wc__db_op_modified(svn_wc__db_t *db,
@@ -5399,7 +5625,9 @@ struct set_changelist_baton_t
};
-/* */
+/* The main part of svn_wc__db_op_set_changelist().
+ *
+ * Implements svn_wc__db_txn_callback_t. */
static svn_error_t *
set_changelist_txn(void *baton,
svn_wc__db_wcroot_t *wcroot,
@@ -5457,7 +5685,9 @@ set_changelist_txn(void *baton,
}
-/* Implement work_callback_t. */
+/* Send notifications for svn_wc__db_op_set_changelist().
+ *
+ * Implements work_callback_t. */
static svn_error_t *
do_changelist_notify(void *baton,
[... 4135 lines stripped ...]