- support for SQLNativeSql()

- dynamic memory allocation for return values in these functions:
  - odbc_sql_get_info_string()
  - odbc_sql_get_connect_attr_string()
  - odbc_sql_get_stmt_attr_string()
  - odbc_sql_get_desc_field_string()
  - odbc_sql_get_cursor_name()
  - odbc_sql_native_sql()
  - odbc_sql_get_data()
  - odbc_sql_describe_col()
  - odbc_sql_get_diag_recs()
- odbc_sql_data_sources() is still broken: sometimes the result string
  is truncated. I'm not sure if this not a unixODBC-bug...
This commit is contained in:
eknauel 2002-09-11 14:12:30 +00:00
parent cd9907c68f
commit 87846eef58
3 changed files with 254 additions and 82 deletions

View File

@ -162,18 +162,12 @@ s48_value odbc_sql_connect(s48_value connection_handle,
SQLHDBC ch;
SQLCHAR *dsn, *user, *auth;
SQLRETURN retval;
int dsn_len, user_len, auth_len;
ODBC_DEBUG_PRINTF("odbc_sql_connect\n");
dsn = (SQLCHAR *) s48_extract_string(ds_name);
user = (SQLCHAR *) s48_extract_string(user_name);
auth = (SQLCHAR *) s48_extract_string(authentication);
dsn_len = S48_STRING_LENGTH(ds_name);
user_len = S48_STRING_LENGTH(user_name);
auth_len = S48_STRING_LENGTH(authentication);
ch = (SQLHDBC) s48_extract_integer(connection_handle);
retval = SQLConnect(ch,
@ -218,10 +212,9 @@ s48_value odbc_sql_data_sources(s48_value env_handle)
SQLHENV eh;
SQLUSMALLINT dir;
SQLRETURN retval;
SQLCHAR server_name[SQL_MAX_DSN_LENGTH+1];
SQLSMALLINT server_name_len;
SQLCHAR driver_descr[ODBC_MAX_DRIVER_NAME_LEN];
SQLSMALLINT driver_descr_len;
SQLCHAR *server_name, *driver_descr;
SQLSMALLINT server_name_len, driver_descr_len;
SQLSMALLINT server_name_needed, driver_descr_needed;
s48_value result = S48_UNSPECIFIC;
int first, more_items;
@ -231,20 +224,59 @@ s48_value odbc_sql_data_sources(s48_value env_handle)
eh = (SQLHENV) s48_extract_integer(env_handle);
ODBC_DEBUG_PRINTF("odbc_sql_data_sources\n");
server_name_len = driver_descr_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
server_name = (SQLCHAR *) calloc(server_name_len, sizeof(SQLCHAR));
driver_descr = (SQLCHAR *) calloc(driver_descr_len, sizeof(SQLCHAR));
if ((server_name == NULL) || (driver_descr == NULL))
{
ODBC_RAISE_EXCEPTION("Could not allocate memory for return values");
return S48_UNSPECIFIC;
}
redo_loop:
ODBC_DEBUG_PRINTF("redo_loop\n");
result = S48_NULL;
first = more_items = 1;
while (more_items) {
printf("Calling SQLDataSources() server_name_len: %d driver_descr_len: %d\n",
sizeof(SQLCHAR)*server_name_len,
sizeof(SQLCHAR)*driver_descr_len);
retval = SQLDataSources(eh,
(first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT),
server_name, SQL_MAX_DSN_LENGTH+1, &server_name_len,
driver_descr, ODBC_MAX_DRIVER_NAME_LEN, &driver_descr_len);
/* FIXME */
if (driver_descr_len > ODBC_MAX_DRIVER_NAME_LEN - 1)
server_name, sizeof(SQLCHAR)*server_name_len, &server_name_needed,
driver_descr, sizeof(SQLCHAR)*driver_descr_len, &driver_descr_needed);
if (ODBC_SUCCESS(retval))
{
ODBC_RAISE_EXCEPTION("SQLDataSources(): string driver_descr to long");
return S48_UNSPECIFIC;
int redo_call = 0;
if (server_name_needed > server_name_len)
{
ODBC_DEBUG_PRINTF("realloc() server_name\n");
printf("needed: %d\n", server_name_needed);
server_name_len = server_name_needed+1;
server_name = (SQLCHAR *) realloc(server_name, (size_t) server_name_len);
redo_call = 1;
}
if (driver_descr_needed > driver_descr_len)
{
ODBC_DEBUG_PRINTF("realloc() driver_desrc\n");
printf("needed: %d\n", driver_descr_needed);
driver_descr_len = driver_descr_needed+1;
driver_descr = (SQLCHAR *) realloc(driver_descr, (size_t) driver_descr_len);
redo_call = 1;
}
if ((server_name == NULL) || (driver_descr == NULL))
{
ODBC_RAISE_EXCEPTION("Could not allocate memory for return values");
return S48_UNSPECIFIC;
}
if (redo_call) goto redo_loop;
}
first = 0;
@ -253,6 +285,7 @@ s48_value odbc_sql_data_sources(s48_value env_handle)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
printf("(cons '%s' '%s')\n", server_name, driver_descr);
result = s48_cons(s48_cons(s48_enter_string(server_name),
s48_enter_string(driver_descr)),
result);
@ -281,6 +314,9 @@ s48_value odbc_sql_data_sources(s48_value env_handle)
}
}
free(server_name);
free(driver_descr);
S48_GC_UNPROTECT();
return result;
}
@ -401,21 +437,35 @@ s48_value odbc_sql_get_info_string(s48_value conn_handle, s48_value info_key)
SQLHDBC ch;
SQLUSMALLINT ik;
SQLRETURN retval;
SQLCHAR info[ODBC_GET_INFO_MAX_LEN];
SQLSMALLINT buffer_size;
SQLCHAR *buffer = NULL;
SQLSMALLINT buffer_needed, buffer_len;
ODBC_DEBUG_PRINTF("odbc_sql_get_info_string\n");
ch = (SQLHDBC) s48_extract_integer(conn_handle);
ik = (SQLUSMALLINT) s48_extract_integer(info_key);
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
retval = SQLGetInfo(ch, ik, &info, ODBC_GET_INFO_MAX_LEN, &buffer_size);
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
printf("SQLGetInfo(): buffer_len %d\n", buffer_len);
retval = SQLGetInfo(ch, ik, buffer, buffer_len, &buffer_needed);
if (ODBC_SUCCESS(retval) && (buffer_needed > buffer_len))
buffer_len = buffer_needed+1;
else
break;
}
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_string(info);
s48_value res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_ERROR:
{
@ -612,21 +662,32 @@ s48_value odbc_sql_get_connect_attr_string(s48_value conn_handle,
SQLHDBC ch;
SQLINTEGER attr;
SQLCHAR buffer[ODBC_GET_CONNECT_ATTR_MAX_LEN];
SQLINTEGER buffer_size;
SQLCHAR *buffer = NULL;
SQLINTEGER buffer_needed, buffer_len;
SQLRETURN retval;
ODBC_DEBUG_PRINTF("odbc_sql_get_connect_attr_string\n");
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
retval = SQLGetConnectAttr(ch, attr,
buffer, ODBC_GET_CONNECT_ATTR_MAX_LEN-1,
&buffer_size);
for (;;) {
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
retval = SQLGetConnectAttr(ch, attr, buffer, buffer_len, &buffer_needed);
if (ODBC_SUCCESS(retval) && (buffer_needed > buffer_len))
buffer_needed = buffer_len;
else
break;
}
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_string(buffer);
s48_value res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_ERROR:
{
@ -816,7 +877,6 @@ s48_value odbc_sql_set_stmt_attr_string(s48_value stmt_handle,
s48_value attribute,
s48_value value)
{
SQLHSTMT sh;
SQLINTEGER attr;
SQLCHAR *val;
@ -828,8 +888,7 @@ s48_value odbc_sql_set_stmt_attr_string(s48_value stmt_handle,
attr = (SQLINTEGER) s48_extract_integer(attribute);
val = (SQLCHAR *) s48_extract_string(value);
retval = SQLSetStmtAttr(sh, attr,
val, S48_STRING_LENGTH(value));
retval = SQLSetStmtAttr(sh, attr, val, S48_STRING_LENGTH(value));
switch (retval)
{
@ -855,10 +914,8 @@ s48_value odbc_sql_set_stmt_attr_string(s48_value stmt_handle,
}
}
s48_value odbc_sql_get_stmt_attr_int(s48_value stmt_handle,
s48_value attribute)
s48_value odbc_sql_get_stmt_attr_int(s48_value stmt_handle, s48_value attribute)
{
SQLHSTMT sh;
SQLINTEGER attr, val, buf_size;
SQLRETURN retval;
@ -899,20 +956,32 @@ s48_value odbc_sql_get_stmt_attr_string(s48_value stmt_handle,
{
SQLHSTMT sh;
SQLINTEGER attr, buf_size;
SQLCHAR buf[ODBC_GET_STMT_ATTR_MAX_LEN];
SQLINTEGER attr, buffer_len, buffer_needed;
SQLCHAR *buffer = NULL;
SQLRETURN retval;
ODBC_DEBUG_PRINTF("odbc_sql_get_stmt_attr_string\n");
retval = SQLGetStmtAttr(sh, attr, &buf,
ODBC_GET_STMT_ATTR_MAX_LEN-1, &buf_size);
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
retval = SQLGetStmtAttr(sh, attr, &buffer, buffer_len, &buffer_needed);
if (ODBC_SUCCESS(retval) && (buffer_needed > buffer_len))
buffer_len = buffer_needed+1;
else
break;
}
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_string(buf);
s48_value res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_ERROR:
{
@ -1007,8 +1076,8 @@ s48_value odbc_sql_get_desc_field_string(s48_value desc_handle, s48_value rec_nu
{
SQLHDESC dh;
SQLSMALLINT rn, fi;
SQLCHAR value[ODBC_MAX_GET_DESC_FIELD_STR_LEN];
SQLINTEGER buffer_len;
SQLCHAR *buffer = NULL;
SQLINTEGER buffer_len, buffer_needed;
SQLRETURN retval;
ODBC_DEBUG_PRINTF("odbc_sql_get_desc_field_string\n");
@ -1017,15 +1086,26 @@ s48_value odbc_sql_get_desc_field_string(s48_value desc_handle, s48_value rec_nu
rn = (SQLSMALLINT) s48_extract_integer(rec_number);
fi = (SQLSMALLINT) s48_extract_integer(field_id);
retval = SQLGetDescField(dh, rn, fi, (SQLPOINTER) value,
(ODBC_MAX_GET_DESC_FIELD_STR_LEN - 1),
&buffer_len);
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
retval = SQLGetDescField(dh, rn, fi, (SQLPOINTER) buffer,
buffer_len, &buffer_needed);
if (ODBC_SUCCESS(retval) && (buffer_needed > buffer_len))
buffer_len = buffer_needed+1;
else
break;
}
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_string(value);
s48_value res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_NO_DATA:
{
@ -1344,20 +1424,32 @@ s48_value odbc_sql_get_cursor_name(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLRETURN retval;
SQLCHAR cursorname[ODBC_MAX_CURSOR_NAME_STR_LEN];
SQLSMALLINT buffer_len;
SQLCHAR *buffer = NULL;
SQLSMALLINT buffer_len, buffer_needed;
ODBC_DEBUG_PRINTF("odbc_sql_get_cursor_name\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
retval = SQLGetCursorName(sh, cursorname, ODBC_MAX_CURSOR_NAME_STR_LEN - 1, &buffer_len);
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
retval = SQLGetCursorName(sh, buffer, buffer_len, &buffer_needed);
if (ODBC_SUCCESS(retval) && (buffer_needed > buffer_len))
buffer_len = buffer_needed+1;
else
break;
}
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_string(cursorname);
s48_value res = s48_enter_string(buffer);
free(buffer);
return s48_enter_string(buffer);
}
case SQL_ERROR:
{
@ -1514,24 +1606,35 @@ s48_value odbc_sql_execute_direct(s48_value stmt_handle,
s48_value odbc_sql_native_sql(s48_value conn_handle, s48_value stmt_txt)
{
SQLHDBC ch;
SQLCHAR *stmt_in, stmt_out[ODBC_MAX_NATIVE_SQL_STR_LEN];
SQLINTEGER buffer_len;
SQLCHAR *stmt_in, *stmt_out = NULL;
SQLINTEGER buffer_len, buffer_needed;
SQLRETURN retval;
ch = (SQLHDBC) s48_extract_integer(conn_handle);
stmt_in = (SQLCHAR *) s48_extract_string(stmt_txt);
ODBC_DEBUG_PRINTF("odbc_sql_native_sql\n");
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
for (;;)
{
odbc_sql_alloc((void **) &stmt_out, buffer_len, sizeof(SQLCHAR));
retval = SQLNativeSql(ch, stmt_in, S48_STRING_LENGTH(stmt_txt),
stmt_out, buffer_len, &buffer_needed);
retval = SQLNativeSql(ch, stmt_in, S48_STRING_LENGTH(stmt_txt),
stmt_out, ODBC_MAX_NATIVE_SQL_STR_LEN - 1,
&buffer_len);
if (ODBC_SUCCESS(retval) && buffer_needed > buffer_len)
buffer_len = buffer_needed+1;
else
break;
}
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_string(stmt_out);
s48_value res = s48_enter_string(stmt_out);
free(stmt_out);
return res;
}
case SQL_ERROR:
{
@ -1672,14 +1775,25 @@ s48_value odbc_sql_get_data(s48_value stmt_handle,
case SQL_C_CHAR:
case SQL_C_BINARY:
{
SQLCHAR str[ODBC_GET_DATA_MAX_STR_LEN];
SQLINTEGER str_len;
retval = SQLGetData(sh, cn, tt,
str, ODBC_GET_DATA_MAX_STR_LEN-1,
&str_len);
SQLCHAR *buffer = NULL;
SQLINTEGER buffer_len, buffer_needed;
s48_value res = S48_UNSPECIFIC;
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
retval = SQLGetData(sh, cn, tt,
buffer, buffer_len, &buffer_needed);
if (ODBC_SUCCESS(retval) && (buffer_needed > buffer_len))
buffer_len = buffer_needed+1;
else
break;
}
check_sql_get_data_result(retval, sh);
return s48_enter_string((char *) str);
res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_C_SSHORT:
case SQL_C_USHORT:
@ -1966,8 +2080,8 @@ s48_value odbc_sql_describe_col(s48_value stmt_handle, s48_value column_number)
SQLHSTMT sh;
SQLSMALLINT cn;
SQLCHAR column_name[ODBC_DESCRIBE_COL_MAX_STR_LEN];
SQLSMALLINT buf_len, data_type, digits, nullable;
SQLCHAR *buffer = NULL;
SQLSMALLINT buffer_len, buffer_needed, data_type, digits, nullable;
SQLUINTEGER col_size;
SQLRETURN retval;
s48_value col_rec = S48_UNSPECIFIC;
@ -1980,14 +2094,20 @@ s48_value odbc_sql_describe_col(s48_value stmt_handle, s48_value column_number)
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
cn = (SQLSMALLINT) s48_extract_integer(column_number);
retval = SQLDescribeCol(sh, cn,
column_name,
ODBC_DESCRIBE_COL_MAX_STR_LEN - 1,
&buf_len,
&data_type,
&col_size,
&digits,
&nullable);
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
retval = SQLDescribeCol(sh, cn,
buffer, buffer_len, &buffer_needed,
&data_type, &col_size, &digits,
&nullable);
if (ODBC_SUCCESS(retval) && (buffer_needed > buffer_len))
buffer_len = buffer_needed+1;
else
break;
}
switch (retval)
{
@ -1995,7 +2115,7 @@ s48_value odbc_sql_describe_col(s48_value stmt_handle, s48_value column_number)
{
col_rec = s48_make_record(odbc_column_record_type);
S48_RECORD_SET(col_rec, SR_ODBC_COLUMN_NAME,
s48_enter_string(column_name));
s48_enter_string(buffer));
S48_RECORD_SET(col_rec, SR_ODBC_COLUMN_TYPE,
s48_enter_integer(data_type));
S48_RECORD_SET(col_rec, SR_ODBC_COLUMN_SIZE,
@ -2006,6 +2126,7 @@ s48_value odbc_sql_describe_col(s48_value stmt_handle, s48_value column_number)
s48_enter_integer(nullable));
S48_GC_UNPROTECT();
free(buffer);
return col_rec;
}
case SQL_STILL_EXECUTING:
@ -2817,8 +2938,8 @@ s48_value odbc_sql_get_diag_recs(s48_value handle_type, s48_value handle)
SQLHANDLE h;
SQLCHAR sql_state[6];
SQLINTEGER native_error;
SQLCHAR message[ERROR_MSG_BUFFER_LEN];
SQLSMALLINT i, message_len, more_recs;
SQLCHAR *buffer = NULL;
SQLSMALLINT i, more_recs, buffer_len, buffer_needed;
SQLRETURN retval;
s48_value res = S48_UNSPECIFIC;
s48_value diag_rec = S48_UNSPECIFIC;
@ -2833,12 +2954,23 @@ s48_value odbc_sql_get_diag_recs(s48_value handle_type, s48_value handle)
ODBC_DEBUG_PRINTF("odbc_sql_get_diag_recs\n");
i = more_recs = 1;
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
while (more_recs) {
diag_rec = s48_make_record(odbc_diag_record_type);
retval = SQLGetDiagRec(ht, h, i,
sql_state, &native_error,
message, sizeof(message), &message_len);
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
retval = SQLGetDiagRec(ht, h, i,
sql_state, &native_error,
buffer, buffer_len, &buffer_needed);
if (ODBC_SUCCESS(retval) && (buffer_needed > buffer_len))
buffer_len = buffer_needed+1;
else
break;
}
switch (retval)
{
@ -2846,7 +2978,7 @@ s48_value odbc_sql_get_diag_recs(s48_value handle_type, s48_value handle)
{
S48_RECORD_SET(diag_rec, SR_ODBC_DIAG_SQL_STATE, s48_enter_string(sql_state));
S48_RECORD_SET(diag_rec, SR_ODBC_DIAG_NATIVE_ERROR, s48_enter_integer(native_error));
S48_RECORD_SET(diag_rec, SR_ODBC_DIAG_MESSAGE, s48_enter_string(message));
S48_RECORD_SET(diag_rec, SR_ODBC_DIAG_MESSAGE, s48_enter_string(buffer));
res = s48_cons(diag_rec, res);
break;
}
@ -2875,6 +3007,7 @@ s48_value odbc_sql_get_diag_recs(s48_value handle_type, s48_value handle)
}
S48_GC_UNPROTECT(); /* res */
free(buffer);
return res;
}
@ -3050,6 +3183,30 @@ s48_value struct_to_sql_timestamp_record(SQL_TIMESTAMP_STRUCT *ts)
return sql_timestamp;
}
void odbc_sql_alloc(void **buffer, size_t buffer_len, size_t type_len)
{
if (*buffer == NULL)
{
#ifdef ODBC_DEBUG_MSGS
printf("calloc %d %d\n", buffer_len+1, type_len);
#endif
*buffer = (void *) calloc(buffer_len+1, type_len);
}
else
{
#ifdef ODBC_DEBUG_MSGS
printf("realloc %d\n", buffer_len*type_len);
#endif
*buffer = (void *) realloc(*buffer, buffer_len*type_len);
}
if (*buffer == NULL)
{
ODBC_RAISE_EXCEPTION("Could not allocate return value buffer");
return;
}
}
void s48_init_odbc(void)
{
/* bindings for record types */

View File

@ -19,6 +19,8 @@
#define ODBC_MAX_NATIVE_SQL_STR_LEN ODBC_MAX_STR_LEN
#define ODBC_MAX_GET_DESC_FIELD_STR_LEN ODBC_MAX_STR_LEN
#define ODBC_RETVAL_BUFFER_INITIAL_SIZE 3
#define ODBC_DEBUG_MSGS 1
#define ODBC_RAISE_EXCEPTION(MSG) s48_raise_string_os_error(MSG)
@ -41,6 +43,9 @@
/* offsets for scheme records */
/* some useful macros */
#define ODBC_SUCCESS(retval) ((retval == SQL_SUCCESS) || (retval == SQL_SUCCESS_WITH_INFO))
/* corresponds to sql-date */
static s48_value sql_date_record_type = S48_FALSE;
@ -419,5 +424,7 @@ s48_value struct_to_sql_time_record(SQL_TIME_STRUCT *ts);
void sql_timestamp_record_to_struct(s48_value sql_timestamp,
SQL_TIMESTAMP_STRUCT *ts);
void odbc_sql_alloc(void **buffer, size_t buffer_len, size_t type_len);
void s48_init_odbc(void);

View File

@ -203,7 +203,7 @@
(define sql-api-sqlsetscrolloptions 69)
(define sql-api-sqltableprivileges 70)
;;; info keys for odbc-sql-get-info-argint/string
;;; info keys for odbc-sql-get-info-arg-int/string
; ODBC 1.0, returns integer
(define sql-get-info-arg-maxdriverconnections 0)
; ODBC 1.0, returns integer
@ -472,7 +472,7 @@
(define (odbc-sql-data-sources env-handle)
(check-arg environment-handle? env-handle odbc-sql-data-sources)
(odbc-sql-data-sources-internal (environment-handle-handle env-handle)))
(reverse (odbc-sql-data-sources-internal (environment-handle-handle env-handle))))
(import-lambda-definition odbc-sql-data-sources-internal
(env-handle)
@ -685,6 +685,14 @@
(stmt-handle stmt-txt)
"odbc_sql_execute_direct")
(define (odbc-sql-native-sql conn-handle stmt-txt)
(check-arg connection-handle? conn-handle odbc-sql-native-sql)
(odbc-sql-native-sql-internal (connection-handle-handle conn-handle)
stmt-txt))
(import-lambda-definition odbc-sql-native-sql-internal
(conn-handle stmt-txt)
"odbc_sql_native_sql")
;;; PART 7