summaryrefslogtreecommitdiff
path: root/subversion/tests/libsvn_wc/wc-queries-test.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-08-05 16:22:51 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-08-05 16:22:51 +0000
commitcf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch)
treeda27775a2161723ef342e91af41a8b51fedef405 /subversion/tests/libsvn_wc/wc-queries-test.c
parentbb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff)
downloadsubversion-tarball-master.tar.gz
Diffstat (limited to 'subversion/tests/libsvn_wc/wc-queries-test.c')
-rw-r--r--subversion/tests/libsvn_wc/wc-queries-test.c223
1 files changed, 198 insertions, 25 deletions
diff --git a/subversion/tests/libsvn_wc/wc-queries-test.c b/subversion/tests/libsvn_wc/wc-queries-test.c
index 0621720..d63aa57 100644
--- a/subversion/tests/libsvn_wc/wc-queries-test.c
+++ b/subversion/tests/libsvn_wc/wc-queries-test.c
@@ -22,6 +22,7 @@
*/
#include "svn_pools.h"
+#include "svn_hash.h"
#include "svn_ctype.h"
#include "private/svn_dep_compat.h"
@@ -30,22 +31,17 @@
#include "../svn_test.h"
#ifdef SVN_SQLITE_INLINE
-/* Include sqlite3 inline, making all symbols private. */
- #define SQLITE_API static
- #ifdef __APPLE__
- #include <Availability.h>
- #if __MAC_OS_X_VERSION_MIN_REQUIRED < 1060
- /* <libkern/OSAtomic.h> is included on OS X by sqlite3.c, and
- on old systems (Leopard or older), it cannot be compiled
- with -std=c89 because it uses inline. This is a work-around. */
- #define inline __inline__
- #include <libkern/OSAtomic.h>
- #undef inline
- #endif
- #endif
- #include <sqlite3.c>
+/* Import the sqlite3 API vtable from sqlite3wrapper.c */
+# define SQLITE_OMIT_DEPRECATED
+# include <sqlite3ext.h>
+extern const sqlite3_api_routines *const svn_sqlite3__api_funcs;
+extern int (*const svn_sqlite3__api_initialize)(void);
+extern int (*const svn_sqlite3__api_config)(int, ...);
+# define sqlite3_api svn_sqlite3__api_funcs
+# define sqlite3_initialize svn_sqlite3__api_initialize
+# define sqlite3_config svn_sqlite3__api_config
#else
- #include <sqlite3.h>
+# include <sqlite3.h>
#endif
#include "../../libsvn_wc/wc-queries.h"
@@ -56,7 +52,7 @@ WC_QUERIES_SQL_DECLARE_STATEMENT_INFO(wc_query_info);
/* The first query after the normal wc queries */
#define STMT_SCHEMA_FIRST STMT_CREATE_SCHEMA
-#define SQLITE_ERR(x) \
+#define SQLITE_ERR(x) do \
{ \
int sqlite_err__temp = (x); \
if (sqlite_err__temp != SQLITE_OK) \
@@ -101,6 +97,7 @@ static const int slow_statements[] =
/* Full temporary table read */
STMT_INSERT_ACTUAL_EMPTIES,
+ STMT_INSERT_ACTUAL_EMPTIES_FILES,
STMT_SELECT_REVERT_LIST_RECURSIVE,
STMT_SELECT_DELETE_LIST,
STMT_SELECT_UPDATE_MOVE_LIST,
@@ -177,15 +174,15 @@ create_memory_db(sqlite3 **db,
static svn_error_t *
test_sqlite_version(apr_pool_t *scratch_pool)
{
- printf("DBG: Using Sqlite %s\n", sqlite3_version);
+ printf("DBG: Using Sqlite %s\n", sqlite3_libversion());
if (sqlite3_libversion_number() != SQLITE_VERSION_NUMBER)
- printf("DBG: Compiled against Sqlite %s", SQLITE_VERSION);
+ printf("DBG: Compiled against Sqlite %s\n", SQLITE_VERSION);
if (sqlite3_libversion_number() < SQLITE_VERSION_NUMBER)
return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
"Compiled against Sqlite %s (at runtime we have Sqlite %s)",
- SQLITE_VERSION, sqlite3_version);
+ SQLITE_VERSION, sqlite3_libversion());
#if !SQLITE_VERSION_AT_LEAST(3, 7, 9)
return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
@@ -307,14 +304,21 @@ parse_explanation_item(struct explanation_item **parsed_item,
item->search = TRUE; /* Search or scan */
token = apr_strtok(NULL, " ", &last);
- if (!MATCH_TOKEN(token, "TABLE"))
+ if (MATCH_TOKEN(token, "TABLE"))
+ {
+ item->table = apr_strtok(NULL, " ", &last);
+ }
+ else if (MATCH_TOKEN(token, "SUBQUERY"))
+ {
+ item->table = apr_psprintf(result_pool, "SUBQUERY-%s",
+ apr_strtok(NULL, " ", &last));
+ }
+ else
{
printf("DBG: Expected 'TABLE', got '%s' in '%s'\n", token, text);
return SVN_NO_ERROR; /* Nothing to parse */
}
- item->table = apr_strtok(NULL, " ", &last);
-
token = apr_strtok(NULL, " ", &last);
/* Skip alias */
@@ -418,7 +422,7 @@ parse_explanation_item(struct explanation_item **parsed_item,
return SVN_NO_ERROR;
}
- /* Parsing successfull */
+ /* Parsing successful */
}
else if (MATCH_TOKEN(item->operation, "EXECUTE"))
{
@@ -606,7 +610,7 @@ test_query_expectations(apr_pool_t *scratch_pool)
apr_pstrcat(iterpool,
"EXPLAIN QUERY PLAN ",
wc_queries[i],
- NULL),
+ SVN_VA_NULL),
-1, &stmt, &tail);
if (r != SQLITE_OK)
@@ -744,6 +748,105 @@ test_query_expectations(apr_pool_t *scratch_pool)
return warnings;
}
+static svn_error_t *
+test_query_duplicates(apr_pool_t *scratch_pool)
+{
+ sqlite3 *sdb;
+ int i;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ svn_error_t *warnings = NULL;
+ svn_boolean_t supports_query_info;
+ apr_hash_t *sha_to_query = apr_hash_make(scratch_pool);
+
+ SVN_ERR(create_memory_db(&sdb, scratch_pool));
+
+ SVN_ERR(supported_explain_query_plan(&supports_query_info, sdb,
+ scratch_pool));
+ if (!supports_query_info)
+ {
+ SQLITE_ERR(sqlite3_close(sdb));
+ return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
+ "Sqlite doesn't support EXPLAIN QUERY PLAN");
+ }
+
+ for (i = 0; i < STMT_SCHEMA_FIRST; i++)
+ {
+ sqlite3_stmt *stmt;
+ const char *tail;
+ int r;
+ svn_stringbuf_t *result;
+ svn_checksum_t *checksum;
+
+ if (is_schema_statement(i))
+ continue;
+
+ /* Prepare statement to find if it is a single statement. */
+ r = sqlite3_prepare_v2(sdb, wc_queries[i], -1, &stmt, &tail);
+
+ if (r != SQLITE_OK)
+ continue; /* Parse failure is already reported by 'test_parable' */
+
+ SQLITE_ERR(sqlite3_finalize(stmt));
+ if (tail[0] != '\0')
+ continue; /* Multi-queries are currently not testable */
+
+ svn_pool_clear(iterpool);
+
+ r = sqlite3_prepare_v2(sdb,
+ apr_pstrcat(iterpool,
+ "EXPLAIN ",
+ wc_queries[i],
+ SVN_VA_NULL),
+ -1, &stmt, &tail);
+
+ if (r != SQLITE_OK)
+ continue; /* EXPLAIN not enabled or doesn't support this query */
+
+ result = svn_stringbuf_create_empty(iterpool);
+
+ while (SQLITE_ROW == (r = sqlite3_step(stmt)))
+ {
+ int col;
+
+ for (col = 0; col < sqlite3_column_count(stmt); col++)
+ {
+ const char *txt = (const char*)sqlite3_column_text(stmt, col);
+ if (txt)
+ svn_stringbuf_appendcstr(result, txt);
+
+ svn_stringbuf_appendcstr(result, "|");
+ }
+
+ svn_stringbuf_appendcstr(result, "\n");
+ }
+
+ SQLITE_ERR(sqlite3_reset(stmt));
+ SQLITE_ERR(sqlite3_finalize(stmt));
+
+ SVN_ERR(svn_checksum(&checksum, svn_checksum_sha1,
+ result->data, result->len,
+ iterpool));
+
+ {
+ const char *hex = svn_checksum_to_cstring(checksum, scratch_pool);
+ const char *other;
+
+ other = svn_hash_gets(sha_to_query, hex);
+ if (other)
+ {
+ warnings = svn_error_createf(SVN_ERR_TEST_FAILED, warnings,
+ "Query %s has an identical execution plan as %s",
+ wc_query_info[i][0], other);
+ }
+ else
+ svn_hash_sets(sha_to_query, hex, wc_query_info[i][0]);
+ }
+ }
+ SQLITE_ERR(sqlite3_close(sdb)); /* Close the DB if ok; otherwise leaked */
+
+ return warnings;
+}
+
/* Helper to verify a bit of data in the sqlite3 statistics */
static int
parse_stat_data(const char *stat)
@@ -824,6 +927,15 @@ test_schema_statistics(apr_pool_t *scratch_pool)
"VALUES (1, '', '')",
NULL, NULL, NULL));
+ SQLITE_ERR(
+ sqlite3_exec(sdb,
+ "INSERT INTO EXTERNALS (wc_id, local_relpath,"
+ " parent_relpath, repos_id,"
+ " presence, kind, def_local_relpath,"
+ " def_repos_relpath) "
+ "VALUES (1, 'subdir', '', 1, 'normal', 'dir', '', '')",
+ NULL, NULL, NULL));
+
/* These are currently not necessary for query optimization, but it's better
to tell Sqlite how we intend to use this table anyway */
SQLITE_ERR(
@@ -882,7 +994,62 @@ test_schema_statistics(apr_pool_t *scratch_pool)
return SVN_NO_ERROR;
}
-struct svn_test_descriptor_t test_funcs[] =
+/* An SQLite application defined function that allows SQL queries to
+ use "relpath_depth(local_relpath)". */
+static void relpath_depth_sqlite(sqlite3_context* context,
+ int argc,
+ sqlite3_value* values[])
+{
+ SVN_ERR_MALFUNCTION_NO_RETURN(); /* STUB! */
+}
+
+/* Parse all verify/check queries */
+static svn_error_t *
+test_verify_parsable(apr_pool_t *scratch_pool)
+{
+ sqlite3 *sdb;
+ int i;
+
+ SVN_ERR(create_memory_db(&sdb, scratch_pool));
+
+ SQLITE_ERR(sqlite3_create_function(sdb, "relpath_depth", 1, SQLITE_ANY, NULL,
+ relpath_depth_sqlite, NULL, NULL));
+
+ for (i=STMT_VERIFICATION_TRIGGERS; wc_queries[i]; i++)
+ {
+ sqlite3_stmt *stmt;
+ const char *text = wc_queries[i];
+
+ /* Some of our statement texts contain multiple queries. We prepare
+ them all. */
+ while (*text != '\0')
+ {
+ const char *tail;
+ int r = sqlite3_prepare_v2(sdb, text, -1, &stmt, &tail);
+
+ if (r != SQLITE_OK)
+ return svn_error_createf(SVN_ERR_SQLITE_ERROR, NULL,
+ "Preparing %s failed: %s\n%s",
+ wc_query_info[i][0],
+ sqlite3_errmsg(sdb),
+ text);
+
+ SQLITE_ERR(sqlite3_finalize(stmt));
+
+ /* Continue after the current statement */
+ text = tail;
+ }
+ }
+
+ SQLITE_ERR(sqlite3_close(sdb)); /* Close the DB if ok; otherwise leaked */
+
+ return SVN_NO_ERROR;
+}
+
+
+static int max_threads = 1;
+
+static struct svn_test_descriptor_t test_funcs[] =
{
SVN_TEST_NULL,
SVN_TEST_PASS2(test_sqlite_version,
@@ -891,7 +1058,13 @@ struct svn_test_descriptor_t test_funcs[] =
"queries are parsable"),
SVN_TEST_PASS2(test_query_expectations,
"test query expectations"),
+ SVN_TEST_PASS2(test_query_duplicates,
+ "test query duplicates"),
SVN_TEST_PASS2(test_schema_statistics,
"test schema statistics"),
+ SVN_TEST_PASS2(test_verify_parsable,
+ "verify queries are parsable"),
SVN_TEST_NULL
};
+
+SVN_TEST_MAIN