diff --git a/test/Makefile.in b/test/Makefile.in index 3f9a9af0..969839dc 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -33,9 +33,9 @@ installcheck: all odbc.ini reset-db runsuite # If the perl 'prove' test running utility is available, use it. It produces # nice output. But otherwise just run the plain suite, it's usable as is too. ifdef PROVE - prove -e ./runsuite $(TESTNAMES) :: --inputdir=$(origdir) + prove -e ./runsuite $(TESTNAMES) :: --inputdir=$(origdir) $(if $(server_version),--server-version=$(server_version)) else - ./runsuite $(TESTNAMES) --inputdir=$(origdir) + ./runsuite $(TESTNAMES) --inputdir=$(origdir) $(if $(server_version),--server-version=$(server_version)) endif override CFLAGS += -Wno-pointer-sign $(CFLAGS_ADD) diff --git a/test/expected/v19/error-rollback.out b/test/expected/v19/error-rollback.out new file mode 100644 index 00000000..b1b5be74 --- /dev/null +++ b/test/expected/v19/error-rollback.out @@ -0,0 +1,58 @@ +Test for rollback protocol 0 +connected +Executing query that will succeed +Executing query that will fail +Failed to execute statement +22P02=ERROR: invalid input syntax for type integer: "fail1"; +Error while executing the query +Rolling back with SQLEndTran +Executing query that will succeed +Result set: +1 +disconnecting +Test for rollback protocol 1 +connected +Executing query that will succeed +Executing query that will fail +Failed to execute statement +22P02=ERROR: invalid input syntax for type integer: "fail1"; +Error while executing the query +Executing query that will succeed +Result set: +1 +disconnecting +Test for rollback protocol 2 +connected +Executing query that will succeed +Executing query that will succeed +Executing query that will fail +Failed to execute statement +22P02=ERROR: invalid input syntax for type integer: "fail-1"; +Error while executing the query +Executing query that will succeed +Executing query that will succeed +Executing query that will fail +Failed to execute statement +22P02=ERROR: invalid input syntax for type integer: "fail-1"; +Error while executing the query +Executing query that will fail +Failed to execute statement +22P02=ERROR: invalid input syntax for type integer: "fail-1"; +Error while executing the query +Executing query that will succeed +Executing procedure call that will fail +Failed to execute procedure call +42883=ERROR: function invalidfunction() does not exist +DETAIL: There is no function of that name.; +Error while executing the query +Executing query that will succeed +Executing query that will succeed +Result set: +1 +2 +3 +4 +5 +6 +7 +disconnecting diff --git a/test/expected/v19/quotes.out b/test/expected/v19/quotes.out new file mode 100644 index 00000000..3bf795a8 --- /dev/null +++ b/test/expected/v19/quotes.out @@ -0,0 +1,34 @@ +connected + +SET standard_conforming_strings=on +Executing: SELECT 'foo', ?::text with param: param'quote +Result set: +foo param'quote +Executing: SELECT 'foo', ?::text with param: param\backslash +Result set: +foo param\backslash +Executing: SELECT 'foo', ?::text with param: ends with backslash\ +Result set: +foo ends with backslash\ +Executing: SELECT 'doubled '' quotes', ?::text with param: param +Result set: +doubled ' quotes param +Executing: SELECT E'escaped quote\' here', ?::text with param: param +Result set: +escaped quote' here param +Executing: SELECT $$dollar quoted string$$, ?::text with param: param +Result set: +dollar quoted string param +Executing: SELECT $xx$complex $dollar quotes$xx$, ?::text with param: param +Result set: +complex $dollar quotes param +Executing: SELECT $dollar$morecomplex $dollar quotes$dollar$, ?::text with param: param +Result set: +morecomplex $dollar quotes param +Executing: SELECT ?::text, '1' a$1 with param: $ in an identifier +Result set: +$ in an identifier 1 +Executing: SELECT '1'::text a$$S1,?::text,$$2 $'s in an identifier$$::text with param: param +Result set: +1 param 2 $'s in an identifier +disconnecting diff --git a/test/runsuite.c b/test/runsuite.c index 6ac37091..bc3000b6 100644 --- a/test/runsuite.c +++ b/test/runsuite.c @@ -27,8 +27,8 @@ #define strdup _strdup #endif -static int rundiff(const char *testname, const char *inputdir); -static int runtest(const char *binname, const char *testname, int testno, const char *inputdir); +static int rundiff(const char *testname, const char *inputdir, int server_version); +static int runtest(const char *binname, const char *testname, int testno, const char *inputdir, int server_version); static char *slurpfile(const char *filename, size_t *len); @@ -109,16 +109,24 @@ int main(int argc, char **argv) int failures; const char *inputdir = "."; int sub_count = 1; + int server_version = 0; if (argc < 2) { printf("Usage: runsuite ...\n"); exit(1); } - if (strncmp(argv[argc - 1], "--inputdir=", 11) == 0) + /* Parse trailing options */ + while (argc - sub_count >= 2) { + const char *arg = argv[argc - sub_count]; + if (strncmp(arg, "--inputdir=", 11) == 0) + inputdir = arg + 11; + else if (strncmp(arg, "--server-version=", 17) == 0) + server_version = atoi(arg + 17); + else + break; sub_count++; - inputdir = argv[argc - 1] + 11; } numtests = argc - sub_count; @@ -132,7 +140,7 @@ int main(int argc, char **argv) for (i = 1, j = 1; i <= numtests; i++, j++) { parse_argument(argv[j], testname, binname); - if (runtest(binname, testname, i, inputdir) != 0) + if (runtest(binname, testname, i, inputdir, server_version) != 0) failures++; } @@ -141,7 +149,7 @@ int main(int argc, char **argv) /* Return 0 on success, 1 on failure */ static int -runtest(const char *binname, const char *testname, int testno, const char *inputdir) +runtest(const char *binname, const char *testname, int testno, const char *inputdir, int server_version) { char cmdline[1024]; int rc; @@ -170,7 +178,7 @@ runtest(const char *binname, const char *testname, int testno, const char *input #endif rc = system(cmdline); - diff = rundiff(testname, inputdir); + diff = rundiff(testname, inputdir, server_version); if (rc != 0) { printf("not ok %d - %s test returned %d\n", testno, testname, rc); @@ -233,9 +241,10 @@ call_diff(const char *inputdir, const char *expected_dir, const char *testname, } static int -rundiff(const char *testname, const char *inputdir) +rundiff(const char *testname, const char *inputdir, int server_version) { char filename[1024]; + char ver_expected_dir[64]; int outputno, no_spec; char *result = NULL; size_t result_len; @@ -250,6 +259,20 @@ rundiff(const char *testname, const char *inputdir) int i, j; const char CR = '\r', LF = '\n'; char se, sr; + const char *dirs[2]; + int num_dirs = 0; + + /* Build list of expected directories to check (version-specific first) */ + if (server_version > 0) + { +#ifdef WIN32 + snprintf(ver_expected_dir, sizeof(ver_expected_dir), "\\expected\\v%d\\", server_version); +#else + snprintf(ver_expected_dir, sizeof(ver_expected_dir), "/expected/v%d/", server_version); +#endif + dirs[num_dirs++] = ver_expected_dir; + } + dirs[num_dirs++] = expected_dir; snprintf(filename, sizeof(filename), "%s%s.out", result_dir, testname); result = slurpfile(filename, &result_len); @@ -259,74 +282,82 @@ rundiff(const char *testname, const char *inputdir) { char *expected; size_t expected_len; + int d; + int found = 0; - if (outputno == 0) - snprintf(filename, sizeof(filename), "%s%s%s.out", inputdir, expected_dir, testname); - else - snprintf(filename, sizeof(filename), "%s%s%s_%d.out", inputdir, expected_dir, testname, outputno); - expected = slurpfile(filename, &expected_len); - if (expected == NULL) + /* Try each expected directory (version-specific first) */ + for (d = 0; d < num_dirs; d++) { if (outputno == 0) - bailout("could not open file %s: %s\n", filename, strerror(ENOENT)); - break; - } - - if (expected_len == result_len && - memcmp(expected, result, expected_len) == 0) - { - /* The files are equal. */ - free(result); - free(expected); - return 0; - } - /* Ignore the difference between CR LF, LF and CR line break */ - for (i = 0, j = 0, se = sr = '\0'; i < expected_len && j < result_len; - se = expected[i], sr = result[j], i++, j++) - { - if (expected[i] == result[j]) + snprintf(filename, sizeof(filename), "%s%s%s.out", inputdir, dirs[d], testname); + else + snprintf(filename, sizeof(filename), "%s%s%s_%d.out", inputdir, dirs[d], testname, outputno); + expected = slurpfile(filename, &expected_len); + if (expected == NULL) continue; - if (result[j] == LF) + found = 1; + + if (expected_len == result_len && + memcmp(expected, result, expected_len) == 0) { - if (expected[i] == CR) + free(result); + free(expected); + return 0; + } + /* Ignore the difference between CR LF, LF and CR line break */ + for (i = 0, j = 0, se = sr = '\0'; i < expected_len && j < result_len; + se = expected[i], sr = result[j], i++, j++) + { + if (expected[i] == result[j]) + continue; + if (result[j] == LF) { - i++; - if (expected[i] != LF) + if (expected[i] == CR) + { + i++; + if (expected[i] != LF) + i--; + continue; + } + else if (sr == CR && se == CR) + { i--; - continue; + continue; + } } - else if (sr == CR && se == CR) + else if (expected[i] == LF) { - i--; - continue; + if (result[j] == CR) + { + j++; + if (result[j] != LF) + j--; + continue; + } + else if (sr == CR && se == CR) + { + j--; + continue; + } } + break; } - else if (expected[i] == LF) + if (i >= expected_len && j >= result_len) { - if (result[j] == CR) - { - j++; - if (result[j] != LF) - j--; - continue; - } - else if (sr == CR && se == CR) - { - j--; - continue; - } + free(result); + free(expected); + return 0; } - break; - } - if (i >= expected_len && j >= result_len) - { - /* The files are equal. */ - free(result); + free(expected); - return 0; } - free(expected); + if (!found) + { + if (outputno == 0) + bailout("could not open file %s%s%s.out: %s\n", inputdir, dirs[num_dirs - 1], testname, strerror(ENOENT)); + break; + } outputno++; } @@ -370,41 +401,53 @@ rundiff(const char *testname, const char *inputdir) * diff. */ no_spec = 0; - if (outputno > 1) { + const char *best_dir = dirs[num_dirs - 1]; const char *tmpdiff = "tmpdiff.diffs"; char outfmt[32]; - int fd, file_size; + int fd, file_size, d; struct stat stbuf; int min_size = -1; snprintf(outfmt, sizeof(outfmt), "> %s", tmpdiff); for (i = 0; i < outputno; i++) { - call_diff(inputdir, expected_dir, testname, i, result_dir, outfmt); - if ((fd = open(tmpdiff, O_RDONLY)) < 0) - break; - if (fstat(fd, &stbuf) == -1) - break; - if (file_size = stbuf.st_size, file_size == 0) - { - min_size = 0; - no_spec = i; - } - else if (min_size < 0) - min_size = file_size; - else if (file_size < min_size) + for (d = 0; d < num_dirs; d++) { - no_spec = i; - min_size = file_size; + call_diff(inputdir, dirs[d], testname, i, result_dir, outfmt); + if ((fd = open(tmpdiff, O_RDONLY)) < 0) + continue; + if (fstat(fd, &stbuf) == -1) + { + close(fd); + continue; + } + if (file_size = stbuf.st_size, file_size == 0) + { + min_size = 0; + no_spec = i; + best_dir = dirs[d]; + } + else if (min_size < 0) + { + min_size = file_size; + no_spec = i; + best_dir = dirs[d]; + } + else if (file_size < min_size) + { + no_spec = i; + min_size = file_size; + best_dir = dirs[d]; + } + close(fd); } - close(fd); } remove(tmpdiff); if (min_size == 0) return 0; + diff_rtn = call_diff(inputdir, best_dir, testname, no_spec, result_dir, ">> regression.diffs"); } - diff_rtn = call_diff(inputdir, expected_dir, testname, no_spec, result_dir, ">> regression.diffs"); return diff_rtn; } diff --git a/test/src/common.c b/test/src/common.c index 656754c3..66793fd0 100644 --- a/test/src/common.c +++ b/test/src/common.c @@ -402,3 +402,25 @@ print_result_with_column_names(HSTMT hstmt) { print_result_all(hstmt, TRUE); } + +/* + * Check server version against a major.minor version. + * Returns: -1 if server < given version, 0 if equal, 1 if server > given version. + * Returns -2 on error. + */ +int +server_version_cmp(SQLHDBC hconn, int major, int minor) +{ + char ver[32]; + int srv_major = 0, srv_minor = 0; + + if (!SQL_SUCCEEDED(SQLGetInfo(hconn, SQL_DBMS_VER, ver, sizeof(ver), NULL))) + return -2; + if (sscanf(ver, "%d.%d", &srv_major, &srv_minor) < 2) + return -2; + if (srv_major != major) + return (srv_major > major) ? 1 : -1; + if (srv_minor != minor) + return (srv_minor > minor) ? 1 : -1; + return 0; +} diff --git a/test/src/common.h b/test/src/common.h index 4de0a41b..5a067091 100644 --- a/test/src/common.h +++ b/test/src/common.h @@ -57,3 +57,10 @@ extern void print_result(HSTMT hstmt); extern void print_result_with_column_names(HSTMT hstmt); extern const char *datatype_str(SQLSMALLINT datatype); extern const char *nullable_str(SQLSMALLINT nullable); +extern int server_version_cmp(SQLHDBC hconn, int major, int minor); + +#define server_version_lt(hconn, major, minor) (server_version_cmp(hconn, major, minor) < 0) +#define server_version_gt(hconn, major, minor) (server_version_cmp(hconn, major, minor) > 0) +#define server_version_ge(hconn, major, minor) (server_version_cmp(hconn, major, minor) >= 0) +#define server_version_le(hconn, major, minor) (server_version_cmp(hconn, major, minor) <= 0) +#define server_version_eq(hconn, major, minor) (server_version_cmp(hconn, major, minor) == 0) diff --git a/test/src/quotes-test.c b/test/src/quotes-test.c index 20e747b3..3c4876b5 100644 --- a/test/src/quotes-test.c +++ b/test/src/quotes-test.c @@ -99,7 +99,9 @@ int main(int argc, char **argv) } runtest(hstmt, 1); - runtest(hstmt, 0); + if (server_version_lt(conn, 19, 0)) { + runtest(hstmt, 0); + } /* Clean up */ test_disconnect();