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

Added filling the res_exps.
For both odbc_relation() and odbc_load() we now call new odbc_query(), which 
does all the work.


diffs (truncated from 316 to 300 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
@@ -181,6 +181,53 @@ map_rescol_type(SQLSMALLINT dataType, SQ
        return sql_bind_subtype(sql->sa, typenm, interval_type, 0);
 }
 
+static char *
+nameofSQLtype(SQLSMALLINT dataType)
+{
+       /* 
https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/sql-data-types */
+       switch (dataType) {
+       case SQL_CHAR:          return "CHAR";
+       case SQL_VARCHAR:       return "VARCHAR";
+       case SQL_LONGVARCHAR:   return "LONG VARCHAR";
+       case SQL_WCHAR:         return "WCHAR";
+       case SQL_WVARCHAR:      return "WVARCHAR";
+       case SQL_WLONGVARCHAR:  return "WLONGVARCHAR";
+       case SQL_DECIMAL:       return "DECIMAL";
+       case SQL_NUMERIC:       return "NUMERIC";
+       case SQL_SMALLINT:      return "SMALLINT";
+       case SQL_INTEGER:       return "INTEGER";
+       case SQL_REAL:          return "REAL";
+       case SQL_FLOAT:         return "FLOAT";
+       case SQL_DOUBLE:        return "DOUBLE";
+       case SQL_BIT:           return "BIT";
+       case SQL_TINYINT:       return "TINYINT";
+       case SQL_BIGINT:        return "BIGINT";
+       case SQL_BINARY:        return "BINARY";
+       case SQL_VARBINARY:     return "VARBINARY";
+       case SQL_LONGVARBINARY: return "LONG VARBINARY";
+       case SQL_DATETIME:      return "DATETIME";
+       case SQL_TYPE_DATE:     return "DATE";
+       case SQL_TYPE_TIME:     return "TIME";
+       case SQL_TYPE_TIMESTAMP:        return "TIMESTAMP";
+       case SQL_INTERVAL_MONTH:        return "INTERVAL MONTH";
+       case SQL_INTERVAL_YEAR:         return "INTERVAL YEAR";
+       case SQL_INTERVAL_YEAR_TO_MONTH: return "INTERVAL YEAR TO MONTH";
+       case SQL_INTERVAL_DAY:          return "INTERVAL DAY";
+       case SQL_INTERVAL_HOUR:         return "INTERVAL HOUR";
+       case SQL_INTERVAL_MINUTE:       return "INTERVAL MINUTE";
+       case SQL_INTERVAL_SECOND:       return "INTERVAL SECOND";
+       case SQL_INTERVAL_DAY_TO_HOUR:  return "INTERVAL DAY TO HOUR";
+       case SQL_INTERVAL_DAY_TO_MINUTE:        return "INTERVAL DAY TO MINUTE";
+       case SQL_INTERVAL_DAY_TO_SECOND:        return "INTERVAL DAY TO SECOND";
+       case SQL_INTERVAL_HOUR_TO_MINUTE:       return "INTERVAL HOUR TO 
MINUTE";
+       case SQL_INTERVAL_HOUR_TO_SECOND:       return "INTERVAL HOUR TO 
SECOND";
+       case SQL_INTERVAL_MINUTE_TO_SECOND:     return "INTERVAL MINUTE TO 
SECOND";
+       case SQL_GUID:          return "GUID";
+/*     case SQL_HUGEINT:       return "HUGEINT";       0x4000 (defined in 
ODBCGlobal.h) */
+       default:                return "Driver specific type";
+       }
+}
+
 /*
  * returns an error string (static or via tmp sa_allocator allocated), NULL on 
success
  *
@@ -191,12 +238,12 @@ map_rescol_type(SQLSMALLINT dataType, SQ
  * Fill the list res_exps, with one result expressions per resulting column.
  */
 static str
-odbc_relation(mvc *sql, sql_subfunc *f, char *url, list *res_exps, char *aname)
+odbc_query(mvc *sql, sql_subfunc *f, char *url, list *res_exps, sql_exp *topn, 
int caller)
 {
-       (void) res_exps;
-       (void) aname;
-       bool trace_enabled = true;
+       (void) topn;
+       bool trace_enabled = true;      /* used for development only */
 
+       /* check received url and extract the ODBC connection string and yhe 
SQL query */
        if (!url || (url && strncasecmp("odbc:", url, 5) != 0))
                return "Invalid URI. Must start with 'odbc:'.";
 
@@ -223,6 +270,8 @@ odbc_relation(mvc *sql, sql_subfunc *f, 
        if (trace_enabled)
                printf("\nExtracted ODBC connection string: %s\nand SQL query: 
%s\n", odbc_con_str, query);
 
+
+       /* now we can try to connect to the ODBC driver and execute the SQL 
query */
        SQLRETURN ret = SQL_INVALID_HANDLE;
        SQLHANDLE env = SQL_NULL_HENV;
        SQLHANDLE dbc = SQL_NULL_HDBC;
@@ -232,17 +281,17 @@ odbc_relation(mvc *sql, sql_subfunc *f, 
        ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
        if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
                errmsg = "Allocate ODBC ENV handle failed.";
-               goto failure;
+               goto finish;
        }
        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;
+               goto finish;
        }
        ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
        if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
                errmsg = "Allocate ODBC DBC handle failed.";
-               goto failure;
+               goto finish;
        }
 
        SQLSMALLINT len = 0;
@@ -250,69 +299,112 @@ odbc_relation(mvc *sql, sql_subfunc *f, 
        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;
+               errmsg = "Could not connect. SQLDriverConnect failed.";
+               goto finish;
        }
 
        ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);
        if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
                errmsg = "Allocate ODBC STMT handle failed.";
-               goto failure;
+               goto finish;
        }
 
        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;
+               errmsg = "SQLExecDirect query failed.";
+               goto finish;
        }
 
        SQLSMALLINT nr_cols = 0;
        ret = SQLNumResultCols(stmt, &nr_cols);
        if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
-               errmsg = "ODBC SQLNumResultCols failed.";
-               goto failure;
+               errmsg = "SQLNumResultCols failed.";
+               goto finish;
        }
        if (nr_cols <= 0) {
                errmsg = "ODBC query did not return a resultset.";
-               goto failure;
+               goto finish;
        }
        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;
+       /* when called from odbc_relation() */
+       if (caller == 1) {
+               char tname[1024];
+               char cname[1024];
+               SQLSMALLINT dataType = 0;
+               SQLULEN columnSize = 0;
+               SQLSMALLINT decimalDigits = 0;
+               sql_subtype * sql_mtype;
+               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 *) cname, 
(SQLSMALLINT) sizeof(cname),
+                               NULL, &dataType, &columnSize, &decimalDigits, 
NULL);
+                       if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) 
{
+                               errmsg = "SQLDescribeCol failed.";
+                               goto finish;
+                       }
+                       if (trace_enabled)
+                               printf("ResCol %d, name: %s, type %d (%s), size 
%d, decdigits %d\n",
+                                       col, cname, (int)dataType, 
nameofSQLtype(dataType), (int)columnSize, (int)decimalDigits);
+                       list_append(nameslist, cname);
+                       sql_mtype = map_rescol_type(dataType, columnSize, 
decimalDigits, sql);
+                       list_append(typelist, sql_mtype);
+
+                       /* also get the table name for this result column */
+                       ret = SQLColAttribute(stmt, col, SQL_DESC_TABLE_NAME, 
(SQLPOINTER) tname, (SQLSMALLINT) sizeof(tname), NULL, NULL);
+                       if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) 
{
+                               strcpy(tname, "");
+                       }
+                       sql_exp *ne = exp_column(sql->sa, tname, cname, 
sql_mtype, CARD_MULTI, 1, 0, 0);
+                       set_basecol(ne);
+                       ne->alias.label = -(sql->nid++);
+                       list_append(res_exps, ne);
                }
-               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->tname = sa_strdup(sql->sa, aname); */
+               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;
+               r->stmt = stmt;
+               r->nr_cols = nr_cols;
+               f->sname = (char*)r; /* pass odbc_loader */
+
+               goto finish;
        }
 
-       f->res = typelist;
-       f->coltypes = typelist;
-       f->colnames = nameslist;
+       /* when called from odbc_load() we can now fetch the data */
+       if (caller == 2 && stmt != SQL_NULL_HSTMT) {
+               // TODO create an internal transient table to store fetched data
+               // if (mvc_create_table(&t, be->mvc, be->mvc->session->tr->tmp 
/* misuse tmp schema */, r->tname /*gettable name*/, tt_remote, false, 
SQL_DECLARED_TABLE, 0, 0, false) != LOG_OK)
+
+               for (SQLUSMALLINT col = 1; col <= (SQLUSMALLINT) nr_cols; 
col++) {
+                       // TODO for each result column create a buffer and bind 
it. Also create a BAT column.
+                       // ret = SQLBindCol(stmt, 1, );
+                       // if (!tp || mvc_create_column(&c, be->mvc, t, name, 
tp) != LOG_OK) {
+               }
 
-       odbc_loader_t *r = (odbc_loader_t *)sa_alloc(sql->sa, 
sizeof(odbc_loader_t));
-       r->env = env;
-       r->dbc = dbc;
-       r->stmt = stmt;
-       r->nr_cols = nr_cols;
-       f->sname = (char*)r; /* pass odbc_loader */
-  failure:
+               // repeat fetching data, adding data work table
+               ret = SQLFetch(stmt);
+               while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
+                       // TODO for each result column append to created 
transient table
+                       for (SQLUSMALLINT col = 1; col <= (SQLUSMALLINT) 
nr_cols; col++) {
+                               // ret = SQLGetData(stmt, col, ...);
+                               // copy buffer value to BUN and append
+                       }
+                       ret = SQLFetch(stmt);   // get data of next row
+               }
+       }
+
+  finish:
        if (query)
                GDKfree(query);
        if (odbc_con_str)
@@ -354,43 +446,28 @@ odbc_relation(mvc *sql, sql_subfunc *f, 
        return (str)errmsg;
 }
 
+/*
+ * returns an error string (static or via tmp sa_allocator allocated), NULL on 
success
+ *
+ * Extend the subfunc f with result columns, ie.
+       f->res = typelist;
+       f->coltypes = typelist;
+       f->colnames = nameslist; use tname if passed, for the relation name
+ * Fill the list res_exps, with one result expressions per resulting column.
+ */
+static str
+odbc_relation(mvc *sql, sql_subfunc *f, char *url, list *res_exps, char *aname)
+{
+       (void) aname;
+       return odbc_query(sql, f, url, res_exps, NULL, 1);
+}
+
 static void *
 odbc_load(void *BE, sql_subfunc *f, char *url, sql_exp *topn)
 {
-       (void) url;
-       (void) topn;
-       (void) BE;
-//     backend *be = (backend*)BE;
-//     mvc *sql = be->mvc;
-       odbc_loader_t *r = (odbc_loader_t*)f->sname;
-       SQLHANDLE stmt = r->stmt;
-       SQLSMALLINT nr_cols = r->nr_cols;
-
-       if (stmt != SQL_NULL_HSTMT) {
-               SQLRETURN ret;
-               // TODO create an internal transient table to store fetched data
-               // if (mvc_create_table(&t, be->mvc, be->mvc->session->tr->tmp 
/* misuse tmp schema */, r->tname /*gettable name*/, tt_remote, false, 
SQL_DECLARED_TABLE, 0, 0, false) != LOG_OK)
-
-               for (SQLSMALLINT i = 1; i <= nr_cols; i++) {
-                       // TODO for each result column create a buffer and bind 
it. Also create a BAT column.
-                       // ret = SQLBindCol(stmt, 1, );
-                       // if (!tp || mvc_create_column(&c, be->mvc, t, name, 
tp) != LOG_OK) {
-               }
-
-               // repeat fetching data, adding data work table
-               ret = SQLFetch(stmt);
-               while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
-                       // TODO for each result column append to created 
transient table
_______________________________________________
checkin-list mailing list -- checkin-list@monetdb.org
To unsubscribe send an email to checkin-list-le...@monetdb.org

Reply via email to