Changeset: 635e396e4286 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/635e396e4286
Branch: default
Log Message:
Merge with Mar2025 branch.
diffs (truncated from 379 to 300 lines):
diff --git a/clients/odbc/driver/SQLConnect.c b/clients/odbc/driver/SQLConnect.c
--- a/clients/odbc/driver/SQLConnect.c
+++ b/clients/odbc/driver/SQLConnect.c
@@ -73,16 +73,22 @@ get_serverinfo(ODBCDbc *dbc)
}
if (mapi_error(dbc->mid))
goto end;
- mapi_close_handle(hdl);
- if ((hdl = mapi_query(dbc->mid, "select id from sys._tables where name
= 'comments' and schema_id = (select id from sys.schemas where name = 'sys')"))
== NULL)
- goto end;
- if (mapi_error(dbc->mid))
- goto end;
- n = NULL;
- while (mapi_fetch_row(hdl)) {
- n = mapi_fetch_field(hdl, 0);
+
+ /* table sys.comments should exist since Mar2018 (11.29) */
+ if (dbc->major == 11 && dbc->minor > 29) {
+ dbc->has_comment = true;
+ } else {
+ mapi_close_handle(hdl);
+ if ((hdl = mapi_query(dbc->mid, "select id from sys._tables
where name = 'comments' and schema_id = (select id from sys.schemas where name
= 'sys')")) == NULL)
+ goto end;
+ if (mapi_error(dbc->mid))
+ goto end;
+ n = NULL;
+ if (mapi_fetch_row(hdl)) {
+ n = mapi_fetch_field(hdl, 0);
+ }
+ dbc->has_comment = n != NULL;
}
- dbc->has_comment = n != NULL;
rc = SQL_SUCCESS;
end:
@@ -136,7 +142,6 @@ makeNulTerminated(const SQLCHAR **argume
char*
buildConnectionString(const char *dsn, const msettings *settings)
{
-
size_t pos = 0;
size_t cap = 1024;
char *buf = malloc(cap); // reallocprintf will deal with allocation
failures
@@ -494,9 +499,6 @@ MNDBConnectSettings(ODBCDbc *dbc, const
return SQL_SUCCESS;
}
-
-
-
SQLRETURN SQL_API
SQLConnect(SQLHDBC ConnectionHandle,
SQLCHAR *ServerName,
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
@@ -11,14 +11,14 @@
*/
#include "monetdb_config.h"
-#include "rel_proto_loader.h"
-#include "rel_exp.h"
#include "gdk.h" // COLnew(), BUNappend()
#include "gdk_time.h" // date_create(), daytime_create(), timestamp_create()
#include "mal_exception.h"
#include "mal_builder.h"
#include "mal_client.h"
#include "mutils.h" /* utf8toutf16(), utf16toutf8() */
+#include "rel_proto_loader.h"
+#include "rel_exp.h"
// #include "sql_decimal.h" /* decimal_from_str() */
#ifdef _MSC_VER
@@ -262,6 +262,22 @@ nameofSQLtype(SQLSMALLINT dataType)
}
}
+/* name of ODBC SQLRETURN codes */
+static char *
+nameOfRetCode(SQLRETURN code)
+{
+ switch (code) {
+ case SQL_SUCCESS: return "SQL_SUCCESS";
+ case SQL_SUCCESS_WITH_INFO: return "SQL_SUCCESS_WITH_INFO";
+ case SQL_ERROR: return "SQL_ERROR";
+ case SQL_INVALID_HANDLE: return "SQL_INVALID_HANDLE";
+ case SQL_STILL_EXECUTING: return "SQL_STILL_EXECUTING";
+ case SQL_NEED_DATA: return "SQL_NEED_DATA";
+ case SQL_NO_DATA: return "SQL_NO_DATA";
+ default: return "SQLRETURN ??";
+ }
+}
+
#ifdef HAVE_HGE
static hge
str_to_hge(const char *s) {
@@ -294,24 +310,28 @@ str_to_hge(const char *s) {
/* an ODBC function call returned an error, get the error msg from the ODBC
driver */
static char *
getErrMsg(SQLSMALLINT handleType, SQLHANDLE handle) {
- SQLRETURN ret = SQL_ERROR;
+ SQLRETURN ret;
SQLCHAR state[SQL_SQLSTATE_SIZE +1];
SQLINTEGER errnr;
- SQLCHAR msg[4096];
- SQLSMALLINT msglen;
+ SQLCHAR msg[SQL_MAX_MESSAGE_LENGTH] = { 0 };
+ SQLSMALLINT msglen = SQL_MAX_MESSAGE_LENGTH -1;
if (handle == SQL_NULL_HSTMT)
return NULL;
// TODO use ODBC W function
- ret = SQLGetDiagRec(handleType, handle, 1, state, &errnr, msg,
(sizeof(msg) -1), &msglen);
+ ret = SQLGetDiagRec(handleType, handle, 1, state, &errnr, msg,
SQL_MAX_MESSAGE_LENGTH -1, &msglen);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
const char format[] = "SQLSTATE %s, Error code %d, Message %s";
- char * retmsg = (char *) malloc(sizeof(format) + MIN(msglen,
4096));
+ if (msglen <= 0) {
+ /* e.g SQL_NTS */
+ msglen = (SQLSMALLINT) strlen((char *)msg);
+ }
+ char * retmsg = (char *) GDKmalloc(sizeof(format) +
SQL_SQLSTATE_SIZE + 10 + msglen);
if (retmsg != NULL) {
if (state[SQL_SQLSTATE_SIZE] != '\0')
state[SQL_SQLSTATE_SIZE] = '\0';
- sprintf(retmsg, format, (char*)state, errnr,
(char*)msg);
+ sprintf(retmsg, format, (char *)state, errnr, (char
*)msg);
return retmsg;
}
}
@@ -383,22 +403,22 @@ odbc_query(int caller, mvc *sql, sql_sub
// skip 'odbc:' prefix from url so we get a connection string including
the query
char * con_str = &url[5];
- /* the connection string must start with 'DSN=' or 'DRIVER=' or
'FILEDSN='
+ /* the connection string must start with 'DSN=' or 'FILEDSN=' or
'DRIVER='
else the ODBC driver manager can't load the ODBC driver */
if (con_str
&& (strncmp("DSN=", con_str, 4) != 0)
&& (strncmp("DRIVER=", con_str, 7) != 0)
&& (strncmp("FILEDSN=", con_str, 8) != 0))
- return "Invalid ODBC connection string. Should start with
'DSN=' or 'DRIVER=' or 'FILEDSN='.";
+ return "Invalid ODBC connection string. Must start with 'DSN='
or 'FILEDSN=' or 'DRIVER='.";
// locate the 'QUERY=' part to extract the SQL query string to execute
char * qry_str = strstr(con_str, "QUERY=");
if (qry_str == NULL)
- return "Incomplete ODBC connection string. Missing 'QUERY='
part (to specify the SQL SELECT query to execute).";
+ return "Incomplete ODBC URI string. Missing 'QUERY=' part to
specify the SQL SELECT query to execute.";
char * query = GDKstrdup(&qry_str[6]); // we expect that QUERY= is at
the end of the connection string
if (query == NULL || (query && (strcmp("", query) == 0)))
- return "Incomplete ODBC connection string. Missing SQL SELECT
query after 'QUERY='.";
+ return "Incomplete ODBC URI string. Missing SQL SELECT query
after 'QUERY='.";
// create a new ODBC connection string without the QUERY= part
char * odbc_con_str = GDKstrndup(con_str, qry_str - con_str);
@@ -425,7 +445,7 @@ odbc_query(int caller, mvc *sql, sql_sub
}
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.";
+ errmsg = "SQLSetEnvAttr(SQL_ATTR_ODBC_VERSION ODBC3) failed.";
goto finish;
}
@@ -437,20 +457,31 @@ odbc_query(int caller, mvc *sql, sql_sub
/* to avoid an endless blocking SQLDriverConnect() set a login timeout
of 8s */
ret = SQLSetConnectAttr(dbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)
(uintptr_t) 8UL, 0);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
- errmsg = "SQLSetConnectAttr (SQL_ATTR_LOGIN_TIMEOUT 8s)
failed.";
+ errmsg = "SQLSetConnectAttr(SQL_ATTR_LOGIN_TIMEOUT 8 sec)
failed.";
goto finish;
}
SQLSMALLINT len = 0;
uint16_t * odbc_con_Wstr = utf8toutf16(odbc_con_str);
+#define MAX_CONNECT_OUT_STR 2048
if (odbc_con_Wstr != NULL) {
- ret = SQLDriverConnectW(dbc, NULL, (SQLWCHAR *) odbc_con_Wstr,
SQL_NTS, NULL, 0, &len, SQL_DRIVER_NOPROMPT);
+ SQLWCHAR outstr[MAX_CONNECT_OUT_STR];
+ ret = SQLDriverConnectW(dbc, NULL, (SQLWCHAR *) odbc_con_Wstr,
SQL_NTS, outstr, MAX_CONNECT_OUT_STR, &len, SQL_DRIVER_NOPROMPT);
/* we no longer need odbc_con_Wstr */
free(odbc_con_Wstr);
- } else
- 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);
+ } else {
+ SQLCHAR outstr[MAX_CONNECT_OUT_STR];
+ ret = SQLDriverConnect(dbc, NULL, (SQLCHAR *) odbc_con_str,
SQL_NTS, outstr, MAX_CONNECT_OUT_STR, &len, SQL_DRIVER_NOPROMPT);
+ }
+ if (ret == SQL_SUCCESS_WITH_INFO && caller == ODBC_RELATION) {
+ /* show the info warning, but only once */
+ char * ODBCmsg = getErrMsg(SQL_HANDLE_DBC, dbc);
+ printf("SQLDriverConnect(%s) returned %s ODBCmsg: %s\n",
odbc_con_str, nameOfRetCode(ret), (ODBCmsg) ? ODBCmsg : "");
+ if (ODBCmsg)
+ GDKfree(ODBCmsg);
+ } else if (trace_enabled) {
+ printf("SQLDriverConnect(%s) returned %s\n", odbc_con_str,
nameOfRetCode(ret));
+ }
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
errmsg = "SQLDriverConnect failed.";
goto finish;
@@ -467,16 +498,16 @@ odbc_query(int caller, mvc *sql, sql_sub
#ifdef HAVE_HGE
{
- char name[1024];
- ret = SQLGetInfo(dbc, SQL_DBMS_NAME, (SQLPOINTER) &name, 1023,
NULL);
- if (trace_enabled)
- printf("After SQLGetInfo(dbc, SQL_DBMS_NAME) returned
%d\n", ret);
+ char DBMSname[128];
+ ret = SQLGetInfo(dbc, SQL_DBMS_NAME, (SQLPOINTER) &DBMSname,
127, NULL);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
- if (strcmp("MonetDB", name) == 0) {
- /* make the MonetDB ODBC driver enable
returning SQL_HUGEINT as column datatype */
+ if (trace_enabled)
+ printf("SQLGetInfo(dbc, SQL_DBMS_NAME) returned
%s\n", DBMSname);
+ if (strcmp("MonetDB", DBMSname) == 0) {
+ /* enable the MonetDB ODBC driver to return
SQL_HUGEINT as column datatype */
ret = SQLGetTypeInfo(stmt, SQL_HUGEINT);
if (trace_enabled)
- printf("After SQLGetTypeInfo(stmt,
SQL_HUGEINT) returned %d\n", ret);
+ printf("SQLGetTypeInfo(stmt,
SQL_HUGEINT) returned %s\n", nameOfRetCode(ret));
if (ret == SQL_SUCCESS || ret ==
SQL_SUCCESS_WITH_INFO) {
ret = SQLCloseCursor(stmt);
}
@@ -490,10 +521,18 @@ odbc_query(int caller, mvc *sql, sql_sub
ret = SQLExecDirectW(stmt, (SQLWCHAR *) query_Wstr, SQL_NTS);
/* we no longer need query_Wstr */
free(query_Wstr);
- } else
+ } else {
ret = SQLExecDirect(stmt, (SQLCHAR *) query, SQL_NTS);
- if (trace_enabled)
- printf("After SQLExecDirect(%s) returned %d\n", query, ret);
+ }
+ if (ret == SQL_SUCCESS_WITH_INFO && caller == ODBC_RELATION) {
+ /* show the info warning, but only once */
+ char * ODBCmsg = getErrMsg(SQL_HANDLE_STMT, stmt);
+ printf("SQLExecDirect(%s) returned %s ODBCmsg: %s\n", query,
nameOfRetCode(ret), (ODBCmsg) ? ODBCmsg : "");
+ if (ODBCmsg)
+ GDKfree(ODBCmsg);
+ } else if (trace_enabled) {
+ printf("SQLExecDirect(%s) returned %s\n", query,
nameOfRetCode(ret));
+ }
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
errmsg = "SQLExecDirect query failed.";
goto finish;
@@ -651,12 +690,12 @@ odbc_query(int caller, mvc *sql, sql_sub
col+1, cname, dataType,
nameofSQLtype(dataType), (unsigned int)columnSize, decimalDigits, battype);
if (trace_enabled)
- printf("Before create BAT %d\n", col+1);
+ printf("Before create BAT %d type %d\n", col+1,
battype);
b = bat_create(battype, 0);
if (b) {
colmetadata[col].bat = b;
if (trace_enabled)
- printf("After create BAT %d\n", col+1);
+ printf("Created BAT %d\n", col+1);
} else {
errmsg = "Failed to create bat.";
/* cleanup already created bats */
@@ -774,7 +813,7 @@ odbc_query(int caller, mvc *sql, sql_sub
break;
case SQL_DECIMAL:
case SQL_NUMERIC:
- /* we read decimal data always
as string data and convert it to the right internal decimal format and bat type
*/
+ /* read decimal data always as
string data and convert it to the right internal decimal format and bat type */
targetType = SQL_C_CHAR;
targetValuePtr = (SQLPOINTER *)
str_val;
bufferLength =
largestStringSize;
@@ -887,9 +926,9 @@ odbc_query(int caller, mvc *sql, sql_sub
printf("Failed to get C_type %d
data for col %u of row %lu. ODBCmsg: %s\n",
targetType, col+1, row,
(ODBCmsg) ? ODBCmsg : "");
if (ODBCmsg)
- free(ODBCmsg);
+ GDKfree(ODBCmsg);
}
- /* as all bats need to be the correct
length, append NULL value */
+ /* as all bats need to be the same
length, append NULL value */
if (BUNappend(b, ATOMnilptr(b->ttype),
false) != GDK_SUCCEED)
if (trace_enabled)
printf("BUNappend(b,
NULL, false) failed\n");
@@ -1191,7 +1230,7 @@ odbc_query(int caller, mvc *sql, sql_sub
GDKfree(odbc_con_str);
if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) {
- /* an ODBC function call returned an error, get the error msg
from the ODBC driver */
+ /* an ODBC function call returned an error or warning, get the
error msg from the ODBC driver */
SQLSMALLINT handleType;
SQLHANDLE handle;
str retmsg;
@@ -1216,7 +1255,7 @@ odbc_query(int caller, mvc *sql, sql_sub
retmsg = sa_message(sql->sa, "odbc_loader" " %s",
(ODBCmsg) ? ODBCmsg : "");
}
if (ODBCmsg)
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]