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]

Reply via email to