You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/08/10 20:06:33 UTC
svn commit: r984153 [27/39] - in /subversion/branches/ignore-mergeinfo: ./
build/ build/ac-macros/ build/generator/ build/generator/templates/
build/hudson/ build/hudson/jobs/subversion-1.6.x-solaris/
build/hudson/jobs/subversion-1.6.x-ubuntu/ build/hu...
Modified: subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c?rev=984153&r1=984152&r2=984153&view=diff
==============================================================================
--- subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/ignore-mergeinfo/subversion/libsvn_wc/wc_db.c Tue Aug 10 18:06:17 2010
@@ -36,7 +36,6 @@
#include "wc.h"
#include "wc_db.h"
#include "adm_files.h"
-#include "wc-metadata.h"
#include "wc-queries.h"
#include "entries.h"
#include "lock.h"
@@ -59,9 +58,9 @@
#define SDB_FILE "wc.db"
#define SDB_FILE_UPGRADE "wc.db.upgrade"
-#define PRISTINE_STORAGE_RELPATH ".svn/pristine"
-#define PRISTINE_TEMPDIR_RELPATH ".svn"
-#define WCROOT_TEMPDIR_RELPATH ".svn/tmp"
+#define PRISTINE_STORAGE_RELPATH "pristine"
+#define PRISTINE_TEMPDIR_RELPATH ""
+#define WCROOT_TEMPDIR_RELPATH "tmp"
/*
@@ -203,18 +202,6 @@ typedef struct svn_wc__db_pdh_t {
### need to undo the SKIP. */
#define SVN__SKIP_SUBDIR
-/* ### duplicates entries.c */
-static const char * const upgrade_sql[] = {
- NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- NULL, NULL,
- WC_METADATA_SQL_12,
- WC_METADATA_SQL_13,
- WC_METADATA_SQL_14,
- WC_METADATA_SQL_15,
- WC_METADATA_SQL_16
-};
-
WC_QUERIES_SQL_DECLARE_STATEMENTS(statements);
@@ -277,6 +264,7 @@ static const svn_token_map_t presence_ma
};
+/* */
static svn_filesize_t
get_translated_size(svn_sqlite__stmt_t *stmt, int slot)
{
@@ -286,6 +274,7 @@ get_translated_size(svn_sqlite__stmt_t *
}
+/* */
static const char *
escape_sqlite_like(const char * const str, apr_pool_t *result_pool)
{
@@ -324,6 +313,7 @@ escape_sqlite_like(const char * const st
}
+/* */
static svn_error_t *
verify_no_work(svn_sqlite__db_t *sdb)
{
@@ -342,6 +332,7 @@ verify_no_work(svn_sqlite__db_t *sdb)
}
+/* */
static apr_status_t
close_wcroot(void *data)
{
@@ -363,6 +354,7 @@ close_wcroot(void *data)
}
+/* */
static svn_error_t *
close_many_wcroots(apr_hash_t *roots,
apr_pool_t *state_pool,
@@ -372,7 +364,7 @@ close_many_wcroots(apr_hash_t *roots,
for (hi = apr_hash_first(scratch_pool, roots); hi; hi = apr_hash_next(hi))
{
- wcroot_t *wcroot = svn_apr_hash_index_val(hi);
+ wcroot_t *wcroot = svn__apr_hash_index_val(hi);
apr_status_t result;
result = apr_pool_cleanup_run(state_pool, wcroot, close_wcroot);
@@ -421,7 +413,7 @@ create_wcroot(wcroot_t **wcroot,
_("This client is too old to work with the working copy at\n"
"'%s' (format %d).\n"
"You need to get a newer Subversion client. For more details, see\n"
- " http://subversion.tigris.org/faq.html#working-copy-format-change\n"
+ " http://subversion.apache.org/faq.html#working-copy-format-change\n"
),
svn_dirent_local_style(wcroot_abspath, scratch_pool),
format);
@@ -453,11 +445,24 @@ create_wcroot(wcroot_t **wcroot,
}
+/* Returns in PRISTINE_ABSPATH a new string allocated from RESULT_POOL,
+ holding the local absolute path to the file location that is dedicated
+ to hold CHECKSUM's pristine file, relating to the pristine store
+ configured for the working copy indicated by PDH. The returned path
+ does not necessarily currently exist.
+#ifndef SVN__SKIP_SUBDIR
+ Iff CREATE_SUBDIR is TRUE, then this function will make sure that the
+ parent directory of PRISTINE_ABSPATH exists. This is only useful when
+ about to create a new pristine.
+#endif
+ Any other allocations are made in SCRATCH_POOL. */
static svn_error_t *
get_pristine_fname(const char **pristine_abspath,
svn_wc__db_pdh_t *pdh,
const svn_checksum_t *checksum,
+#ifndef SVN__SKIP_SUBDIR
svn_boolean_t create_subdir,
+#endif
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -474,9 +479,11 @@ get_pristine_fname(const char **pristine
/* ### need to fix this to use a symbol for ".svn". we don't need
### to use join_many since we know "/" is the separator for
### internal canonical paths */
- base_dir_abspath = svn_dirent_join(pdh->wcroot->abspath,
- PRISTINE_STORAGE_RELPATH,
- scratch_pool);
+ base_dir_abspath = svn_dirent_join_many(scratch_pool,
+ pdh->wcroot->abspath,
+ svn_wc_get_adm_dir(scratch_pool),
+ PRISTINE_STORAGE_RELPATH,
+ NULL);
/* We should have a valid checksum and (thus) a valid digest. */
SVN_ERR_ASSERT(hexdigest != NULL);
@@ -515,6 +522,7 @@ get_pristine_fname(const char **pristine
}
+/* */
static svn_error_t *
fetch_repos_info(const char **repos_root_url,
const char **repos_uuid,
@@ -545,11 +553,13 @@ fetch_repos_info(const char **repos_root
/* Scan from LOCAL_RELPATH upwards through parent nodes until we find a parent
that has values in the 'repos_id' and 'repos_relpath' columns. Return
- that information in REPOS_ID and REPOS_RELPATH (either may be NULL). */
+ that information in REPOS_ID and REPOS_RELPATH (either may be NULL).
+ Use LOCAL_ABSPATH for diagnostics */
static svn_error_t *
scan_upwards_for_repos(apr_int64_t *repos_id,
const char **repos_relpath,
const wcroot_t *wcroot,
+ const char *local_abspath,
const char *local_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -586,14 +596,14 @@ scan_upwards_for_repos(apr_int64_t *repo
err = svn_error_createf(
SVN_ERR_WC_CORRUPT, NULL,
_("Parent(s) of '%s' should have been present."),
- svn_dirent_local_style(local_relpath, scratch_pool));
+ svn_dirent_local_style(local_abspath, scratch_pool));
}
else
{
err = svn_error_createf(
SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("The node '%s' was not found."),
- svn_dirent_local_style(local_relpath, scratch_pool));
+ svn_dirent_local_style(local_abspath, scratch_pool));
}
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
@@ -626,7 +636,7 @@ scan_upwards_for_repos(apr_int64_t *repo
return svn_error_createf(
SVN_ERR_WC_CORRUPT, NULL,
_("Parent(s) of '%s' should have repository information."),
- svn_relpath_local_style(local_relpath, scratch_pool));
+ svn_relpath_local_style(local_abspath, scratch_pool));
}
/* Strip a path segment off the end, and append it to the suffix
@@ -690,6 +700,7 @@ get_old_version(int *version,
}
+/* */
static svn_wc__db_pdh_t *
get_or_create_pdh(svn_wc__db_t *db,
const char *local_dir_abspath,
@@ -777,6 +788,7 @@ determine_obstructed_file(svn_boolean_t
}
+/* */
static svn_error_t *
fetch_wc_id(apr_int64_t *wc_id,
svn_sqlite__db_t *sdb,
@@ -800,6 +812,7 @@ fetch_wc_id(apr_int64_t *wc_id,
}
+/* */
static svn_error_t *
open_db(svn_sqlite__db_t **sdb,
const char *dir_abspath,
@@ -813,7 +826,7 @@ open_db(svn_sqlite__db_t **sdb,
return svn_error_return(svn_sqlite__open(sdb, sdb_abspath,
smode, statements,
- SVN_WC__VERSION, upgrade_sql,
+ 0, NULL,
result_pool, scratch_pool));
}
@@ -1252,6 +1265,7 @@ get_statement_for_path(svn_sqlite__stmt_
}
+/* */
static svn_error_t *
navigate_to_parent(svn_wc__db_pdh_t **parent_pdh,
svn_wc__db_t *db,
@@ -1318,6 +1332,7 @@ create_repos_id(apr_int64_t *repos_id,
}
+/* */
static svn_error_t *
insert_base_node(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
{
@@ -1389,7 +1404,7 @@ insert_base_node(void *baton, svn_sqlite
name,
scratch_pool),
pibb->local_relpath,
- pibb->revision));
+ (apr_int64_t)pibb->revision));
SVN_ERR(svn_sqlite__insert(NULL, stmt));
}
}
@@ -1398,6 +1413,7 @@ insert_base_node(void *baton, svn_sqlite
}
+/* */
static svn_error_t *
gather_children(const apr_array_header_t **children,
svn_boolean_t base_only,
@@ -1449,6 +1465,7 @@ gather_children(const apr_array_header_t
}
+/* */
static void
flush_entries(const svn_wc__db_pdh_t *pdh)
{
@@ -1457,6 +1474,105 @@ flush_entries(const svn_wc__db_pdh_t *pd
}
+/* Add a single WORK_ITEM into the given SDB's WORK_QUEUE table. This does
+ not perform its work within a transaction, assuming the caller will
+ manage that. */
+static svn_error_t *
+add_single_work_item(svn_sqlite__db_t *sdb,
+ const svn_skel_t *work_item,
+ apr_pool_t *scratch_pool)
+{
+ svn_stringbuf_t *serialized;
+ svn_sqlite__stmt_t *stmt;
+
+ serialized = svn_skel__unparse(work_item, scratch_pool);
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_WORK_ITEM));
+ SVN_ERR(svn_sqlite__bind_blob(stmt, 1, serialized->data, serialized->len));
+ return svn_error_return(svn_sqlite__insert(NULL, stmt));
+}
+
+
+/* Add work item(s) to the given SDB. Also see add_one_work_item(). This
+ SKEL is usually passed to the various wc_db operation functions. It may
+ be NULL, indicating no additional work items are needed, it may be a
+ single work item, or it may be a list of work items. */
+static svn_error_t *
+add_work_items(svn_sqlite__db_t *sdb,
+ const svn_skel_t *skel,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool;
+
+ /* Maybe there are no work items to insert. */
+ if (skel == NULL)
+ return SVN_NO_ERROR;
+
+ /* Should have a list. */
+ SVN_ERR_ASSERT(!skel->is_atom);
+
+ /* If SKEL has an atom as its first child, then this is a work item
+ (and that atom is one of the OP_* values). */
+ if (skel->children->is_atom)
+ return svn_error_return(add_single_work_item(sdb, skel, scratch_pool));
+
+ /* SKEL is a list-of-lists, aka list of work items. */
+
+ iterpool = svn_pool_create(scratch_pool);
+ for (skel = skel->children; skel; skel = skel->next)
+ {
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(add_single_work_item(sdb, skel, iterpool));
+ }
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Determine which trees' nodes exist for a given WC_ID and LOCAL_RELPATH
+ in the specified SDB. */
+static svn_error_t *
+which_trees_exist(svn_boolean_t *base_exists,
+ svn_boolean_t *working_exists,
+ svn_sqlite__db_t *sdb,
+ apr_int64_t wc_id,
+ const char *local_relpath)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ *base_exists = FALSE;
+ *working_exists = FALSE;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_DETERMINE_TREE_FOR_RECORDING));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ {
+ int value = svn_sqlite__column_int(stmt, 0);
+
+ if (value)
+ *working_exists = TRUE; /* value == 1 */
+ else
+ *base_exists = TRUE; /* value == 0 */
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ {
+ /* If both rows, then both tables. */
+ *base_exists = TRUE;
+ *working_exists = TRUE;
+ }
+ }
+
+ return svn_error_return(svn_sqlite__reset(stmt));
+}
+
+
+/* */
static svn_error_t *
create_db(svn_sqlite__db_t **sdb,
apr_int64_t *repos_id,
@@ -1474,6 +1590,9 @@ create_db(svn_sqlite__db_t **sdb,
svn_sqlite__mode_rwcreate,
result_pool, scratch_pool));
+ /* Create the database's schema. */
+ SVN_ERR(svn_sqlite__exec_statements(*sdb, STMT_CREATE_SCHEMA));
+
/* Insert the repository. */
SVN_ERR(create_repos_id(repos_id, repos_root_url, repos_uuid, *sdb,
scratch_pool));
@@ -2125,6 +2244,70 @@ svn_wc__db_base_get_info(svn_wc__db_stat
}
+/* A WORKING version of svn_wc__db_base_get_info, stripped down to
+ just the status column.
+
+ ### This function should not exist! What I really want is presence
+ ### not status, and so it's a mistake to return an
+ ### svn_wc__db_status_t here as it doesn't have quite the same
+ ### meaning as status returned by other functions. I think I need
+ ### to abandon this function and work out how to decode status back
+ ### into presence :(
+*/
+static svn_error_t *
+db_working_get_status(svn_wc__db_status_t *status,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ svn_error_t *err = SVN_NO_ERROR;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readonly,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_SELECT_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ if (have_row)
+ {
+ svn_wc__db_kind_t node_kind = svn_sqlite__column_token(stmt, 1,
+ kind_map);
+
+ *status = svn_sqlite__column_token(stmt, 0, presence_map);
+
+ if (node_kind == svn_wc__db_kind_subdir
+ && *status == svn_wc__db_status_normal)
+ {
+ /* We're looking at the subdir record in the *parent* directory,
+ which implies per-dir .svn subdirs. We should be looking
+ at the subdir itself; therefore, it is missing or obstructed
+ in some way. Inform the caller. */
+ *status = svn_wc__db_status_obstructed;
+ }
+ }
+ else
+ {
+ err = svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+ _("The node '%s' was not found."),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+ }
+
+
+ return svn_error_compose_create(err, svn_sqlite__reset(stmt));
+}
+
+
svn_error_t *
svn_wc__db_base_get_prop(const svn_string_t **propval,
svn_wc__db_t *db,
@@ -2176,6 +2359,12 @@ svn_wc__db_base_get_props(apr_hash_t **p
err = svn_sqlite__column_properties(props, stmt, 0, result_pool,
scratch_pool);
+ if (err == NULL && *props == NULL)
+ {
+ /* ### is this a DB constraint violation? the column "probably" should
+ ### never be null. */
+ *props = apr_hash_make(result_pool);
+ }
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
}
@@ -2205,6 +2394,8 @@ svn_wc__db_base_set_dav_cache(svn_wc__db
STMT_UPDATE_BASE_DAV_CACHE, scratch_pool));
SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
+ /* ### we should assert that 1 row was affected. */
+
return svn_error_return(svn_sqlite__step_done(stmt));
}
@@ -2248,6 +2439,7 @@ svn_wc__db_pristine_read(svn_stream_t **
svn_wc__db_pdh_t *pdh;
const char *local_relpath;
const char *pristine_abspath;
+ svn_error_t *err;
SVN_ERR_ASSERT(contents != NULL);
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
@@ -2262,9 +2454,12 @@ svn_wc__db_pristine_read(svn_stream_t **
/* ### should we look in the PRISTINE table for anything? */
- SVN_ERR(get_pristine_fname(&pristine_abspath, pdh, checksum,
- FALSE /* create_subdir */,
- scratch_pool, scratch_pool));
+ err = get_pristine_fname(&pristine_abspath, pdh, checksum,
+#ifndef SVN__SKIP_SUBDIR
+ FALSE /* create_subdir */,
+#endif
+ scratch_pool, scratch_pool);
+ SVN_ERR(err);
return svn_error_return(svn_stream_open_readonly(
contents, pristine_abspath,
@@ -2273,40 +2468,6 @@ svn_wc__db_pristine_read(svn_stream_t **
svn_error_t *
-svn_wc__db_pristine_write(svn_stream_t **contents,
- svn_wc__db_t *db,
- const char *wri_abspath,
- const svn_checksum_t *checksum,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_ASSERT(contents != NULL);
- SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
- SVN_ERR_ASSERT(checksum != NULL);
-
- VERIFY_CHECKSUM_KIND(checksum);
-
- NOT_IMPLEMENTED();
-
-#if 0
- const char *path;
-
- SVN_ERR(get_pristine_fname(&path, pdh, checksum, TRUE /* create_subdir */,
- scratch_pool, scratch_pool));
-
- SVN_ERR(svn_stream_open_writable(contents, path, result_pool, scratch_pool));
-
- /* ### we should wrap the stream. count the bytes. at close, then we
- ### should write the count into the sqlite database. */
- /* ### euh... no. stream closure could happen after an error, so there
- ### isn't enough information here. */
-
- return SVN_NO_ERROR;
-#endif
-}
-
-
-svn_error_t *
svn_wc__db_pristine_get_tempdir(const char **temp_dir_abspath,
svn_wc__db_t *db,
const char *wri_abspath,
@@ -2324,9 +2485,11 @@ svn_wc__db_pristine_get_tempdir(const ch
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
- *temp_dir_abspath = svn_dirent_join(pdh->wcroot->abspath,
- PRISTINE_TEMPDIR_RELPATH,
- result_pool);
+ *temp_dir_abspath = svn_dirent_join_many(result_pool,
+ pdh->wcroot->abspath,
+ svn_wc_get_adm_dir(scratch_pool),
+ PRISTINE_TEMPDIR_RELPATH,
+ NULL);
return SVN_NO_ERROR;
}
@@ -2344,6 +2507,7 @@ svn_wc__db_pristine_install(svn_wc__db_t
const char *pristine_abspath;
apr_finfo_t finfo;
svn_sqlite__stmt_t *stmt;
+ svn_error_t *err;
SVN_ERR_ASSERT(svn_dirent_is_absolute(tempfile_abspath));
SVN_ERR_ASSERT(sha1_checksum != NULL);
@@ -2364,9 +2528,12 @@ svn_wc__db_pristine_install(svn_wc__db_t
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
- SVN_ERR(get_pristine_fname(&pristine_abspath, pdh, sha1_checksum,
- TRUE /* create_subdir */,
- scratch_pool, scratch_pool));
+ err = get_pristine_fname(&pristine_abspath, pdh, sha1_checksum,
+#ifndef SVN__SKIP_SUBDIR
+ TRUE /* create_subdir */,
+#endif
+ scratch_pool, scratch_pool);
+ SVN_ERR(err);
/* Put the file into its target location. */
SVN_ERR(svn_io_file_rename(tempfile_abspath, pristine_abspath,
@@ -2514,6 +2681,11 @@ struct set_props_baton
svn_wc__db_pdh_t *pdh;
};
+/* 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'. */
static svn_error_t *
set_props_txn(void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool)
{
@@ -2570,18 +2742,22 @@ svn_wc__db_op_set_props(svn_wc__db_t *db
scratch_pool));
}
-svn_error_t *
-svn_wc__db_temp_op_set_pristine_props(svn_wc__db_t *db,
- const char *local_abspath,
- const apr_hash_t *props,
- svn_boolean_t on_working,
- apr_pool_t *scratch_pool)
+
+/* Set properties in a given table. The row must exist. */
+static svn_error_t *
+set_properties(svn_wc__db_t *db,
+ const char *local_abspath,
+ const apr_hash_t *props,
+ int stmt_idx,
+ const char *table_name,
+ apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
int affected_rows;
- SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
- on_working ? STMT_UPDATE_WORKING_PROPS
- : STMT_UPDATE_BASE_PROPS,
+
+ SVN_ERR_ASSERT(props != NULL);
+
+ SVN_ERR(get_statement_for_path(&stmt, db, local_abspath, stmt_idx,
scratch_pool));
SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool));
@@ -2592,11 +2768,38 @@ svn_wc__db_temp_op_set_pristine_props(sv
_("Can't store properties for '%s' in '%s'."),
svn_dirent_local_style(local_abspath,
scratch_pool),
- on_working ? "working_node" : "base_node");
+ table_name);
return SVN_NO_ERROR;
}
+
+svn_error_t *
+svn_wc__db_temp_base_set_props(svn_wc__db_t *db,
+ const char *local_abspath,
+ const apr_hash_t *props,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_return(set_properties(db, local_abspath, props,
+ STMT_UPDATE_BASE_PROPS,
+ "base_node",
+ scratch_pool));
+}
+
+
+svn_error_t *
+svn_wc__db_temp_working_set_props(svn_wc__db_t *db,
+ const char *local_abspath,
+ const apr_hash_t *props,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_return(set_properties(db, local_abspath, props,
+ STMT_UPDATE_WORKING_PROPS,
+ "working_node",
+ scratch_pool));
+}
+
+
svn_error_t *
svn_wc__db_op_delete(svn_wc__db_t *db,
const char *local_abspath,
@@ -2639,6 +2842,7 @@ struct set_changelist_baton
const char *changelist;
};
+/* */
static svn_error_t *
set_changelist_txn(void *baton,
svn_sqlite__db_t *sdb,
@@ -2792,6 +2996,7 @@ struct set_tc_baton
};
+/* */
static svn_error_t *
set_tc_txn(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
{
@@ -2801,10 +3006,6 @@ set_tc_txn(void *baton, svn_sqlite__db_t
const char *tree_conflict_data;
apr_hash_t *conflicts;
- /* ### f13: just insert, remove or replace the row from the CONFLICT_VICTIM
- ### table, rather than all this parsing, unparsing garbage. (and we
- ### probably won't need a transaction, either.)*/
-
/* Get the conflict information for the parent of LOCAL_ABSPATH. */
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_ACTUAL_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", stb->wc_id, stb->local_relpath));
@@ -2899,35 +3100,6 @@ svn_wc__db_op_revert(svn_wc__db_t *db,
NOT_IMPLEMENTED();
}
-svn_error_t *
-svn_wc__db_op_set_last_mod_time(svn_wc__db_t *db,
- const char *local_abspath,
- apr_time_t last_mod_time,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_pdh_t *pdh;
- const char *local_relpath;
- svn_sqlite__stmt_t *stmt;
-
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
- SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readwrite,
- scratch_pool, scratch_pool));
- VERIFY_USABLE_PDH(pdh);
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
- STMT_UPDATE_BASE_LAST_MOD_TIME));
- SVN_ERR(svn_sqlite__bindf(stmt, "isi",
- pdh->wcroot->wc_id, local_relpath,
- last_mod_time));
- SVN_ERR(svn_sqlite__step_done(stmt));
-
- flush_entries(pdh);
-
- return SVN_NO_ERROR;
-}
-
svn_error_t *
svn_wc__db_op_read_tree_conflict(
@@ -2964,9 +3136,6 @@ svn_wc__db_op_read_tree_conflict(
VERIFY_USABLE_PDH(pdh);
- /* ### f13: just read the row from the CONFLICT_VICTIM table, rather than
- ### all this parsing, unparsing garbage. */
-
/* Get the conflict information for the parent of LOCAL_ABSPATH. */
SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
STMT_SELECT_ACTUAL_NODE));
@@ -3011,7 +3180,7 @@ svn_wc__db_temp_op_remove_entry(svn_wc__
svn_wc__db_pdh_t *pdh;
svn_sqlite__stmt_t *stmt;
svn_sqlite__db_t *sdb;
- wcroot_t *wcroot;
+ apr_int64_t wc_id;
const char *current_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
@@ -3037,19 +3206,19 @@ svn_wc__db_temp_op_remove_entry(svn_wc__
flush_entries(pdh);
}
- wcroot = pdh->wcroot;
- sdb = wcroot->sdb;
+ sdb = pdh->wcroot->sdb;
+ wc_id = pdh->wcroot->wc_id;
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_BASE_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, current_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, current_relpath));
SVN_ERR(svn_sqlite__step_done(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_DELETE_ACTUAL_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, current_relpath));
return svn_error_return(svn_sqlite__step_done(stmt));
}
@@ -3064,8 +3233,6 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
{
svn_wc__db_pdh_t *pdh;
svn_sqlite__stmt_t *stmt;
- svn_sqlite__db_t *sdb;
- wcroot_t *wcroot;
const char *current_relpath;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath) &&
@@ -3076,22 +3243,21 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
- wcroot = pdh->wcroot;
- sdb = wcroot->sdb;
-
/* ### We set depth on working and base to match entry behavior.
Maybe these should be separated later? */
if (flush_entry_cache)
flush_entries(pdh);
- SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_UPDATE_BASE_DEPTH));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_UPDATE_BASE_DEPTH));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, current_relpath));
SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_depth_to_word(depth)));
SVN_ERR(svn_sqlite__step_done(stmt));
- SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_UPDATE_WORKING_DEPTH));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath));
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_UPDATE_WORKING_DEPTH));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, current_relpath));
SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_depth_to_word(depth)));
SVN_ERR(svn_sqlite__step_done(stmt));
@@ -3102,7 +3268,6 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
err = navigate_to_parent(&pdh, db, pdh, svn_sqlite__mode_readwrite,
scratch_pool);
-
if (err && err->apr_err == SVN_ERR_WC_NOT_WORKING_COPY)
{
/* No parent to update */
@@ -3119,65 +3284,386 @@ svn_wc__db_temp_op_set_dir_depth(svn_wc_
}
-svn_error_t *
-svn_wc__db_read_info(svn_wc__db_status_t *status,
- svn_wc__db_kind_t *kind,
- svn_revnum_t *revision,
- const char **repos_relpath,
- const char **repos_root_url,
- const char **repos_uuid,
- svn_revnum_t *changed_rev,
- apr_time_t *changed_date,
- const char **changed_author,
- apr_time_t *last_mod_time,
- svn_depth_t *depth,
- const svn_checksum_t **checksum,
- svn_filesize_t *translated_size,
- const char **target,
- const char **changelist,
- const char **original_repos_relpath,
- const char **original_root_url,
- const char **original_uuid,
- svn_revnum_t *original_revision,
- svn_boolean_t *text_mod,
- svn_boolean_t *props_mod,
- svn_boolean_t *base_shadowed,
- svn_boolean_t *conflicted,
- svn_wc__db_lock_t **lock,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+/* Update the working node for LOCAL_ABSPATH setting presence=STATUS */
+static svn_error_t *
+db_working_update_presence(svn_wc__db_status_t status,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
{
svn_wc__db_pdh_t *pdh;
const char *local_relpath;
- svn_sqlite__stmt_t *stmt_base;
- svn_sqlite__stmt_t *stmt_work;
- svn_sqlite__stmt_t *stmt_act;
- svn_boolean_t have_base;
- svn_boolean_t have_work;
- svn_boolean_t have_act;
- svn_error_t *err = NULL;
+ svn_sqlite__stmt_t *stmt;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
- svn_sqlite__mode_readonly,
+ svn_sqlite__mode_readwrite,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
- SVN_ERR(svn_sqlite__get_statement(&stmt_base, pdh->wcroot->sdb,
- lock ? STMT_SELECT_BASE_NODE_WITH_LOCK
- : STMT_SELECT_BASE_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt_base, "is",
- pdh->wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step(&have_base, stmt_base));
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_UPDATE_WORKING_PRESENCE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "ist", pdh->wcroot->wc_id, local_relpath,
+ presence_map, status));
+ SVN_ERR(svn_sqlite__step_done(stmt));
- SVN_ERR(svn_sqlite__get_statement(&stmt_work, pdh->wcroot->sdb,
- STMT_SELECT_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt_work, "is",
- pdh->wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__step(&have_work, stmt_work));
+ flush_entries(pdh);
+
+ /* ### Parent stub? I don't know; I'll punt for now as it passes
+ the regression tests as is and the problem will evaporate
+ when the db is centralised. */
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Delete working and actual nodes for LOCAL_ABSPATH */
+static svn_error_t *
+db_working_actual_remove(svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_sqlite__stmt_t *stmt;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_DELETE_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_DELETE_ACTUAL_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ flush_entries(pdh);
+
+ if (*local_relpath == '\0')
+ {
+ /* ### Delete parent stub. Remove when db is centralised. */
+ SVN_ERR(navigate_to_parent(&pdh, db, pdh, svn_sqlite__mode_readwrite,
+ scratch_pool));
+ local_relpath = svn_dirent_basename(local_abspath, NULL);
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_DELETE_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ flush_entries(pdh);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Insert a working node for LOCAL_ABSPATH with presence=STATUS. */
+static svn_error_t *
+db_working_insert(svn_wc__db_status_t status,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_sqlite__stmt_t *stmt;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_INSERT_WORKING_NODE_FROM_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "ist", pdh->wcroot->wc_id, local_relpath,
+ presence_map, status));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ flush_entries(pdh);
+
+ if (*local_relpath == '\0')
+ {
+ /* ### Insert parent stub. Remove when db is centralised. */
+ SVN_ERR(navigate_to_parent(&pdh, db, pdh, svn_sqlite__mode_readwrite,
+ scratch_pool));
+ local_relpath = svn_dirent_basename(local_abspath, NULL);
+ VERIFY_USABLE_PDH(pdh);
+
+ /* ### Should the parent stub have a full row like this? */
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, pdh->wcroot->sdb,
+ STMT_INSERT_WORKING_NODE_FROM_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "ist",
+ pdh->wcroot->wc_id, local_relpath,
+ presence_map, status));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ flush_entries(pdh);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Set *ROOT_OF_COPY to TRUE if LOCAL_ABSPATH is an add or the root of
+ a copy, to FALSE otherwise. */
+static svn_error_t*
+is_add_or_root_of_copy(svn_boolean_t *add_or_root_of_copy,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+ const char *op_root_abspath;
+ const char *original_repos_relpath, *original_repos_root;
+ const char *original_repos_uuid;
+ svn_revnum_t original_revision;
+
+ SVN_ERR(svn_wc__db_scan_addition(&status, &op_root_abspath,
+ NULL, NULL, NULL,
+ &original_repos_relpath,
+ &original_repos_root,
+ &original_repos_uuid,
+ &original_revision,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR_ASSERT(status == svn_wc__db_status_added
+ || status == svn_wc__db_status_copied);
+ SVN_ERR_ASSERT(op_root_abspath != NULL);
+
+ *add_or_root_of_copy = (status == svn_wc__db_status_added
+ || !strcmp(local_abspath, op_root_abspath));
+
+ if (*add_or_root_of_copy && status == svn_wc__db_status_copied)
+ {
+ /* ### merge sets the wrong copyfrom when adding a tree and so
+ the root detection above is unreliable. I'm "fixing" it
+ here because I just need to detect whether this is an
+ instance of the merge bug, and that's easier than fixing
+ scan_addition or merge. */
+ const char *parent_abspath;
+ const char *name;
+ svn_wc__db_status_t parent_status;
+ const char *parent_original_repos_relpath, *parent_original_repos_root;
+ const char *parent_original_repos_uuid;
+ svn_revnum_t parent_original_revision;
+ svn_error_t *err;
+
+ svn_dirent_split(local_abspath, &parent_abspath, &name, scratch_pool);
+
+ err = svn_wc__db_scan_addition(&parent_status,
+ NULL, NULL, NULL, NULL,
+ &parent_original_repos_relpath,
+ &parent_original_repos_root,
+ &parent_original_repos_uuid,
+ &parent_original_revision,
+ db, parent_abspath,
+ scratch_pool, scratch_pool);
+ if (err)
+ {
+ if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+ return svn_error_return(err);
+ /* It really is a root */
+ svn_error_clear(err);
+ }
+ else if (parent_status == svn_wc__db_status_copied
+ && original_revision == parent_original_revision
+ && !strcmp(original_repos_uuid, parent_original_repos_uuid)
+ && !strcmp(original_repos_root, parent_original_repos_root)
+ && !strcmp(original_repos_relpath,
+ svn_dirent_join(parent_original_repos_relpath,
+ name,
+ scratch_pool)))
+ /* An instance of the merge bug */
+ *add_or_root_of_copy = FALSE;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Delete LOCAL_ABSPATH. Implements the delete transition from
+ notes/wc-ng/transitions. */
+svn_error_t *
+svn_wc__db_temp_op_delete(svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err;
+ svn_boolean_t base_none, working_none, new_working_none;
+ svn_wc__db_status_t base_status, working_status, new_working_status;
+
+ err = svn_wc__db_base_get_info(&base_status,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool);
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ base_none = TRUE;
+ svn_error_clear(err);
+ }
+ else if (! err)
+ base_none = FALSE;
+ else
+ return svn_error_return(err);
+
+ /* ### should error on excluded, too. excluded nodes could be removed
+ ### from our metadata, but they cannot be scheduled for deletion. */
+ if (!base_none && base_status == svn_wc__db_status_absent)
+ return SVN_NO_ERROR; /* ### should return an error.... WHICH ONE? */
+
+ err = db_working_get_status(&working_status,
+ db, local_abspath, scratch_pool);
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ working_none = TRUE;
+ svn_error_clear(err);
+ }
+ else if (! err)
+ working_none = FALSE;
+ else
+ return svn_error_return(err);
+
+ if (base_none && working_none)
+ return SVN_NO_ERROR; /* ### should return PATH_NOT_FOUND */
+
+ new_working_none = working_none;
+ new_working_status = working_status;
+ if (working_none)
+ {
+ if (base_status == svn_wc__db_status_normal
+ || base_status == svn_wc__db_status_obstructed
+ || base_status == svn_wc__db_status_incomplete
+ || base_status == svn_wc__db_status_excluded)
+ {
+ new_working_none = FALSE;
+ new_working_status = svn_wc__db_status_base_deleted;
+ }
+ }
+ else if ((working_status == svn_wc__db_status_normal
+ || working_status == svn_wc__db_status_obstructed)
+ && (base_none || base_status == svn_wc__db_status_not_present))
+ {
+ svn_boolean_t add_or_root_of_copy;
+ SVN_ERR(is_add_or_root_of_copy(&add_or_root_of_copy,
+ db, local_abspath, scratch_pool));
+ if (add_or_root_of_copy)
+ new_working_none = TRUE;
+ else
+ new_working_status = svn_wc__db_status_not_present;
+ }
+ else if (working_status == svn_wc__db_status_normal)
+ {
+ svn_boolean_t add_or_root_of_copy;
+ SVN_ERR(is_add_or_root_of_copy(&add_or_root_of_copy,
+ db, local_abspath, scratch_pool));
+ if (add_or_root_of_copy)
+ new_working_status = svn_wc__db_status_base_deleted;
+ else
+ new_working_status = svn_wc__db_status_not_present;
+ }
+ else if (working_status == svn_wc__db_status_incomplete)
+ {
+ svn_boolean_t add_or_root_of_copy;
+ SVN_ERR(is_add_or_root_of_copy(&add_or_root_of_copy,
+ db, local_abspath, scratch_pool));
+ if (add_or_root_of_copy)
+ new_working_none = TRUE;
+ }
+
+ if (new_working_none && !working_none)
+ {
+ SVN_ERR(db_working_actual_remove(db, local_abspath, scratch_pool));
+ /* ### Search the cached directories in db for directories below
+ local_abspath and close their handles to allow deleting
+ them from the working copy */
+ SVN_ERR(svn_wc__db_temp_forget_directory(db, local_abspath,
+ scratch_pool));
+ }
+ else if (!new_working_none && working_none)
+ SVN_ERR(db_working_insert(new_working_status,
+ db, local_abspath, scratch_pool));
+ else if (!new_working_none && !working_none
+ && new_working_status != working_status)
+ SVN_ERR(db_working_update_presence(new_working_status,
+ db, local_abspath, scratch_pool));
+ /* ### else nothing to do, return an error? */
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_read_info(svn_wc__db_status_t *status,
+ svn_wc__db_kind_t *kind,
+ svn_revnum_t *revision,
+ const char **repos_relpath,
+ const char **repos_root_url,
+ const char **repos_uuid,
+ svn_revnum_t *changed_rev,
+ apr_time_t *changed_date,
+ const char **changed_author,
+ apr_time_t *last_mod_time,
+ svn_depth_t *depth,
+ const svn_checksum_t **checksum,
+ svn_filesize_t *translated_size,
+ const char **target,
+ const char **changelist,
+ const char **original_repos_relpath,
+ const char **original_root_url,
+ const char **original_uuid,
+ svn_revnum_t *original_revision,
+ svn_boolean_t *text_mod,
+ svn_boolean_t *props_mod,
+ svn_boolean_t *base_shadowed,
+ svn_boolean_t *conflicted,
+ svn_wc__db_lock_t **lock,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_sqlite__stmt_t *stmt_base;
+ svn_sqlite__stmt_t *stmt_work;
+ svn_sqlite__stmt_t *stmt_act;
+ svn_boolean_t have_base;
+ svn_boolean_t have_work;
+ svn_boolean_t have_act;
+ svn_error_t *err = NULL;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readonly,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt_base, pdh->wcroot->sdb,
+ lock ? STMT_SELECT_BASE_NODE_WITH_LOCK
+ : STMT_SELECT_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt_base, "is",
+ pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_base, stmt_base));
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt_work, pdh->wcroot->sdb,
+ STMT_SELECT_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt_work, "is",
+ pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_work, stmt_work));
SVN_ERR(svn_sqlite__get_statement(&stmt_act, pdh->wcroot->sdb,
STMT_SELECT_ACTUAL_NODE));
@@ -3592,6 +4078,7 @@ svn_wc__db_read_props(apr_hash_t **props
if (have_row)
return SVN_NO_ERROR;
+ /* No local changes. Return the pristine props for this node. */
return svn_error_return(
svn_wc__db_read_pristine_props(props, db, local_abspath,
result_pool, scratch_pool));
@@ -3606,36 +4093,41 @@ svn_wc__db_read_pristine_props(apr_hash_
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row, have_value;
- svn_error_t *err = NULL;
+ svn_boolean_t have_row;
+ svn_error_t *err;
+
*props = NULL;
SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
STMT_SELECT_WORKING_PROPS, scratch_pool));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (have_row && !svn_sqlite__column_is_null(stmt, 0))
+ /* If there is a WORKING row, then we're done.
+
+ For adds/copies/moves, then properties are in this row.
+ For deletes, there are no properties.
+
+ Regardless, we never look at BASE. The properties (or not) are here. */
+ if (have_row)
{
- have_value = TRUE;
err = svn_sqlite__column_properties(props, stmt, 0, result_pool,
scratch_pool);
+ SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+ if (*props == NULL)
+ {
+ /* ### is this a DB constraint violation? the column "probably"
+ ### should never be null. maybe we should leave it null for
+ ### delete operations, so this is okay. */
+ *props = apr_hash_make(result_pool);
+ }
+ return SVN_NO_ERROR;
}
- else
- have_value = FALSE;
-
- SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
-
- if (have_value)
- return SVN_NO_ERROR;
-
- err = svn_wc__db_base_get_props(props, db, local_abspath,
- result_pool, scratch_pool);
-
- if (err && (!have_row || err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND))
- return svn_error_return(err);
+ SVN_ERR(svn_sqlite__reset(stmt));
- svn_error_clear(err);
- return SVN_NO_ERROR;
+ /* No WORKING node, so the props must be in the BASE node. */
+ return svn_error_return(svn_wc__db_base_get_props(props, db, local_abspath,
+ result_pool,
+ scratch_pool));
}
@@ -3662,6 +4154,7 @@ struct relocate_baton
};
+/* */
static svn_error_t *
relocate_txn(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
{
@@ -3843,6 +4336,7 @@ struct commit_baton {
};
+/* */
static svn_error_t *
commit_node(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
{
@@ -4049,6 +4543,7 @@ commit_node(void *baton, svn_sqlite__db_
}
+/* */
static svn_error_t *
determine_repos_info(apr_int64_t *repos_id,
const char **repos_relpath,
@@ -4107,7 +4602,7 @@ determine_repos_info(apr_int64_t *repos_
/* The REPOS_ID will be the same (### until we support mixed-repos) */
SVN_ERR(scan_upwards_for_repos(repos_id, &repos_parent_relpath,
- pdh->wcroot,
+ pdh->wcroot, pdh->local_abspath,
"" /* local_relpath. see above. */,
scratch_pool, scratch_pool));
@@ -4182,45 +4677,218 @@ svn_wc__db_global_commit(svn_wc__db_t *d
}
+struct update_baton {
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+
+ const char *new_repos_relpath;
+ svn_revnum_t new_revision;
+ const apr_hash_t *new_props;
+ svn_revnum_t new_changed_rev;
+ apr_time_t new_changed_date;
+ const char *new_changed_author;
+ const apr_array_header_t *new_children;
+ const svn_checksum_t *new_checksum;
+ const char *new_target;
+ const svn_skel_t *conflict;
+ const svn_skel_t *work_items;
+};
+
+
svn_error_t *
-svn_wc__db_lock_add(svn_wc__db_t *db,
- const char *local_abspath,
- const svn_wc__db_lock_t *lock,
- apr_pool_t *scratch_pool)
+svn_wc__db_global_update(svn_wc__db_t *db,
+ const char *local_abspath,
+ const char *new_repos_relpath,
+ svn_revnum_t new_revision,
+ const apr_hash_t *new_props,
+ svn_revnum_t new_changed_rev,
+ apr_time_t new_changed_date,
+ const char *new_changed_author,
+ const apr_array_header_t *new_children,
+ const svn_checksum_t *new_checksum,
+ const char *new_target,
+ const svn_skel_t *conflict,
+ const svn_skel_t *work_items,
+ apr_pool_t *scratch_pool)
{
svn_wc__db_pdh_t *pdh;
const char *local_relpath;
- const char *repos_relpath;
- apr_int64_t repos_id;
- svn_sqlite__stmt_t *stmt;
+ struct update_baton ub;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- SVN_ERR_ASSERT(lock != NULL);
+ /* ### allow NULL for NEW_REPOS_RELPATH to indicate "no change"? */
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(new_repos_relpath, scratch_pool));
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_revision));
+ SVN_ERR_ASSERT(new_props != NULL);
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_changed_rev));
+ SVN_ERR_ASSERT((new_children != NULL
+ && new_checksum == NULL
+ && new_target == NULL)
+ || (new_children == NULL
+ && new_checksum != NULL
+ && new_target == NULL)
+ || (new_children == NULL
+ && new_checksum == NULL
+ && new_target != NULL));
SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
svn_sqlite__mode_readwrite,
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
- SVN_ERR(scan_upwards_for_repos(&repos_id, &repos_relpath,
- pdh->wcroot, local_relpath,
- scratch_pool, scratch_pool));
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
- STMT_INSERT_LOCK));
- SVN_ERR(svn_sqlite__bindf(stmt, "iss",
- repos_id, repos_relpath, lock->token));
+ ub.pdh = pdh;
+ ub.local_relpath = local_relpath;
- if (lock->owner != NULL)
- SVN_ERR(svn_sqlite__bind_text(stmt, 4, lock->owner));
+ ub.new_repos_relpath = new_repos_relpath;
+ ub.new_revision = new_revision;
+ ub.new_props = new_props;
+ ub.new_changed_rev = new_changed_rev;
+ ub.new_changed_date = new_changed_date;
+ ub.new_changed_author = new_changed_author;
+ ub.new_children = new_children;
+ ub.new_checksum = new_checksum;
+ ub.new_target = new_target;
- if (lock->comment != NULL)
- SVN_ERR(svn_sqlite__bind_text(stmt, 5, lock->comment));
+ ub.conflict = conflict;
+ ub.work_items = work_items;
- if (lock->date != 0)
- SVN_ERR(svn_sqlite__bind_int64(stmt, 6, lock->date));
+ NOT_IMPLEMENTED();
- SVN_ERR(svn_sqlite__insert(NULL, stmt));
+#if 0
+ SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb, update_node, &ub,
+ scratch_pool));
+#endif
+
+ /* We *totally* monkeyed the entries. Toss 'em. */
+ flush_entries(pdh);
+
+ return SVN_NO_ERROR;
+}
+
+
+struct record_baton {
+ apr_int64_t wc_id;
+ const char *local_relpath;
+
+ svn_filesize_t translated_size;
+ apr_time_t last_mod_time;
+
+ /* For error reporting. */
+ const char *local_abspath;
+};
+
+
+/* Record TRANSLATED_SIZE and LAST_MOD_TIME into the WORKING tree if a
+ node is present; otherwise, record it into the BASE tree. One of them
+ must exist. */
+static svn_error_t *
+record_fileinfo(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
+{
+ struct record_baton *rb = baton;
+ svn_boolean_t base_exists;
+ svn_boolean_t working_exists;
+ svn_sqlite__stmt_t *stmt;
+ int affected_rows;
+
+ SVN_ERR(which_trees_exist(&base_exists, &working_exists,
+ sdb, rb->wc_id, rb->local_relpath));
+ if (!base_exists && !working_exists)
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+ _("Could not find node '%s' for recording file "
+ "information."),
+ svn_dirent_local_style(rb->local_abspath,
+ scratch_pool));
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ working_exists
+ ? STMT_UPDATE_WORKING_FILEINFO
+ : STMT_UPDATE_BASE_FILEINFO));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isii",
+ rb->wc_id, rb->local_relpath,
+ rb->translated_size, rb->last_mod_time));
+ SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+ SVN_ERR_ASSERT(affected_rows == 1);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_global_record_fileinfo(svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_filesize_t translated_size,
+ apr_time_t last_mod_time,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ struct record_baton rb;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ rb.wc_id = pdh->wcroot->wc_id;
+ rb.local_relpath = local_relpath;
+
+ rb.translated_size = translated_size;
+ rb.last_mod_time = last_mod_time;
+
+ rb.local_abspath = local_abspath;
+
+ SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb, record_fileinfo, &rb,
+ scratch_pool));
+
+ /* We *totally* monkeyed the entries. Toss 'em. */
+ flush_entries(pdh);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_lock_add(svn_wc__db_t *db,
+ const char *local_abspath,
+ const svn_wc__db_lock_t *lock,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ const char *repos_relpath;
+ apr_int64_t repos_id;
+ svn_sqlite__stmt_t *stmt;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ SVN_ERR_ASSERT(lock != NULL);
+
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(scan_upwards_for_repos(&repos_id, &repos_relpath,
+ pdh->wcroot, local_abspath, local_relpath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_INSERT_LOCK));
+ SVN_ERR(svn_sqlite__bindf(stmt, "iss",
+ repos_id, repos_relpath, lock->token));
+
+ if (lock->owner != NULL)
+ SVN_ERR(svn_sqlite__bind_text(stmt, 4, lock->owner));
+
+ if (lock->comment != NULL)
+ SVN_ERR(svn_sqlite__bind_text(stmt, 5, lock->comment));
+
+ if (lock->date != 0)
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 6, lock->date));
+
+ SVN_ERR(svn_sqlite__insert(NULL, stmt));
/* There may be some entries, and the lock info is now out of date. */
flush_entries(pdh);
@@ -4248,7 +4916,7 @@ svn_wc__db_lock_remove(svn_wc__db_t *db,
VERIFY_USABLE_PDH(pdh);
SVN_ERR(scan_upwards_for_repos(&repos_id, &repos_relpath,
- pdh->wcroot, local_relpath,
+ pdh->wcroot, local_abspath, local_relpath,
scratch_pool, scratch_pool));
SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
@@ -4285,7 +4953,7 @@ svn_wc__db_scan_base_repos(const char **
VERIFY_USABLE_PDH(pdh);
SVN_ERR(scan_upwards_for_repos(&repos_id, repos_relpath,
- pdh->wcroot, local_relpath,
+ pdh->wcroot, local_abspath, local_relpath,
result_pool, scratch_pool));
if (repos_root_url || repos_uuid)
@@ -4569,9 +5237,14 @@ svn_wc__db_scan_deletion(const char **ba
/* No row means no WORKING node at this path, which means we just
fell off the top of the WORKING tree.
- The child cannot be not-present, as that would imply the
- root of the (added) WORKING subtree was deleted. */
- SVN_ERR_ASSERT(child_presence != svn_wc__db_status_not_present);
+ If the child was not-present this implies the root of the
+ (added) WORKING subtree was deleted. This can occur
+ during post-commit processing when the copied parent that
+ was in the WORKING tree has been moved to the BASE tree. */
+ if (work_del_abspath != NULL
+ && child_presence == svn_wc__db_status_not_present
+ && *work_del_abspath == NULL)
+ *work_del_abspath = apr_pstrdup(result_pool, child_abspath);
/* If the child did not have a BASE node associated with it, then
we're looking at a deletion that occurred within an added tree.
@@ -4728,8 +5401,8 @@ svn_wc__db_upgrade_apply_dav_cache(svn_s
hi;
hi = apr_hash_next(hi))
{
- const char *local_relpath = svn_apr_hash_index_key(hi);
- apr_hash_t *props = svn_apr_hash_index_val(hi);
+ const char *local_relpath = svn__apr_hash_index_key(hi);
+ apr_hash_t *props = svn__apr_hash_index_val(hi);
svn_pool_clear(iterpool);
@@ -4785,8 +5458,6 @@ svn_wc__db_wq_add(svn_wc__db_t *db,
{
svn_wc__db_pdh_t *pdh;
const char *local_relpath;
- svn_stringbuf_t *serialized;
- svn_sqlite__stmt_t *stmt;
SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
SVN_ERR_ASSERT(work_item != NULL);
@@ -4816,12 +5487,10 @@ svn_wc__db_wq_add(svn_wc__db_t *db,
}
#endif
- serialized = svn_skel__unparse(work_item, scratch_pool);
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
- STMT_INSERT_WORK_ITEM));
- SVN_ERR(svn_sqlite__bind_blob(stmt, 1, serialized->data, serialized->len));
- return svn_error_return(svn_sqlite__insert(NULL, stmt));
+ /* Add the work item(s) to the WORK_QUEUE. */
+ return svn_error_return(add_work_items(pdh->wcroot->sdb,
+ work_item,
+ scratch_pool));
}
@@ -5180,8 +5849,8 @@ svn_wc__db_temp_get_all_access(svn_wc__d
hi;
hi = apr_hash_next(hi))
{
- const void *key = svn_apr_hash_index_key(hi);
- const svn_wc__db_pdh_t *pdh = svn_apr_hash_index_val(hi);
+ const void *key = svn__apr_hash_index_key(hi);
+ const svn_wc__db_pdh_t *pdh = svn__apr_hash_index_val(hi);
if (pdh->adm_access != NULL)
apr_hash_set(result, key, APR_HASH_KEY_STRING, pdh->adm_access);
@@ -5280,6 +5949,9 @@ svn_wc__db_temp_determine_keep_local(svn
{
svn_sqlite__stmt_t *stmt;
+ /* ### This will fail for nodes that don't have a WORKING_NODE record,
+ but this is not an issue for this function, as this call is only
+ valid for deleted nodes anyway. */
SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
STMT_SELECT_KEEP_LOCAL_FLAG, scratch_pool));
SVN_ERR(svn_sqlite__step_row(stmt));
@@ -5290,6 +5962,33 @@ svn_wc__db_temp_determine_keep_local(svn
}
svn_error_t *
+svn_wc__db_temp_set_keep_local(svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_boolean_t keep_local,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_sqlite__stmt_t *stmt;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ /* First flush the entries */
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ flush_entries(pdh);
+
+ /* Then update the database */
+ SVN_ERR(get_statement_for_path(&stmt, db, local_abspath,
+ STMT_UPDATE_KEEP_LOCAL_FLAG, scratch_pool));
+
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 3, keep_local ? 1 : 0));
+
+ return svn_error_return(svn_sqlite__step_done(stmt));
+}
+
+svn_error_t *
svn_wc__db_read_conflict_victims(const apr_array_header_t **victims,
svn_wc__db_t *db,
const char *local_abspath,
@@ -5359,7 +6058,7 @@ svn_wc__db_read_conflict_victims(const a
hi = apr_hash_next(hi))
{
const char *child_name =
- svn_dirent_basename(svn_apr_hash_index_key(hi), result_pool);
+ svn_dirent_basename(svn__apr_hash_index_key(hi), result_pool);
/* Using a hash avoids duplicates */
apr_hash_set(found, child_name, APR_HASH_KEY_STRING, child_name);
@@ -5566,9 +6265,11 @@ svn_wc__db_temp_wcroot_tempdir(const cha
scratch_pool, scratch_pool));
VERIFY_USABLE_PDH(pdh);
- *temp_dir_abspath = svn_dirent_join(pdh->wcroot->abspath,
- WCROOT_TEMPDIR_RELPATH,
- result_pool);
+ *temp_dir_abspath = svn_dirent_join_many(result_pool,
+ pdh->wcroot->abspath,
+ svn_wc_get_adm_dir(scratch_pool),
+ WCROOT_TEMPDIR_RELPATH,
+ NULL);
return SVN_NO_ERROR;
}
@@ -5600,7 +6301,7 @@ svn_wc__db_wclock_set(svn_wc__db_t *db,
SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
STMT_INSERT_WC_LOCK));
SVN_ERR(svn_sqlite__bindf(stmt, "isi", pdh->wcroot->wc_id, local_relpath,
- levels_to_lock));
+ (apr_int64_t) levels_to_lock));
err = svn_sqlite__insert(NULL, stmt);
if (err)
return svn_error_createf(SVN_ERR_WC_LOCKED, err,
@@ -5612,6 +6313,7 @@ svn_wc__db_wclock_set(svn_wc__db_t *db,
}
+/* */
static svn_error_t *
is_wclocked(svn_boolean_t *locked,
svn_wc__db_t *db,
@@ -5647,6 +6349,12 @@ is_wclocked(svn_boolean_t *locked,
SVN_ERR(svn_sqlite__reset(stmt));
+ if (svn_dirent_is_root(local_abspath, strlen(local_abspath)))
+ {
+ *locked = FALSE;
+ return SVN_NO_ERROR;
+ }
+
return svn_error_return(is_wclocked(locked, db,
svn_dirent_dirname(local_abspath,
scratch_pool),
@@ -5719,3 +6427,706 @@ svn_wc__db_temp_own_lock(svn_boolean_t *
return SVN_NO_ERROR;
}
+
+svn_error_t *
+svn_wc__db_temp_op_set_base_incomplete(svn_wc__db_t *db,
+ const char *local_dir_abspath,
+ svn_boolean_t incomplete,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_wc__db_pdh_t *pdh;
+ int affected_rows;
+ svn_wc__db_status_t base_status;
+
+ SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ db, local_dir_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR_ASSERT(base_status == svn_wc__db_status_normal ||
+ base_status == svn_wc__db_status_incomplete);
+
+ SVN_ERR(get_statement_for_path(&stmt, db, local_dir_abspath,
+ STMT_UPDATE_BASE_PRESENCE, scratch_pool));
+
+ SVN_ERR(svn_sqlite__bind_text(stmt, 3, incomplete ? "incomplete" : "normal"));
+
+ SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+ if (affected_rows > 0)
+ {
+ pdh = get_or_create_pdh(db, local_dir_abspath, FALSE, scratch_pool);
+ flush_entries(pdh);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_temp_op_set_working_incomplete(svn_wc__db_t *db,
+ const char *local_dir_abspath,
+ svn_boolean_t incomplete,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_wc__db_pdh_t *pdh;
+ int affected_rows;
+ svn_wc__db_status_t status;
+
+ SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ db, local_dir_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR_ASSERT(status == svn_wc__db_status_normal ||
+ status == svn_wc__db_status_incomplete);
+
+ SVN_ERR(get_statement_for_path(&stmt, db, local_dir_abspath,
+ STMT_UPDATE_WORKING_PRESENCE, scratch_pool));
+
+ SVN_ERR(svn_sqlite__bind_text(stmt, 3, incomplete ? "incomplete" : "normal"));
+
+ SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+ if (affected_rows > 0)
+ {
+ pdh = get_or_create_pdh(db, local_dir_abspath, FALSE, scratch_pool);
+ flush_entries(pdh);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_temp_op_set_base_last_change(svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_revnum_t changed_rev,
+ apr_time_t changed_date,
+ const char *changed_author,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ svn_sqlite__stmt_t *stmt;
+ const char *local_relpath;
+ int affected;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_UPDATE_BASE_LAST_CHANGE));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "isiis",
+ pdh->wcroot->wc_id, local_relpath,
+ (apr_int64_t)changed_rev,
+ (apr_int64_t)changed_date,
+ changed_author));
+
+ SVN_ERR(svn_sqlite__update(&affected, stmt));
+
+ /* ### Theoretically this check can fail if all the values match
+ the values in the database. But we only call this function
+ if the revision changes */
+ if (affected != 1)
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+ _("'%s' has no BASE_NODE"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+
+ flush_entries(pdh);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_temp_op_set_working_last_change(svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_revnum_t changed_rev,
+ apr_time_t changed_date,
+ const char *changed_author,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ svn_sqlite__stmt_t *stmt;
+ const char *local_relpath;
+ int affected;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_UPDATE_WORKING_LAST_CHANGE));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "isiis",
+ pdh->wcroot->wc_id, local_relpath,
+ (apr_int64_t)changed_rev,
+ (apr_int64_t)changed_date,
+ changed_author));
+
+ SVN_ERR(svn_sqlite__update(&affected, stmt));
+
+ /* The following check might fail if none of the values changes.
+ But currently this function is never called in such cases */
+ if (affected != 1)
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+ _("'%s' has no WORKING_NODE"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+
+ flush_entries(pdh);
+
+ return SVN_NO_ERROR;
+}
+
+struct start_directory_update_baton
+{
+ svn_wc__db_t *db;
+ const char *local_abspath;
+ apr_int64_t wc_id;
+ const char *local_relpath;
+ svn_revnum_t new_rev;
+ const char *new_repos_relpath;
+};
+
+static svn_error_t *
+start_directory_update_txn(void *baton,
+ svn_sqlite__db_t *db,
+ apr_pool_t *scratch_pool)
+{
+ struct start_directory_update_baton *du = baton;
+ const char *repos_relpath;
+ svn_sqlite__stmt_t *stmt;
+
+ SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath, NULL, NULL,
+ du->db, du->local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (strcmp(du->new_repos_relpath, repos_relpath) == 0)
+ {
+ /* Just update revision and status */
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, db,
+ STMT_UPDATE_BASE_PRESENCE_AND_REVNUM));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "isti",
+ du->wc_id,
+ du->local_relpath,
+ presence_map, svn_wc__db_status_incomplete,
+ (apr_int64_t)du->new_rev));
+ }
+ else
+ {
+ /* ### TODO: Maybe check if we can make repos_relpath NULL. */
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, db,
+ STMT_UPDATE_BASE_PRESENCE_REVNUM_AND_REPOS_RELPATH));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "istis",
+ du->wc_id,
+ du->local_relpath,
+ presence_map, svn_wc__db_status_incomplete,
+ (apr_int64_t)du->new_rev,
+ du->new_repos_relpath));
+ }
+
+ return svn_error_return(svn_sqlite__step_done(stmt));
+}
+
+svn_error_t *
+svn_wc__db_temp_op_start_directory_update(svn_wc__db_t *db,
+ const char *local_abspath,
+ const char* new_repos_relpath,
+ svn_revnum_t new_rev,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ struct start_directory_update_baton du;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_rev));
+ SVN_ERR_ASSERT(svn_relpath_is_canonical(new_repos_relpath, scratch_pool));
+
+ SVN_ERR(parse_local_abspath(&pdh, &du.local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ du.db = db;
+ du.wc_id = pdh->wcroot->wc_id;
+ du.local_abspath = local_abspath;
+ du.new_rev = new_rev;
+ du.new_repos_relpath = new_repos_relpath;
+
+ SVN_ERR(svn_sqlite__with_transaction(pdh->wcroot->sdb,
+ start_directory_update_txn, &du,
+ scratch_pool));
+
+ flush_entries(pdh);
+
+ return SVN_NO_ERROR;
+}
+
+/* Baton for make_copy_txn */
+struct make_copy_baton
+{
+ svn_wc__db_t *db;
+ const char *local_abspath;
+
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_boolean_t remove_base;
+ svn_boolean_t is_root;
+};
+
+/* Transaction callback for svn_wc__db_temp_op_make_copy */
+static svn_error_t *
+make_copy_txn(void *baton,
+ svn_sqlite__db_t *sdb,
+ apr_pool_t *scratch_pool)
+{
+ struct make_copy_baton *mcb = baton;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ svn_boolean_t remove_working = FALSE;
+ svn_boolean_t check_base = TRUE;
+ svn_boolean_t add_working_normal = FALSE;
+ svn_boolean_t add_working_not_present = FALSE;
+ const apr_array_header_t *children;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ svn_wc__db_kind_t kind;
+ int i;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", mcb->pdh->wcroot->wc_id,
+ mcb->local_relpath));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ if (have_row)
+ {
+ svn_wc__db_status_t working_status;
+
+ working_status = svn_sqlite__column_token(stmt, 0, presence_map);
+ kind = svn_sqlite__column_token(stmt, 1, kind_map);
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ SVN_ERR_ASSERT(working_status == svn_wc__db_status_normal
+ || working_status == svn_wc__db_status_base_deleted
+ || working_status == svn_wc__db_status_not_present
+ || working_status == svn_wc__db_status_incomplete);
+
+ /* Make existing deletions of BASE_NODEs remove WORKING_NODEs */
+ if (working_status == svn_wc__db_status_base_deleted)
+ {
+ remove_working = TRUE;
+ add_working_not_present = TRUE;
+ }
+
+ check_base = FALSE;
+ }
+ else
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ if (check_base)
+ {
+ svn_wc__db_status_t base_status;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", mcb->pdh->wcroot->wc_id,
+ mcb->local_relpath));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ /* If there is no BASE_NODE, we don't have to copy anything */
+ if (!have_row)
+ return svn_error_return(svn_sqlite__reset(stmt));
+
+ base_status = svn_sqlite__column_token(stmt, 2, presence_map);
+ kind = svn_sqlite__column_token(stmt, 3, kind_map);
+
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ switch (base_status)
+ {
+ case svn_wc__db_status_normal:
+ case svn_wc__db_status_incomplete:
+ add_working_normal = TRUE;
+ break;
+ case svn_wc__db_status_not_present:
+ add_working_not_present = TRUE;
+ break;
+ case svn_wc__db_status_excluded:
+ case svn_wc__db_status_absent:
+ /* ### Make the copy match the WC or the repository? */
+ add_working_not_present = TRUE; /* ### Match WC */
+ break;
+ default:
+ SVN_ERR_MALFUNCTION();
+ }
+ }
+
+ /* Get the BASE children, as WORKING children don't need modifications */
+ SVN_ERR(svn_wc__db_base_get_children(&children, mcb->db, mcb->local_abspath,
+ scratch_pool, iterpool));
+
+ for (i = 0; i < children->nelts; i++)
+ {
+ const char *name = APR_ARRAY_IDX(children, i, const char *);
+ struct make_copy_baton cbt;
+
+ svn_pool_clear(iterpool);
+ cbt.local_abspath = svn_dirent_join(mcb->local_abspath, name, iterpool);
+
+ SVN_ERR(parse_local_abspath(&cbt.pdh, &cbt.local_relpath, mcb->db,
+ cbt.local_abspath,
+ svn_sqlite__mode_readwrite,
+ iterpool, iterpool));
+
+ VERIFY_USABLE_PDH(cbt.pdh);
+
+ cbt.db = mcb->db;
+ cbt.remove_base = mcb->remove_base;
+ cbt.is_root = FALSE;
+
+ SVN_ERR(make_copy_txn(&cbt, cbt.pdh->wcroot->sdb, iterpool));
+ }
+
+ if (remove_working)
+ {
+ /* Remove current WORKING_NODE record */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_DELETE_WORKING_NODE));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ mcb->pdh->wcroot->wc_id,
+ mcb->local_relpath));
+
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+
+ if (add_working_normal)
+ {
+ /* Add a copy of the BASE_NODE to WORKING_NODE */
+
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, sdb,
+ STMT_INSERT_WORKING_NODE_NORMAL_FROM_BASE_NODE));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ mcb->pdh->wcroot->wc_id,
+ mcb->local_relpath));
+
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+ else if (add_working_not_present)
+ {
+ /* Add a not present WORKING_NODE */
+
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, sdb,
+ STMT_INSERT_WORKING_NODE_NOT_PRESENT_FROM_BASE_NODE));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ mcb->pdh->wcroot->wc_id,
+ mcb->local_relpath));
+
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+
+ if (mcb->is_root && (add_working_normal || add_working_not_present))
+ {
+ const char *repos_relpath, *repos_root_url, *repos_uuid;
+ apr_int64_t repos_id;
+ /* Make sure the copy origin is set on the root even if the node
+ didn't have a local relpath */
+
+ SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath, &repos_root_url,
+ &repos_uuid, mcb->db,
+ mcb->local_abspath,
+ iterpool, iterpool));
+
+ SVN_ERR(create_repos_id(&repos_id, repos_root_url, repos_uuid, sdb,
+ iterpool));
+
+ /* ### this is not setting the COPYFROM_REVISION column!! */
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_UPDATE_COPYFROM));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isis",
+ mcb->pdh->wcroot->wc_id,
+ mcb->local_relpath,
+ repos_id,
+ repos_relpath));
+
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+
+ /* And now, do the same for the parent stub :( If we kind from the
+ working node could the base node be different? Not until we move
+ to a single db and then the parent stubs should go away. */
+ if (kind == svn_wc__db_kind_dir)
+ {
+ if (remove_working)
+ {
+ const char *local_relpath;
+ svn_wc__db_pdh_t *pdh;
+
+ /* Remove WORKING_NODE stub */
+ SVN_ERR(navigate_to_parent(&pdh, mcb->db, mcb->pdh,
+ svn_sqlite__mode_readwrite,
+ iterpool));
+ local_relpath = svn_dirent_basename(mcb->local_abspath, NULL);
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_DELETE_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+
+ if (add_working_normal)
+ {
+ const char *local_relpath;
+ svn_wc__db_pdh_t *pdh;
+
+ /* Add a copy of the BASE_NODE to WORKING_NODE for the stub */
+ SVN_ERR(navigate_to_parent(&pdh, mcb->db, mcb->pdh,
+ svn_sqlite__mode_readwrite,
+ iterpool));
+ local_relpath = svn_dirent_basename(mcb->local_abspath, NULL);
+ VERIFY_USABLE_PDH(pdh);
+
+ /* Remove old data */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_DELETE_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ /* And insert the right data */
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, pdh->wcroot->sdb,
+ STMT_INSERT_WORKING_NODE_NORMAL_FROM_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+ else if (add_working_not_present)
+ {
+ const char *local_relpath;
+ svn_wc__db_pdh_t *pdh;
+
+ /* Add a not present WORKING_NODE stub */
+ SVN_ERR(navigate_to_parent(&pdh, mcb->db, mcb->pdh,
+ svn_sqlite__mode_readwrite,
+ iterpool));
+ local_relpath = svn_dirent_basename(mcb->local_abspath, NULL);
+ VERIFY_USABLE_PDH(pdh);
+
+ /* Remove old data */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_DELETE_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ /* And insert the right data */
+ SVN_ERR(svn_sqlite__get_statement(
+ &stmt, pdh->wcroot->sdb,
+ STMT_INSERT_WORKING_NODE_NOT_PRESENT_FROM_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+ }
+
+ /* Remove the BASE_NODE if the caller asked us to do that */
+ if (mcb->remove_base)
+ {
+ const char *local_relpath;
+ svn_wc__db_pdh_t *pdh;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_DELETE_BASE_NODE));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ mcb->pdh->wcroot->wc_id,
+ mcb->local_relpath));
+
+ SVN_ERR(svn_sqlite__step_done(stmt));
+
+ /* Remove BASE_NODE_STUB */
+ if (kind == svn_wc__db_kind_dir)
+ {
+ SVN_ERR(navigate_to_parent(&pdh, mcb->db, mcb->pdh,
+ svn_sqlite__mode_readwrite,
+ iterpool));
+ local_relpath = svn_dirent_basename(mcb->local_abspath, NULL);
+ VERIFY_USABLE_PDH(pdh);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_DELETE_BASE_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is",
+ pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+
+ flush_entries(mcb->pdh);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_temp_op_make_copy(svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_boolean_t remove_base,
+ apr_pool_t *scratch_pool)
+{
+ struct make_copy_baton mcb;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(parse_local_abspath(&mcb.pdh, &mcb.local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(mcb.pdh);
+
+ mcb.db = db;
+ mcb.local_abspath = local_abspath;
+ mcb.remove_base = remove_base;
+ mcb.is_root = TRUE;
+
+ SVN_ERR(svn_sqlite__with_transaction(mcb.pdh->wcroot->sdb,
+ make_copy_txn, &mcb,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__db_temp_elide_copyfrom(svn_wc__db_t *db,
+ const char *local_abspath,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_pdh_t *pdh;
+ const char *local_relpath;
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ apr_int64_t original_repos_id;
+ const char *original_repos_relpath;
+ svn_revnum_t original_revision;
+ const char *parent_abspath;
+ const char *name;
+ svn_error_t *err;
+ const char *op_root_abspath;
+ const char *parent_repos_relpath;
+ const char *parent_uuid;
+ svn_revnum_t parent_revision;
+ const char *implied_relpath;
+ const char *original_uuid;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ SVN_ERR(parse_local_abspath(&pdh, &local_relpath, db, local_abspath,
+ svn_sqlite__mode_readwrite,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_PDH(pdh);
+
+ /* Examine the current WORKING_NODE row's copyfrom information. If there
+ is no WORKING node, then simply exit. */
+ SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+ STMT_SELECT_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (!have_row)
+ return svn_error_return(svn_sqlite__reset(stmt));
+
+ /* Already inheriting copyfrom information? */
+ if (svn_sqlite__column_is_null(stmt, 9 /* copyfrom_repos_id */))
+ return svn_error_return(svn_sqlite__reset(stmt));
+
+ original_repos_id = svn_sqlite__column_int64(stmt, 9);
+ original_repos_relpath = svn_sqlite__column_text(stmt, 10, scratch_pool);
+ original_revision = svn_sqlite__column_revnum(stmt, 11);
+
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ /* If this node is copied/moved, then there MUST be a parent. The above
+ copyfrom values cannot be set on a wcroot. */
+ svn_dirent_split(local_abspath, &parent_abspath, &name, scratch_pool);
+ err = svn_wc__db_scan_addition(NULL, &op_root_abspath, NULL, NULL, NULL,
+ &parent_repos_relpath,
+ NULL,
+ &parent_uuid,
[... 56 lines stripped ...]