Changeset: 4577f6fa20b3 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/4577f6fa20b3
Modified Files:
        sql/backends/monet5/vaults/odbc/odbc_loader.c
Branch: odbc_loader
Log Message:

Add retrieval and conversion of result columns meta data.


diffs (266 lines):

diff --git a/sql/backends/monet5/vaults/odbc/odbc_loader.c 
b/sql/backends/monet5/vaults/odbc/odbc_loader.c
--- a/sql/backends/monet5/vaults/odbc/odbc_loader.c
+++ b/sql/backends/monet5/vaults/odbc/odbc_loader.c
@@ -51,6 +51,111 @@ odbc_cleanup(SQLHANDLE env, SQLHANDLE db
        }
 }
 
+
+static sql_subtype *
+map_rescol_type(SQLSMALLINT dataType, SQLULEN columnSize, SQLSMALLINT 
decimalDigits, mvc * sql)
+{
+       char * typenm;
+
+       switch (dataType) {
+       case SQL_CHAR:
+       case SQL_VARCHAR:
+       case SQL_LONGVARCHAR:
+       case SQL_WCHAR:
+       case SQL_WVARCHAR:
+       case SQL_WLONGVARCHAR:
+       default:
+               return sql_bind_subtype(sql->sa, "varchar", (int) columnSize, 
0);
+
+       case SQL_DECIMAL:
+       case SQL_NUMERIC:
+               return sql_bind_subtype(sql->sa, "decimal", (int) 
decimalDigits, 6);
+
+       case SQL_BINARY:
+       case SQL_VARBINARY:
+       case SQL_LONGVARBINARY:
+               return sql_bind_subtype(sql->sa, "blob", (int) columnSize, 0);
+
+       case SQL_TINYINT:
+               typenm = "tinyint";
+               break;
+       case SQL_SMALLINT:
+               typenm = "smallint";
+               break;
+       case SQL_INTEGER:
+               typenm = "integer";
+               break;
+       case SQL_BIGINT:
+               typenm = "bigint";
+               break;
+       case SQL_REAL:
+               typenm = "real";
+               break;
+       case SQL_DOUBLE:
+               typenm = "double";
+               break;
+       case SQL_FLOAT:
+               typenm = "float";
+               break;
+       case SQL_TYPE_DATE:
+               typenm = "date";
+               break;
+       case SQL_TYPE_TIME:
+               typenm = "time";
+               break;
+       case SQL_TYPE_TIMESTAMP:
+               typenm = "timeestamp";
+               break;
+       case SQL_BIT:
+               typenm = "boolean";
+               break;
+       case SQL_INTERVAL_MONTH:
+               typenm = "INTERVAL MONTH";
+               break;
+       case SQL_INTERVAL_YEAR:
+               typenm = "INTERVAL YEAR";
+               break;
+       case SQL_INTERVAL_YEAR_TO_MONTH:
+               typenm = "INTERVAL YEAR TO MONTH";
+               break;
+       case SQL_INTERVAL_DAY:
+               typenm = "INTERVAL DAY";
+               break;
+       case SQL_INTERVAL_HOUR:
+               typenm = "INTERVAL HOUR";
+               break;
+       case SQL_INTERVAL_MINUTE:
+               typenm = "INTERVAL MINUTE";
+               break;
+       case SQL_INTERVAL_SECOND:
+               typenm = "INTERVAL SECOND";
+               break;
+       case SQL_INTERVAL_DAY_TO_HOUR:
+               typenm = "INTERVAL DAY TO HOUR";
+               break;
+       case SQL_INTERVAL_DAY_TO_MINUTE:
+               typenm = "INTERVAL DAY TO MINUTE";
+               break;
+       case SQL_INTERVAL_DAY_TO_SECOND:
+               typenm = "INTERVAL DAY TO SECOND";
+               break;
+       case SQL_INTERVAL_HOUR_TO_MINUTE:
+               typenm = "INTERVAL HOUR TO MINUTE";
+               break;
+       case SQL_INTERVAL_HOUR_TO_SECOND:
+               typenm = "INTERVAL HOUR TO SECOND";
+               break;
+       case SQL_INTERVAL_MINUTE_TO_SECOND:
+               typenm = "INTERVAL MINUTE TO SECOND";
+               break;
+       case SQL_GUID:
+               typenm = "UUID";
+               break;
+       }
+
+       return sql_bind_subtype(sql->sa, typenm, 0, 0);
+}
+
 /*
  * returns an error string (static or via tmp sa_allocator allocated), NULL on 
success
  *
@@ -65,11 +170,10 @@ odbc_relation(mvc *sql, sql_subfunc *f, 
 {
        (void) res_exps;
        (void) aname;
-//     list *typelist = sa_list(sql->sa);
-//     list *nameslist = sa_list(sql->sa);
+       bool trace_enabled = true;
 
        if (!url || (url && strncasecmp("odbc:", url, 5) != 0))
-               return "Invalid URI. Expected to start with 'odbc:'.";
+               return "Invalid URI. Must start with 'odbc:'.";
 
        // skip 'odbc:' prefix from url so we get a connection string including 
the query
        char * con_str = &url[5];
@@ -87,60 +191,92 @@ odbc_relation(mvc *sql, sql_subfunc *f, 
        // create a new ODBC connection string without the QUERY= part
        char * odbc_con_str = GDKstrndup(con_str, qry_str - con_str);
 
+       if (trace_enabled)
+               printf("\nExtracted ODBC connection string: %s\nand SQL query: 
%s\n", odbc_con_str, query);
+
+       SQLRETURN ret = SQL_INVALID_HANDLE;
        SQLHANDLE env = SQL_NULL_HENV;
        SQLHANDLE dbc = SQL_NULL_HDBC;
        SQLHANDLE stmt = SQL_NULL_HSTMT;
-       SQLRETURN ret;
-       SQLSMALLINT nr_cols = 0;
        char * errmsg = NULL;
 
-       // printf("Extracted ODBC connection string: %s\nand SQL query: %s\n", 
odbc_con_str, query);
-
        ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
-       if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
-               ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) 
(uintptr_t) SQL_OV_ODBC3, 0);
-               if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
-                       ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
-                       if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) 
{
-                               SQLSMALLINT len = 0;
-                               ret = SQLDriverConnect(dbc, NULL, (SQLCHAR *) 
odbc_con_str, SQL_NTS, NULL, 0, &len, SQL_DRIVER_NOPROMPT);
-                               // printf("After SQLDriverConnect(%s)\n", 
odbc_con_str);
-                               if (ret == SQL_SUCCESS || ret == 
SQL_SUCCESS_WITH_INFO) {
-                                       ret = SQLAllocHandle(SQL_HANDLE_STMT, 
dbc, &stmt);
-                                       if (ret == SQL_SUCCESS || ret == 
SQL_SUCCESS_WITH_INFO) {
-                                               ret = SQLExecDirect(stmt, 
(SQLCHAR *) query, SQL_NTS);
-                                               // printf("After 
SQLExecDirect(%s)\n", query);
-                                               if (ret == SQL_SUCCESS || ret 
== SQL_SUCCESS_WITH_INFO) {
-                                                       ret = 
SQLNumResultCols(stmt, &nr_cols);
-                                                       // printf("Query has %d 
result columns\n", nr_cols);
-                                                       // TODO for each column 
get the name, type, size/digits and scale
-                                                               // 
list_append(nameslist, name);
-                                                               // 
list_append(typelist, type);
-                                               } else {
-                                                       errmsg = "ODBC 
SQLExecDirect query failed.";
-                                                       goto failure;
-                                               }
-                                       } else {
-                                               errmsg = "Allocate ODBC STMT 
handle failed.";
-                                               goto failure;
-                                       }
-                               } else {
-                                       errmsg = "Could not connect. ODBC 
SQLDriverConnect failed.";
-                                       goto failure;
-                               }
-                       } else {
-                               errmsg = "Allocate ODBC DBC handle failed.";
-                               goto failure;
-                       }
-               } else {
-                       errmsg = "SQLSetEnvAttr (SQL_ATTR_ODBC_VERSION ODBC3) 
failed.";
+       if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
+               errmsg = "Allocate ODBC ENV handle failed.";
+               goto failure;
+       }
+       ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) 
(uintptr_t) SQL_OV_ODBC3, 0);
+       if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
+               errmsg = "SQLSetEnvAttr (SQL_ATTR_ODBC_VERSION ODBC3) failed.";
+               goto failure;
+       }
+       ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
+       if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
+               errmsg = "Allocate ODBC DBC handle failed.";
+               goto failure;
+       }
+
+       SQLSMALLINT len = 0;
+       ret = SQLDriverConnect(dbc, NULL, (SQLCHAR *) odbc_con_str, SQL_NTS, 
NULL, 0, &len, SQL_DRIVER_NOPROMPT);
+       if (trace_enabled)
+               printf("After SQLDriverConnect(%s) returned %d\n", 
odbc_con_str, ret);
+       if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
+               errmsg = "Could not connect. ODBC SQLDriverConnect failed.";
+               goto failure;
+       }
+
+       ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
+       if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
+               errmsg = "Allocate ODBC STMT handle failed.";
+               goto failure;
+       }
+
+       ret = SQLExecDirect(stmt, (SQLCHAR *) query, SQL_NTS);
+       if (trace_enabled)
+               printf("After SQLExecDirect(%s) returned %d\n", query, ret);
+       if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
+               errmsg = "ODBC SQLExecDirect query failed.";
+               goto failure;
+       }
+
+       SQLSMALLINT nr_cols = 0;
+       ret = SQLNumResultCols(stmt, &nr_cols);
+       if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
+               errmsg = "ODBC SQLNumResultCols failed.";
+               goto failure;
+       }
+       if (nr_cols <= 0) {
+               errmsg = "ODBC query did not return a resultset.";
+               goto failure;
+       }
+       if (trace_enabled)
+               printf("Query has %d result columns\n", nr_cols);
+
+       char name[2048];
+       SQLSMALLINT dataType = 0;
+       SQLULEN columnSize = 0;
+       SQLSMALLINT decimalDigits = 0;
+       list * typelist = sa_list(sql->sa);
+       list * nameslist = sa_list(sql->sa);
+       for (SQLUSMALLINT col = 1; col <= (SQLUSMALLINT) nr_cols; col++) {
+               /* for each result column get name, datatype, size and 
decdigits */
+               ret = SQLDescribeCol(stmt, col, (SQLCHAR *) name, (SQLSMALLINT) 
sizeof(name),
+                       NULL, &dataType, &columnSize, &decimalDigits, NULL);
+               if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
+                       errmsg = "ODBC SQLDescribeCol failed.";
                        goto failure;
                }
-       } else {
-               errmsg = "Allocate ODBC environment handle failed.";
-               goto failure;
+               if (trace_enabled)
+                       printf("ResCol %d, name: %s, type %d, size %d, 
decdigits %d\n",
+                               col, name, (int)dataType, (int)columnSize, 
(int)decimalDigits);
+               list_append(nameslist, name);
+               list_append(typelist, map_rescol_type(dataType, columnSize, 
decimalDigits, sql));
        }
 
+       f->res = typelist;
+       f->coltypes = typelist;
+       f->colnames = nameslist;
+
        odbc_loader_t *r = (odbc_loader_t *)sa_alloc(sql->sa, 
sizeof(odbc_loader_t));
        r->env = env;
        r->dbc = dbc;
_______________________________________________
checkin-list mailing list -- checkin-list@monetdb.org
To unsubscribe send an email to checkin-list-le...@monetdb.org

Reply via email to