Return-Path: X-Original-To: apmail-subversion-commits-archive@minotaur.apache.org Delivered-To: apmail-subversion-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 01E35DB61 for ; Sun, 6 Jan 2013 02:34:51 +0000 (UTC) Received: (qmail 49437 invoked by uid 500); 6 Jan 2013 02:34:50 -0000 Delivered-To: apmail-subversion-commits-archive@subversion.apache.org Received: (qmail 49397 invoked by uid 500); 6 Jan 2013 02:34:50 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 49388 invoked by uid 99); 6 Jan 2013 02:34:50 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 06 Jan 2013 02:34:50 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 06 Jan 2013 02:34:47 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 7E0AF2388BA6; Sun, 6 Jan 2013 02:33:55 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1429457 [11/21] - in /subversion/branches/tree-read-api: ./ build/ build/ac-macros/ build/generator/templates/ build/win32/ contrib/server-side/svncutter/ doc/ subversion/bindings/cxxhl/include/ subversion/bindings/cxxhl/include/svncxxhl/ ... Date: Sun, 06 Jan 2013 02:33:39 -0000 To: commits@subversion.apache.org From: julianfoad@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130106023355.7E0AF2388BA6@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c?rev=1429457&r1=1429456&r2=1429457&view=diff ============================================================================== --- subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c (original) +++ subversion/branches/tree-read-api/subversion/libsvn_wc/wc_db.c Sun Jan 6 02:33:34 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, @@ -342,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, @@ -383,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 * @@ -493,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, @@ -507,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. */ @@ -526,8 +496,6 @@ repos_location_from_columns(apr_int64_t *repos_relpath = svn_sqlite__column_text(stmt, col_repos_relpath, result_pool); } - - return err; } @@ -614,6 +582,12 @@ blank_ibb(insert_base_baton_t *pibb) /* Extend any delete of the parent of LOCAL_RELPATH to LOCAL_RELPATH. + ### What about KIND and OP_DEPTH? KIND ought to be redundant; I'm + discussing on dev@ whether we can let that be null for presence + == base-deleted. OP_DEPTH is the op-depth of what, and why? + It is used to select the lowest working node higher than OP_DEPTH, + so, in terms of the API, OP_DEPTH means ...? + Given a wc: 0 1 2 3 4 @@ -637,17 +611,19 @@ blank_ibb(insert_base_baton_t *pibb) 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. + When adding a node if the parent has a higher working node then the + parent node is deleted (or replaced) and the delete must be extended + to cover new 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; @@ -658,28 +634,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)); } } @@ -688,22 +665,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; @@ -711,7 +690,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, @@ -722,7 +703,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. */ @@ -748,7 +729,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)); } @@ -766,7 +747,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 */ @@ -790,10 +771,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)); @@ -850,13 +835,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)); } } @@ -879,12 +867,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) { @@ -987,7 +978,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, @@ -1013,7 +1006,7 @@ insert_working_node(void *baton, 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, @@ -1036,6 +1029,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)); @@ -1113,8 +1110,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; } @@ -1237,6 +1234,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. */ @@ -1390,25 +1422,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. */ @@ -1418,32 +1446,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)); @@ -1476,23 +1505,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; } @@ -2058,26 +2080,20 @@ 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_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; @@ -2087,14 +2103,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), @@ -2148,12 +2164,12 @@ db_base_remove(void *baton, if (node_kind == svn_kind_dir) SVN_ERR(svn_wc__wq_build_dir_remove(&work_item, - rb->db, wcroot->abspath, + db, wcroot->abspath, node_abspath, FALSE, iterpool, iterpool)); else SVN_ERR(svn_wc__wq_build_file_remove(&work_item, - rb->db, + db, wcroot->abspath, node_abspath, iterpool, iterpool)); @@ -2166,14 +2182,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)); @@ -2190,7 +2206,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, @@ -2229,7 +2245,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) @@ -2240,7 +2257,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); @@ -2249,7 +2266,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; @@ -2260,9 +2277,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; } @@ -2279,7 +2297,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)); @@ -2287,14 +2304,10 @@ 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, not_present_revision, + conflict, work_items, scratch_pool), + wcroot); /* If this used to be a directory we should remove children so pass * depth infinity. */ @@ -2319,6 +2332,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, @@ -2337,8 +2351,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) { @@ -2346,10 +2361,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) @@ -2377,12 +2392,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) @@ -2414,8 +2425,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); } } @@ -2447,6 +2475,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, @@ -2468,7 +2497,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); @@ -2509,7 +2538,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); @@ -2521,10 +2549,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); @@ -2557,32 +2583,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; } @@ -2697,6 +2715,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, @@ -2715,8 +2734,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) { @@ -2724,13 +2744,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) { @@ -2753,12 +2773,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) @@ -2790,6 +2806,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 { @@ -2804,11 +2836,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; @@ -2816,7 +2844,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, @@ -2895,6 +2929,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) { @@ -2907,6 +2943,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, @@ -2929,7 +2968,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) @@ -3246,25 +3285,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; @@ -3279,7 +3314,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)); @@ -3294,9 +3328,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; } @@ -3552,15 +3586,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 */ } } @@ -3781,7 +3814,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)); @@ -3802,15 +3835,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, @@ -3820,7 +3882,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 @@ -4070,7 +4211,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; @@ -4085,10 +4226,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; @@ -4191,7 +4335,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); @@ -4361,10 +4506,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; @@ -4408,7 +4555,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)); @@ -4474,162 +4622,33 @@ 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. */ static svn_error_t * catch_copy_of_server_excluded(svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *scratch_pool) -{ - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - const char *server_excluded_relpath; - - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_HAS_SERVER_EXCLUDED_DESCENDANTS)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", - wcroot->wc_id, - local_relpath)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - if (have_row) - server_excluded_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool); - SVN_ERR(svn_sqlite__reset(stmt)); - 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 *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; + const char *server_excluded_relpath; 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)); + STMT_HAS_SERVER_EXCLUDED_DESCENDANTS)); + 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; - } + server_excluded_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_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_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; } @@ -4868,6 +4887,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) { @@ -4891,6 +4911,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; @@ -4908,6 +4933,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) { @@ -4931,6 +4957,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; @@ -4946,6 +4977,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) { @@ -4972,6 +5004,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; @@ -4984,13 +5021,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, @@ -5004,7 +5042,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); @@ -5016,8 +5054,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; @@ -5030,8 +5068,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)); @@ -5042,18 +5080,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, @@ -5085,18 +5117,23 @@ 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 @@ -5104,31 +5141,32 @@ set_props_txn(void *baton, ACTUAL props are okay as provided, so go ahead and set them. */ 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; } @@ -5143,7 +5181,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; @@ -5153,77 +5190,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, @@ -5400,7 +5373,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, @@ -5458,7 +5433,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, svn_wc__db_wcroot_t *wcroot, @@ -5554,11 +5531,11 @@ svn_wc__db_op_set_changelist(svn_wc__db_ } /* Implementation of svn_wc__db_op_mark_conflict() */ -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) +svn_error_t * +svn_wc__db_mark_conflict_internal(svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + const svn_skel_t *conflict_skel, + apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; svn_boolean_t got_row; @@ -5617,7 +5594,8 @@ svn_wc__db_op_mark_conflict(svn_wc__db_t local_abspath, scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - SVN_ERR(mark_conflict(wcroot, local_relpath, conflict_skel, scratch_pool)); + SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath, + conflict_skel, scratch_pool)); /* ### Should be handled in the same transaction as setting the conflict */ if (work_items) @@ -5629,24 +5607,18 @@ svn_wc__db_op_mark_conflict(svn_wc__db_t } -/* Baton for db_op_mark_resolved */ -struct op_mark_resolved_baton -{ - svn_boolean_t resolved_text; - svn_boolean_t resolved_props; - svn_boolean_t resolved_tree; - const svn_skel_t *work_items; - svn_wc__db_t *db; -}; - -/* Helper for svn_wc__db_op_mark_resolved */ +/* The body of svn_wc__db_op_mark_resolved(). + */ static svn_error_t * -db_op_mark_resolved(void *baton, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *scratch_pool) +db_op_mark_resolved(svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + svn_wc__db_t *db, + svn_boolean_t resolved_text, + svn_boolean_t resolved_props, + svn_boolean_t resolved_tree, + const svn_skel_t *work_items, + apr_pool_t *scratch_pool) { - struct op_mark_resolved_baton *rb = baton; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; int total_affected_rows = 0; @@ -5690,10 +5662,10 @@ db_op_mark_resolved(void *baton, SVN_ERR(svn_sqlite__reset(stmt)); SVN_ERR(svn_wc__conflict_skel_resolve(&resolved_all, conflicts, - rb->db, wcroot->abspath, - rb->resolved_text, - rb->resolved_props ? "" : NULL, - rb->resolved_tree, + db, wcroot->abspath, + resolved_text, + resolved_props ? "" : NULL, + resolved_tree, scratch_pool, scratch_pool)); SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, @@ -5719,7 +5691,7 @@ db_op_mark_resolved(void *baton, 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)); return SVN_NO_ERROR; } @@ -5735,7 +5707,6 @@ svn_wc__db_op_mark_resolved(svn_wc__db_t { svn_wc__db_wcroot_t *wcroot; const char *local_relpath; - struct op_mark_resolved_baton rb; SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); @@ -5743,14 +5714,11 @@ svn_wc__db_op_mark_resolved(svn_wc__db_t local_abspath, scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - rb.resolved_props = resolved_props; - rb.resolved_text = resolved_text; - rb.resolved_tree = resolved_tree; - rb.work_items = work_items; - rb.db = db; - - SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, db_op_mark_resolved, - &rb, scratch_pool)); + SVN_WC__DB_WITH_TXN( + db_op_mark_resolved(wcroot, local_relpath, db, + resolved_text, resolved_props, resolved_tree, + work_items, scratch_pool), + wcroot); SVN_ERR(flush_entries(wcroot, local_abspath, svn_depth_empty, scratch_pool)); return SVN_NO_ERROR; @@ -5782,14 +5750,17 @@ clear_moved_to(const char *local_relpath SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_CLEAR_MOVED_TO_RELPATH)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, - moved_from_relpath)); + SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, + moved_from_relpath, + relpath_depth(moved_from_relpath))); SVN_ERR(svn_sqlite__step_done(stmt)); return SVN_NO_ERROR; } -/* This implements svn_wc__db_txn_callback_t */ +/* One of the two alternative bodies of svn_wc__db_op_revert(). + * + * Implements svn_wc__db_txn_callback_t. */ static svn_error_t * op_revert_txn(void *baton, svn_wc__db_wcroot_t *wcroot, @@ -5906,7 +5877,9 @@ op_revert_txn(void *baton, } -/* This implements svn_wc__db_txn_callback_t */ +/* One of the two alternative bodies of svn_wc__db_op_revert(). + * + * Implements svn_wc__db_txn_callback_t. */ static svn_error_t * op_revert_recursive_txn(void *baton, svn_wc__db_wcroot_t *wcroot, @@ -6066,29 +6039,26 @@ svn_wc__db_op_revert(svn_wc__db_t *db, return SVN_NO_ERROR; } -struct revert_list_read_baton { - svn_boolean_t *reverted; - apr_array_header_t *marker_paths; - svn_boolean_t *copied_here; - svn_kind_t *kind; - apr_pool_t *result_pool; - svn_wc__db_t *db; -}; - +/* The body of svn_wc__db_revert_list_read(). + */ static svn_error_t * -revert_list_read(void *baton, +revert_list_read(svn_boolean_t *reverted, + const apr_array_header_t **marker_paths, + svn_boolean_t *copied_here, + svn_kind_t *kind, svn_wc__db_wcroot_t *wcroot, const char *local_relpath, + svn_wc__db_t *db, + apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - struct revert_list_read_baton *b = baton; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - *(b->reverted) = FALSE; - b->marker_paths = NULL; - *(b->copied_here) = FALSE; - *(b->kind) = svn_kind_unknown; + *reverted = FALSE; + *marker_paths = NULL; + *copied_here = FALSE; + *kind = svn_kind_unknown; SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_REVERT_LIST)); @@ -6108,35 +6078,32 @@ revert_list_read(void *baton, scratch_pool); if (conflict_data) { - const apr_array_header_t *marker_paths; svn_skel_t *conflicts = svn_skel__parse(conflict_data, conflict_len, scratch_pool); - SVN_ERR(svn_wc__conflict_read_markers(&marker_paths, - b->db, wcroot->abspath, + SVN_ERR(svn_wc__conflict_read_markers(marker_paths, + db, wcroot->abspath, conflicts, - b->result_pool, + result_pool, scratch_pool)); - /* De-const-ify. */ - b->marker_paths = (apr_array_header_t *)marker_paths; } if (!svn_sqlite__column_is_null(stmt, 1)) /* notify */ - *(b->reverted) = TRUE; + *reverted = TRUE; SVN_ERR(svn_sqlite__step(&another_row, stmt)); } if (!is_actual || another_row) { - *(b->reverted) = TRUE; + *reverted = TRUE; if (!svn_sqlite__column_is_null(stmt, 4)) /* repos_id */ { int op_depth = svn_sqlite__column_int(stmt, 3); - *(b->copied_here) = (op_depth == relpath_depth(local_relpath)); + *copied_here = (op_depth == relpath_depth(local_relpath)); } - *(b->kind) = svn_sqlite__column_token(stmt, 2, kind_map); + *kind = svn_sqlite__column_token(stmt, 2, kind_map); } } @@ -6165,43 +6132,35 @@ svn_wc__db_revert_list_read(svn_boolean_ { svn_wc__db_wcroot_t *wcroot; const char *local_relpath; - struct revert_list_read_baton b; - - b.reverted = reverted; - b.copied_here = copied_here; - b.kind = kind; - b.result_pool = result_pool; - b.db = db; SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, local_abspath, scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, revert_list_read, &b, - scratch_pool)); - *marker_files = b.marker_paths; + SVN_WC__DB_WITH_TXN( + revert_list_read(reverted, marker_files, copied_here, kind, + wcroot, local_relpath, db, + result_pool, scratch_pool), + wcroot); return SVN_NO_ERROR; } -struct revert_list_read_copied_children_baton { - const apr_array_header_t **children; - apr_pool_t *result_pool; -}; - +/* The body of svn_wc__db_revert_list_read_copied_children(). + */ static svn_error_t * -revert_list_read_copied_children(void *baton, - svn_wc__db_wcroot_t *wcroot, +revert_list_read_copied_children(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, + const apr_array_header_t **children_p, + apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - struct revert_list_read_copied_children_baton *b = baton; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; apr_array_header_t *children; children = - apr_array_make(b->result_pool, 0, + apr_array_make(result_pool, 0, sizeof(svn_wc__db_revert_list_copied_child_info_t *)); SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, @@ -6214,11 +6173,11 @@ revert_list_read_copied_children(void *b svn_wc__db_revert_list_copied_child_info_t *child_info; const char *child_relpath; - child_info = apr_palloc(b->result_pool, sizeof(*child_info)); + child_info = apr_palloc(result_pool, sizeof(*child_info)); child_relpath = svn_sqlite__column_text(stmt, 0, NULL); child_info->abspath = svn_dirent_join(wcroot->abspath, child_relpath, - b->result_pool); + result_pool); child_info->kind = svn_sqlite__column_token(stmt, 1, kind_map); APR_ARRAY_PUSH( children, @@ -6228,7 +6187,7 @@ revert_list_read_copied_children(void *b } SVN_ERR(svn_sqlite__reset(stmt)); - *b->children = children; + *children_p = children; return SVN_NO_ERROR; } @@ -6243,18 +6202,15 @@ svn_wc__db_revert_list_read_copied_child { svn_wc__db_wcroot_t *wcroot; const char *local_relpath; - struct revert_list_read_copied_children_baton b; - - b.children = children; - b.result_pool = result_pool; SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, local_abspath, scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - SVN_ERR(svn_wc__db_with_txn(wcroot, local_relpath, - revert_list_read_copied_children, &b, - scratch_pool)); + SVN_WC__DB_WITH_TXN( + revert_list_read_copied_children(wcroot, local_relpath, children, + result_pool, scratch_pool), + wcroot); return SVN_NO_ERROR; } @@ -6327,30 +6283,24 @@ svn_wc__db_revert_list_done(svn_wc__db_t return SVN_NO_ERROR; } -/* Baton for remove_node_txn */ -struct remove_node_baton -{ - svn_wc__db_t *db; - svn_boolean_t left_changes; - svn_boolean_t destroy_wc; - svn_boolean_t destroy_changes; - svn_revnum_t not_present_rev; - svn_wc__db_status_t not_present_status; - svn_kind_t not_present_kind; - const svn_skel_t *conflict; - const svn_skel_t *work_items; - svn_cancel_func_t cancel_func; - void *cancel_baton; -}; - -/* Implements svn_wc__db_txn_callback_t for svn_wc__db_op_remove_node */ +/* The body of svn_wc__db_op_remove_node(). + */ static svn_error_t * -remove_node_txn(void *baton, +remove_node_txn(svn_boolean_t *left_changes, svn_wc__db_wcroot_t *wcroot, const char *local_relpath, + svn_wc__db_t *db, + svn_boolean_t destroy_wc, + svn_boolean_t destroy_changes, + svn_revnum_t not_present_rev, + svn_wc__db_status_t not_present_status, + svn_kind_t not_present_kind, + const svn_skel_t *conflict, + const svn_skel_t *work_items, + svn_cancel_func_t cancel_func, + void *cancel_baton, apr_pool_t *scratch_pool) { - struct remove_node_baton *rnb = baton; svn_sqlite__stmt_t *stmt; apr_int64_t repos_id; @@ -6360,19 +6310,22 @@ remove_node_txn(void *baton, function to be called on a wcroot! */ /* db set when destroying wc */ - SVN_ERR_ASSERT(!rnb->destroy_wc || rnb->db != NULL); + SVN_ERR_ASSERT(!destroy_wc || db != NULL); + + if (left_changes) + *left_changes = FALSE; /* Need info for not_present node? */ - if (SVN_IS_VALID_REVNUM(rnb->not_present_rev)) + if (SVN_IS_VALID_REVNUM(not_present_rev)) SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, 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 (rnb->destroy_wc - && (!rnb->destroy_changes || *local_relpath == '\0')) + if (destroy_wc + && (!destroy_changes || *local_relpath == '\0')) { svn_boolean_t have_row; apr_pool_t *iterpool; @@ -6395,7 +6348,7 @@ remove_node_txn(void *baton, svn_kind_t child_kind; svn_boolean_t have_checksum; svn_filesize_t recorded_size; - apr_int64_t recorded_mod_time; + apr_int64_t recorded_time; const svn_io_dirent2_t *dirent; svn_boolean_t modified_p = TRUE; svn_skel_t *work_item = NULL; @@ -6412,11 +6365,11 @@ remove_node_txn(void *baton, { have_checksum = !svn_sqlite__column_is_null(stmt, 2); recorded_size = get_recorded_size(stmt, 3); - recorded_mod_time = svn_sqlite__column_int64(stmt, 4); + recorded_time = svn_sqlite__column_int64(stmt, 4); } - if (rnb->cancel_func) - err = rnb->cancel_func(rnb->cancel_baton); + if (cancel_func) + err = cancel_func(cancel_baton); if (err) break; @@ -6427,7 +6380,7 @@ remove_node_txn(void *baton, if (err) break; - if (rnb->destroy_changes + if (destroy_changes || dirent->kind != svn_node_file || child_kind != svn_kind_file) { @@ -6437,31 +6390,34 @@ remove_node_txn(void *baton, else if (child_kind == svn_kind_file && dirent->kind == svn_node_file && dirent->filesize == recorded_size - && dirent->mtime == recorded_mod_time) + && dirent->mtime == recorded_time) { modified_p = FALSE; /* File matches recorded state */ } else if (have_checksum) err = svn_wc__internal_file_modified_p(&modified_p, - rnb->db, child_abspath, + db, child_abspath, FALSE, iterpool); if (err) break; if (modified_p) - rnb->left_changes = TRUE; + { + if (left_changes) + *left_changes = TRUE; + } else if (child_kind == svn_kind_dir) { err = svn_wc__wq_build_dir_remove(&work_item, - rnb->db, wcroot->abspath, + db, wcroot->abspath, child_abspath, FALSE, iterpool, iterpool); } else /* svn_kind_file || svn_kind_symlink */ { err = svn_wc__wq_build_file_remove(&work_item, - rnb->db, wcroot->abspath, + db, wcroot->abspath, child_abspath, iterpool, iterpool); } @@ -6483,7 +6439,7 @@ remove_node_txn(void *baton, SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt))); } - if (rnb->destroy_wc && *local_relpath != '\0') + if (destroy_wc && *local_relpath != '\0') { /* Create work item for destroying the root */ svn_wc__db_status_t status; @@ -6506,9 +6462,9 @@ remove_node_txn(void *baton, if (kind == svn_kind_dir) { SVN_ERR(svn_wc__wq_build_dir_remove(&work_item, - rnb->db, wcroot->abspath, + db, wcroot->abspath, local_abspath, - rnb->destroy_changes + destroy_changes /* recursive */, scratch_pool, scratch_pool)); } @@ -6516,23 +6472,25 @@ remove_node_txn(void *baton, { svn_boolean_t modified_p = FALSE; - if (!rnb->destroy_changes) + if (!destroy_changes) { SVN_ERR(svn_wc__internal_file_modified_p(&modified_p, - rnb->db, - local_abspath, + db, local_abspath, FALSE, scratch_pool)); } if (!modified_p) SVN_ERR(svn_wc__wq_build_file_remove(&work_item, - rnb->db, wcroot->abspath, + db, wcroot->abspath, local_abspath, scratch_pool, scratch_pool)); else - rnb->left_changes = TRUE; + { + if (left_changes) + *left_changes = TRUE; + } [... 3063 lines stripped ...]