Woah!
Still catching up here, but I don't think you should be using LIKE in
*any* SQL statement. That is a yellow flag right there, for more
investigation. For the most part, it says "do a full table scan". Bad
bad bad.
Looking at the code, I think what you really want is to examine
parent_relpath, NOT do a LIKE clause.
Right?
Cheers,
-g
On Thu, Jun 25, 2009 at 21:02, Hyrum K. Wright <hyrum_at_hyrumwright.org> wrote:
>
> Author: hwright
> Date: Thu Jun 25 12:02:05 2009
> New Revision: 38202
>
> Log:
> Simplify a little bit of the relocate sql updating logic. Â Also, properly
> escape URLs being passed into a 'like' clause.
>
> * subversion/libsvn_wc/wc_db.c
> Â (statement_keys, statements): Remove and refresh a few statements.
> Â (LIKE_ESCAPE_CHAR): New.
> Â (escape_sqlite_like): New.
> Â (relocate_txn): Use the improved SQL statements, and be sure to escape
> Â Â URLs used in like clauses.
>
> Modified:
> Â trunk/subversion/libsvn_wc/wc_db.c
>
> Modified: trunk/subversion/libsvn_wc/wc_db.c
> URL: http://svn.collab.net/viewvc/svn/trunk/subversion/libsvn_wc/wc_db.c?pathrev=38202&r1=38201&r2=38202
> ==============================================================================
> --- trunk/subversion/libsvn_wc/wc_db.c  Thu Jun 25 08:17:12 2009     (r38201)
> +++ trunk/subversion/libsvn_wc/wc_db.c  Thu Jun 25 12:02:05 2009     (r38202)
> @@ -190,13 +190,15 @@ enum statement_keys {
> Â STMT_SELECT_DELETION_INFO,
> Â STMT_SELECT_PARENT_STUB_INFO,
> Â STMT_DELETE_LOCK,
> - Â STMT_UPDATE_BASE_REPO,
> - Â STMT_UPDATE_BASE_CHILDREN_REPO,
> - Â STMT_UPDATE_WORKING_COPYFROM_REPO,
> - Â STMT_UPDATE_WORKING_CHILDREN_COPYFROM_REPO,
> + Â STMT_UPDATE_BASE_RECURSIVE_REPO,
> + Â STMT_UPDATE_WORKING_RECURSIVE_COPYFROM_REPO,
> Â STMT_UPDATE_LOCK_REPOS_ID
> Â };
>
> +/* This is a character used to escape itself and the globbing character in
> + Â globbing sql expressions below. Â See escape_sqlite_glob(). */
> +#define LIKE_ESCAPE_CHAR Â Â "#"
> +
> Â static const char * const statements[] = {
> Â /* STMT_SELECT_BASE_NODE */
> Â "select wc_id, local_relpath, repos_id, repos_relpath, "
> @@ -332,26 +334,23 @@ static const char * const statements[] =
> Â "delete from lock "
> Â "where repos_id = ?1 and repos_relpath = ?2;",
>
> - Â /* STMT_UPDATE_BASE_REPO */
> - Â "update base_node set repos_id = ?3 "
> - Â "where wc_id = ?1 and local_relpath = ?2;",
> -
> - Â /* STMT_UPDATE_BASE_CHILDREN_REPO */
> - Â "update base_node set repos_id = ?3 "
> - Â "where repos_id is not null and wc_id = ?1 and parent_relpath like ?2;",
> -
> - Â /* STMT_UPDATE_WORKING_COPYFROM_REPO */
> - Â "update working_node set copyfrom_repos_id = ?3 "
> - Â "where copyfrom_repos_id is not null and wc_id = ?1 and local_relpath = ?2;",
> -
> - Â /* STMT_UPDATE_WORKING_CHILDREN_COPYFROM_REPO */
> - Â "update working_node set copyfrom_repos_id = ?3 "
> - Â "where copyfrom_repos_id is not null and wc_id = ?1 "
> - Â " Â and parent_relpath like ?2;",
> + Â /* STMT_UPDATE_BASE_RECURSIVE_REPO */
> + Â "update base_node set repos_id = ?4 "
> + Â "where repos_id is not null and wc_id = ?1 and "
> + Â " Â (local_relpath = ?2 or "
> + Â " Â local_relpath like ?3 escape '" LIKE_ESCAPE_CHAR "');",
> +
> + Â /* STMT_UPDATE_WORKING_RECURSIVE_COPYFROM_REPO */
> + Â "update working_node set copyfrom_repos_id = ?4 "
> + Â "where copyfrom_repos_id is not null and wc_id = ?1 and "
> + Â " Â (local_relpath = ?2 or "
> + Â " Â local_relpath like ?3 escape '" LIKE_ESCAPE_CHAR "');",
>
> Â /* STMT_UPDATE_LOCK_REPOS_ID */
> - Â "update lock set repos_id = ?3 "
> - Â "where repos_id = ?1 and repos_relpath like ?2;",
> + Â "update lock set repos_id = ?4 "
> + Â "where repos_id = ?1 and "
> + Â " Â (repos_relpath = ?2 or "
> + Â " Â repos_relpath like ?3 escape '" LIKE_ESCAPE_CHAR "');",
>
> Â NULL
> Â };
> @@ -485,6 +484,42 @@ get_translated_size(svn_sqlite__stmt_t *
> Â return svn_sqlite__column_int64(stmt, slot);
> Â }
>
> +static const char *
> +escape_sqlite_like(const char * const str, apr_pool_t *result_pool)
> +{
> + Â char *result;
> + Â const char *old_ptr;
> + Â char *new_ptr;
> + Â int len = 0;
> +
> + Â /* Count the number of extra characters we'll need in the escaped string.
> + Â Â We could just use the worst case (double) value, but we'd still need to
> + Â Â iterate over the string to get it's length. Â So why not do something
> + Â Â useful why iterating over it, and save some memory at the same time? */
> + Â for (old_ptr = str; *old_ptr; ++old_ptr)
> + Â Â {
> + Â Â Â len++;
> + Â Â Â if (*old_ptr == '%'
> + Â Â Â Â Â Â || *old_ptr == '_'
> + Â Â Â Â Â Â || *old_ptr == LIKE_ESCAPE_CHAR[0])
> + Â Â Â Â len++;
> + Â Â }
> +
> + Â result = apr_pcalloc(result_pool, len + 1);
> +
> + Â /* Now do the escaping. */
> + Â for (old_ptr = str, new_ptr = result; *old_ptr; ++old_ptr, ++new_ptr)
> + Â Â {
> + Â Â Â if (*old_ptr == '%'
> + Â Â Â Â Â Â || *old_ptr == '_'
> + Â Â Â Â Â Â || *old_ptr == LIKE_ESCAPE_CHAR[0])
> + Â Â Â Â *(new_ptr++) = LIKE_ESCAPE_CHAR[0];
> + Â Â Â *new_ptr = *old_ptr;
> + Â Â }
> +
> + Â return result;
> +}
> +
>
> Â /* Construct a new wcroot_t. The WCROOT_ABSPATH and SDB parameters must
> Â Â have lifetime of at least RESULT_POOL. Â */
> @@ -3083,6 +3118,7 @@ static svn_error_t *
> Â relocate_txn(void *baton, svn_sqlite__db_t *sdb)
> Â {
> Â struct relocate_baton *rb = baton;
> + Â const char *like_arg;
> Â apr_pool_t *scratch_pool = rb->scratch_pool;
> Â svn_sqlite__stmt_t *stmt;
> Â apr_int64_t new_repos_id;
> @@ -3098,51 +3134,41 @@ relocate_txn(void *baton, svn_sqlite__db
> Â SVN_ERR(create_repos_id(&new_repos_id, rb->repos_root_url, rb->repos_uuid,
> Â Â Â Â Â Â Â Â Â Â Â Â Â sdb, scratch_pool));
>
> - Â if (rb->have_base_node)
> - Â Â {
> - Â Â Â /* Update the BASE_NODE.repos_id. */
> - Â Â Â SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_UPDATE_BASE_REPO));
> - Â Â Â SVN_ERR(svn_sqlite__bindf(stmt, "isi", rb->wc_id, rb->local_relpath,
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â new_repos_id));
> -
> - Â Â Â SVN_ERR(svn_sqlite__step_done(stmt));
> - Â Â }
> -
> - Â /* Update a non-NULL WORKING_NODE.copyfrom_repos_id. */
> - Â SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â STMT_UPDATE_WORKING_COPYFROM_REPO));
> - Â SVN_ERR(svn_sqlite__bindf(stmt, "isi", rb->wc_id, rb->local_relpath,
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â new_repos_id));
> - Â SVN_ERR(svn_sqlite__step_done(stmt));
> + Â if (rb->local_relpath[0] == 0)
> + Â Â like_arg = "%";
> + Â else
> + Â Â like_arg = apr_psprintf(scratch_pool, "%s/%%",
> + Â Â Â Â Â Â Â Â Â Â Â escape_sqlite_like(rb->local_relpath, scratch_pool));
>
> - Â /* Update and child working nodes. */
> + Â /* Update non-NULL WORKING_NODE.copyfrom_repos_id. */
> Â SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â STMT_UPDATE_WORKING_CHILDREN_COPYFROM_REPO));
> - Â SVN_ERR(svn_sqlite__bindf(stmt, "isi", rb->wc_id,
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â apr_psprintf(scratch_pool, "%s/%%",
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â rb->local_relpath),
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â new_repos_id));
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â STMT_UPDATE_WORKING_RECURSIVE_COPYFROM_REPO));
> + Â SVN_ERR(svn_sqlite__bindf(stmt, "issi", rb->wc_id, rb->local_relpath,
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â like_arg, new_repos_id));
> Â SVN_ERR(svn_sqlite__step_done(stmt));
>
> Â /* Do a bunch of stuff which is conditional on us actually having a
> Â Â Â base_node in the first place. */
> Â if (rb->have_base_node)
> Â Â {
> - Â Â Â /* Update any children which have non-NULL repos_id's */
> + Â Â Â /* Update any BASE which have non-NULL repos_id's */
> Â Â Â SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â STMT_UPDATE_BASE_CHILDREN_REPO));
> - Â Â Â SVN_ERR(svn_sqlite__bindf(stmt, "isi", rb->wc_id, rb->local_relpath,
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â new_repos_id));
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â STMT_UPDATE_BASE_RECURSIVE_REPO));
> + Â Â Â SVN_ERR(svn_sqlite__bindf(stmt, "issi", rb->wc_id, rb->local_relpath,
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â like_arg, new_repos_id));
> Â Â Â SVN_ERR(svn_sqlite__step_done(stmt));
>
> Â Â Â /* Update any locks for the root or its children. */
> + Â Â Â if (rb->repos_relpath[0] == 0)
> + Â Â Â Â like_arg = "%";
> + Â Â Â else
> + Â Â Â Â like_arg = apr_psprintf(scratch_pool, "%s/%%",
> + Â Â Â Â Â Â Â Â Â Â Â escape_sqlite_like(rb->repos_relpath, scratch_pool));
> +
> Â Â Â SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
> Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â STMT_UPDATE_LOCK_REPOS_ID));
> - Â Â Â SVN_ERR(svn_sqlite__bindf(stmt, "isi",
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â rb->old_repos_id,
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â apr_psprintf(scratch_pool, "%s/%%",
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â rb->repos_relpath),
> - Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â new_repos_id));
> + Â Â Â SVN_ERR(svn_sqlite__bindf(stmt, "issi", rb->old_repos_id,
> + Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â rb->repos_relpath, like_arg, new_repos_id));
> Â Â Â SVN_ERR(svn_sqlite__step_done(stmt));
> Â Â }
>
> ------------------------------------------------------
> http://subversion.tigris.org/ds/viewMessage.do?dsForumId=495&dsMessageId=2365439
------------------------------------------------------
http://subversion.tigris.org/ds/viewMessage.do?dsForumId=462&dsMessageId=2365537
Received on 2009-06-26 01:55:16 CEST