Changeset: 70a438bdb54f for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/70a438bdb54f
Modified Files:
clients/odbc/tests/ODBCmetadata.c
Branch: Sep2022
Log Message:
Add tests for PLAN SELECT, EXPLAIN SELECT, TRACE SELECT and DEBUG SELECT
queries via ODBC API.
diffs (227 lines):
diff --git a/clients/odbc/tests/ODBCmetadata.c
b/clients/odbc/tests/ODBCmetadata.c
--- a/clients/odbc/tests/ODBCmetadata.c
+++ b/clients/odbc/tests/ODBCmetadata.c
@@ -142,14 +142,14 @@ nameofSQLtype(SQLSMALLINT dataType)
}
static void
-compareResult(SQLHANDLE stmt, SQLRETURN retcode, const char * functionname,
const char * expected)
+compareResultOptClose(SQLHANDLE stmt, SQLRETURN retcode, const char *
functionname, const char * expected, int closeCursor)
{
SQLRETURN ret;
SQLSMALLINT columns; /* Number of columns in result-set */
SQLLEN rows; /* Number of rows in result-set */
size_t expct_len = strlen(expected);
size_t outp_len = expct_len + 10000;
- char * outp = malloc(outp_len);
+ char * outp = NULL;
size_t pos = 0;
SQLUSMALLINT col;
SQLLEN indicator;
@@ -158,14 +158,20 @@ compareResult(SQLHANDLE stmt, SQLRETURN
SQLULEN columnSize = 0;
SQLSMALLINT decimalDigits = 0;
int replaceId = 0; /* used to replace system id values in column
SPECIFIC_NAME of getProcedures and getProcedureColumns */
+ int replaceTraceData = 0; /* used to replace second result set data of
a TRACE query */
+ check(retcode, SQL_HANDLE_STMT, stmt, functionname);
+ if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) {
+ fprintf(stderr, "Invalid retcode (%d). Skipping
compareResult(%s)\n", retcode, functionname);
+ return;
+ }
+
+ outp = malloc(outp_len);
if (outp == NULL) {
fprintf(stderr, "Failed to allocate %zu memory!\n", outp_len);
return;
}
- check(retcode, SQL_HANDLE_STMT, stmt, functionname);
-
/* How many columns are there */
ret = SQLNumResultCols(stmt, &columns);
check(ret, SQL_HANDLE_STMT, stmt, "SQLNumResultCols()");
@@ -229,6 +235,11 @@ compareResult(SQLHANDLE stmt, SQLRETURN
}
}
+ /* detect if special handling of data returned by second TRACE
resultset is needed */
+ if (columns == 2 && (strncmp("TRACE(2) ", functionname, 9) == 0)) {
+ replaceTraceData = 1;
+ }
+
/* Loop through the rows in the result-set */
ret = SQLFetch(stmt);
check(ret, SQL_HANDLE_STMT, stmt, "SQLFetch(1)");
@@ -239,6 +250,20 @@ compareResult(SQLHANDLE stmt, SQLRETURN
ret = SQLGetData(stmt, col, SQL_C_CHAR, buf,
sizeof(buf), &indicator);
check(ret, SQL_HANDLE_STMT, stmt, "SQLGetData()");
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
+ /* some rows of EXPLAIN output (which has only
1 result column) must be surpressed to get stable output */
+ if (columns == 1 &&
+ (strncmp(buf, "# optimizer.", 12) == 0 ||
+ strncmp(buf, "barrier X_", 10) == 0 ||
+ strncmp(buf, "exit X_", 7) == 0) ) {
+ continue;
+ }
+
+ if (replaceTraceData == 1) {
+ pos += snprintf(outp + pos, outp_len -
pos,
+ (col == 1) ? "4" : "\tvariable
output");
+ continue;
+ }
+
/* Check if we need to replace the system id
values to get stable output */
if (replaceId == 0 ||
(replaceId == 1 && col < columns)) {
@@ -257,17 +282,41 @@ compareResult(SQLHANDLE stmt, SQLRETURN
}
if (strcmp(expected, outp) != 0) {
- fprintf(stderr, "Testing %s\nExpected:\n%s\nGotten:\n%s\n",
- functionname, expected, outp);
+ size_t len_expected = strlen(expected);
+ size_t len_outp = strlen(outp);
+ int c = 0;
+ int line = 1;
+ int pos = 1;
+
+ fprintf(stderr, "Testing %s\nExpected (strlen=%ld):\n%s\nGotten
(strlen=%ld):\n%s\n",
+ functionname, len_expected, expected, len_outp, outp);
+
+ /* scan string to find location (line and position in line) of
first character difference */
+ while (expected[c] != '\0' && outp[c] != '\0' && expected[c] ==
outp[c]) {
+ if (expected[c] == '\n') {
+ line++;
+ pos = 0;
+ }
+ c++;
+ pos++;
+ }
+ fprintf(stderr, "First difference found at line %d, position
%d, data: %-20s\n\n",
+ line, pos, (expected[c] != '\0' ? &expected[c] :
&outp[c]) );
}
/* cleanup */
free(outp);
- ret = SQLCloseCursor(stmt);
- check(ret, SQL_HANDLE_STMT, stmt, "SQLCloseCursor");
+ if (closeCursor == 1) {
+ ret = SQLCloseCursor(stmt);
+ check(ret, SQL_HANDLE_STMT, stmt, "SQLCloseCursor");
+ }
}
+#define compareResultNoClose(stmt, retcode, functionname, expected)
compareResultOptClose(stmt, retcode, functionname, expected, 0)
+#define compareResult(stmt, retcode, functionname, expected)
compareResultOptClose(stmt, retcode, functionname, expected, 1)
+
+
int
main(int argc, char **argv)
{
@@ -1369,6 +1418,104 @@ main(int argc, char **argv)
"interval minute to second 113 13 ' '
precision 1 0 2 -1 0 -1 NULL 0
0 10 13 -1 10\n"
"hugeint 16384 38 NULL NULL NULL 1
0 2 0 0 0 NULL 0 0 16384 -1
10 -1\n");
+ // test SELECT query
+ ret = SQLExecDirect(stmt, (SQLCHAR *) "SELECT * from
odbctst.\"LINES\";\n", SQL_NTS);
+ compareResult(stmt, ret, "SELECT * from odbctst.\"LINES\"",
+ "Resultset with 4 columns\n"
+ "Resultset with 0 rows\n"
+ "ORDERID LINES PARTID QUANTITY\n"
+ "INTEGER INTEGER INTEGER DECIMAL(9,3)\n");
+
+ // test PLAN SELECT query
+ ret = SQLExecDirect(stmt, (SQLCHAR *) "PLAN SELECT * from
odbctst.\"LINES\";\n", SQL_NTS);
+ compareResult(stmt, ret, "PLAN SELECT * from odbctst.\"LINES\"",
+ "Resultset with 1 columns\n"
+ "Resultset with 3 rows\n"
+ "rel\n"
+ "WLONGVARCHAR(176)\n"
+ "project (\n"
+ "| table(\"odbctst\".\"LINES\") [ \"LINES\".\"ORDERID\" NOT
NULL UNIQUE HASHCOL , \"LINES\".\"LINES\" NOT NULL UNIQUE, \"LINES\".\"PARTID\"
NOT NULL UNIQUE, \"LINES\".\"QUANTITY\" NOT NULL UNIQUE ]\n"
+ ") [ \"LINES\".\"ORDERID\" NOT NULL UNIQUE HASHCOL ,
\"LINES\".\"LINES\" NOT NULL UNIQUE, \"LINES\".\"PARTID\" NOT NULL UNIQUE,
\"LINES\".\"QUANTITY\" NOT NULL UNIQUE ]\n");
+
+ // test EXPLAIN SELECT query
+ ret = SQLExecDirect(stmt, (SQLCHAR *) "EXPLAIN SELECT * from
odbctst.\"LINES\";\n", SQL_NTS);
+ compareResult(stmt, ret, "EXPLAIN SELECT * from odbctst.\"LINES\"",
+ "Resultset with 1 columns\n"
+ "Resultset with 48 rows\n"
+ "mal\n"
+ "WLONGVARCHAR(174)\n"
+ "function user.main():void;\n"
+ " X_1:void := querylog.define(\"explain select * from
odbctst.\\\"LINES\\\";\":str, \"default_pipe\":str, 26:int);\n"
+ "\n"
+ " X_33:bat[:int] := bat.new(nil:int);\n"
+ " X_34:bat[:int] := bat.new(nil:int);\n"
+ " X_35:bat[:int] := bat.new(nil:int);\n"
+ " X_36:bat[:int] := bat.new(nil:int);\n"
+ " X_38:bat[:str] := bat.pack(\"odbctst.LINES\":str,
\"odbctst.LINES\":str, \"odbctst.LINES\":str, \"odbctst.LINES\":str);\n"
+ " X_39:bat[:str] := bat.pack(\"ORDERID\":str, \"LINES\":str,
\"PARTID\":str, \"QUANTITY\":str);\n"
+ " X_40:bat[:str] := bat.pack(\"int\":str, \"int\":str,
\"int\":str, \"decimal\":str);\n"
+ " X_41:bat[:int] := bat.pack(32:int, 32:int, 32:int,
9:int);\n"
+ " X_42:bat[:int] := bat.pack(0:int, 0:int, 0:int, 3:int);\n"
+ "\n"
+ " X_37:int := sql.resultSet(X_38:bat[:str], X_39:bat[:str],
X_40:bat[:str], X_41:bat[:int], X_42:bat[:int], X_33:bat[:int], X_34:bat[:int],
X_35:bat[:int], X_36:bat[:int]);\n"
+ "end user.main;\n"
+ "\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n\n\n\n\n\n\n\n"
+ "\n\n\n");
+
+ // test TRACE SELECT query. This will return two resultsets: first with
the query results and next with the trace results
+ ret = SQLExecDirect(stmt, (SQLCHAR *) "TRACE SELECT * from
odbctst.\"LINES\";\n", SQL_NTS);
+ compareResultNoClose(stmt, ret, "TRACE(1) SELECT * from
odbctst.\"LINES\"",
+ "Resultset with 4 columns\n"
+ "Resultset with 0 rows\n"
+ "ORDERID LINES PARTID QUANTITY\n"
+ "INTEGER INTEGER INTEGER DECIMAL(9,3)\n");
+ ret = SQLMoreResults(stmt);
+ check(ret, SQL_HANDLE_STMT, stmt, "SQLMoreResults()");
+ if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
+ compareResult(stmt, ret, "TRACE(2) SELECT * from
odbctst.\"LINES\"",
+ "Resultset with 2 columns\n"
+ "Resultset with 12 rows\n"
+ "usec statement\n"
+ "BIGINT WLONGVARCHAR(213)\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n"
+ "4 variable output\n");
+ /* next is the original output but it is varying a lot on usec
values, X_## values and even the order of rows,
+ so all data is replaced (see above) for stable output
comparison.
+ "1 X_1=0@0:void := querylog.define(\"trace
select * from odbctst.\\\"LINES\\\";\":str, \"default_pipe\":str, 26:int);\n"
+ "9 X_33=[0]:bat[:int] := bat.new(nil:int);\n"
+ "8 X_34=[0]:bat[:int] := bat.new(nil:int);\n"
+ "7 X_36=[0]:bat[:int] := bat.new(nil:int);\n"
+ "6 X_35=[0]:bat[:int] := bat.new(nil:int);\n"
+ "8 X_41=[4]:bat[:int] := bat.pack(32:int,
32:int, 32:int, 9:int);\n"
+ "13 X_42=[4]:bat[:int] := bat.pack(0:int,
0:int, 0:int, 3:int);\n"
+ "14 X_38=[4]:bat[:str] :=
bat.pack(\"odbctst.LINES\":str, \"odbctst.LINES\":str, \"odbctst.LINES\":str,
\"odbctst.LINES\":str);\n"
+ "16 X_40=[4]:bat[:str] := bat.pack(\"int\":str,
\"int\":str, \"int\":str, \"decimal\":str);\n"
+ "15 X_39=[4]:bat[:str] :=
bat.pack(\"ORDERID\":str, \"LINES\":str, \"PARTID\":str, \"QUANTITY\":str);\n"
+ "316 barrier X_106=false:bit :=
language.dataflow();\n"
+ "22 X_37=76:int :=
sql.resultSet(X_38=[4]:bat[:str], X_39=[4]:bat[:str], X_40=[4]:bat[:str],
X_41=[4]:bat[:int], X_42=[4]:bat[:int], X_33=[0]:bat[:int], X_34=[0]:bat[:int],
X_35=[0]:bat[:int], X_36=[0]:bat[:int]);\n");
+ */
+ }
+
+ // test DEBUG SELECT query. DEBUG statements are not supported in ODBC
and should produce an Error
+ ret = SQLExecDirect(stmt, (SQLCHAR *) "DEBUG SELECT * from
odbctst.\"LINES\";\n", SQL_NTS);
+ if (ret != SQL_ERROR) {
+ /* Error: SQLstate 42000, Errnr 0, Message [MonetDB][ODBC
Driver 11.45.0][MonetDB-Test]SQL debugging only supported in interactive mode
in: "debug" */
+ compareResult(stmt, ret, "DEBUG SELECT * from
odbctst.\"LINES\"",
+ "We do not expect DEBUG to be possible via ODBC API.
Only supported in mclient.\n");
+ }
+
// cleanup
ret = SQLExecDirect(stmt, (SQLCHAR *)
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]