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

Introduce a struct to keep col meta data. This is needed to improve the way col 
data is bind and fetched and converted to the expected bat type for that result 
column.


diffs (truncated from 512 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
@@ -39,6 +39,13 @@
 #define MAX_COL_NAME_LEN  1024
 #define MAX_TBL_NAME_LEN  1024
 
+typedef struct {
+       SQLSMALLINT dataType;           /* ODBC datatype */
+       SQLULEN columnSize;             /* ODBC colsize */
+       SQLSMALLINT decimalDigits;      /* ODBC dec. digits */
+       int mtype;                      /* MonetDB atom type, used to create 
the BAT */
+       BAT * bat;                      /* MonetDB BAT */
+} rescol_t;
 
 /* map ODBC SQL datatype to MonetDB SQL datatype */
 static sql_subtype *
@@ -196,6 +203,12 @@ map_rescol_mtype(SQLSMALLINT dataType, S
                return TYPE_int;
        case SQL_BIGINT:
                return TYPE_lng;
+       case SQL_DECIMAL:
+       case SQL_NUMERIC:
+               return TYPE_lng;        // depends on max number of digits
+#ifdef HAVE_HGE
+// TODO                return TYPE_hge;        // depends on max number of 
digits
+#endif
        case SQL_REAL:
                return TYPE_flt;
        case SQL_FLOAT:
@@ -230,10 +243,6 @@ map_rescol_mtype(SQLSMALLINT dataType, S
        case SQL_INTERVAL_HOUR_TO_SECOND:
        case SQL_INTERVAL_MINUTE_TO_SECOND:
                return TYPE_lng;
-
-       case SQL_DECIMAL:
-       case SQL_NUMERIC:
-               // we will fetch decimals as string data
        default:
                return TYPE_str;
        }
@@ -332,6 +341,49 @@ bat_create(int adt, BUN nr)
        return b;
 }
 
+static lng
+convert_numericstr2lng(str val, int columnSize, SQLSMALLINT decimalDigits) {
+       lng ret = 0;
+       int i = 0;
+       int digits = 0;
+       int decdigits = 0;
+       char c;
+       char sign = '+';
+       int decsep = -1;
+
+       if (!val)
+               return 0;
+
+       c = val[i];
+       if (c == '-' || c == '+') {
+               sign = c;
+               i++;
+       }
+       while (val[i]) {
+               if (digits >= columnSize || decdigits >= decimalDigits)
+                       break;  // we have read enough
+               c = val[i];
+               if (c >= '0' && c <= '9') {
+                       ret *= 10;
+                       ret += (int) c - '0';
+                       digits++;
+                       if (decsep >= 0)
+                               decdigits++;
+               } else if (c == '.') {
+                       decsep = i;
+               }
+               i++;
+       }
+       while (decdigits < decimalDigits) {
+               // align to the scale
+               ret *= 10;
+               decdigits++;
+       }
+       if (sign == '-')
+               ret = -ret;
+       return ret;
+}
+
 /*
  * odbc_query() contains the logic for both odbc_relation() and ODBCloader()
  * the caller arg is 1 when called from odbc_relation and 2 when called from 
ODBCloader
@@ -502,18 +554,12 @@ odbc_query(mvc *sql, sql_subfunc *f, cha
 
        /* when called from ODBCloader() */
        if (caller == ODBC_LOADER) {
-               BAT ** bats = (BAT **) GDKzalloc(nr_cols * sizeof(BAT *));
-               if (bats == NULL) {
-                       errmsg = "GDKmalloc bats failed.";
+               rescol_t * colmetadata = (rescol_t *) GDKzalloc(nr_cols * 
sizeof(rescol_t));
+               if (colmetadata == NULL) {
+                       errmsg = "GDKzalloc colmetadata[nr_cols] failed.";
                        goto finish;
                }
-               int * mtypes = (int *) GDKzalloc(nr_cols * sizeof(int));
-               if (mtypes == NULL) {
-                       errmsg = "GDKmalloc mtypes failed.";
-                       GDKfree(bats);
-                       bats = NULL;
-                       goto finish;
-               }
+
                SQLULEN largestStringSize = 0;
                bool hasBlobCols = false;
                SQLULEN largestBlobSize = 0;
@@ -535,15 +581,16 @@ odbc_query(mvc *sql, sql_subfunc *f, cha
                                /* cleanup already created bats */
                                while (col > 0) {
                                        col--;
-                                       BBPreclaim(bats[col]);
-                                       bats[col] = NULL;
+                                       BBPreclaim(colmetadata[col].bat);
                                }
-                               GDKfree(bats);
-                               GDKfree(mtypes);
+                               GDKfree(colmetadata);
                                goto finish;
                        }
+                       colmetadata[col].dataType = dataType;
+                       colmetadata[col].columnSize = columnSize;
+                       colmetadata[col].decimalDigits = decimalDigits;
                        mtype = map_rescol_mtype(dataType, columnSize);
-                       mtypes[col] = mtype;
+                       colmetadata[col].mtype = mtype;
                        if (mtype == TYPE_str) {
                                if (columnSize > largestStringSize) {
                                        largestStringSize = columnSize;
@@ -563,7 +610,7 @@ odbc_query(mvc *sql, sql_subfunc *f, cha
                                printf("Before create BAT %d\n", col+1);
                        b = bat_create(mtype, 0);
                        if (b) {
-                               bats[col] = b;
+                               colmetadata[col].bat = b;
                                if (trace_enabled)
                                        printf("After create BAT %d\n", col+1);
                        } else {
@@ -571,21 +618,22 @@ odbc_query(mvc *sql, sql_subfunc *f, cha
                                /* cleanup already created bats */
                                while (col > 0) {
                                        col--;
-                                       BBPreclaim(bats[col]);
-                                       bats[col] = NULL;
+                                       BBPreclaim(colmetadata[col].bat);
                                }
-                               GDKfree(bats);
-                               GDKfree(mtypes);
+                               GDKfree(colmetadata);
                                goto finish;
                        }
                }
 
-               /* allocate storage for all the fixed size atom types. TODO 
num_val for decimals and numeric data */
+               /* allocate storage for all the fixed size atom types. */
                bit bit_val;
                bte bte_val;
                sht sht_val;
                int int_val;
                lng lng_val;
+#ifdef HAVE_HGE
+// TODO                hge hge_val;    // for large decimals
+#endif
                flt flt_val;
                dbl dbl_val;
                DATE_STRUCT date_val;
@@ -631,68 +679,109 @@ odbc_query(mvc *sql, sql_subfunc *f, cha
                                printf("Fetched row %lu\n", row);
 
                        for (SQLUSMALLINT col = 0; col < (SQLUSMALLINT) 
nr_cols; col++) {
-                               int mtype = mtypes[col];
-                               BAT * b = bats[col];
-                               if (!b)
-                                       continue;
-
+                               SQLSMALLINT sqltype = colmetadata[col].dataType;
+                               int mtype = colmetadata[col].mtype;
+                               BAT * b = colmetadata[col].bat;
                                SQLSMALLINT targetType;
                                SQLPOINTER * targetValuePtr;
                                SQLLEN bufferLength = 0;
                                SQLLEN strLen = 0;
                                /* mapping based on 
https://learn.microsoft.com/en-us/sql/odbc/reference/appendixes/c-data-types */
-                               switch(mtype) {
-                                       case TYPE_str:
+                               switch(sqltype) {
+                                       case SQL_CHAR:
+                                       case SQL_VARCHAR:
+                                       case SQL_LONGVARCHAR:
+                                       case SQL_WCHAR:
+                                       case SQL_WVARCHAR:
+                                       case SQL_WLONGVARCHAR:
                                        default:
                                                targetType = SQL_C_CHAR;        
// TODO later: SQL_C_WCHAR
                                                targetValuePtr = (SQLPOINTER *) 
str_val;
                                                bufferLength = 
largestStringSize;
                                                break;
-                                       case TYPE_bit:
+                                       case SQL_BIT:
                                                targetType = SQL_C_BIT;
                                                targetValuePtr = (SQLPOINTER *) 
&bit_val;
                                                break;
-                                       case TYPE_bte:
+                                       case SQL_TINYINT:
                                                targetType = SQL_C_STINYINT;
                                                targetValuePtr = (SQLPOINTER *) 
&bte_val;
                                                break;
-                                       case TYPE_sht:
+                                       case SQL_SMALLINT:
                                                targetType = SQL_C_SSHORT;
                                                targetValuePtr = (SQLPOINTER *) 
&sht_val;
                                                break;
-                                       case TYPE_int:
+                                       case SQL_INTEGER:
                                                targetType = SQL_C_SLONG;
                                                targetValuePtr = (SQLPOINTER *) 
&int_val;
                                                break;
-                                       case TYPE_lng:
+                                       case SQL_BIGINT:
                                                targetType = SQL_C_SBIGINT;
                                                targetValuePtr = (SQLPOINTER *) 
&lng_val;
                                                break;
-                                       case TYPE_flt:
+                                       case SQL_DECIMAL:
+                                       case SQL_NUMERIC:
+                                               /* we read the decimal data as 
string data and convert it to lng (or hge) */
+                                               targetType = SQL_C_CHAR;
+                                               targetValuePtr = (SQLPOINTER *) 
str_val;
+                                               bufferLength = 
largestStringSize;
+                                               break;
+                                       case SQL_REAL:
                                                targetType = SQL_C_FLOAT;
                                                targetValuePtr = (SQLPOINTER *) 
&flt_val;
                                                break;
-                                       case TYPE_dbl:
+                                       case SQL_FLOAT:
+                                               if (mtype == TYPE_flt) {
+                                                       targetType = 
SQL_C_FLOAT;
+                                                       targetValuePtr = 
(SQLPOINTER *) &flt_val;
+                                               } else {
+                                                       targetType = 
SQL_C_DOUBLE;
+                                                       targetValuePtr = 
(SQLPOINTER *) &dbl_val;
+                                               }
+                                               break;
+                                       case SQL_DOUBLE:
                                                targetType = SQL_C_DOUBLE;
                                                targetValuePtr = (SQLPOINTER *) 
&dbl_val;
                                                break;
-                                       case TYPE_date:
+                                       case SQL_TYPE_DATE:
                                                targetType = SQL_C_TYPE_DATE;
                                                targetValuePtr = (SQLPOINTER *) 
&date_val;
                                                break;
-                                       case TYPE_daytime:
+                                       case SQL_TYPE_TIME:
                                                targetType = SQL_C_TYPE_TIME;
                                                targetValuePtr = (SQLPOINTER *) 
&time_val;
                                                break;
-                                       case TYPE_timestamp:
+                                       case SQL_DATETIME:
+                                       case SQL_TYPE_TIMESTAMP:
                                                targetType = 
SQL_C_TYPE_TIMESTAMP;
                                                targetValuePtr = (SQLPOINTER *) 
&ts_val;
                                                break;
-                                       case TYPE_uuid:
+                                       case SQL_INTERVAL_MONTH:
+                                       case SQL_INTERVAL_YEAR:
+                                       case SQL_INTERVAL_YEAR_TO_MONTH:
+                                               targetType = SQL_C_SLONG;
+                                               targetValuePtr = (SQLPOINTER *) 
&int_val;
+                                               break;
+                                       case SQL_INTERVAL_DAY:
+                                       case SQL_INTERVAL_HOUR:
+                                       case SQL_INTERVAL_MINUTE:
+                                       case SQL_INTERVAL_SECOND:
+                                       case SQL_INTERVAL_DAY_TO_HOUR:
+                                       case SQL_INTERVAL_DAY_TO_MINUTE:
+                                       case SQL_INTERVAL_DAY_TO_SECOND:
+                                       case SQL_INTERVAL_HOUR_TO_MINUTE:
+                                       case SQL_INTERVAL_HOUR_TO_SECOND:
+                                       case SQL_INTERVAL_MINUTE_TO_SECOND:
+                                               targetType = SQL_C_SBIGINT;
+                                               targetValuePtr = (SQLPOINTER *) 
&lng_val;
+                                               break;
+                                       case SQL_GUID:
                                                targetType = SQL_C_GUID;
                                                targetValuePtr = (SQLPOINTER *) 
&guid_val;
                                                break;
-                                       case TYPE_blob:
+                                       case SQL_BINARY:
+                                       case SQL_VARBINARY:
+                                       case SQL_LONGVARBINARY:
                                                targetType = SQL_C_BINARY;
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to