Modified: subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.c URL: http://svn.apache.org/viewvc/subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.c?rev=1662177&r1=1662176&r2=1662177&view=diff ============================================================================== --- subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.c (original) +++ subversion/branches/reuse-ra-session/subversion/libsvn_wc/wc_db.c Wed Feb 25 08:15:39 2015 @@ -278,10 +278,9 @@ add_work_items(svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool); static svn_error_t * -set_actual_props(apr_int64_t wc_id, +set_actual_props(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, apr_hash_t *props, - svn_sqlite__db_t *db, apr_pool_t *scratch_pool); static svn_error_t * @@ -487,35 +486,6 @@ repos_location_from_columns(apr_int64_t } } - -/* Get the statement given by STMT_IDX, and bind the appropriate wc_id and - local_relpath based upon LOCAL_ABSPATH. Store it in *STMT, and use - SCRATCH_POOL for temporary allocations. - - Note: WC_ID and LOCAL_RELPATH must be arguments 1 and 2 in the statement. */ -static svn_error_t * -get_statement_for_path(svn_sqlite__stmt_t **stmt, - svn_wc__db_t *db, - const char *local_abspath, - int stmt_idx, - apr_pool_t *scratch_pool) -{ - svn_wc__db_wcroot_t *wcroot; - const char *local_relpath; - - SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); - - SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, - local_abspath, scratch_pool, scratch_pool)); - VERIFY_USABLE_WCROOT(wcroot); - - SVN_ERR(svn_sqlite__get_statement(stmt, wcroot->sdb, stmt_idx)); - SVN_ERR(svn_sqlite__bindf(*stmt, "is", wcroot->wc_id, local_relpath)); - - return SVN_NO_ERROR; -} - - /* For a given REPOS_ROOT_URL/REPOS_UUID pair, return the existing REPOS_ID value. If one does not exist, then create a new one. */ static svn_error_t * @@ -611,8 +581,7 @@ blank_ibb(insert_base_baton_t *pibb) was recorded, otherwise to FALSE. */ static svn_error_t * -db_extend_parent_delete(svn_boolean_t *added_delete, - svn_wc__db_wcroot_t *wcroot, +db_extend_parent_delete(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, svn_node_kind_t kind, int op_depth, @@ -625,9 +594,6 @@ db_extend_parent_delete(svn_boolean_t *a SVN_ERR_ASSERT(local_relpath[0]); - if (added_delete) - *added_delete = FALSE; - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_LOWEST_WORKING_NODE)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, parent_relpath, @@ -654,9 +620,6 @@ db_extend_parent_delete(svn_boolean_t *a local_relpath, parent_op_depth, parent_relpath, kind_map, kind)); SVN_ERR(svn_sqlite__update(NULL, stmt)); - - if (added_delete) - *added_delete = TRUE; } } @@ -750,6 +713,7 @@ insert_base_node(const insert_base_baton svn_sqlite__stmt_t *stmt; svn_filesize_t recorded_size = SVN_INVALID_FILESIZE; apr_int64_t recorded_time; + svn_boolean_t present; /* The directory at the WCROOT has a NULL parent_relpath. Otherwise, bind the appropriate parent_relpath. */ @@ -780,6 +744,9 @@ insert_base_node(const insert_base_baton SVN_ERR(svn_sqlite__reset(stmt)); } + present = (pibb->status == svn_wc__db_status_normal + || pibb->status == svn_wc__db_status_incomplete); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE)); SVN_ERR(svn_sqlite__bindf(stmt, "isdsisr" "tstr" /* 8 - 11 */ @@ -792,15 +759,16 @@ insert_base_node(const insert_base_baton pibb->repos_relpath, pibb->revision, presence_map, pibb->status, /* 8 */ - (pibb->kind == svn_node_dir) ? /* 9 */ - svn_token__to_word(depth_map, pibb->depth) : NULL, + (pibb->kind == svn_node_dir && present) /* 9 */ + ? svn_token__to_word(depth_map, pibb->depth) + : NULL, kind_map, pibb->kind, /* 10 */ pibb->changed_rev, /* 11 */ pibb->changed_date, /* 12 */ pibb->changed_author, /* 13 */ - (pibb->kind == svn_node_symlink) ? + (pibb->kind == svn_node_symlink && present) ? pibb->target : NULL)); /* 19 */ - if (pibb->kind == svn_node_file) + if (pibb->kind == svn_node_file && present) { if (!pibb->checksum && pibb->status != svn_wc__db_status_not_present @@ -825,11 +793,14 @@ insert_base_node(const insert_base_baton 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)); + if (present) + { + SVN_ERR(svn_sqlite__bind_properties(stmt, 15, pibb->props, + scratch_pool)); - SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, pibb->iprops, + SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, pibb->iprops, scratch_pool)); + } if (pibb->dav_cache) SVN_ERR(svn_sqlite__bind_properties(stmt, 18, pibb->dav_cache, @@ -859,8 +830,8 @@ insert_base_node(const insert_base_baton new_actual_props = NULL; } - SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, new_actual_props, - wcroot->sdb, scratch_pool)); + SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props, + scratch_pool)); } if (pibb->kind == svn_node_dir && pibb->children) @@ -881,8 +852,7 @@ insert_base_node(const insert_base_baton || (pibb->status == svn_wc__db_status_incomplete)) && ! pibb->file_external) { - SVN_ERR(db_extend_parent_delete(NULL, - wcroot, local_relpath, + SVN_ERR(db_extend_parent_delete(wcroot, local_relpath, pibb->kind, 0, scratch_pool)); } @@ -1035,6 +1005,7 @@ insert_working_node(const insert_working const char *moved_to_relpath = NULL; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; + svn_boolean_t present; SVN_ERR_ASSERT(piwb->op_depth > 0); @@ -1053,6 +1024,9 @@ insert_working_node(const insert_working moved_to_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool); SVN_ERR(svn_sqlite__reset(stmt)); + present = (piwb->presence == svn_wc__db_status_normal + || piwb->presence == svn_wc__db_status_incomplete); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_INSERT_NODE)); SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnntstrisn" "nnnn" /* properties translated_size last_mod_time dav_cache */ @@ -1061,14 +1035,14 @@ insert_working_node(const insert_working piwb->op_depth, parent_relpath, presence_map, piwb->presence, - (piwb->kind == svn_node_dir) + (piwb->kind == svn_node_dir && present) ? svn_token__to_word(depth_map, piwb->depth) : NULL, kind_map, piwb->kind, piwb->changed_rev, piwb->changed_date, piwb->changed_author, /* Note: incomplete nodes may have a NULL target. */ - (piwb->kind == svn_node_symlink) + (piwb->kind == svn_node_symlink && present) ? piwb->target : NULL, moved_to_relpath)); @@ -1077,7 +1051,7 @@ insert_working_node(const insert_working SVN_ERR(svn_sqlite__bind_int(stmt, 8, TRUE)); } - if (piwb->kind == svn_node_file) + if (piwb->kind == svn_node_file && present) { SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, piwb->checksum, scratch_pool)); @@ -1094,7 +1068,8 @@ insert_working_node(const insert_working 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)); + if (present && piwb->original_repos_relpath) + SVN_ERR(svn_sqlite__bind_properties(stmt, 15, piwb->props, scratch_pool)); SVN_ERR(svn_sqlite__insert(NULL, stmt)); @@ -1131,8 +1106,8 @@ insert_working_node(const insert_working new_actual_props = NULL; } - SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, new_actual_props, - wcroot->sdb, scratch_pool)); + SVN_ERR(set_actual_props(wcroot, local_relpath, new_actual_props, + scratch_pool)); } if (piwb->kind == svn_node_dir) @@ -1178,119 +1153,40 @@ insert_working_node(const insert_working } -/* Each name is allocated in RESULT_POOL and stored into CHILDREN as a key - pointed to the same name. */ -static svn_error_t * -add_children_to_hash(apr_hash_t *children, - int stmt_idx, - svn_sqlite__db_t *sdb, - apr_int64_t wc_id, - const char *parent_relpath, - apr_pool_t *result_pool) -{ - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, stmt_idx)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, parent_relpath)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - while (have_row) - { - const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL); - const char *name = svn_relpath_basename(child_relpath, result_pool); - - svn_hash_sets(children, name, name); - - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - } - - return svn_sqlite__reset(stmt); -} - - -/* Set *CHILDREN to a new array of the (const char *) basenames of the - immediate children, whatever their status, of the working node at - LOCAL_RELPATH. */ -static svn_error_t * -gather_children2(const apr_array_header_t **children, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - apr_hash_t *names_hash = apr_hash_make(scratch_pool); - apr_array_header_t *names_array; - - /* All of the names get allocated in RESULT_POOL. It - appears to be faster to use the hash to remove duplicates than to - use DISTINCT in the SQL query. */ - SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_WORKING_CHILDREN, - wcroot->sdb, wcroot->wc_id, - local_relpath, result_pool)); - - SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool)); - *children = names_array; - return SVN_NO_ERROR; -} - /* Return in *CHILDREN all of the children of the directory LOCAL_RELPATH, of any status, in all op-depths in the NODES table. */ static svn_error_t * gather_children(const apr_array_header_t **children, svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, + const char *parent_relpath, + int stmt_idx, + int op_depth, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - apr_hash_t *names_hash = apr_hash_make(scratch_pool); - apr_array_header_t *names_array; - - /* All of the names get allocated in RESULT_POOL. It - appears to be faster to use the hash to remove duplicates than to - use DISTINCT in the SQL query. */ - SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_NODE_CHILDREN, - wcroot->sdb, wcroot->wc_id, - local_relpath, result_pool)); - - SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool)); - *children = names_array; - return SVN_NO_ERROR; -} - - -/* Set *CHILDREN to a new array of (const char *) names of the children of - the repository directory corresponding to WCROOT:LOCAL_RELPATH:OP_DEPTH - - that is, only the children that are at the same op-depth as their parent. */ -static svn_error_t * -gather_repo_children(const apr_array_header_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) -{ - apr_array_header_t *result - = apr_array_make(result_pool, 0, sizeof(const char *)); + apr_array_header_t *result; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - 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)); + result = apr_array_make(result_pool, 16, sizeof(const char*)); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, stmt_idx)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, parent_relpath)); + if (op_depth >= 0) + SVN_ERR(svn_sqlite__bind_int(stmt, 3, op_depth)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); while (have_row) { const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL); + const char *name = svn_relpath_basename(child_relpath, result_pool); - /* Allocate the name in RESULT_POOL so we won't have to copy it. */ - APR_ARRAY_PUSH(result, const char *) - = svn_relpath_basename(child_relpath, result_pool); + APR_ARRAY_PUSH(result, const char *) = name; SVN_ERR(svn_sqlite__step(&have_row, stmt)); } - SVN_ERR(svn_sqlite__reset(stmt)); + SVN_ERR(svn_sqlite__reset(stmt)); *children = result; return SVN_NO_ERROR; } @@ -1585,7 +1481,7 @@ svn_wc__db_init(svn_wc__db_t *db, /* ### REPOS_ROOT_URL and REPOS_UUID may be NULL. ... more doc: tbd */ - SVN_ERR(svn_config_get_bool((svn_config_t *)db->config, &sqlite_exclusive, + SVN_ERR(svn_config_get_bool(db->config, &sqlite_exclusive, SVN_CONFIG_SECTION_WORKING_COPY, SVN_CONFIG_OPTION_SQLITE_EXCLUSIVE, FALSE)); @@ -2177,7 +2073,7 @@ clear_moved_here(svn_wc__db_wcroot_t *wc svn_error_t * svn_wc__db_op_break_move_internal(svn_wc__db_wcroot_t *wcroot, const char *src_relpath, - int src_op_depth, + int delete_op_depth, const char *dst_relpath, const svn_skel_t *work_items, apr_pool_t *scratch_pool) @@ -2188,7 +2084,7 @@ svn_wc__db_op_break_move_internal(svn_wc SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_CLEAR_MOVED_TO_RELPATH)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, src_relpath, - src_op_depth)); + delete_op_depth)); SVN_ERR(svn_sqlite__update(&affected, stmt)); if (affected != 1) @@ -2211,9 +2107,9 @@ db_base_remove(svn_wc__db_wcroot_t *wcro const char *local_relpath, svn_wc__db_t *db, /* For checking conflicts */ svn_boolean_t keep_as_working, - svn_boolean_t queue_deletes, - svn_boolean_t remove_locks, - svn_revnum_t not_present_revision, + svn_boolean_t mark_not_present, + svn_boolean_t mark_excluded, + svn_revnum_t marker_revision, svn_skel_t *conflict, svn_skel_t *work_items, apr_pool_t *scratch_pool) @@ -2221,66 +2117,80 @@ db_base_remove(svn_wc__db_wcroot_t *wcro svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; svn_wc__db_status_t status; + svn_revnum_t revision; apr_int64_t repos_id; const char *repos_relpath; svn_node_kind_t kind; svn_boolean_t keep_working; + int op_depth; + svn_node_kind_t wrk_kind; + svn_boolean_t no_delete_wc = FALSE; - SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, NULL, + SVN_ERR(svn_wc__db_base_get_info_internal(&status, &kind, &revision, &repos_relpath, &repos_id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, wcroot, local_relpath, scratch_pool, scratch_pool)); - if (remove_locks) - { - svn_sqlite__stmt_t *lock_stmt; + /* Check if there is already a working node */ + 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(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb, - STMT_DELETE_LOCK_RECURSIVELY)); - SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath)); - SVN_ERR(svn_sqlite__step_done(lock_stmt)); - } + if (!have_row) + return svn_error_trace(svn_sqlite__reset(stmt)); /* No BASE */ + + op_depth = svn_sqlite__column_int(stmt, 0); + wrk_kind = svn_sqlite__column_token(stmt, 4, kind_map); - if (status == svn_wc__db_status_normal - && keep_as_working) + if (op_depth > 0 + && op_depth == relpath_depth(local_relpath)) { - SVN_ERR(svn_wc__db_op_make_copy(db, - svn_dirent_join(wcroot->abspath, - local_relpath, - scratch_pool), - NULL, NULL, - scratch_pool)); - keep_working = TRUE; + svn_wc__db_status_t presence; + presence = svn_sqlite__column_token(stmt, 3, presence_map); + + if (presence == svn_wc__db_status_base_deleted) + { + keep_working = FALSE; + no_delete_wc = TRUE; + } + else + { + keep_working = TRUE; + } } else + keep_working = FALSE; + SVN_ERR(svn_sqlite__reset(stmt)); + + if (keep_as_working && op_depth == 0) { - /* Check if there is already a working node */ - 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(&keep_working, stmt)); - SVN_ERR(svn_sqlite__reset(stmt)); + if (status == svn_wc__db_status_normal + || status == svn_wc__db_status_incomplete) + { + SVN_ERR(svn_wc__db_op_make_copy_internal(wcroot, local_relpath, TRUE, + NULL, NULL, + scratch_pool)); + } + keep_working = TRUE; } /* Step 1: Create workqueue operations to remove files and dirs in the local-wc */ - if (!keep_working - && queue_deletes - && (status == svn_wc__db_status_normal - || status == svn_wc__db_status_incomplete)) + if (!keep_working && !no_delete_wc) { svn_skel_t *work_item; const char *local_abspath; local_abspath = svn_dirent_join(wcroot->abspath, local_relpath, scratch_pool); - if (kind == svn_node_dir) + if (wrk_kind == svn_node_dir) { apr_pool_t *iterpool; SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_SELECT_BASE_PRESENT)); + STMT_SELECT_WORKING_PRESENT)); SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); iterpool = svn_pool_create(scratch_pool); @@ -2359,27 +2269,12 @@ db_base_remove(svn_wc__db_wcroot_t *wcro ACTUAL_NODE records */ /* Step 3: Delete WORKING nodes */ - if (conflict) + if (!keep_working) { apr_pool_t *iterpool; - /* - * When deleting a conflicted node, moves of any moved-outside children - * of the node must be broken. Else, the destination will still be marked - * moved-here after the move source disappears from the working copy. - * - * ### FIXME: It would be nicer to have the conflict resolver - * break the move instead. It might also be a good idea to - * flag a tree conflict on each moved-away child. But doing so - * might introduce actual-only nodes without direct parents, - * and we're not yet sure if other existing code is prepared - * to handle such nodes. To be revisited post-1.8. - * - * ### In case of a conflict we are most likely creating WORKING nodes - * describing a copy of what was in BASE. The move information - * should be updated to describe a move from the WORKING layer. - * When stored that way the resolver of the tree conflict still has - * the knowledge of what was moved. + /* When deleting everything in working we should break moves from + here and to here. */ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_OUTSIDE)); @@ -2403,10 +2298,51 @@ db_base_remove(svn_wc__db_wcroot_t *wcro svn_pool_destroy(iterpool); SVN_ERR(svn_sqlite__reset(stmt)); } - if (keep_working) + else { + /* We are keeping things that are in WORKING, but we should still + break moves of things in BASE. (Mixed revisions make it + impossible to guarantee that we can keep everything moved) */ + + apr_pool_t *iterpool; + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_DELETE_WORKING_BASE_DELETE)); + STMT_SELECT_MOVED_DESCENDANTS_SRC)); + SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, + local_relpath, 0)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + iterpool = svn_pool_create(scratch_pool); + while (have_row) + { + int delete_op_depth = svn_sqlite__column_int(stmt, 0); + const char *src_relpath; + const char *dst_relpath; + svn_error_t *err; + + svn_pool_clear(iterpool); + + src_relpath = svn_sqlite__column_text(stmt, 1, iterpool); + dst_relpath = svn_sqlite__column_text(stmt, 4, iterpool); + + err = svn_wc__db_op_break_move_internal(wcroot, src_relpath, + delete_op_depth, + dst_relpath, + NULL, + iterpool); + + if (err) + return svn_error_compose_create(err, svn_sqlite__reset(stmt)); + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + } + svn_pool_destroy(iterpool); + SVN_ERR(svn_sqlite__reset(stmt)); + } + if (keep_working) + { + SVN_ERR(svn_sqlite__get_statement( + &stmt, wcroot->sdb, + STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE)); SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath, 0)); SVN_ERR(svn_sqlite__step_done(stmt)); } @@ -2432,25 +2368,19 @@ db_base_remove(svn_wc__db_wcroot_t *wcro SVN_ERR(db_retract_parent_delete(wcroot, local_relpath, 0, scratch_pool)); - /* Step 6: Delete actual node if we don't keep working */ - if (! keep_working) - { - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_DELETE_ACTUAL_NODE)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); - SVN_ERR(svn_sqlite__step_done(stmt)); - } - - if (SVN_IS_VALID_REVNUM(not_present_revision)) + if (mark_not_present || mark_excluded) { struct insert_base_baton_t ibb; blank_ibb(&ibb); ibb.repos_id = repos_id; - ibb.status = svn_wc__db_status_not_present; + ibb.status = mark_excluded ? svn_wc__db_status_excluded + : svn_wc__db_status_not_present; ibb.kind = kind; ibb.repos_relpath = repos_relpath; - ibb.revision = not_present_revision; + ibb.revision = SVN_IS_VALID_REVNUM(marker_revision) + ? marker_revision + : revision; /* Depending upon KIND, any of these might get used. */ ibb.children = NULL; @@ -2474,9 +2404,9 @@ svn_error_t * svn_wc__db_base_remove(svn_wc__db_t *db, const char *local_abspath, svn_boolean_t keep_as_working, - svn_boolean_t queue_deletes, - svn_boolean_t remove_locks, - svn_revnum_t not_present_revision, + svn_boolean_t mark_not_present, + svn_boolean_t mark_excluded, + svn_revnum_t marker_revision, svn_skel_t *conflict, svn_skel_t *work_items, apr_pool_t *scratch_pool) @@ -2491,8 +2421,9 @@ svn_wc__db_base_remove(svn_wc__db_t *db, VERIFY_USABLE_WCROOT(wcroot); SVN_WC__DB_WITH_TXN(db_base_remove(wcroot, local_relpath, - db, keep_as_working, queue_deletes, - remove_locks, not_present_revision, + db, keep_as_working, + mark_not_present, mark_excluded, + marker_revision, conflict, work_items, scratch_pool), wcroot); @@ -2843,8 +2774,10 @@ svn_wc__db_base_get_children(const apr_a scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - return gather_repo_children(children, wcroot, local_relpath, 0, - result_pool, scratch_pool); + return svn_error_trace( + gather_children(children, wcroot, local_relpath, + STMT_SELECT_OP_DEPTH_CHILDREN, 0, + result_pool, scratch_pool)); } @@ -2854,12 +2787,20 @@ svn_wc__db_base_set_dav_cache(svn_wc__db const apr_hash_t *props, apr_pool_t *scratch_pool) { + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; svn_sqlite__stmt_t *stmt; int affected_rows; - SVN_ERR(get_statement_for_path(&stmt, db, local_abspath, - STMT_UPDATE_BASE_NODE_DAV_CACHE, - scratch_pool)); + SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, + local_abspath, scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_UPDATE_BASE_NODE_DAV_CACHE)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool)); SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); @@ -2881,11 +2822,20 @@ svn_wc__db_base_get_dav_cache(apr_hash_t apr_pool_t *result_pool, apr_pool_t *scratch_pool) { + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - SVN_ERR(get_statement_for_path(&stmt, db, local_abspath, - STMT_SELECT_BASE_DAV_CACHE, scratch_pool)); + SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, + local_abspath, scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_SELECT_BASE_DAV_CACHE)); + SVN_ERR(svn_sqlite__step(&have_row, stmt)); if (!have_row) return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, @@ -4038,9 +3988,7 @@ scan_deletion_txn(const char **base_del_ scan = (moved_to_op_root_relpath || moved_to_relpath); SVN_ERR(svn_sqlite__get_statement( - &stmt, wcroot->sdb, - scan ? STMT_SELECT_DELETION_INFO_SCAN - : STMT_SELECT_DELETION_INFO)); + &stmt, wcroot->sdb, STMT_SELECT_DELETION_INFO)); SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, current_relpath)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); @@ -4614,8 +4562,9 @@ db_op_copy(svn_wc__db_wcroot_t *src_wcro int src_op_depth; SVN_ERR(op_depth_of(&src_op_depth, src_wcroot, src_relpath)); - SVN_ERR(gather_repo_children(&children, src_wcroot, src_relpath, - src_op_depth, scratch_pool, scratch_pool)); + SVN_ERR(gather_children(&children, src_wcroot, src_relpath, + STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth, + scratch_pool, scratch_pool)); } else children = NULL; @@ -4839,6 +4788,72 @@ svn_wc__db_op_copy(svn_wc__db_t *db, return SVN_NO_ERROR; } +/* Remove unneeded actual nodes for svn_wc__db_op_copy_layer_internal */ +static svn_error_t * +clear_or_remove_actual(svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + int op_depth, + apr_pool_t *scratch_pool) +{ + svn_sqlite__stmt_t *stmt; + svn_boolean_t have_row, shadowed; + svn_boolean_t keep_conflict = FALSE; + + 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)); + + if (have_row) + { + svn_wc__db_status_t presence; + + shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth); + presence = svn_sqlite__column_token(stmt, 3, presence_map); + + if (shadowed && presence == svn_wc__db_status_base_deleted) + { + keep_conflict = TRUE; + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + + if (have_row) + shadowed = (svn_sqlite__column_int(stmt, 0) > op_depth); + else + shadowed = FALSE; + } + } + else + shadowed = FALSE; + + SVN_ERR(svn_sqlite__reset(stmt)); + if (shadowed) + return SVN_NO_ERROR; + + if (keep_conflict) + { + /* We don't want to accidentally remove delete-delete conflicts */ + SVN_ERR(svn_sqlite__get_statement( + &stmt, wcroot->sdb, + STMT_CLEAR_ACTUAL_NODE_LEAVING_CONFLICT)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_DELETE_ACTUAL_EMPTY)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); + } + else + { + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_DELETE_ACTUAL_NODE)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); + } + + return SVN_NO_ERROR; +} + svn_error_t * svn_wc__db_op_copy_layer_internal(svn_wc__db_wcroot_t *wcroot, const char *src_op_relpath, @@ -4878,15 +4893,12 @@ svn_wc__db_op_copy_layer_internal(svn_wc { const char *src_relpath; const char *dst_relpath; - svn_boolean_t exists; svn_pool_clear(iterpool); src_relpath = svn_sqlite__column_text(stmt, 0, iterpool); dst_relpath = svn_sqlite__column_text(stmt, 2, iterpool); - exists = !svn_sqlite__column_is_null(stmt, 3); - err = svn_sqlite__bindf(stmt2, "isdsds", wcroot->wc_id, src_relpath, src_op_depth, dst_relpath, dst_op_depth, @@ -4899,21 +4911,11 @@ svn_wc__db_op_copy_layer_internal(svn_wc if (err) break; - if (strlen(dst_relpath) > strlen(dst_op_relpath)) + /* The node can't be deleted where it is added, so extension of + an existing shadowing is only interesting 2 levels deep. */ + if (relpath_depth(dst_relpath) > (dst_op_depth+1)) { - svn_boolean_t added_delete = FALSE; - svn_node_kind_t kind = svn_sqlite__column_token(stmt, 1, kind_map); - - /* The op root can't be shadowed, so extension of a parent delete - is only needed when the parent can be deleted */ - if (relpath_depth(dst_relpath) > (dst_op_depth+1)) - { - err = db_extend_parent_delete(&added_delete, wcroot, dst_relpath, - kind, dst_op_depth, iterpool); - - if (err) - break; - } + svn_boolean_t exists = !svn_sqlite__column_is_null(stmt, 3); if (exists) { @@ -4921,28 +4923,19 @@ svn_wc__db_op_copy_layer_internal(svn_wc presence = svn_sqlite__column_token(stmt, 3, presence_map); - if (presence == svn_wc__db_status_not_present) + if (presence != svn_wc__db_status_normal) exists = FALSE; } - /* ### Fails in a few tests... Needs further research */ - /*SVN_ERR_ASSERT(!(exists && added_delete));*/ - if (!exists) { - svn_boolean_t shadowed; + svn_node_kind_t kind = svn_sqlite__column_token(stmt, 1, kind_map); - shadowed = svn_sqlite__column_int(stmt, 4); + err = db_extend_parent_delete(wcroot, dst_relpath, + kind, dst_op_depth, iterpool); - /*if (!shadowed && !added_delete) - { - err = svn_error_createf( - SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL, - _("Node '%s' was unexpectedly added unshadowed"), - path_for_error_message(wcroot, dst_relpath, - iterpool)); - break; - }*/ + if (err) + break; } } @@ -4992,6 +4985,12 @@ svn_wc__db_op_copy_layer_internal(svn_wc err = svn_sqlite__step_done(stmt2); /* stmt2 is reset (never modified or by step_done) */ + if (err) + break; + + /* Delete ACTUAL information about this node that we just deleted */ + err = clear_or_remove_actual(wcroot, dst_relpath, dst_op_depth, + scratch_pool); if (err) break; @@ -5009,8 +5008,6 @@ svn_wc__db_op_copy_layer_internal(svn_wc SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt))); - /* ### TODO: Did we handle ACTUAL as intended? */ - SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool)); if (conflict) @@ -5427,8 +5424,9 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr return SVN_NO_ERROR; } - SVN_ERR(gather_repo_children(&children, src_wcroot, src_relpath, - src_op_depth, scratch_pool, iterpool)); + SVN_ERR(gather_children(&children, src_wcroot, src_relpath, + STMT_SELECT_OP_DEPTH_CHILDREN, src_op_depth, + scratch_pool, iterpool)); for (i = 0; i < children->nelts; i++) { @@ -5615,8 +5613,8 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db, const char *original_uuid, svn_revnum_t original_revision, const apr_array_header_t *children, - svn_boolean_t is_move, svn_depth_t depth, + svn_boolean_t is_move, const svn_skel_t *conflict, const svn_skel_t *work_items, apr_pool_t *scratch_pool) @@ -5643,11 +5641,6 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db, iwb.presence = svn_wc__db_status_normal; iwb.kind = svn_node_dir; - iwb.props = props; - iwb.changed_rev = changed_rev; - iwb.changed_date = changed_date; - iwb.changed_author = changed_author; - if (original_root_url != NULL) { SVN_ERR(create_repos_id(&iwb.original_repos_id, @@ -5655,6 +5648,11 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db, wcroot->sdb, scratch_pool)); iwb.original_repos_relpath = original_repos_relpath; iwb.original_revnum = original_revision; + + iwb.props = props; + iwb.changed_rev = changed_rev; + iwb.changed_date = changed_date; + iwb.changed_author = changed_author; } /* ### Should we do this inside the transaction? */ @@ -5723,11 +5721,6 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db iwb.presence = svn_wc__db_status_normal; iwb.kind = svn_node_file; - iwb.props = props; - iwb.changed_rev = changed_rev; - iwb.changed_date = changed_date; - iwb.changed_author = changed_author; - if (original_root_url != NULL) { SVN_ERR(create_repos_id(&iwb.original_repos_id, @@ -5735,6 +5728,11 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db wcroot->sdb, scratch_pool)); iwb.original_repos_relpath = original_repos_relpath; iwb.original_revnum = original_revision; + + iwb.props = props; + iwb.changed_rev = changed_rev; + iwb.changed_date = changed_date; + iwb.changed_author = changed_author; } /* ### Should we do this inside the transaction? */ @@ -5777,6 +5775,7 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t const char *original_uuid, svn_revnum_t original_revision, const char *target, + svn_boolean_t is_move, const svn_skel_t *conflict, const svn_skel_t *work_items, apr_pool_t *scratch_pool) @@ -5801,11 +5800,6 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t iwb.presence = svn_wc__db_status_normal; iwb.kind = svn_node_symlink; - iwb.props = props; - iwb.changed_rev = changed_rev; - iwb.changed_date = changed_date; - iwb.changed_author = changed_author; - iwb.moved_here = FALSE; if (original_root_url != NULL) { @@ -5814,6 +5808,11 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t wcroot->sdb, scratch_pool)); iwb.original_repos_relpath = original_repos_relpath; iwb.original_revnum = original_revision; + + iwb.props = props; + iwb.changed_rev = changed_rev; + iwb.changed_date = changed_date; + iwb.changed_author = changed_author; } /* ### Should we do this inside the transaction? */ @@ -5823,6 +5822,8 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t wcroot, local_relpath, scratch_pool)); iwb.target = target; + iwb.moved_here = is_move && (parent_op_depth == 0 || + iwb.op_depth == parent_op_depth); iwb.work_items = work_items; iwb.conflict = conflict; @@ -6032,27 +6033,39 @@ svn_wc__db_global_record_fileinfo(svn_wc * 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, +set_actual_props(svn_wc__db_wcroot_t *wcroot, const char *local_relpath, apr_hash_t *props, - svn_sqlite__db_t *db, apr_pool_t *scratch_pool) { svn_sqlite__stmt_t *stmt; int affected_rows; - SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_UPDATE_ACTUAL_PROPS)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_UPDATE_ACTUAL_PROPS)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, scratch_pool)); SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); if (affected_rows == 1 || !props) - return SVN_NO_ERROR; /* We are done */ + { + /* Perhaps the entire ACTUAL record is unneeded now? */ + if (!props && affected_rows) + { + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_DELETE_ACTUAL_EMPTY)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); + } + + return SVN_NO_ERROR; /* We are done */ + } /* We have to insert a row in ACTUAL */ - SVN_ERR(svn_sqlite__get_statement(&stmt, db, STMT_INSERT_ACTUAL_PROPS)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_INSERT_ACTUAL_PROPS)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); if (*local_relpath != '\0') SVN_ERR(svn_sqlite__bind_text(stmt, 3, svn_relpath_dirname(local_relpath, @@ -6068,8 +6081,7 @@ svn_wc__db_op_set_props_internal(svn_wc_ svn_boolean_t clear_recorded_info, apr_pool_t *scratch_pool) { - SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath, - props, wcroot->sdb, scratch_pool)); + SVN_ERR(set_actual_props(wcroot, local_relpath, props, scratch_pool)); if (clear_recorded_info) { @@ -6348,7 +6360,7 @@ set_changelist_txn(void *baton, if (scb->new_changelist) { SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_INSERT_ACTUAL_EMPTIES)); + STMT_INSERT_ACTUAL_EMPTIES_FILES)); SVN_ERR(svn_sqlite__step_done(stmt)); } @@ -6565,15 +6577,15 @@ svn_wc__db_op_mark_conflict(svn_wc__db_t /* The body of svn_wc__db_op_mark_resolved(). */ -static svn_error_t * -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) +svn_error_t * +svn_wc__db_op_mark_resolved_internal(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) { svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; @@ -6671,7 +6683,8 @@ svn_wc__db_op_mark_resolved(svn_wc__db_t VERIFY_USABLE_WCROOT(wcroot); SVN_WC__DB_WITH_TXN( - db_op_mark_resolved(wcroot, local_relpath, db, + svn_wc__db_op_mark_resolved_internal( + wcroot, local_relpath, db, resolved_text, resolved_props, resolved_tree, work_items, scratch_pool), wcroot); @@ -6739,6 +6752,7 @@ op_revert_txn(void *baton, int affected_rows; const char *moved_to; int op_depth_increased = 0; + int op_depth_below; svn_skel_t *conflict; /* ### Similar structure to op_revert_recursive_txn, should they be @@ -6786,6 +6800,13 @@ op_revert_txn(void *baton, op_depth = svn_sqlite__column_int(stmt, 0); moved_here = svn_sqlite__column_boolean(stmt, 15); moved_to = svn_sqlite__column_text(stmt, 17, scratch_pool); + + SVN_ERR(svn_sqlite__step(&have_row, stmt)); + if (have_row) + op_depth_below = svn_sqlite__column_int(stmt, 0); + else + op_depth_below = -1; + SVN_ERR(svn_sqlite__reset(stmt)); if (moved_to) @@ -6796,7 +6817,7 @@ op_revert_txn(void *baton, } else { - SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, wcroot, + SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, NULL, wcroot, local_relpath, scratch_pool, scratch_pool)); } @@ -6873,7 +6894,7 @@ op_revert_txn(void *baton, || reason == svn_wc_conflict_reason_replaced) { SVN_ERR(svn_wc__db_op_raise_moved_away_internal( - wcroot, local_relpath, op_depth+1, db, + wcroot, local_relpath, op_depth_below, db, operation, action, (locations && locations->nelts > 0) ? APR_ARRAY_IDX(locations, 0, @@ -7024,7 +7045,7 @@ op_revert_recursive_txn(void *baton, STMT_DELETE_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE)); SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath)); SVN_ERR(svn_sqlite__step_done(stmt)); - + SVN_ERR(svn_sqlite__get_statement( &stmt, wcroot->sdb, STMT_CLEAR_ACTUAL_NODE_LEAVING_CHANGELIST_RECURSIVE)); @@ -7397,9 +7418,6 @@ remove_node_txn(svn_boolean_t *left_chan 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_node_kind_t not_present_kind, const svn_skel_t *conflict, const svn_skel_t *work_items, svn_cancel_func_t cancel_func, @@ -7408,9 +7426,6 @@ remove_node_txn(svn_boolean_t *left_chan { svn_sqlite__stmt_t *stmt; - apr_int64_t repos_id; - const char *repos_relpath; - /* Note that unlike many similar functions it is a valid scenario for this function to be called on a wcroot! */ @@ -7420,15 +7435,6 @@ remove_node_txn(svn_boolean_t *left_chan if (left_changes) *left_changes = FALSE; - /* Need info for not_present node? */ - 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, - wcroot, local_relpath, - scratch_pool, scratch_pool)); - if (destroy_wc && (!destroy_changes || *local_relpath == '\0')) { @@ -7625,26 +7631,6 @@ remove_node_txn(svn_boolean_t *left_chan local_relpath)); SVN_ERR(svn_sqlite__step_done(stmt)); - /* Should we leave a not-present node? */ - if (SVN_IS_VALID_REVNUM(not_present_rev)) - { - insert_base_baton_t ibb; - blank_ibb(&ibb); - - ibb.repos_id = repos_id; - - SVN_ERR_ASSERT(not_present_status == svn_wc__db_status_not_present - || not_present_status == svn_wc__db_status_excluded); - - ibb.status = not_present_status; - ibb.kind = not_present_kind; - - ibb.repos_relpath = repos_relpath; - ibb.revision = not_present_rev; - - SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, 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, @@ -7659,9 +7645,6 @@ svn_wc__db_op_remove_node(svn_boolean_t const char *local_abspath, svn_boolean_t destroy_wc, svn_boolean_t destroy_changes, - svn_revnum_t not_present_revision, - svn_wc__db_status_t not_present_status, - svn_node_kind_t not_present_kind, const svn_skel_t *conflict, const svn_skel_t *work_items, svn_cancel_func_t cancel_func, @@ -7680,8 +7663,7 @@ svn_wc__db_op_remove_node(svn_boolean_t SVN_WC__DB_WITH_TXN(remove_node_txn(left_changes, wcroot, local_relpath, db, destroy_wc, destroy_changes, - not_present_revision, not_present_status, - not_present_kind, conflict, work_items, + conflict, work_items, cancel_func, cancel_baton, scratch_pool), wcroot); @@ -9812,7 +9794,7 @@ svn_wc__db_read_pristine_info(svn_wc__db } svn_error_t * -svn_wc__db_read_children_walker_info(apr_hash_t **nodes, +svn_wc__db_read_children_walker_info(const apr_array_header_t **items, svn_wc__db_t *db, const char *dir_abspath, apr_pool_t *result_pool, @@ -9822,6 +9804,7 @@ svn_wc__db_read_children_walker_info(apr const char *dir_relpath; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; + apr_array_header_t *nodes; SVN_ERR_ASSERT(svn_dirent_is_absolute(dir_abspath)); @@ -9835,16 +9818,18 @@ svn_wc__db_read_children_walker_info(apr SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, dir_relpath)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); - *nodes = apr_hash_make(result_pool); + nodes = apr_array_make(result_pool, 16, + sizeof(struct svn_wc__db_walker_info_t *)); while (have_row) { struct svn_wc__db_walker_info_t *child; const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL); - const char *name = svn_relpath_basename(child_relpath, NULL); + const char *name = svn_relpath_basename(child_relpath, result_pool); int op_depth = svn_sqlite__column_int(stmt, 1); svn_error_t *err; child = apr_palloc(result_pool, sizeof(*child)); + child->name = name; child->status = svn_sqlite__column_token(stmt, 2, presence_map); if (op_depth > 0) { @@ -9853,13 +9838,16 @@ svn_wc__db_read_children_walker_info(apr SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt))); } child->kind = svn_sqlite__column_token(stmt, 3, kind_map); - svn_hash_sets(*nodes, apr_pstrdup(result_pool, name), child); + + APR_ARRAY_PUSH(nodes, struct svn_wc__db_walker_info_t *) = child; SVN_ERR(svn_sqlite__step(&have_row, stmt)); } SVN_ERR(svn_sqlite__reset(stmt)); + *items = nodes; + return SVN_NO_ERROR; } @@ -9943,35 +9931,34 @@ svn_wc__db_read_node_install_info(const -/* The body of svn_wc__db_read_url(). +/* The body of svn_wc__db_read_repos_info(). */ static svn_error_t * -read_url_txn(const char **url, - svn_wc__db_wcroot_t *wcroot, - const char *local_relpath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +db_read_repos_info(svn_revnum_t *revision, + const char **repos_relpath, + apr_int64_t *repos_id, + svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_wc__db_status_t status; - const char *repos_relpath; - const char *repos_root_url; - apr_int64_t repos_id; - svn_boolean_t have_base; - SVN_ERR(read_info(&status, NULL, NULL, &repos_relpath, &repos_id, NULL, + SVN_ERR(read_info(&status, NULL, revision, repos_relpath, repos_id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &have_base, NULL, NULL, - wcroot, local_relpath, scratch_pool, scratch_pool)); + NULL, NULL, NULL, + wcroot, local_relpath, result_pool, scratch_pool)); - if (repos_relpath == NULL) + if ((repos_relpath && !*repos_relpath) + || (repos_id && *repos_id == INVALID_REPOS_ID)) { if (status == svn_wc__db_status_added) { - SVN_ERR(scan_addition(NULL, NULL, &repos_relpath, &repos_id, NULL, + SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL, NULL, NULL, NULL, NULL, NULL, wcroot, local_relpath, - scratch_pool, scratch_pool)); + result_pool, scratch_pool)); } else if (status == svn_wc__db_status_deleted) { @@ -9985,26 +9972,7 @@ read_url_txn(const char **url, scratch_pool, scratch_pool)); - if (base_del_relpath) - { - 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, - wcroot, - base_del_relpath, - scratch_pool, - scratch_pool)); - - repos_relpath = svn_relpath_join( - repos_relpath, - svn_dirent_skip_ancestor(base_del_relpath, - local_relpath), - scratch_pool); - } - else + if (work_del_relpath) { /* The parent of the WORKING delete, must be an addition */ const char *work_relpath = NULL; @@ -10017,34 +9985,57 @@ read_url_txn(const char **url, work_relpath = svn_relpath_dirname(work_del_relpath, scratch_pool); - SVN_ERR(scan_addition(NULL, NULL, &repos_relpath, &repos_id, + SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL, NULL, NULL, NULL, NULL, NULL, wcroot, work_relpath, scratch_pool, scratch_pool)); - repos_relpath = svn_relpath_join( - repos_relpath, + if (repos_relpath) + *repos_relpath = svn_relpath_join( + *repos_relpath, svn_dirent_skip_ancestor(work_relpath, local_relpath), - scratch_pool); + result_pool); + } + else + { + SVN_ERR(svn_wc__db_base_get_info_internal(NULL, NULL, revision, + repos_relpath, + repos_id, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + wcroot, + base_del_relpath, + scratch_pool, + scratch_pool)); + + if (repos_relpath) + *repos_relpath = svn_relpath_join( + *repos_relpath, + svn_dirent_skip_ancestor(base_del_relpath, + local_relpath), + result_pool); } } else if (status == svn_wc__db_status_excluded) { const char *parent_relpath; const char *name; - const char *url2; - /* Set 'url' to the *full URL* of the parent WC dir, - * and 'name' to the *single path component* that is the - * basename of this WC directory, so that joining them will result - * in the correct full URL. */ + /* A BASE excluded would have had repository information, so + we have a working exclude, which must be below an addition */ + svn_relpath_split(&parent_relpath, &name, local_relpath, scratch_pool); - SVN_ERR(read_url_txn(&url2, wcroot, parent_relpath, - scratch_pool, scratch_pool)); + SVN_ERR(scan_addition(NULL, NULL, repos_relpath, repos_id, NULL, + NULL, NULL, NULL, NULL, NULL, + wcroot, parent_relpath, + scratch_pool, scratch_pool)); - *url = svn_path_url_add_component2(url2, name, result_pool); + if (repos_relpath) + *repos_relpath = svn_relpath_join(*repos_relpath, name, + result_pool); return SVN_NO_ERROR; } @@ -10056,26 +10047,23 @@ read_url_txn(const char **url, } } - SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, NULL, wcroot, - repos_id, scratch_pool)); - - SVN_ERR_ASSERT(repos_root_url != NULL && repos_relpath != NULL); - *url = svn_path_url_add_component2(repos_root_url, repos_relpath, - result_pool); - return SVN_NO_ERROR; } svn_error_t * -svn_wc__db_read_url(const char **url, - svn_wc__db_t *db, - const char *local_abspath, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) +svn_wc__db_read_repos_info(svn_revnum_t *revision, + const char **repos_relpath, + const char **repos_root_url, + const char **repos_uuid, + svn_wc__db_t *db, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_wc__db_wcroot_t *wcroot; const char *local_relpath; + apr_int64_t repos_id = INVALID_REPOS_ID; SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); @@ -10084,9 +10072,17 @@ svn_wc__db_read_url(const char **url, scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - SVN_WC__DB_WITH_TXN(read_url_txn(url, wcroot, local_relpath, - result_pool, scratch_pool), - wcroot); + SVN_WC__DB_WITH_TXN4(db_read_repos_info(revision, repos_relpath, + (repos_root_url || repos_uuid) + ? &repos_id : NULL, + wcroot, local_relpath, + result_pool, scratch_pool), + svn_wc__db_fetch_repos_info(repos_root_url, + repos_uuid, + wcroot, repos_id, + result_pool), + SVN_NO_ERROR, SVN_NO_ERROR, + wcroot); return SVN_NO_ERROR; } @@ -10928,8 +10924,34 @@ svn_wc__db_read_children_of_working_node scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - return gather_children2(children, wcroot, local_relpath, - result_pool, scratch_pool); + return svn_error_trace( + gather_children(children, wcroot, local_relpath, + STMT_SELECT_WORKING_CHILDREN, -1, + result_pool, scratch_pool)); +} + +svn_error_t * +svn_wc__db_base_read_not_present_children( + const apr_array_header_t **children, + svn_wc__db_t *db, + const char *local_abspath, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; + + SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, + local_abspath, + scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + return svn_error_trace( + gather_children(children, wcroot, local_relpath, + STMT_SELECT_BASE_NOT_PRESENT_CHILDREN, -1, + result_pool, scratch_pool)); } /* Helper for svn_wc__db_node_check_replace(). @@ -11116,6 +11138,7 @@ svn_wc__db_read_children(const apr_array VERIFY_USABLE_WCROOT(wcroot); return gather_children(children, wcroot, local_relpath, + STMT_SELECT_NODE_CHILDREN, -1, result_pool, scratch_pool); } @@ -11321,35 +11344,18 @@ determine_repos_info(apr_int64_t *repos_ return SVN_NO_ERROR; } -/* Helper for svn_wc__db_global_commit() - - Makes local_relpath and all its descendants at the same op-depth represent - the copy origin repos_id:repos_relpath@revision. - - This code is only valid to fix-up a move from an old location, to a new - location during a commit. - - Assumptions: - * local_relpath is not the working copy root (can't be moved) - * repos_relpath is not the repository root (can't be moved) - */ static svn_error_t * -moved_descendant_commit(svn_wc__db_wcroot_t *wcroot, +moved_descendant_collect(apr_hash_t **map, + svn_wc__db_wcroot_t *wcroot, const char *local_relpath, int op_depth, - apr_int64_t repos_id, - const char *repos_relpath, - svn_revnum_t revision, + apr_pool_t *result_pool, apr_pool_t *scratch_pool) { - apr_hash_t *children; - apr_pool_t *iterpool; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; - apr_hash_index_t *hi; - SVN_ERR_ASSERT(*local_relpath != '\0' - && *repos_relpath != '\0'); + *map = NULL; SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_DESCENDANTS_SRC)); @@ -11361,21 +11367,56 @@ moved_descendant_commit(svn_wc__db_wcroo if (! have_row) return svn_error_trace(svn_sqlite__reset(stmt)); - children = apr_hash_make(scratch_pool); - - /* First, obtain all moved descendants */ - /* To keep error handling simple, first cache them in a hashtable */ + /* Find all moved descendants. Key them on target, because that is + always unique */ while (have_row) { - const char *src_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool); - const char *to_relpath = svn_sqlite__column_text(stmt, 4, scratch_pool); + const char *src_relpath = svn_sqlite__column_text(stmt, 1, result_pool); + const char *to_relpath = svn_sqlite__column_text(stmt, 4, result_pool); + + if (!*map) + *map = apr_hash_make(result_pool); - svn_hash_sets(children, src_relpath, to_relpath); + svn_hash_sets(*map, to_relpath, src_relpath); SVN_ERR(svn_sqlite__step(&have_row, stmt)); } SVN_ERR(svn_sqlite__reset(stmt)); + return SVN_NO_ERROR; +} + +/* Helper for svn_wc__db_global_commit() + + Makes local_relpath and all its descendants at the same op-depth represent + the copy origin repos_id:repos_relpath@revision. + + This code is only valid to fix-up a move from an old location, to a new + location during a commit. + + Assumptions: + * local_relpath is not the working copy root (can't be moved) + * repos_relpath is not the repository root (can't be moved) + */ +static svn_error_t * +moved_descendant_commit(svn_wc__db_wcroot_t *wcroot, + const char *local_relpath, + apr_int64_t repos_id, + const char *repos_relpath, + svn_revnum_t revision, + apr_hash_t *children, + apr_pool_t *scratch_pool) +{ + apr_pool_t *iterpool; + svn_sqlite__stmt_t *stmt; + apr_hash_index_t *hi; + + SVN_ERR_ASSERT(*local_relpath != '\0' + && *repos_relpath != '\0'); + + if (!children) + return SVN_NO_ERROR; + /* Then update them */ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_COMMIT_UPDATE_ORIGIN)); @@ -11383,11 +11424,12 @@ moved_descendant_commit(svn_wc__db_wcroo iterpool = svn_pool_create(scratch_pool); for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi)) { - const char *src_relpath = apr_hash_this_key(hi); - const char *to_relpath = apr_hash_this_val(hi); + const char *src_relpath = apr_hash_this_val(hi); + const char *to_relpath = apr_hash_this_key(hi); const char *new_repos_relpath; int to_op_depth = relpath_depth(to_relpath); int affected; + apr_hash_t *map; svn_pool_clear(iterpool); @@ -11414,9 +11456,11 @@ moved_descendant_commit(svn_wc__db_wcroo SVN_ERR_ASSERT(affected >= 1); /* If this fails there is no move dest */ #endif - SVN_ERR(moved_descendant_commit(wcroot, to_relpath, to_op_depth, + SVN_ERR(moved_descendant_collect(&map, wcroot, to_relpath, to_op_depth, + iterpool, iterpool)); + SVN_ERR(moved_descendant_commit(wcroot, to_relpath, repos_id, new_repos_relpath, revision, - iterpool)); + map, iterpool)); } svn_pool_destroy(iterpool); @@ -11475,7 +11519,6 @@ commit_node(svn_wc__db_wcroot_t *wcroot, apr_time_t changed_date, const char *changed_author, const svn_checksum_t *new_checksum, - const apr_array_header_t *new_children, apr_hash_t *new_dav_cache, svn_boolean_t keep_changelist, svn_boolean_t no_unlock, @@ -11497,6 +11540,7 @@ commit_node(svn_wc__db_wcroot_t *wcroot, const char *repos_relpath; int op_depth; svn_wc__db_status_t old_presence; + svn_boolean_t moved_here; /* If we are adding a file or directory, then we need to get repository information from the parent node since "this node" does @@ -11526,6 +11570,7 @@ commit_node(svn_wc__db_wcroot_t *wcroot, /* Figure out the new node's kind. It will be whatever is in WORKING_NODE, or there will be a BASE_NODE that has it. */ + old_presence = svn_sqlite__column_token(stmt_info, 3, presence_map); new_kind = svn_sqlite__column_token(stmt_info, 4, kind_map); /* What will the new depth be? */ @@ -11544,26 +11589,35 @@ commit_node(svn_wc__db_wcroot_t *wcroot, svn_sqlite__column_text(stmt_info, 2, NULL)) == 0); } - /* Find the appropriate new properties -- ACTUAL overrides any properties - in WORKING that arrived as part of a copy/move. + if (old_presence != svn_wc__db_status_base_deleted) + { + /* Find the appropriate new properties -- ACTUAL overrides any properties + in WORKING that arrived as part of a copy/move. - Note: we'll keep them as a big blob of data, rather than - deserialize/serialize them. */ - if (have_act) - prop_blob.data = svn_sqlite__column_blob(stmt_act, 1, &prop_blob.len, - scratch_pool); - if (prop_blob.data == NULL) - prop_blob.data = svn_sqlite__column_blob(stmt_info, 14, &prop_blob.len, - scratch_pool); - - inherited_prop_blob.data = svn_sqlite__column_blob(stmt_info, 16, - &inherited_prop_blob.len, - scratch_pool); + Note: we'll keep them as a big blob of data, rather than + deserialize/serialize them. */ + if (have_act) + prop_blob.data = svn_sqlite__column_blob(stmt_act, 1, &prop_blob.len, + scratch_pool); + if (prop_blob.data == NULL) + prop_blob.data = svn_sqlite__column_blob(stmt_info, 14, &prop_blob.len, + scratch_pool); - if (keep_changelist && have_act) - changelist = svn_sqlite__column_text(stmt_act, 0, scratch_pool); + inherited_prop_blob.data = svn_sqlite__column_blob( + stmt_info, 16, + &inherited_prop_blob.len, + scratch_pool); - old_presence = svn_sqlite__column_token(stmt_info, 3, presence_map); + if (keep_changelist && have_act) + changelist = svn_sqlite__column_text(stmt_act, 0, scratch_pool); + + moved_here = svn_sqlite__column_int(stmt_info, 15); + } + else + { + moved_here = FALSE; + changelist = NULL; + } /* ### other stuff? */ @@ -11574,6 +11628,24 @@ commit_node(svn_wc__db_wcroot_t *wcroot, { int affected_rows; + SVN_ERR_ASSERT(op_depth == relpath_depth(local_relpath)); + + /* First clear the moves that we are going to delete in a bit */ + { + apr_hash_t *old_moves; + apr_hash_index_t *hi; + SVN_ERR(moved_descendant_collect(&old_moves, wcroot, local_relpath, 0, + scratch_pool, scratch_pool)); + + if (old_moves) + for (hi = apr_hash_first(scratch_pool, old_moves); + hi; hi = apr_hash_next(hi)) + { + SVN_ERR(clear_moved_here(wcroot, apr_hash_this_key(hi), + scratch_pool)); + } + } + /* This removes all layers of this node and at the same time determines if we need to remove shadowed layers below our descendants. */ @@ -11606,26 +11678,40 @@ commit_node(svn_wc__db_wcroot_t *wcroot, be integrated, they really affect a different op-depth and completely different nodes (via a different recursion pattern). */ - /* Collapse descendants of the current op_depth in layer 0 */ - SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth, - repos_id, repos_relpath, new_revision, - scratch_pool)); + if (old_presence != svn_wc__db_status_base_deleted) + { + /* Collapse descendants of the current op_depth to layer 0, + this includes moved-from/to clearing */ + SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth, + repos_id, repos_relpath, new_revision, + scratch_pool)); + } + + if (old_presence != svn_wc__db_status_base_deleted) + { + apr_hash_t *moves = NULL; + + SVN_ERR(moved_descendant_collect(&moves, wcroot, local_relpath, 0, + scratch_pool, scratch_pool)); - /* And make the recorded local moves represent moves of the node we just - committed. */ - SVN_ERR(moved_descendant_commit(wcroot, local_relpath, 0, + /* And make the recorded local moves represent moves of the node we + just committed. */ + SVN_ERR(moved_descendant_commit(wcroot, local_relpath, repos_id, repos_relpath, new_revision, - scratch_pool)); + moves, scratch_pool)); + } - /* This node is no longer modified, so no node was moved here */ - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_CLEAR_MOVED_TO_FROM_DEST)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, - local_relpath)); + if (moved_here) + { + /* This node is no longer modified, so no node was moved here */ + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_CLEAR_MOVED_TO_FROM_DEST)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, + local_relpath)); - SVN_ERR(svn_sqlite__step_done(stmt)); + SVN_ERR(svn_sqlite__step_done(stmt)); + } } - /* Update or add the BASE_NODE row with all the new information. */ if (*local_relpath == '\0') @@ -11634,38 +11720,56 @@ commit_node(svn_wc__db_wcroot_t *wcroot, parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool); /* Preserve any incomplete status */ - new_presence = (old_presence == svn_wc__db_status_incomplete - ? svn_wc__db_status_incomplete - : svn_wc__db_status_normal); - - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_APPLY_CHANGES_TO_BASE_NODE)); - /* symlink_target not yet used */ - SVN_ERR(svn_sqlite__bindf(stmt, "issisrtstrisnbn", - wcroot->wc_id, local_relpath, - parent_relpath, - repos_id, - repos_relpath, - new_revision, - presence_map, new_presence, - new_depth_str, - kind_map, new_kind, - changed_rev, - changed_date, - changed_author, - prop_blob.data, prop_blob.len)); - - SVN_ERR(svn_sqlite__bind_checksum(stmt, 13, new_checksum, - scratch_pool)); - SVN_ERR(svn_sqlite__bind_properties(stmt, 15, new_dav_cache, - scratch_pool)); - if (inherited_prop_blob.data != NULL) + if (old_presence != svn_wc__db_status_base_deleted) { - SVN_ERR(svn_sqlite__bind_blob(stmt, 17, inherited_prop_blob.data, - inherited_prop_blob.len)); - } + new_presence = (old_presence == svn_wc__db_status_incomplete + ? svn_wc__db_status_incomplete + : svn_wc__db_status_normal); - SVN_ERR(svn_sqlite__step_done(stmt)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_APPLY_CHANGES_TO_BASE_NODE)); + /* symlink_target not yet used */ + SVN_ERR(svn_sqlite__bindf(stmt, "issisrtstrisnbn", + wcroot->wc_id, local_relpath, + parent_relpath, + repos_id, + repos_relpath, + new_revision, + presence_map, new_presence, + new_depth_str, + kind_map, new_kind, + changed_rev, + changed_date, + changed_author, + prop_blob.data, prop_blob.len)); + + SVN_ERR(svn_sqlite__bind_checksum(stmt, 13, new_checksum, + scratch_pool)); + SVN_ERR(svn_sqlite__bind_properties(stmt, 15, new_dav_cache, + scratch_pool)); + if (inherited_prop_blob.data != NULL) + { + SVN_ERR(svn_sqlite__bind_blob(stmt, 17, inherited_prop_blob.data, + inherited_prop_blob.len)); + } + + SVN_ERR(svn_sqlite__step_done(stmt)); + } + else + { + struct insert_base_baton_t ibb; + blank_ibb(&ibb); + + ibb.repos_id = repos_id; + ibb.status = svn_wc__db_status_not_present; + ibb.kind = new_kind; + ibb.repos_relpath = repos_relpath; + ibb.revision = new_revision; + + SVN_ERR(insert_base_node(&ibb, wcroot, local_relpath, scratch_pool)); + + keep_changelist = FALSE; /* Nothing there */ + } if (have_act) { @@ -11693,23 +11797,21 @@ commit_node(svn_wc__db_wcroot_t *wcroot, } } - if (new_kind == svn_node_dir) - { - /* When committing a directory, we should have its new children. */ - /* ### one day. just not today. */ -#if 0 - SVN_ERR_ASSERT(new_children != NULL); -#endif - - /* ### process the children */ - } - if (!no_unlock) { svn_sqlite__stmt_t *lock_stmt; + svn_boolean_t op_root = (op_depth > 0 + && (relpath_depth(local_relpath) == op_depth)); + /* If we are committing an add of a delete, we can assume we own + all locks at or below REPOS_RELPATH (or the server would have + denied the commit). As we must have passed these to the server + we can now safely remove them. + */ SVN_ERR(svn_sqlite__get_statement(&lock_stmt, wcroot->sdb, - STMT_DELETE_LOCK_RECURSIVELY)); + op_root + ? STMT_DELETE_LOCK_RECURSIVELY + : STMT_DELETE_LOCK)); SVN_ERR(svn_sqlite__bindf(lock_stmt, "is", repos_id, repos_relpath)); SVN_ERR(svn_sqlite__step_done(lock_stmt)); } @@ -11729,7 +11831,6 @@ svn_wc__db_global_commit(svn_wc__db_t *d apr_time_t changed_date, const char *changed_author, const svn_checksum_t *new_checksum, - const apr_array_header_t *new_children, apr_hash_t *new_dav_cache, svn_boolean_t keep_changelist, svn_boolean_t no_unlock, @@ -11741,7 +11842,6 @@ svn_wc__db_global_commit(svn_wc__db_t *d SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath)); SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(new_revision)); - SVN_ERR_ASSERT(new_checksum == NULL || new_children == NULL); SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, local_abspath, scratch_pool, scratch_pool)); @@ -11750,7 +11850,7 @@ svn_wc__db_global_commit(svn_wc__db_t *d SVN_WC__DB_WITH_TXN( commit_node(wcroot, local_relpath, new_revision, changed_revision, changed_date, changed_author, - new_checksum, new_children, new_dav_cache, keep_changelist, + new_checksum, new_dav_cache, keep_changelist, no_unlock, work_items, scratch_pool), wcroot); @@ -11997,11 +12097,11 @@ bump_node_revision(svn_wc__db_wcroot_t * || (child_info->status == svn_wc__db_status_server_excluded && child_info->revnum != new_rev)) { - SVN_ERR(db_base_remove(wcroot, - child_local_relpath, - db, FALSE, FALSE, FALSE, - SVN_INVALID_REVNUM, - NULL, NULL, scratch_pool)); + svn_sqlite__stmt_t *stmt; + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_DELETE_BASE_NODE)); + SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, child_local_relpath)); + SVN_ERR(svn_sqlite__step_done(stmt)); continue; } @@ -13085,191 +13185,6 @@ svn_wc__db_upgrade_begin(svn_sqlite__db_ return SVN_NO_ERROR; } - -svn_error_t * -svn_wc__db_upgrade_apply_dav_cache(svn_sqlite__db_t *sdb, - const char *dir_relpath, - apr_hash_t *cache_values, - apr_pool_t *scratch_pool) -{ - apr_pool_t *iterpool = svn_pool_create(scratch_pool); - apr_int64_t wc_id; - apr_hash_index_t *hi; - svn_sqlite__stmt_t *stmt; - - SVN_ERR(svn_wc__db_util_fetch_wc_id(&wc_id, sdb, iterpool)); - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPDATE_BASE_NODE_DAV_CACHE)); - - /* Iterate over all the wcprops, writing each one to the wc_db. */ - for (hi = apr_hash_first(scratch_pool, cache_values); - hi; - hi = apr_hash_next(hi)) - { - const char *name = apr_hash_this_key(hi); - apr_hash_t *props = apr_hash_this_val(hi); - const char *local_relpath; - - svn_pool_clear(iterpool); - - local_relpath = svn_relpath_join(dir_relpath, name, iterpool); - - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); - SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, iterpool)); - SVN_ERR(svn_sqlite__step_done(stmt)); - } - - svn_pool_destroy(iterpool); - - return SVN_NO_ERROR; -} - - -svn_error_t * -svn_wc__db_upgrade_apply_props(svn_sqlite__db_t *sdb, - const char *dir_abspath, - const char *local_relpath, - apr_hash_t *base_props, - apr_hash_t *revert_props, - apr_hash_t *working_props, - int original_format, - apr_int64_t wc_id, - apr_pool_t *scratch_pool) -{ - svn_sqlite__stmt_t *stmt; - svn_boolean_t have_row; - int top_op_depth = -1; - int below_op_depth = -1; - svn_wc__db_status_t top_presence; - svn_wc__db_status_t below_presence; - int affected_rows; - - /* ### working_props: use set_props_txn. - ### if working_props == NULL, then skip. what if they equal the - ### pristine props? we should probably do the compare here. - ### - ### base props go into WORKING_NODE if avail, otherwise BASE. - ### - ### revert only goes into BASE. (and WORKING better be there!) - - Prior to 1.4.0 (ORIGINAL_FORMAT < 8), REVERT_PROPS did not exist. If a - file was deleted, then a copy (potentially with props) was disallowed - and could not replace the deletion. An addition *could* be performed, - but that would never bring its own props. - - 1.4.0 through 1.4.5 created the concept of REVERT_PROPS, but had a - bug in svn_wc_add_repos_file2() whereby a copy-with-props did NOT - construct a REVERT_PROPS if the target had no props. Thus, reverting - the delete/copy would see no REVERT_PROPS to restore, leaving the - props from the copy source intact, and appearing as if they are (now) - the base props for the previously-deleted file. (wc corruption) - - 1.4.6 ensured that an empty REVERT_PROPS would be established at all - times. See issue 2530, and r861670 as starting points. - - We will use ORIGINAL_FORMAT and SVN_WC__NO_REVERT_FILES to determine - the handling of our inputs, relative to the state of this node. - */ - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_NODE_INFO)); - SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath)); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - if (have_row) - { - top_op_depth = svn_sqlite__column_int(stmt, 0); - top_presence = svn_sqlite__column_token(stmt, 3, presence_map); - SVN_ERR(svn_sqlite__step(&have_row, stmt)); - if (have_row) - { - below_op_depth = svn_sqlite__column_int(stmt, 0); - below_presence = svn_sqlite__column_token(stmt, 3, presence_map); - } - } - SVN_ERR(svn_sqlite__reset(stmt)); - - /* Detect the buggy scenario described above. We cannot upgrade this - working copy if we have no idea where BASE_PROPS should go. */ - if (original_format > SVN_WC__NO_REVERT_FILES - && revert_props == NULL - && top_op_depth != -1 - && top_presence == svn_wc__db_status_normal - && below_op_depth != -1 - && below_presence != svn_wc__db_status_not_present) - { - /* There should be REVERT_PROPS, so it appears that we just ran into - the described bug. Sigh. */ - return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, - _("The properties of '%s' are in an " - "indeterminate state and cannot be " - "upgraded. See issue #2530."), - svn_dirent_local_style( - svn_dirent_join(dir_abspath, local_relpath, - scratch_pool), scratch_pool)); - } - - /* Need at least one row, or two rows if there are revert props */ - if (top_op_depth == -1 - || (below_op_depth == -1 && revert_props)) - return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL, - _("Insufficient NODES rows for '%s'"), - svn_dirent_local_style( - svn_dirent_join(dir_abspath, local_relpath, - scratch_pool), scratch_pool)); - - /* one row, base props only: upper row gets base props - two rows, base props only: lower row gets base props - two rows, revert props only: lower row gets revert props - two rows, base and revert props: upper row gets base, lower gets revert */ - - - if (revert_props || below_op_depth == -1) - { - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPDATE_NODE_PROPS)); - SVN_ERR(svn_sqlite__bindf(stmt, "isd", - wc_id, local_relpath, top_op_depth)); - SVN_ERR(svn_sqlite__bind_properties(stmt, 4, base_props, scratch_pool)); - SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); - - SVN_ERR_ASSERT(affected_rows == 1); - } - - if (below_op_depth != -1) - { - apr_hash_t *props = revert_props ? revert_props : base_props; - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, - STMT_UPDATE_NODE_PROPS)); - SVN_ERR(svn_sqlite__bindf(stmt, "isd", - wc_id, local_relpath, below_op_depth)); - SVN_ERR(svn_sqlite__bind_properties(stmt, 4, props, scratch_pool)); - SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); - - SVN_ERR_ASSERT(affected_rows == 1); - } - - /* If there are WORKING_PROPS, then they always go into ACTUAL_NODE. */ - if (working_props != NULL - && base_props != NULL) - { - apr_array_header_t *diffs; - - SVN_ERR(svn_prop_diffs(&diffs, working_props, base_props, scratch_pool)); - - if (diffs->nelts == 0) - working_props = NULL; /* No differences */ - } -
[... 917 lines stripped ...]
