Changeset: deab5b429396 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/deab5b429396
Added Files:
        clients/odbc/samples/metadata.c
        sql/odbc/samples/Tests/metadata.SQL.sh
Modified Files:
        clients/odbc/samples/CMakeLists.txt
        sql/odbc/samples/Tests/All
Branch: default
Log Message:

Adding a new ODBC test program to test ODBC metadata functions, such as 
SQLTables(), SQLColumns(), SQLPrimaryKeys(), etc.


diffs (truncated from 318 to 300 lines):

diff --git a/clients/odbc/samples/CMakeLists.txt 
b/clients/odbc/samples/CMakeLists.txt
--- a/clients/odbc/samples/CMakeLists.txt
+++ b/clients/odbc/samples/CMakeLists.txt
@@ -36,11 +36,19 @@ if(TESTING)
     PRIVATE
     ODBC::ODBC)
 
+  add_executable(metadata
+    metadata.c)
+
+  target_link_libraries(metadata
+    PRIVATE
+    ODBC::ODBC)
+
   install(TARGETS
     odbcsample1
     testgetinfo
     arraytest
     testStmtAttr
+    metadata
     RUNTIME
     DESTINATION
     ${CMAKE_INSTALL_BINDIR}
@@ -52,6 +60,7 @@ if(TESTING)
       $<TARGET_PDB_FILE:testgetinfo>
       $<TARGET_PDB_FILE:arraytest>
       $<TARGET_PDB_FILE:testStmtAttr>
+      $<TARGET_PDB_FILE:metadata>
       DESTINATION ${CMAKE_INSTALL_BINDIR}
       OPTIONAL)
   endif()
diff --git a/clients/odbc/samples/metadata.c b/clients/odbc/samples/metadata.c
new file mode 100644
--- /dev/null
+++ b/clients/odbc/samples/metadata.c
@@ -0,0 +1,250 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0.  If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright 1997 - July 2008 CWI, August 2008 - 2022 MonetDB B.V.
+ */
+
+#ifdef _MSC_VER
+#include <WTypes.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sql.h>
+#include <sqlext.h>
+#include <string.h>
+
+static void
+prerr(SQLSMALLINT tpe, SQLHANDLE hnd, const char *func, const char *pref)
+{
+       SQLCHAR state[6];
+       SQLINTEGER errnr;
+       SQLCHAR msg[256];
+       SQLSMALLINT msglen;
+       SQLRETURN ret;
+
+       ret = SQLGetDiagRec(tpe, hnd, 1, state, &errnr, msg, sizeof(msg), 
&msglen);
+       switch (ret) {
+       case SQL_SUCCESS_WITH_INFO:
+               if (msglen >= (signed int) sizeof(msg))
+                       fprintf(stderr, "(message truncated)\n");
+               /* fall through */
+       case SQL_SUCCESS:
+               fprintf(stderr, "%s: %s: SQLstate %s, Errnr %d, Message %s\n", 
func, pref, (char*)state, (int)errnr, (char*)msg);
+               break;
+       case SQL_INVALID_HANDLE:
+               fprintf(stderr, "%s: %s, invalid handle passed to error 
function\n", func, pref);
+               break;
+       case SQL_ERROR:
+               fprintf(stderr, "%s: %s, unexpected error from 
SQLGetDiagRec\n", func, pref);
+               break;
+       case SQL_NO_DATA:
+               break;
+       default:
+               fprintf(stderr, "%s: %s, weird return value from 
SQLGetDiagRec\n", func, pref);
+               break;
+       }
+}
+
+static void
+check(SQLRETURN ret, SQLSMALLINT tpe, SQLHANDLE hnd, const char *func)
+{
+       switch (ret) {
+       case SQL_SUCCESS:
+               break;
+       case SQL_SUCCESS_WITH_INFO:
+               prerr(tpe, hnd, func, "Info");
+               break;
+       case SQL_ERROR:
+               prerr(tpe, hnd, func, "Error");
+               break;
+       case SQL_NO_DATA:
+               break;
+       case SQL_INVALID_HANDLE:
+               fprintf(stderr, "%s: Error: invalid handle\n", func);
+               exit(1);
+       default:
+               fprintf(stderr, "%s: Unexpected return value\n", func);
+               break;
+       }
+}
+
+static void
+renewStmtHandle(SQLHANDLE dbc, SQLHANDLE stmt)
+{
+       SQLRETURN ret;
+
+       ret = SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+       check(ret, SQL_HANDLE_STMT, stmt, "SQLFreeHandle (STMT)");
+
+       ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
+       check(ret, SQL_HANDLE_DBC, dbc, "SQLAllocHandle (STMT)");
+}
+
+static void
+compareResult(SQLHANDLE stmt, const char * functionname, const char * expected)
+{
+       SQLRETURN ret;
+       SQLSMALLINT columns;    // Number of columns in result-set
+       size_t expct_len = strlen(expected);
+       size_t outp_len = expct_len + 1000;
+       char * outp = malloc(outp_len);
+       size_t pos = 0;
+       SQLUSMALLINT col;
+       SQLLEN indicator;
+       char buf[255];
+
+       SQLSMALLINT nameLength;
+       SQLSMALLINT dataType;
+
+       // How many columns are there
+       ret = SQLNumResultCols(stmt, &columns);
+       check(ret, SQL_HANDLE_STMT, stmt, "SQLNumResultCols()");
+       pos += snprintf(outp + pos, outp_len - pos, "Resultset with %d 
columns\n", columns);
+
+       // get Result Column Names and print them
+       for (col = 1; col <= columns; col++) {
+               ret = SQLDescribeCol(stmt, col, (SQLCHAR *) buf, sizeof(buf),
+                       &nameLength, &dataType, NULL, NULL, NULL);
+               check(ret, SQL_HANDLE_STMT, stmt, "SQLDescribeCol()");
+               pos += snprintf(outp + pos, outp_len - pos,
+                               (col > 1) ? "\t%s" : "%s", buf);
+       }
+       pos += snprintf(outp + pos, outp_len - pos, "\n");
+
+       /* Loop through the rows in the result-set */
+       ret = SQLFetch(stmt);
+       check(ret, SQL_HANDLE_STMT, stmt, "SQLFetch(1)");
+       while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
+               // Loop through the columns
+               for (col = 1; col <= columns; col++) {
+                       // Retrieve column data as a string
+                       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) 
{
+                               // Handle null columns
+                               if (indicator == SQL_NULL_DATA)
+                                       strcpy(buf, "NULL");
+
+                               pos += snprintf(outp + pos, outp_len - pos,
+                                       (col > 1) ? "\t%s" : "%s", buf);
+                       }
+               }
+               pos += snprintf(outp + pos, outp_len - pos, "\n");
+               ret = SQLFetch(stmt);
+               check(ret, SQL_HANDLE_STMT, stmt, "SQLFetch(n)");
+       }
+
+       if (strcmp(expected, outp) != 0) {
+               fprintf(stderr, "Testing %s\nExpected:\n%s\nGotten:\n%s\n",
+                       functionname, expected, outp);
+       }
+
+       // cleanup
+       free(outp);
+}
+
+int
+main(int argc, char **argv)
+{
+       SQLRETURN ret;
+       SQLHANDLE env;
+       SQLHANDLE dbc;
+       SQLHANDLE stmt;
+       char *dsn = "MonetDB";
+       char *user = "monetdb";
+       char *pass = "monetdb";
+
+       if (argc > 1)
+               dsn = argv[1];
+       if (argc > 2)
+               user = argv[2];
+       if (argc > 3)
+               pass = argv[3];
+       if (argc > 4 || *dsn == '-') {
+               fprintf(stderr, "Usage: %s [datasource [user [password]]]\n", 
argv[0]);
+               exit(1);
+       }
+
+       ret = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &env);
+       if (ret != SQL_SUCCESS) {
+               fprintf(stderr, "Cannot allocate ODBC environment handle!\n");
+               exit(1);
+       }
+
+       ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) 
(uintptr_t) SQL_OV_ODBC3, 0);
+       check(ret, SQL_HANDLE_ENV, env, "SQLSetEnvAttr (SQL_ATTR_ODBC_VERSION 
ODBC3)");
+
+       ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
+       check(ret, SQL_HANDLE_ENV, env, "SQLAllocHandle (DBC)");
+
+       ret = SQLConnect(dbc, (SQLCHAR *) dsn, SQL_NTS, (SQLCHAR *) user, 
SQL_NTS, (SQLCHAR *) pass, SQL_NTS);
+       check(ret, SQL_HANDLE_DBC, dbc, "SQLConnect");
+
+       ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
+       check(ret, SQL_HANDLE_DBC, dbc, "SQLAllocHandle (STMT)");
+
+       /* run actual tests */
+       // All catalogs query
+       ret = SQLTables(stmt, (SQLCHAR*)SQL_ALL_CATALOGS, SQL_NTS,
+                       (SQLCHAR*)"", SQL_NTS, (SQLCHAR*)"", SQL_NTS,
+                       (SQLCHAR*)"", SQL_NTS);
+       check(ret, SQL_HANDLE_STMT, stmt, "SQLTables (SQL_ALL_CATALOGS)");
+       compareResult(stmt, "SQLTables (SQL_ALL_CATALOGS)",
+                       "Resultset with 5 columns\n"
+                       "table_cat      table_schem     table_name      
table_type      remarks\n"
+                       "mTests_sql_odbc_samples        NULL    NULL    NULL    
NULL\n");
+       renewStmtHandle(dbc, stmt);
+
+       // All schemas query
+       ret = SQLTables(stmt, (SQLCHAR*)"", SQL_NTS,
+                       (SQLCHAR*)SQL_ALL_SCHEMAS, SQL_NTS,
+                       (SQLCHAR*)"", SQL_NTS, (SQLCHAR*)"", SQL_NTS);
+       check(ret, SQL_HANDLE_STMT, stmt, "SQLTables (SQL_ALL_SCHEMAS)");
+       compareResult(stmt, "SQLTables (SQL_ALL_SCHEMAS)",
+                       "Resultset with 5 columns\n"
+                       "table_cat      table_schem     table_name      
table_type      remarks\n"
+                       "NULL   json    NULL    NULL    NULL\n"
+                       "NULL   logging NULL    NULL    NULL\n"
+                       "NULL   profiler        NULL    NULL    NULL\n"
+                       "NULL   sys     NULL    NULL    NULL\n"
+                       "NULL   tmp     NULL    NULL    NULL\n"
+                       "NULL   wlc     NULL    NULL    NULL\n"
+                       "NULL   wlr     NULL    NULL    NULL\n");
+       renewStmtHandle(dbc, stmt);
+
+       // All table types query
+       ret = SQLTables(stmt, (SQLCHAR*)"", SQL_NTS,
+                       (SQLCHAR*)"", SQL_NTS, (SQLCHAR*)"", SQL_NTS,
+                       (SQLCHAR*)SQL_ALL_TABLE_TYPES, SQL_NTS);
+       check(ret, SQL_HANDLE_STMT, stmt, "SQLTables (SQL_ALL_TABLE_TYPES)");
+       compareResult(stmt, "SQLTables (SQL_ALL_TABLE_TYPES)",
+                       "Resultset with 5 columns\n"
+                       "table_cat      table_schem     table_name      
table_type      remarks\n"
+                       "NULL   NULL    NULL    GLOBAL TEMPORARY TABLE  NULL\n"
+                       "NULL   NULL    NULL    LOCAL TEMPORARY TABLE   NULL\n"
+                       "NULL   NULL    NULL    MERGE TABLE     NULL\n"
+                       "NULL   NULL    NULL    REMOTE TABLE    NULL\n"
+                       "NULL   NULL    NULL    REPLICA TABLE   NULL\n"
+                       "NULL   NULL    NULL    SYSTEM TABLE    NULL\n"
+                       "NULL   NULL    NULL    SYSTEM VIEW     NULL\n"
+                       "NULL   NULL    NULL    TABLE   NULL\n"
+                       "NULL   NULL    NULL    UNLOGGED TABLE  NULL\n"
+                       "NULL   NULL    NULL    VIEW    NULL\n");
+
+       ret = SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+       check(ret, SQL_HANDLE_STMT, stmt, "SQLFreeHandle (STMT)");
+
+       ret = SQLDisconnect(dbc);
+       check(ret, SQL_HANDLE_DBC, dbc, "SQLDisconnect");
+
+       ret = SQLFreeHandle(SQL_HANDLE_DBC, dbc);
+       check(ret, SQL_HANDLE_DBC, dbc, "SQLFreeHandle (DBC)");
+
+       ret = SQLFreeHandle(SQL_HANDLE_ENV, env);
+       check(ret, SQL_HANDLE_ENV, env, "SQLFreeHandle (ENV)");
+
+       return 0;
+}
diff --git a/sql/odbc/samples/Tests/All b/sql/odbc/samples/Tests/All
--- a/sql/odbc/samples/Tests/All
+++ b/sql/odbc/samples/Tests/All
@@ -4,3 +4,4 @@
 #
 HAVE_ODBC&NOT_WIN32?odbcsample1
 HAVE_ODBC&NOT_WIN32?testgetinfo
+HAVE_ODBC&NOT_WIN32?metadata
diff --git a/sql/odbc/samples/Tests/metadata.SQL.sh 
b/sql/odbc/samples/Tests/metadata.SQL.sh
new file mode 100755
--- /dev/null
+++ b/sql/odbc/samples/Tests/metadata.SQL.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to