scsh-0.6/scsh/odbc/odbc.c

3801 lines
93 KiB
C

#include "odbc.h"
/*
*
* PART 1
*
* Connecting to a data source
*
*/
/* Call SQLAllocHandle and get an environment handle. After that
* call odbc_set_environment to set the ODBC version */
s48_value odbc_alloc_environment_handle()
{
SQLHENV henv;
SQLRETURN retval;
retval = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
ODBC_DEBUG_PRINTF_2("odbc_alloc_environment(): %x\n", henv);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
return s48_enter_integer(henv);
case SQL_ERROR:
ODBC_RAISE_EXCEPTION("SQLAllocHandle returned SQL_ERROR");
default:
ODBC_RAISE_EXCEPTION("SQLAllocHandle unknown return value");
}
}
/* given a valid environment handle (type SQLHENV) this function
* sets the environment attributes. This needs to be done before
* allocating a connection handle */
void odbc_sql_set_env_attr(SQLHENV env_handle)
{
SQLRETURN retval;
retval = SQLSetEnvAttr(env_handle, SQL_ATTR_ODBC_VERSION,
(void *)SQL_OV_ODBC3, 0);
ODBC_DEBUG_PRINTF_2("odbc_set_environment() %x\n", env_handle);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLSetEnvAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLSetEnvAttr got invalid handle. Is your ODBC broken?");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLSetEnvAttr returned unknown error code");
break;
}
}
}
/* Given a valid environment handle get a connection handle */
s48_value odbc_alloc_connection_handle(s48_value env_handle) {
SQLHDBC hdbc;
SQLRETURN retval;
SQLHENV envh;
envh = (SQLHENV) s48_extract_integer(env_handle);
retval = SQLAllocHandle(SQL_HANDLE_DBC, envh, &hdbc);
ODBC_DEBUG_PRINTF_3("odbc_alloc_connection_handle() %x %x\n", envh, hdbc);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer((long)hdbc);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLAllocHandle returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLAllocHandle got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLAllocHandle returned unknown error code");
break;
}
}
}
/* Given a valid connection handle get a statement handle */
s48_value odbc_alloc_statement_handle(s48_value conn_handle) {
SQLHSTMT hstmt;
SQLRETURN retval;
SQLHANDLE ch;
ch = (SQLHANDLE) s48_extract_integer(conn_handle);
retval = SQLAllocHandle(SQL_HANDLE_STMT, ch, &hstmt);
ODBC_DEBUG_PRINTF_3("odbc_alloc_statement_handle() %x %x\n", ch, hstmt);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer((long)hstmt);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLAllocHandle returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLAllocHandle got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLAllocHandle returned unknown error code");
break;
}
}
}
/* for ODBC 1.0 compatibility */
s48_value odbc_sql_alloc_env()
{
SQLRETURN retval;
SQLHENV eh;
ODBC_DEBUG_PRINTF("odbc_sql_alloc_env()\n");
retval = SQLAllocEnv(&eh);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
return s48_enter_inteeger(eh);
case SQL_ERROR:
ODBC_RAISE_EXCEPTION("SQLAllocHandle() returned SQL_ERROR");
default:
ODBC_RAISE_EXCEPTION("SQLAllocHandle() returned unknown error code");
}
}
s48_value odbc_sql_alloc_connect(s48_value env_handle)
{
SQLRETURN retval;
SQLHENV eh;
SQLHDBC ch;
eh = (SQLHENV) s48_extract_integer(env_handle);
ODBC_DEBUG_PRINTF("odbc_sql_alloc_connect(): eh:%d\n");
retval = SQLAllocConnect(ch, &eh);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
return s48_enter_integer(ch);
case SQL_ERROR:
ODBC_RAISE_EXCEPTION("SQLAllocConnect returned SQL_ERROR");
case SQL_INVALID_HANDLE:
ODBC_RAISE_EXCEPTION("SQLAllocConnect got invalid handle");
default:
ODBC_RAISE_EXCEPTION("SQLAllocConnect returned unknown error");
}
}
s48_value odbc_sql_alloc_stmt(s48_value conn_handle)
{
SQLRETURN retval;
SQLHDBC ch;
SQLHSTMT sh;
ch = (SQLHDBC) s48_extract_integer(conn_handle);
ODBC_DEBUG_PRINTF("odbc_sql_alloc_stmt(): ch:%d\n");
retval = SQLAllocStmt(ch, &eh);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
return s48_enter_integer(eh);
case SQL_ERROR:
ODBC_RAISE_EXCEPTION("SQLAllocStmt returned SQL_ERROR");
case SQL_INVALID_HANDLE:
ODBC_RAISE_EXCEPTION("SQLAllocStmt got invalid handle");
default:
ODBC_RAISE_EXCEPTION("SQLAllocStmt returned unknown error code");
}
}
/* Connect to a server */
s48_value odbc_sql_connect(s48_value connection_handle,
s48_value ds_name,
s48_value user_name,
s48_value authentication)
{
SQLHDBC ch;
SQLCHAR *dsn, *user, *auth;
SQLRETURN retval;
dsn = (SQLCHAR *) s48_extract_string(ds_name);
user = (SQLCHAR *) s48_extract_string(user_name);
auth = (SQLCHAR *) s48_extract_string(authentication);
ch = (SQLHDBC) s48_extract_integer(connection_handle);
ODBC_DEBUG_PRINTF_5("odbc_sql_connect() %x '%s' '%s' '%s'\n",
ch, dsn, user,auth);
retval = SQLConnect(ch,
dsn, SQL_NTS,
user, SQL_NTS,
auth, SQL_NTS);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLConnect returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLConnect got invalid handle");
break;
}
default:
ODBC_RAISE_EXCEPTION("SQLConnect returned an unknown error code");
break;
}
}
s48_value odbc_sql_browse_connect(s48_value conn_handle, s48_value conn_string)
{
SQLHDBC ch;
SQLCHAR *buffer = NULL;
SQLRETURN retval;
SQLSMALLINT buffer_needed, buffer_len;
ch = (SQLHDBC) s48_extract_integer(conn_handle);
ODBC_DEBUG_PRINTF_3("odbc_sql_browse_connect() %x '%s'\n", ch, s48_extract_string(conn_string));
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
retval = SQLBrowseConnect(ch, (SQLCHAR *) s48_extract_string(conn_string),
(SQLSMALLINT) S48_STRING_LENGTH(conn_string),
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:
{
s48_value res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLBrowseConnect returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLBrowseConnect got invalid handle");
break;
}
case SQL_NEED_DATA:
{
return s48_enter_integer(SQL_NEED_DATA);
}
default:
{
ODBC_RAISE_EXCEPTION("SQLBrowseConnect returned unknown error code");
break;
}
}
}
/*
*
* PART 2
*
* Obtaining information about a driver and data source
*
*/
/* Returns a list of available data sources. */
s48_value odbc_sql_data_sources(s48_value env_handle)
{
SQLHENV eh;
SQLUSMALLINT dir;
SQLRETURN retval;
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;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(result);
eh = (SQLHENV) s48_extract_integer(env_handle);
ODBC_DEBUG_PRINTF_1("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_1("redo_loop\n");
result = S48_NULL;
first = more_items = 1;
while (more_items) {
retval = SQLDataSources(eh,
(first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT),
server_name, sizeof(SQLCHAR)*server_name_len, &server_name_needed,
driver_descr, sizeof(SQLCHAR)*driver_descr_len, &driver_descr_needed);
if (ODBC_SUCCESS(retval))
{
int redo_call = 0;
if (server_name_needed > server_name_len)
{
ODBC_DEBUG_PRINTF_2("realloc() server_name %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_2("realloc() driver_descr %d\n", driver_descr_needed+1);
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;
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
result = s48_cons(s48_cons(s48_enter_string(server_name),
s48_enter_string(driver_descr)),
result);
break;
}
case SQL_NO_DATA:
{
more_items = 0;
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLDataSources returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLDataSources got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLDataSources returned unknown error code");
break;
}
}
}
free(server_name);
free(driver_descr);
S48_GC_UNPROTECT();
return result;
}
/* Returns the list of installed drivers and their attributes. */
s48_value odbc_sql_drivers(s48_value env_handle)
{
SQLHENV eh;
SQLRETURN retval;
SQLCHAR driver_descr[ODBC_MAX_DRIVER_NAME_LEN];
SQLSMALLINT driver_descr_len;
SQLCHAR driver_attr[ODBC_MAX_DRIVER_NAME_LEN];
SQLSMALLINT driver_attr_len;
s48_value result = S48_UNSPECIFIC;
int first, more_items;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(result);
eh = (SQLHENV) s48_extract_integer(env_handle);
ODBC_DEBUG_PRINTF_1("odbc_sql_drivers\n");
result = S48_NULL;
first = more_items = 0;
while (more_items) {
retval = SQLDrivers(eh,
(SQLUSMALLINT) (first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT),
driver_descr, ODBC_MAX_DRIVER_NAME_LEN, &driver_descr_len,
driver_attr, ODBC_MAX_DRIVER_NAME_LEN, &driver_attr_len);
first = 1;
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
result = s48_cons(s48_cons(s48_enter_string(driver_descr),
s48_enter_string(driver_attr)),
result);
break;
}
case SQL_NO_DATA:
{
more_items = 0;
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLDrivers returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLDrivers got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLDrivers returned unknown error code");
break;
}
}
}
S48_GC_UNPROTECT();
return result;
}
/* Returns information about a specific driver and data source.
* (use if the information is an integer) */
s48_value odbc_sql_get_info_int(s48_value conn_handle, s48_value info_key)
{
SQLHDBC ch;
SQLUSMALLINT ik;
SQLRETURN retval;
SQLUINTEGER info;
SQLSMALLINT buffer_size;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_info_int\n");
ch = (SQLHDBC) s48_extract_integer(conn_handle);
ik = (SQLUSMALLINT) s48_extract_integer(info_key);
retval = SQLGetInfo(ch, ik, &info, sizeof(SQLUINTEGER), &buffer_size);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(info);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetInfo returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetInfo got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetInfo returned unknown error code");
break;
}
}
}
/* Returns information about a specific driver and data source.
* (use if the information is a string) */
s48_value odbc_sql_get_info_string(s48_value conn_handle, s48_value info_key)
{
SQLHDBC ch;
SQLUSMALLINT ik;
SQLRETURN retval;
SQLCHAR *buffer = NULL;
SQLSMALLINT buffer_needed, buffer_len;
ODBC_DEBUG_PRINTF_1("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;
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
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:
{
s48_value res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetInfo returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetInfo got invalid exception");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetInfo returned unknown error code");
break;
}
}
}
/* Returns supported driver functions. (for a multiple functions) */
s48_value odbc_sql_get_func_exists(s48_value conn_handle, s48_value fun_id)
{
SQLHDBC ch;
SQLUSMALLINT fi, supported[SQL_API_ODBC3_ALL_FUNCTIONS_SIZE];
SQLRETURN retval;
s48_value vec;
int i;
ODBC_DEBUG_PRINTF_1("odbc_sql_func_exists\n");
ch = (SQLHDBC) s48_extract_integer(conn_handle);
fi = (SQLUSMALLINT) s48_extract_integer(fun_id);
retval = SQLGetFunctions(ch, fi, supported);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return SQL_FUNC_EXISTS(supported, fi) == SQL_TRUE ? S48_TRUE : S48_FALSE;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetFunctions returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetFunctions got invalid exception");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetFunctions returned unknown error code");
break;
}
}
}
/* Returns information about supported data types. */
s48_value odbc_sql_get_type_info(s48_value stmt_handle, s48_value data_type)
{
SQLHSTMT sh;
SQLSMALLINT dt;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_type_info\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
dt = (SQLSMALLINT) s48_extract_integer(data_type);
retval = SQLGetTypeInfo(sh, dt);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetTypeInfo returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetTypeInfo got invalid handle");
break;
}
/* TODO: handle SQL_STILL_EXECUTING */
default:
{
ODBC_RAISE_EXCEPTION("SQLGetTypeInfo returned unknown error code");
break;
}
}
}
/*
*
* PART 3
*
* Setting and retrieving driver attributes
*
*/
s48_value odbc_sql_set_connect_attr_int(s48_value conn_handle,
s48_value attribute,
s48_value value)
{
SQLHDBC ch;
SQLINTEGER attr;
SQLUINTEGER val;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_set_connect_attr_int\n");
ch = (SQLHDBC) s48_extract_integer(conn_handle);
attr = (SQLINTEGER) s48_extract_integer(attribute);
val = (SQLUINTEGER) s48_extract_integer(value);
retval = SQLSetConnectAttr(ch, attr, &val, 0);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLSetConnectAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLSetConnectAttr got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLSetConnectAttr got unknown error code");
break;
}
}
}
s48_value odbc_sql_set_connect_attr_string(s48_value conn_handle,
s48_value attribute,
s48_value value)
{
SQLHDBC ch;
SQLINTEGER attr;
SQLCHAR *val;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_set_connect_attr_string\n");
ch = (SQLHDBC) s48_extract_integer(conn_handle);
attr = (SQLINTEGER) s48_extract_integer(attribute);
val = (SQLCHAR *) s48_extract_string(value);
retval = SQLSetConnectAttr(ch, attr, val, S48_STRING_LENGTH(value));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLSetConnectAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLSetConnectAttr got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLSetConnectAttr got unknown error code");
break;
}
}
}
s48_value odbc_sql_get_connect_attr_string(s48_value conn_handle,
s48_value attribute)
{
SQLHDBC ch;
SQLINTEGER attr;
SQLCHAR *buffer = NULL;
SQLINTEGER buffer_needed, buffer_len;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_connect_attr_string\n");
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_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:
{
s48_value res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetConnectAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetConnectAttr got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetConnectAttr returned unknown error code");
break;
}
}
}
s48_value odbc_sql_get_connect_attr_int(s48_value conn_handle,
s48_value attribute)
{
SQLHDBC ch;
SQLINTEGER attr;
SQLUINTEGER buffer;
SQLINTEGER buffer_size;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_connect_attr_int\n");
retval = SQLGetConnectAttr(ch, attr,
&buffer, sizeof(SQLUINTEGER), &buffer_size);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(buffer);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetConnectAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetConnectAttr got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetConnectAttr returned unknown error code");
break;
}
}
}
s48_value odbc_sql_set_env_attr_int(s48_value env_handle,
s48_value attribute,
s48_value value)
{
SQLHENV eh;
SQLINTEGER attr;
SQLUINTEGER val;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_set_env_attr\n");
eh = (SQLHENV) s48_extract_integer(env_handle);
attr = (SQLINTEGER) s48_extract_integer(attribute);
val = (SQLUINTEGER) s48_extract_integer(value);
retval = SQLSetEnvAttr(eh, attr, &val, sizeof(SQLUINTEGER));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLSetEnvAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLSetEnvAttr got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLSetEnvAttr returned unknown error code");
break;
}
}
}
s48_value odbc_sql_get_env_attr_int(s48_value env_handle,
s48_value attribute,
s48_value value)
{
SQLHENV eh;
SQLINTEGER attr;
SQLUINTEGER val, str_len;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_env_attr_int\n");
eh = (SQLHENV) s48_extract_integer(env_handle);
attr = (SQLINTEGER) s48_extract_integer(attribute);
val = (SQLUINTEGER) s48_extract_integer(value);
retval = SQLGetEnvAttr(eh, attr, &val, sizeof(SQLUINTEGER), &str_len);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(val);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetEnvAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetEnvAttr got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetEnvAttr returned unknown error code");
break;
}
}
}
/* Sets a statement attribute */
s48_value odbc_sql_set_stmt_attr_int(s48_value stmt_handle,
s48_value attribute,
s48_value value)
{
SQLHSTMT sh;
SQLINTEGER attr;
SQLUINTEGER val;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_stmt_attr_int\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
attr = (SQLINTEGER) s48_extract_integer(attribute);
val = (SQLUINTEGER) s48_extract_integer(value);
retval = SQLSetStmtAttr(sh, attr, &val, 0);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLSetStmtAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLSetStmtAttr got invalid handel");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLSetStmtAttr returned unknown error code");
break;
}
}
}
s48_value odbc_sql_set_stmt_attr_string(s48_value stmt_handle,
s48_value attribute,
s48_value value)
{
SQLHSTMT sh;
SQLINTEGER attr;
SQLCHAR *val;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_set_stmt_attr_string\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
attr = (SQLINTEGER) s48_extract_integer(attribute);
val = (SQLCHAR *) s48_extract_string(value);
retval = SQLSetStmtAttr(sh, attr, val, S48_STRING_LENGTH(value));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLSetStmtAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLSetStmtAttr got invalid handel");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLSetStmtAttr returned unknown error code");
break;
}
}
}
s48_value odbc_sql_get_stmt_attr_int(s48_value stmt_handle, s48_value attribute)
{
SQLHSTMT sh;
SQLINTEGER attr, val, buf_size;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_stmt_attr_int\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
attr = (SQLINTEGER) s48_extract_integer(attribute);
retval = SQLGetStmtAttr(sh, attr, &val, sizeof(SQLINTEGER), &buf_size);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(val);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetStmtAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetStmtAttr got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetStmtAttr returned unknown error code");
break;
}
}
}
s48_value odbc_sql_get_stmt_attr_string(s48_value stmt_handle,
s48_value attribute)
{
SQLHSTMT sh;
SQLINTEGER attr, buffer_len, buffer_needed;
SQLCHAR *buffer = NULL;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_stmt_attr_string\n");
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:
{
s48_value res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetStmtAttr returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetStmtAttr got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetStmtAttr returned unknown error code");
break;
}
}
}
/*
*
* PART 4
*
* Setting and retrieving descriptor fields
*
*/
/* Returns the value of a single descriptor field (for integers) */
s48_value odbc_sql_get_desc_field_int(s48_value desc_handle, s48_value rec_number,
s48_value field_id)
{
SQLHDESC dh;
SQLSMALLINT rn, fi;
SQLINTEGER value, buffer_len;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_desc_field_int\n");
dh = (SQLHDESC) s48_extract_integer(desc_handle);
rn = (SQLSMALLINT) s48_extract_integer(rec_number);
fi = (SQLSMALLINT) s48_extract_integer(field_id);
retval = SQLGetDescField(dh, rn, fi, (SQLPOINTER) &value,
sizeof(SQLINTEGER), &buffer_len);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
switch (buffer_len)
{
case SQL_IS_INTEGER:
return s48_enter_integer((SQLINTEGER) value);
case SQL_IS_UINTEGER:
return s48_enter_integer((SQLUINTEGER) value);
case SQL_IS_SMALLINT:
return s48_enter_integer((SQLSMALLINT) value);
case SQL_IS_USMALLINT:
return s48_enter_integer((SQLUSMALLINT) value);
default:
{
ODBC_RAISE_EXCEPTION("SQLGetDescField returned unknown integer type");
break;
}
}
}
case SQL_NO_DATA:
{
return S48_FALSE;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetDescField returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetDescField got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetDescField returned unknown error code");
break;
}
}
}
/* Returns the value of a single descriptor field (for strings/binary data) */
s48_value odbc_sql_get_desc_field_string(s48_value desc_handle, s48_value rec_number,
s48_value field_id)
{
SQLHDESC dh;
SQLSMALLINT rn, fi;
SQLCHAR *buffer = NULL;
SQLINTEGER buffer_len, buffer_needed;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_desc_field_string\n");
dh = (SQLHDESC) s48_extract_integer(desc_handle);
rn = (SQLSMALLINT) s48_extract_integer(rec_number);
fi = (SQLSMALLINT) s48_extract_integer(field_id);
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:
{
s48_value res = s48_enter_string(buffer);
free(buffer);
return res;
}
case SQL_NO_DATA:
{
return S48_FALSE;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetDescField returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetDescField got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetDescField returned unknown error code");
break;
}
}
}
/*
*
* PART 5
*
* Preparing SQL requests
*
*/
/* Prepare a SQL statement for execution */
s48_value odbc_sql_prepare(s48_value stmt_handle, s48_value stmt_txt)
{
SQLHSTMT sh;
SQLCHAR *query;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_prepare\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
query = (SQLCHAR *) s48_extract_string(stmt_txt);
retval = SQLPrepare(sh, query, S48_STRING_LENGTH(stmt_txt));
switch (retval) {
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLPrepare got invalid handle");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLPrepare returned SQL_ERROR");
break;
}
case SQL_STILL_EXECUTING:
{
/* Not yet implemented, raise an error meanwhile */
ODBC_RAISE_EXCEPTION("SQLPrepare returned SQL_STILL_EXECUTING");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLPrepare returned an unknown error code");
break;
}
}
}
s48_value odbc_sql_bind_parameter_exec_out(s48_value stmt_handle,
s48_value param_vals)
{
SQLHSTMT sh;
SQLSMALLINT value_type, param_type;
SQLRETURN retval;
unsigned int i;
ODBC_DEBUG_PRINTF_1("odbc_sql_bind_parameter_exec_out\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
/* bind parameters */
for (i = 0; i < S48_VECTOR_LENGTH(param_vals); i++) {
ODBC_DEBUG_PRINTF_2("Binding parameter %d", i);
value_type = (SQLSMALLINT)
s48_extract_integer(S48_CAR(S48_CDR(S48_VECTOR_REF(param_vals, i))));
param_type = (SQLSMALLINT)
s48_extract_integer(S48_CDR(S48_CDR(S48_VECTOR_REF(param_vals, i))));
switch (value_type)
{
case SQL_C_CHAR:
case SQL_C_BINARY:
{
SQLCHAR *value;
SQLUINTEGER val_len;
ODBC_DEBUG_PRINTF_1("value_type is string\n");
value = (SQLCHAR *)
s48_extract_string(S48_CAR(S48_VECTOR_REF(param_vals, i)));
val_len =
(SQLUINTEGER) S48_STRING_LENGTH(S48_CAR(S48_VECTOR_REF(param_vals, i)));
retval = SQLBindParameter(sh, (SQLUSMALLINT) (i+1),
SQL_PARAM_OUTPUT,
value_type, param_type,
val_len, 0,
value, 0, (void *)SQL_NTS);
break;
}
case SQL_C_SHORT:
case SQL_C_LONG:
{
SQLINTEGER value;
SQLINTEGER cb_val;
ODBC_DEBUG_PRINTF_1("value_type integer\n");
cb_val = 0;
value = (SQLINTEGER)
s48_extract_integer(S48_CAR(S48_VECTOR_REF(param_vals, i)));
retval = SQLBindParameter(sh, (SQLUSMALLINT) (i+1),
SQL_PARAM_OUTPUT,
value_type, param_type,
0, 0,
&value, 0, &cb_val);
break;
}
case SQL_C_BIT:
case SQL_C_STINYINT:
case SQL_C_UTINYINT:
{
SQLCHAR value;
SQLINTEGER cb_val;
cb_val = 0;
value = (SQLCHAR)
s48_extract_char(S48_CAR(S48_VECTOR_REF(param_vals, i)));
retval = SQLBindParameter(sh, (SQLUSMALLINT) (i+1),
SQL_PARAM_OUTPUT,
value_type, param_type,
0, 0,
&value, 0, &cb_val);
break;
}
case SQL_C_FLOAT:
{
SQLREAL value;
SQLINTEGER cb_val;
ODBC_DEBUG_PRINTF_1("value_type is float\n");
cb_val = 0;
value = (SQLREAL)
S48_UNSAFE_EXTRACT_DOUBLE(S48_CAR(S48_VECTOR_REF(param_vals, i)));
retval = SQLBindParameter(sh, (SQLUSMALLINT) (i+1),
SQL_PARAM_OUTPUT,
value_type, param_type,
0, 0,
&value, 0, &cb_val);
break;
}
case SQL_C_DOUBLE:
{
SQLDOUBLE value;
SQLINTEGER cb_val;
ODBC_DEBUG_PRINTF_1("value_type is double\n");
cb_val = 0;
value = (SQLDOUBLE)
S48_UNSAFE_EXTRACT_DOUBLE(S48_CAR(S48_VECTOR_REF(param_vals, i)));
retval = SQLBindParameter(sh, (SQLUSMALLINT) (i+1),
SQL_PARAM_OUTPUT,
value_type, param_type,
0, 0,
&value, 0, &cb_val);
break;
}
case SQL_C_TYPE_DATE:
{
SQL_DATE_STRUCT value;
SQLINTEGER cb_val;
ODBC_DEBUG_PRINTF_1("value_type is date\n");
cb_val = 0;
sql_date_record_to_struct(param_vals, &value);
retval = SQLBindParameter(sh, (SQLUSMALLINT) (i+1),
SQL_PARAM_OUTPUT,
value_type, param_type,
0, 0,
&value, 0, &cb_val);
break;
}
case SQL_C_TYPE_TIME:
{
SQL_TIME_STRUCT value;
SQLINTEGER cb_val;
ODBC_DEBUG_PRINTF_1("value_type is time\n");
cb_val = 0;
sql_time_record_to_struct(param_vals, &value);
retval = SQLBindParameter(sh, (SQLUSMALLINT) (i+1),
SQL_PARAM_OUTPUT,
value_type, param_type,
0, 0,
&value, 0, &cb_val);
break;
}
case SQL_C_TYPE_TIMESTAMP:
{
SQL_TIMESTAMP_STRUCT value;
SQLINTEGER cb_val;
ODBC_DEBUG_PRINTF_1("value_type is timestamp\n");
cb_val = 0;
sql_timestamp_record_to_struct(param_vals, &value);
retval = SQLBindParameter(sh, (SQLUSMALLINT) (i+1),
SQL_PARAM_OUTPUT,
value_type, param_type,
0, 0,
&value, 0, &cb_val);
break;
}
/* case SQL_C_NUMERIC: */
/* { */
/* SQL_NUMERIC_STRUCT value; */
/* SQLINTEGER cb_val; */
/* cb_val = 0; */
/* value.precision = (SQLCHAR) */
/* s48_extract_char(S48_RECORD_REF(S48_CAR(S48_VECTOR_REF(param_vals, i)), */
/* SR_SQL_NUMERIC_PRECISION)); */
/* value.scale = (SQLSCHAR) */
/* s48_extract_char(S48_RECORD_REF(S48_CAR(S48_VECTOR_REF(param_vals, i)), */
/* SR_SQL_NUMERIC_SCALE)); */
/* value.sign = (SQLCHAR) */
/* s48_extract_char(S48_RECORD_REF(S48_CAR(S48_VECTOR_REF(param_vals, i)), */
/* SR_SQL_NUMERIC_SIGN)); */
/* } */
default:
{
ODBC_RAISE_EXCEPTION("SQLBindParameter: unknown/unsupported value type");
break;
}
}
ODBC_DEBUG_PRINTF_1("All parameters bound\n");
/* check the return value of SQLBindParameter */
if ((retval != SQL_SUCCESS) || (retval != SQL_SUCCESS_WITH_INFO)) {
switch (retval)
{
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLBindParameter returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLBindParameter got invalid handle");
break;
}
}
}
} /* for */
ODBC_DEBUG_PRINTF_1("Executing statement\n");
/* execute statement */
retval = SQLExecute(sh);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLExcute returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLExcute got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLExcute returned unknown error code");
break;
}
}
}
s48_value odbc_sql_get_cursor_name(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLRETURN retval;
SQLCHAR *buffer = NULL;
SQLSMALLINT buffer_len, buffer_needed;
ODBC_DEBUG_PRINTF_1("odbc_sql_get_cursor_name\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
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:
{
s48_value res = s48_enter_string(buffer);
free(buffer);
return s48_enter_string(buffer);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetCursorName returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetCursorName got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetCursorName returned unknown error code");
break;
}
}
}
void odbc_sql_set_cursor_name(s48_value stmt_handle, s48_value cursorname)
{
SQLHSTMT sh;
SQLCHAR *cn;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_set_cursor_name\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
cn = (SQLCHAR *) s48_extract_string(cursorname);
retval = SQLSetCursorName(sh, cn, S48_STRING_LENGTH(cursorname));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLSetCursorName returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLSetCursorName got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLSetCursorName returned unknown error code");
break;
}
}
}
/*
*
* PART 6
*
* Submitting requests
*
*/
s48_value odbc_sql_execute(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_execute\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
retval = SQLExecute(sh);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLExecute returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLExecute got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLExecute returned unknown error code");
break;
}
}
}
s48_value odbc_sql_execute_direct(s48_value stmt_handle,
s48_value stmt)
{
SQLHSTMT sh;
SQLCHAR *query;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_execute_direct\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
query = (SQLCHAR *) s48_extract_string(stmt);
retval = SQLExecDirect(sh, query, S48_STRING_LENGTH(stmt));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
case SQL_NEED_DATA: case SQL_NO_DATA:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLExecDirect returned SQL_ERROR");
break;
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLExecDirect returned SQL_STILL_EXECUTING, not implemented yet");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLExecDirect got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLExecDirect returned unknown error code");
break;
}
}
}
/* Returns the text of an SQL statement as translated by the driver. */
s48_value odbc_sql_native_sql(s48_value conn_handle, s48_value stmt_txt)
{
SQLHDBC ch;
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_1("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);
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:
{
s48_value res = s48_enter_string(stmt_out);
free(stmt_out);
return res;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLNativeSql returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLNativeSql got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLNativeSql returned unknoen error code");
break;
}
}
}
/* Returns the description for a specific parameter in a statement */
s48_value odbc_sql_describe_param(s48_value stmt_handle, s48_value parameter_no)
{
SQLHSTMT sh;
SQLUSMALLINT pn;
SQLUINTEGER ps;
SQLSMALLINT dt, dd, n;
SQLRETURN retval;
s48_value result = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(result);
ODBC_DEBUG_PRINTF_1("odbc_sql_describe_param\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
pn = (SQLUSMALLINT) s48_extract_integer(parameter_no);
retval = SQLDescribeParam(sh, pn, &dt, &ps, &dd, &n);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
result = s48_make_record(odbc_parameter_record_type);
S48_RECORD_SET(result, SR_ODBC_PARAMETER_TYPE, s48_enter_integer(dt));
S48_RECORD_SET(result, SR_ODBC_PARAMETER_SIZE, s48_enter_integer(ps));
S48_RECORD_SET(result, SR_ODBC_PARAMETER_DIGITS, s48_enter_integer(dd));
S48_RECORD_SET(result, SR_ODBC_PARAMETER_NULLABLE, s48_enter_integer(n));
return result;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLDescribeParam returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLDescribeParam got invalid handle");
break;
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLDescribeParam returned SQL_STILL_EXECUTING. Not implemented");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLDescribeParam returned unknown error code");
break;
}
}
}
/* Returns the number of parameters in a statement */
s48_value odbc_sql_num_params(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLSMALLINT params;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_num_params\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
retval = SQLNumParams(sh, &params);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(params);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLNumParams returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLNumParams returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLNumParams got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLNumParams returned unknown error code");
break;
}
}
}
/*
*
* PART 7
*
* Retrieving results and information about results
*
*/
s48_value odbc_sql_row_count(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLRETURN retval;
SQLINTEGER rowcount;
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
ODBC_DEBUG_PRINTF_1("odbc_sql_row_count\n");
retval = SQLRowCount(sh, &rowcount);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(rowcount);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLRowCount returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLRowCount got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLRowCount returned unknown error code");
break;
}
}
}
s48_value odbc_sql_get_data(s48_value stmt_handle, s48_value column_number,
s48_value target_type, s48_value buffer_size)
{
SQLHSTMT sh;
SQLUSMALLINT cn, bl;
SQLSMALLINT tt;
SQLRETURN retval;
SQLINTEGER buffer_needed;
void *buffer = NULL;
s48_value result = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
cn = (SQLUSMALLINT) s48_extract_integer(column_number);
tt = (SQLSMALLINT) s48_extract_integer(target_type);
bl = (SQLUSMALLINT) s48_extract_integer(buffer_size);
ODBC_DEBUG_PRINTF_5("odbc_sql_get_data() sh:%x cn:%d tt:%d bl:%d\n", sh, cn, tt, bl);
odbc_sql_alloc((void **) &buffer, buffer_size, sizeof_sql_c_type_identifier(tt));
retval = SQLGetData(sh, cn, tt, buffer, buffer_size, &buffer_needed);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
S48_GC_PROTECT_1(result);
result = s48_cons(buffer_to_s48_value(buffer, tt),
s48_enter_integer(buffer_needed));
free(buffer);
S48_GC_UNPROTECT();
return result;
}
case SQL_NO_DATA:
ODBC_RAISE_EXCEPTION("SQLGetData returned SQL_NO_DATA");
case SQL_STILL_EXECUTING:
ODBC_RAISE_EXCEPTION("SQLGetData returned SQL_STILL_EXECUTING, not yet implemented");
case SQL_ERROR:
ODBC_RAISE_EXCEPTION("SQLGetData returned SQL_ERROR");
default:
ODBC_RAISE_EXCEPTION("SQLGetData returned unknown error code");
}
}
/* Positions a cursor within a fetched block of data and allows an application
to refresh data in the rowset or to update or delete data in the result
set */
s48_value odbc_sql_set_pos(s48_value stmt_handle, s48_value row_number,
s48_value operation, s48_value lock_type)
{
SQLHSTMT sh;
SQLUSMALLINT rn, op, lt;
SQLRETURN retval;
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
rn = (SQLUSMALLINT) s48_extract_integer(row_number);
op = (SQLUSMALLINT) s48_extract_integer(operation);
lt = (SQLUSMALLINT) s48_extract_integer(lock_type);
ODBC_DEBUG_PRINTF_5("odbc_sql_set_pos() sh:%x rn:%d op:%d lt:%d\n", sh, rn, op, lt);
retval = SQLSetPos(sh, rn, op, lt);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
case SQL_NEED_DATA:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLSetPos returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLSetPos returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLSetPos got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLSetPos returned unknown error code");
break;
}
}
}
/* Performs bulk insertions and bulk bookmark operations, including
update, delete, and fetch by bookmark. */
s48_value odbc_sql_bulk_operations(s48_value stmt_handle, s48_value operation)
{
SQLHSTMT sh;
SQLUSMALLINT op;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_bulk_operations\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
op = (SQLUSMALLINT) s48_extract_integer(operation);
retval = SQLBulkOperations(sh, op);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
case SQL_NEED_DATA:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLBulkOperations returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLBulkOperations returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLBulkOperations got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLBulkOperations returned unknown error code");
break;
}
}
}
/* Determines whether there are more result sets available and, if so,
initializes processing for the next result set */
s48_value odbc_sql_more_results(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_more_results\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
retval = SQLMoreResults(sh);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
case SQL_NO_DATA:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLMoreResults returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLMoreResults returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLMoreResults got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLMoreResults returned unknown error code");
break;
}
}
}
s48_value odbc_sql_fetch(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLRETURN retval;
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
ODBC_DEBUG_PRINTF_2("odbc_sql_fetch() %x\n", sh);
retval = SQLFetch(sh);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
case SQL_NO_DATA:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLFetch returned SQL_STILL_EXECUTING, not yet implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLFetch returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLFetch got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLFetch returned unknown error code");
break;
}
}
}
s48_value odbc_sql_num_result_cols(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLSMALLINT numcols;
SQLRETURN retval;
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
ODBC_DEBUG_PRINTF_1("odbc_sql_num_result_cols\n");
retval = SQLNumResultCols(sh, &numcols);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(numcols);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLNumResultCols returned SQL_STILL_EXECUTING, not yet implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLNumResultCols returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLNumResultCols got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLNumResultCols returned unknown error code");
break;
}
}
}
s48_value odbc_sql_describe_col(s48_value stmt_handle, s48_value column_number)
{
SQLHSTMT sh;
SQLSMALLINT cn;
SQLCHAR *buffer = NULL;
SQLSMALLINT buffer_len, buffer_needed, data_type, digits, nullable;
SQLUINTEGER col_size;
SQLRETURN retval;
s48_value col_rec = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(col_rec);
ODBC_DEBUG_PRINTF_1("odbc_sql_describe_col\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
cn = (SQLSMALLINT) s48_extract_integer(column_number);
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)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
col_rec = s48_make_record(odbc_column_record_type);
S48_RECORD_SET(col_rec, SR_ODBC_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,
s48_enter_integer(col_size));
S48_RECORD_SET(col_rec, SR_ODBC_COLUMN_DIGITS,
s48_enter_integer(digits));
S48_RECORD_SET(col_rec, SR_ODBC_COLUMN_NULLABLE,
s48_enter_integer(nullable));
S48_GC_UNPROTECT();
free(buffer);
return col_rec;
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLDescribeCol returned SQL_STILL_EXECUTING, not yet implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLDescribeCol returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLDescribeCol got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLDescribeCol returned unknown error code");
break;
}
}
}
/* Describes attributes of a column in the result set */
s48_value odbc_sql_col_attribute(s48_value stmt_handle, s48_value column_number,
s48_value field_id)
{
SQLHSTMT sh;
SQLUSMALLINT cn, fi;
SQLCHAR *buffer = NULL;
SQLSMALLINT buffer_len, buffer_needed;
SQLINTEGER intbuffer;
SQLRETURN retval;
s48_value res_string, res;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(res);
ODBC_DEBUG_PRINTF_1("odbc_sql_col_attribute\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
cn = (SQLUSMALLINT) s48_extract_integer(column_number);
fi = (SQLUSMALLINT) s48_extract_integer(field_id);
buffer_len = ODBC_RETVAL_BUFFER_INITIAL_SIZE;
for (;;)
{
odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR));
retval = SQLColAttribute(sh, cn, fi,
buffer, buffer_len, &buffer_needed,
&intbuffer);
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:
{
res = s48_cons(s48_enter_string(buffer), s48_enter_integer(intbuffer));
free(buffer);
S48_GC_UNPROTECT();
return res;
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLColAttribute returned SQL_STILL_EXECUTING. Not implemented yet.");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLColAttribute returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLColAttribute got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLColAttribute returned unknown error code");
break;
}
}
}
ColumnRecPtr bindcol_lookup_binding(SQLHSTMT stmt_handle, SQLUSMALLINT column_no)
{
StmtRecPtr stmt;
ColumnRecPtr col;
ODBC_DEBUG_PRINTF_3("bindcol_lookup_binding() %x %d\n", stmt_handle, column_no);
stmt = global_bindcol_list;
while (stmt != NULL)
{
if (stmt->stmt_handle == stmt_handle)
{
col = stmt->col_recs;
while ((col != NULL) && (col->col_no != column_no))
col = col->next;
return col;
}
col = col->next;
}
return NULL;
}
s48_value bindcol_lookup_binding_scheme(s48_value stmt_handle, s48_value column_no)
{
SQLHSTMT sh;
SQLUSMALLINT cn;
ColumnRecPtr col;
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
cn = (SQLUSMALLINT) s48_extract_integer(column_no);
ODBC_DEBUG_PRINTF_3("bindcol_lookup_binding_scheme() sh:%x cn:%d\n", sh, cn);
col = bindcol_lookup_binding(sh, cn);
if (col == NULL)
s48_call_scheme(S48_SHARED_BINDING_REF(signal_unbound_column), 2,
stmt_handle, column_no);
else
{
ODBC_DEBUG_PRINTF_2("bindcol_lookup_binding_scheme(): col_buf:%x\n", col->col_buffer);
return buffer_to_s48_value(col->col_buffer, col->target_type);
}
}
/* Semantics differs from original SQLBindCol(), due to the need of
bookkeeping a target buffer list in C. odbc_sql_bindcol() handles
column binding and rebinding, but not unbinding. To unbind a column
use bindcol_unbind_column() or bindcol_finalize_bindcols(). */
s48_value odbc_sql_bindcol(s48_value stmt_handle, s48_value column_no,
s48_value target_type, s48_value buffer_len)
{
SQLHSTMT sh;
SQLUSMALLINT cn;
SQLSMALLINT tt;
SQLLEN bl;
SQLRETURN retval;
ColumnRecPtr col = NULL;
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
cn = (SQLUSMALLINT) s48_extract_integer(column_no);
tt = (SQLSMALLINT) s48_extract_integer(target_type);
bl = (SQLLEN) s48_extract_integer(buffer_len);
ODBC_DEBUG_PRINTF_5("odbc_sql_bindcol() %x %d %d %d\n", sh, cn, tt, bl);
/* try to look up ColumRec */
col = bindcol_lookup_binding(sh, cn);
if (col == NULL)
{
/* There is no binding for this stmt-handle/column-no yet */
ODBC_DEBUG_PRINTF_1("odbc_sql_bindcol(): new binding\n");
col = (ColumnRec *) malloc(sizeof(ColumnRec));
if (col == NULL)
ODBC_RAISE_EXCEPTION("odbc_sql_bindcol(): Could not allocate buffer");
/* initialize it */
col->col_no = cn;
col->target_type = tt;
col->buffer_len = bl;
col->buffer_needed = 0;
col->next = NULL;
col->col_buffer = (void *) malloc(sizeof_sql_c_type_identifier(tt)*bl);
ODBC_DEBUG_PRINTF_3("odbc_sql_bindcol() malloc %x %d\n",
col->col_buffer, sizeof_sql_c_type_identifier(tt)*bl);
if (col->col_buffer == NULL)
ODBC_RAISE_EXCEPTION("odbc_sql_bindcol(): Could not allocate buffer");
/* store col in global_bindcol_list */
bindcol_bind_column(sh, cn, col);
}
else
{
/* user wishes to rebind column for whatever reason */
ODBC_DEBUG_PRINTF_1("odbc_sql_bindcol(): rebinding existing binding\n");
if (tt != col->target_type)
ODBC_RAISE_EXCEPTION("odbc_sql_bindcol(): While rebinding buffers: old/new target type do not match");
/* free the old buffer, allocate a new one */
free(col->col_buffer);
col->col_buffer = (void *) malloc(sizeof_sql_c_type_identifier(tt)*bl);
col->buffer_len = sizeof_sql_c_type_identifier(tt)*bl;
ODBC_DEBUG_PRINTF_3("odbc_sql_bindcol() reallocate %x %d\n", col->col_buffer,
sizeof_sql_c_type_identifier(tt)*bl);
if (col->col_buffer == NULL)
ODBC_RAISE_EXCEPTION("odbc_sql_bindcol(): Could not allocate buffer");
}
/* at this point ColumRecPtr col has been created or updated, call SQLBindCol() */
retval = SQLBindCol(sh, cn, tt, col->col_buffer, col->buffer_len, &col->buffer_needed);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return S48_UNSPECIFIC;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLBindCol returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLBindCol got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLBindCol returned unknown error code");
break;
}
}
}
void bindcol_bind_column(SQLHSTMT stmt_handle, SQLUSMALLINT column_no, ColumnRecPtr new_col)
{
StmtRecPtr stmt, prev_stmt, new_stmt;
ColumnRecPtr col, prev_col;
ODBC_DEBUG_PRINTF_4("bindcol_bind_column() %x %d %x\n", stmt_handle, column_no, new_col);
prev_stmt = stmt = global_bindcol_list;
while (stmt != NULL)
{
if (stmt->stmt_handle == stmt_handle)
{
prev_col = col = stmt->col_recs;
while ((col != NULL) && (col->col_no != column_no))
{
prev_col = col;
col = col->next;
}
if (col == NULL)
{
prev_col->next = new_col;
return;
}
}
prev_stmt = stmt;
stmt = stmt->next;
}
if (stmt == NULL)
{
ODBC_DEBUG_PRINTF_1("bindcol_bind_column() global_bindcol_list is empty\n");
new_stmt = (StmtRecPtr) malloc(sizeof(StmtRec));
if (new_stmt == NULL)
ODBC_RAISE_EXCEPTION("bindcol_bind_column(): Error allocating memory");
new_stmt->next = NULL;
new_stmt->stmt_handle = stmt_handle;
new_stmt->col_recs = new_col;
if (global_bindcol_list == NULL)
global_bindcol_list = new_stmt;
else
prev_stmt->next = new_stmt;
}
}
void bindcol_unbind_colum(SQLHSTMT stmt_handle, SQLUSMALLINT column_no)
{
StmtRecPtr stmt, prev_stmt;
ColumnRecPtr col, prev_col;
ODBC_DEBUG_PRINTF_3("bindcol_unbind_colum() %x %d\n", stmt_handle, column_no);
prev_stmt = stmt = global_bindcol_list;
while (stmt != NULL)
{
if (stmt->stmt_handle == stmt_handle)
{
prev_col = col = stmt->col_recs;
while ((col != NULL) && (col->col_no != column_no))
{
prev_col = col;
col = col->next;
}
if (col == NULL)
s48_call_scheme(S48_SHARED_BINDING_REF(signal_unbound_column), 2, stmt_handle, column_no);
ODBC_DEBUG_PRINTF_2("bindcol_unbind_colum() free %x\n", col->col_buffer);
free(col->col_buffer);
prev_col->next = col->next;
free(col);
if (stmt->col_recs == NULL)
{
prev_stmt->next = stmt->next;
free(stmt);
}
return;
}
prev_stmt = stmt;
stmt = stmt->next;
}
s48_call_scheme(S48_SHARED_BINDING_REF(signal_unbound_column), 2,
s48_enter_integer((SQLHSTMT) stmt_handle), s48_enter_integer(column_no));
}
s48_value bindcol_finalize_bindcols(s48_value stmt_handle)
{
SQLHSTMT sh;
StmtRecPtr stmt, prev_stmt;
ColumnRecPtr col, prev_col, first_col;
SQLRETURN retval;
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
ODBC_DEBUG_PRINTF_2("bindcol_finalize_bindcols() %x\n", sh);
prev_stmt = stmt = global_bindcol_list;
while (stmt != NULL)
{
if (stmt->stmt_handle == sh)
{
/* a rather dumb approach... */
first_col = stmt->col_recs;
while (first_col != NULL)
{
col = first_col;
while (col != NULL)
{
if (col->next == NULL)
{
/* this bindcol_rec is the last in chain */
SQLLEN dummy;
retval = SQLBindCol(sh, col->col_no, col->target_type,
NULL, 0, &dummy);
free(col->col_buffer);
free(col);
prev_col->next = NULL;
}
prev_col = col;
col = col->next;
}
}
}
stmt = stmt->next;
}
return S48_UNSPECIFIC;
}
/*
*
* PART 8
*
* Obtaining information about the data source's
* system tables (catalog functxbions)
*
*/
/* Returns a list of columns and associated privileges for one or more tables */
s48_value odbc_sql_column_privileges(s48_value stmt_handle, s48_value catalog_name,
s48_value schema_name, s48_value table_name,
s48_value column_name)
{
SQLHSTMT sh;
SQLCHAR *catalog, *schema, *table, *column;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_column_privileges\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
catalog = (SQLCHAR *) s48_extract_string(catalog_name);
schema = (SQLCHAR *) s48_extract_string(schema_name);
table = (SQLCHAR *) s48_extract_string(table_name);
column = (SQLCHAR *) s48_extract_string(column_name);
retval = SQLColumnPrivileges(sh,
catalog, S48_STRING_LENGTH(catalog_name),
schema, S48_STRING_LENGTH(schema_name),
table, S48_STRING_LENGTH(table_name),
column, S48_STRING_LENGTH(column_name));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLColumnPrivileges returned SQL_STILL_EXECUTING. Not implemented yet");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLColumnPrivileges returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLColumnPrivileges got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLColumnPrivileges returned unknown error code");
break;
}
}
}
/* Returns the list of column names in a specified table */
s48_value odbc_sql_columns(s48_value stmt_handle, s48_value catalog_name,
s48_value schema_name, s48_value table_name,
s48_value column_name)
{
SQLHSTMT sh;
SQLCHAR *catalog, *schema, *table, *column;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_columns\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
catalog = (SQLCHAR *) s48_extract_string(catalog_name);
schema = (SQLCHAR *) s48_extract_string(schema_name);
table = (SQLCHAR *) s48_extract_string(table_name);
column = (SQLCHAR *) s48_extract_string(column_name);
retval = SQLColumns(sh,
catalog, S48_STRING_LENGTH(catalog_name),
schema, S48_STRING_LENGTH(schema_name),
table, S48_STRING_LENGTH(table_name),
column, S48_STRING_LENGTH(column_name));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLColumns returned SQL_STILL_EXECUTING. Not implemented yet");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLColumns returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLColumns got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLColumns returned unknown error code");
break;
}
}
}
/* Returns a list of columns names that make up foreign keys,
if the exist for a specified table */
s48_value odbc_sql_foreign_keys(s48_value stmt_handle, s48_value pk_catalog_name,
s48_value pk_schema_name, s48_value pk_table_name,
s48_value fk_catalog_name, s48_value fk_schema_name,
s48_value fk_table_name)
{
SQLHSTMT sh;
SQLCHAR *pk_catalog, *pk_schema, *pk_table;
SQLCHAR *fk_catalog, *fk_schema, *fk_table;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_foreign_keys\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
pk_catalog = (SQLCHAR *) s48_extract_string(pk_catalog_name);
pk_schema = (SQLCHAR *) s48_extract_string(pk_schema_name);
pk_table = (SQLCHAR *) s48_extract_string(pk_table_name);
fk_catalog = (SQLCHAR *) s48_extract_string(fk_catalog_name);
fk_schema = (SQLCHAR *) s48_extract_string(fk_schema_name);
fk_table = (SQLCHAR *) s48_extract_string(fk_table_name);
retval = SQLForeignKeys(sh,
pk_catalog, S48_STRING_LENGTH(pk_catalog_name),
pk_schema, S48_STRING_LENGTH(pk_schema_name),
pk_table, S48_STRING_LENGTH(pk_table_name),
fk_catalog, S48_STRING_LENGTH(fk_catalog_name),
fk_schema, S48_STRING_LENGTH(fk_schema_name),
fk_table, S48_STRING_LENGTH(fk_table_name));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLForeignKeys returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLForeignKeys returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLForeignKeys got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLForeignKeys returned unknwon error code");
break;
}
}
}
/* Returns the list of column names that make up the primary key for a table */
s48_value odbc_sql_primary_keys(s48_value stmt_handle, s48_value catalog_name,
s48_value schema_name, s48_value table_name)
{
SQLHSTMT sh;
SQLCHAR *catalog, *schema, *table;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_primary_keys\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
catalog = (SQLCHAR *) s48_extract_string(catalog_name);
schema = (SQLCHAR *) s48_extract_string(schema_name);
table = (SQLCHAR *) s48_extract_string(table_name);
retval = SQLPrimaryKeys(sh,
catalog, S48_STRING_LENGTH(catalog_name),
schema, S48_STRING_LENGTH(schema_name),
table, S48_STRING_LENGTH(table_name));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLPrimaryKeys returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLPrimaryKeys returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLPrimaryKeys got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLPrimaryKeys returned unknown error code");
break;
}
}
}
/* Returns the list of input and output parameters, as well as the columns
that make up the result set for the specified procedures */
s48_value odbc_sql_procedure_columns(s48_value stmt_handle, s48_value catalog_name,
s48_value schema_name, s48_value proc_name,
s48_value column_name)
{
SQLHSTMT sh;
SQLCHAR *catalog, *schema, *proc, *column;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_procedure_columns\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
catalog = (SQLCHAR *) s48_extract_string(catalog_name);
schema = (SQLCHAR *) s48_extract_string(schema_name);
proc = (SQLCHAR *) s48_extract_string(proc_name);
column = (SQLCHAR *) s48_extract_string(column_name);
retval = SQLProcedureColumns(sh,
catalog, S48_STRING_LENGTH(catalog_name),
schema, S48_STRING_LENGTH(schema_name),
proc, S48_STRING_LENGTH(proc_name),
column, S48_STRING_LENGTH(column_name));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLProcedureColumns returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLProcedureColumns returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLProcedureColumns got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLProcedureColumns return unknown error code");
break;
}
}
}
/* Returns the list of procedure names stored in a specific data source. */
s48_value odbc_sql_procedures(s48_value stmt_handle, s48_value catalog_name,
s48_value schema_name, s48_value proc_name)
{
SQLHSTMT sh;
SQLCHAR *catalog, *schema, *proc;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_procedures\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
catalog = (SQLCHAR *) s48_extract_string(catalog_name);
schema = (SQLCHAR *) s48_extract_string(schema_name);
proc = (SQLCHAR *) s48_extract_string(proc_name);
retval = SQLProcedures(sh,
catalog, S48_STRING_LENGTH(catalog_name),
schema, S48_STRING_LENGTH(schema_name),
proc, S48_STRING_LENGTH(proc_name));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLProcedures returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLProcedures returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLProcedures got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLProcedures returned unknown error code");
break;
}
}
}
/* Returns information about the optimal set of columns that uniquely identifies
a row in a specified table, or the columns that are automatically updated
when any value in the row is updated by a transaction */
s48_value odbc_sql_special_columns(s48_value stmt_handle, s48_value identifier_type,
s48_value catalog_name, s48_value schema_name,
s48_value table_name, s48_value scope,
s48_value nullable)
{
SQLHSTMT sh;
SQLCHAR *catalog, *schema, *table;
SQLSMALLINT s, n, it;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_special_columns\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
it = (SQLSMALLINT) s48_extract_integer(identifier_type);
catalog = (SQLCHAR *) s48_extract_string(catalog_name);
schema = (SQLCHAR *) s48_extract_string(schema_name);
table = (SQLCHAR *) s48_extract_string(table_name);
s = (SQLSMALLINT) s48_extract_integer(scope);
n = (SQLSMALLINT) s48_extract_integer(nullable);
retval = SQLSpecialColumns(sh, it,
catalog, S48_STRING_LENGTH(catalog_name),
schema, S48_STRING_LENGTH(schema_name),
table, S48_STRING_LENGTH(table_name),
s, n);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLSpecialColumns returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLSpecialColumns returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLSpecialColumns got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLSpecialColumns returned unknown error code");
break;
}
}
}
/* Returns statistics about a single table and the list of indexes associated
with the table */
s48_value odbc_sql_statistics(s48_value stmt_handle, s48_value catalog_name,
s48_value schema_name, s48_value table_name,
s48_value unique, s48_value reserved)
{
SQLHSTMT sh;
SQLCHAR *catalog, *schema, *table;
SQLSMALLINT u, r;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_statistics\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
catalog = (SQLCHAR *) s48_extract_string(catalog_name);
schema = (SQLCHAR *) s48_extract_string(schema_name);
table = (SQLCHAR *) s48_extract_string(table_name);
u = (SQLSMALLINT) s48_extract_integer(unique);
r = (SQLSMALLINT) s48_extract_integer(reserved);
retval = SQLStatistics(sh,
catalog, S48_STRING_LENGTH(catalog_name),
schema, S48_STRING_LENGTH(schema_name),
table, S48_STRING_LENGTH(table_name),
u, r);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLStatistics returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLStatistics returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLStatistics got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLStatistics returned unknown error code");
break;
}
}
}
/* Returns a list of tables and the privileges associated with each table */
s48_value odbc_sql_table_privileges(s48_value stmt_handle, s48_value catalog_name,
s48_value schema_name, s48_value table_name)
{
SQLHSTMT sh;
SQLCHAR *catalog, *schema, *table;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_table_privileges\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
catalog = (SQLCHAR *) s48_extract_string(catalog_name);
schema = (SQLCHAR *) s48_extract_string(schema_name);
table = (SQLCHAR *) s48_extract_string(table_name);
retval = SQLTablePrivileges(sh,
catalog, S48_STRING_LENGTH(catalog_name),
schema, S48_STRING_LENGTH(schema_name),
table, S48_STRING_LENGTH(table_name));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLTablePrivileges returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLTablePrivileges returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLTablePrivileges got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLTablePrivileges returned unknown error code");
break;
}
}
}
/* Returns the list of table names stored in a specific data source */
s48_value odbc_sql_tables(s48_value stmt_handle, s48_value catalog_name,
s48_value schema_name, s48_value table_name,
s48_value table_type)
{
SQLHSTMT sh;
SQLCHAR *catalog, *schema, *tablen, *tablet;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_tables\n");
retval = SQLTables(sh,
catalog, S48_STRING_LENGTH(catalog_name),
schema, S48_STRING_LENGTH(schema_name),
tablen, S48_STRING_LENGTH(table_name),
tablet, S48_STRING_LENGTH(table_type));
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_STILL_EXECUTING:
{
ODBC_RAISE_EXCEPTION("SQLTables returned SQL_STILL_EXECUTING. Not implemented");
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLTables returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLTables got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLTables returned unknown error code");
break;
}
}
}
/*
*
* PART 9
*
* Terminating a statement
*
*/
/* Ends statement processing, discards pending resilt, and,
* optionally, frees all resources associated with the
* statement handle */
s48_value odbc_sql_free_statement(s48_value stmt_handle, s48_value option)
{
SQLHSTMT sh;
SQLUSMALLINT opt;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_free_statement\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
opt = (SQLUSMALLINT) s48_extract_integer(option);
retval = SQLFreeStmt(sh, opt);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLFreeStmt returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLFreeStmt got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLFreeStmt returned unknown error");
break;
}
}
}
/* Closes a cursor that has been opened on a statement handle */
s48_value odbc_sql_close_cursor(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_close_cursor\n");
sh = (SQLHSTMT) s48_extract_integer(stmt_handle);
retval = SQLCloseCursor(sh);
switch (retval) {
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLCloseCursor returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLCloseCursor got an invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLCloseCursor returned an unknown error code");
break;
}
}
}
/* Cancels an SQL statement */
s48_value odbc_sql_cancel(s48_value stmt_handle)
{
SQLHSTMT sh;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_cancel\n");
retval = SQLCancel(sh);
switch (retval) {
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLCancel returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLCancel got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLCancel returned unknown error code");
break;
}
}
}
/* Commits or rolls back a transaction */
s48_value odbc_sql_endtran(s48_value handle_type, s48_value handle,
s48_value completion_type)
{
SQLSMALLINT ht, ct;
SQLHANDLE h;
SQLRETURN retval;
ODBC_DEBUG_PRINTF_1("odbc_sql_endtran\n");
ht = (SQLSMALLINT) s48_extract_integer(handle_type);
h = (SQLHANDLE) s48_extract_integer(handle);
ct = (SQLSMALLINT) s48_extract_integer(completion_type);
retval = SQLEndTran(ht, h, ct);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLEndTran returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLEndTran got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLEndTran returned unknown error code");
break;
}
}
}
/*
*
* PART 10
*
* Terminating a connection
*
*/
/* Closes the connection */
s48_value odbc_sql_disconnect(s48_value conn_handle)
{
SQLHDBC ch;
SQLRETURN retval;
ch = (SQLHDBC) s48_extract_integer(conn_handle);
ODBC_DEBUG_PRINTF_2("odbc_sql_disconnect() %x\n", ch);
retval = SQLDisconnect(ch);
switch (retval)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLDisconnect returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLDisconnect got invalid hande");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLDisconnect returned unknown error code");
break;
}
}
}
/* Free a handle */
s48_value odbc_sql_free_handle(s48_value handle_type, s48_value handle)
{
SQLSMALLINT ht;
SQLHANDLE h;
SQLRETURN retval;
ht = (SQLSMALLINT) s48_extract_integer(handle_type);
h = (SQLHANDLE) s48_extract_integer(handle);
ODBC_DEBUG_PRINTF_3("odbc_sql_free_handle() %x %d\n", h, ht);
retval = SQLFreeHandle(ht, h);
switch (retval)
{
case SQL_SUCCESS:
{
return s48_enter_integer(retval);
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLFreeHandle returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLFreeHandle got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLFreeHandle returned unknown error code");
break;
}
}
}
/*
*
* PART 11
*
* misc. functions
*
*/
s48_value odbc_sql_get_diag_recs(s48_value handle_type, s48_value handle)
{
SQLSMALLINT ht;
SQLHANDLE h;
SQLCHAR sql_state[6];
SQLINTEGER native_error;
SQLCHAR *buffer = NULL;
SQLSMALLINT i, more_recs, buffer_len, buffer_needed;
SQLRETURN retval;
s48_value res = S48_UNSPECIFIC;
s48_value diag_rec = S48_UNSPECIFIC;
S48_DECLARE_GC_PROTECT(2);
S48_GC_PROTECT_2(res, diag_rec);
ht = (SQLSMALLINT) s48_extract_integer(handle_type);
h = (SQLHANDLE) s48_extract_integer(handle);
res = S48_NULL;
ODBC_DEBUG_PRINTF_1("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);
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)
{
case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO:
{
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(buffer));
res = s48_cons(diag_rec, res);
break;
}
case SQL_NO_DATA:
{
more_recs = 0;
break;
}
case SQL_ERROR:
{
ODBC_RAISE_EXCEPTION("SQLGetDiagRec returned SQL_ERROR");
break;
}
case SQL_INVALID_HANDLE:
{
ODBC_RAISE_EXCEPTION("SQLGetDiagRec got invalid handle");
break;
}
default:
{
ODBC_RAISE_EXCEPTION("SQLGetDiagRec returned unknown error code");
break;
}
}
i++;
}
S48_GC_UNPROTECT(); /* res */
free(buffer);
return res;
}
#ifdef ODBC_DEBUG_MSGS
/* print detailed debug information */
void odbc_debug_msgs(SQLSMALLINT handle_type, SQLHANDLE handle)
{
SQLCHAR sql_state[5];
SQLINTEGER native_error;
SQLCHAR message[ERROR_MSG_BUFFER_LEN];
SQLSMALLINT i, message_len;
SQLRETURN retval;
printf("fetching diag_rec from odbc driver.\n");
i = 1;
while (1) {
retval = SQLGetDiagRec(handle_type, handle,
i, sql_state,
&native_error,
message, ERROR_MSG_BUFFER_LEN-1,
&message_len);
if (retval == SQL_NO_DATA)
break;
if (retval == SQL_INVALID_HANDLE) {
printf("ODBC: Could not get debug information: invalid handle provided\n");
break;
}
if (retval == SQL_ERROR) {
printf("ODBC: SQLGetDiagRec returned SQL_ERROR\n");
break;
}
if (retval == SQL_SUCCESS_WITH_INFO)
printf("ODBC warning: error message buffer too small.\n");
if (retval == SQL_SUCCESS) {
printf("\nODBC status record %d:\n", i);
printf("SQL state: %s\n", (char *)sql_state);
/* TODO:
* Need to find out how to printf the
* native_error here
*/
printf("error msg: %s\n", message);
}
i++;
}
}
#endif
/* convert Scheme sql-date record to SQL_DATE_STRUCT */
void sql_date_record_to_struct(s48_value sql_date, SQL_DATE_STRUCT *ds)
{
ds->year = (SQLSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_date, SR_SQL_DATE_YEAR));
ds->month = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_date, SR_SQL_DATE_MONTH));
ds->day = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_date, SR_SQL_DATE_DAY));
}
/* convert SQL_DATE_STRUCT to Scheme sql-date record */
s48_value struct_to_sql_date_record(SQL_DATE_STRUCT *ds)
{
s48_value sql_date;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(sql_date);
sql_date = s48_make_record(sql_date_record_type);
S48_RECORD_SET(sql_date, SR_SQL_DATE_YEAR,
s48_enter_integer(ds->year));
S48_RECORD_SET(sql_date, SR_SQL_DATE_MONTH,
s48_enter_integer(ds->month));
S48_RECORD_SET(sql_date, SR_SQL_DATE_DAY,
s48_enter_integer(ds->day));
S48_GC_UNPROTECT();
return sql_date;
}
/* convert Scheme sql-time record to SQL_TIME_STRUCT */
void sql_time_record_to_struct(s48_value sql_time, SQL_TIME_STRUCT *ts)
{
ts->hour = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_time, SR_SQL_TIME_HOUR));
ts->minute = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_time, SR_SQL_TIME_MINUTE));
ts->second = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_time, SR_SQL_TIME_SECOND));
}
/* convert SQL_TIME_STRUCT to Scheme sql-time record */
s48_value struct_to_sql_time_record(SQL_TIME_STRUCT *ts)
{
s48_value sql_time;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(sql_time);
sql_time = s48_make_record(sql_time_record_type);
S48_RECORD_SET(sql_time, SR_SQL_TIME_HOUR,
s48_extract_integer(ts->hour));
S48_RECORD_SET(sql_time, SR_SQL_TIME_MINUTE,
s48_extract_integer(ts->minute));
S48_RECORD_SET(sql_time, SR_SQL_TIME_SECOND,
s48_extract_integer(ts->second));
S48_GC_UNPROTECT();
return sql_time;
}
/* convert Scheme sql-timestamp record to SQL_TIMESTAMP_STRUCT */
void sql_timestamp_record_to_struct(s48_value sql_timestamp,
SQL_TIMESTAMP_STRUCT *ts)
{
ts->year = (SQLSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_timestamp, SR_SQL_TIMESTAMP_YEAR));
ts->month = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_timestamp, SR_SQL_TIMESTAMP_MONTH));
ts->day = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_timestamp, SR_SQL_TIMESTAMP_DAY));
ts->hour = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_timestamp, SR_SQL_TIMESTAMP_HOUR));
ts->minute = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_timestamp, SR_SQL_TIMESTAMP_MINUTE));
ts->second = (SQLUSMALLINT)
s48_extract_integer(S48_RECORD_REF(sql_timestamp, SR_SQL_TIMESTAMP_SECOND));
ts->fraction = (SQLUINTEGER)
s48_extract_integer(S48_RECORD_REF(sql_timestamp, SR_SQL_TIMESTAMP_FRACTION));
}
/* convert SQL_TIMESTAMP_STRUCT to Scheme sql-timestamp record */
s48_value struct_to_sql_timestamp_record(SQL_TIMESTAMP_STRUCT *ts)
{
s48_value sql_timestamp;
S48_DECLARE_GC_PROTECT(1);
S48_GC_PROTECT_1(sql_timestamp);
sql_timestamp = s48_make_record(sql_timestamp_record_type);
S48_RECORD_SET(sql_timestamp, SR_SQL_TIMESTAMP_YEAR,
s48_extract_integer(ts->year));
S48_RECORD_SET(sql_timestamp, SR_SQL_TIMESTAMP_MONTH,
s48_extract_integer(ts->month));
S48_RECORD_SET(sql_timestamp, SR_SQL_TIMESTAMP_DAY,
s48_extract_integer(ts->day));
S48_RECORD_SET(sql_timestamp, SR_SQL_TIMESTAMP_HOUR,
s48_extract_integer(ts->hour));
S48_RECORD_SET(sql_timestamp, SR_SQL_TIMESTAMP_MINUTE,
s48_extract_integer(ts->minute));
S48_RECORD_SET(sql_timestamp, SR_SQL_TIMESTAMP_SECOND,
s48_extract_integer(ts->second));
S48_RECORD_SET(sql_timestamp, SR_SQL_TIMESTAMP_FRACTION,
s48_extract_integer(ts->fraction));
S48_GC_UNPROTECT();
return sql_timestamp;
}
/* gets a C type identifier and returns the size of this type,
according to Appendix D of ODBC Programmer's reference */
size_t sizeof_sql_c_type_identifier(SQLSMALLINT ctypeid)
{
switch (ctypeid)
{
case SQL_C_CHAR: return sizeof(SQLCHAR);
case SQL_C_SSHORT: case SQL_C_SHORT: return sizeof(SQLSMALLINT);
case SQL_C_USHORT: return sizeof(SQLUSMALLINT);
case SQL_C_SLONG: case SQL_C_LONG: return sizeof(SQLINTEGER);
case SQL_C_ULONG: return sizeof(SQLUINTEGER);
case SQL_C_FLOAT: return sizeof(SQLREAL);
case SQL_C_DOUBLE: return sizeof(SQLDOUBLE);
case SQL_C_BIT: return sizeof(SQLCHAR);
case SQL_C_STINYINT: return sizeof(SQLSCHAR);
case SQL_C_UTINYINT: return sizeof(SQLCHAR);
/* case SQL_SBIGINT: return sizeof(SQLBIGINT); */
/* case SQL_UBIGINT: return sizeof(SQLUBIGINT); */
case SQL_C_BINARY: return sizeof(SQLCHAR);
/* I don't know what to do with these types... */
/* case SQL_C_BOOKMARK: return sizeof(BOOKMARK); */
/* case SQL_C_VARBOOKMARK: return sizeof(SQLCHAR); */
case SQL_C_TYPE_DATE: return sizeof(SQL_DATE_STRUCT);
case SQL_C_TYPE_TIME: return sizeof(SQL_TIME_STRUCT);
case SQL_C_TYPE_TIMESTAMP: return sizeof(SQL_TIMESTAMP_STRUCT);
case SQL_C_NUMERIC: return sizeof(SQL_NUMERIC_STRUCT);
/* case SQL_C_GUID: return sizeof(SQLGUID); */
default:
ODBC_RAISE_EXCEPTION("Unknown c data type identifier");
break;
}
}
void odbc_sql_alloc(void **buffer, size_t buffer_len, size_t type_len)
{
ODBC_DEBUG_PRINTF_4("odbc_sql_alloc(): bf:%x bl:%d tl: %d\n", buffer, buffer_len, type_len);
if (*buffer == NULL)
{
ODBC_DEBUG_PRINTF_3("calloc bl:%d tl:%d\n", buffer_len+1, type_len);
*buffer = (void *) calloc(buffer_len+1, type_len);
}
else
{
ODBC_DEBUG_PRINTF_2("realloc bl:%d\n", buffer_len*type_len);
*buffer = (void *) realloc(*buffer, buffer_len*type_len);
}
if (*buffer == NULL)
{
ODBC_RAISE_EXCEPTION("Could not allocate return value buffer");
return;
}
}
s48_value buffer_to_s48_value(void *buffer, SQLSMALLINT ctypeid)
{
ODBC_DEBUG_PRINTF_3("buffer_to_s48_value(): %x %d\n", buffer, ctypeid);
switch (ctypeid)
{
case SQL_C_CHAR:
return s48_enter_string((SQLCHAR *) buffer);
case SQL_C_SSHORT: case SQL_C_SHORT:
return s48_enter_integer(*((SQLSMALLINT*) buffer));
case SQL_C_USHORT:
return s48_enter_integer(*((SQLUSMALLINT*) buffer));
case SQL_C_SLONG: case SQL_C_LONG:
return s48_enter_integer(*((SQLINTEGER*) buffer));
case SQL_C_ULONG:
return s48_enter_integer(*((SQLUINTEGER*) buffer));
/* case SQL_C_FLOAT: */
/* case SQL_C_DOUBLE: */
/* case SQL_C_BIT: */
case SQL_C_STINYINT:
return s48_enter_integer(*((SQLSCHAR *) buffer));
case SQL_C_UTINYINT:
return s48_enter_integer(*((SQLCHAR *) buffer));
case SQL_C_BINARY:
return s48_enter_string((SQLCHAR *) buffer);
case SQL_C_TYPE_DATE:
return struct_to_sql_date_record((SQL_DATE_STRUCT *) buffer);
case SQL_C_TYPE_TIME:
return struct_to_sql_time_record((SQL_TIME_STRUCT *) buffer);
case SQL_C_TYPE_TIMESTAMP:
return struct_to_sql_timestamp_record((SQL_TIMESTAMP_STRUCT *) buffer);
/* case SQL_C_NUMERIC: */
default:
ODBC_RAISE_EXCEPTION("Unknown c data type identifier");
break;
}
}
void s48_init_odbc(void)
{
/* bindings for record types */
S48_GC_PROTECT_GLOBAL(odbc_diag_record_type);
odbc_diag_record_type = s48_get_imported_binding("odbc-diag");
S48_GC_PROTECT_GLOBAL(odbc_column_record_type);
odbc_column_record_type = s48_get_imported_binding("odbc-column");
S48_GC_PROTECT_GLOBAL(odbc_parameter_record_type);
odbc_column_record_type = s48_get_imported_binding("odbc-parameter");
S48_GC_PROTECT_GLOBAL(signal_unbound_column);
signal_unbound_column = s48_get_imported_binding("signal-unbound-column");
S48_GC_PROTECT_GLOBAL(signal_buffer_exceeded);
signal_buffer_exceeded = s48_get_imported_binding("signal-buffer-exceeded");
S48_GC_PROTECT_GLOBAL(bindcol_buffer_record_type);
bindcol_buffer_record_type = s48_get_imported_binding("bindcol-buffer");
/* init global variables */
global_bindcol_list = NULL;
/* functions for SQLBindCol() */
S48_EXPORT_FUNCTION(bindcol_lookup_binding_scheme);
S48_EXPORT_FUNCTION(odbc_sql_bindcol);
/* PART 1 */
S48_EXPORT_FUNCTION(odbc_alloc_environment_handle);
S48_EXPORT_FUNCTION(odbc_alloc_connection_handle);
S48_EXPORT_FUNCTION(odbc_alloc_statement_handle);
S48_EXPORT_FUNCTION(odbc_sql_connect);
S48_EXPORT_FUNCTION(odbc_sql_browse_connect);
/* PART 2 */
S48_EXPORT_FUNCTION(odbc_sql_data_sources);
S48_EXPORT_FUNCTION(odbc_sql_drivers);
S48_EXPORT_FUNCTION(odbc_sql_get_info_int);
S48_EXPORT_FUNCTION(odbc_sql_get_info_string);
S48_EXPORT_FUNCTION(odbc_sql_get_func_exists);
S48_EXPORT_FUNCTION(odbc_sql_get_type_info);
/* PART 3 */
S48_EXPORT_FUNCTION(odbc_sql_set_connect_attr_int);
S48_EXPORT_FUNCTION(odbc_sql_set_connect_attr_string);
S48_EXPORT_FUNCTION(odbc_sql_get_connect_attr_string);
S48_EXPORT_FUNCTION(odbc_sql_get_connect_attr_int);
S48_EXPORT_FUNCTION(odbc_sql_set_env_attr_int);
S48_EXPORT_FUNCTION(odbc_sql_get_env_attr_int);
S48_EXPORT_FUNCTION(odbc_sql_set_stmt_attr_int);
S48_EXPORT_FUNCTION(odbc_sql_set_stmt_attr_string);
S48_EXPORT_FUNCTION(odbc_sql_get_stmt_attr_int);
S48_EXPORT_FUNCTION(odbc_sql_get_stmt_attr_string);
/* PART 4 */
S48_EXPORT_FUNCTION(odbc_sql_get_desc_field_int);
S48_EXPORT_FUNCTION(odbc_sql_get_desc_field_string);
/* PART 5 */
S48_EXPORT_FUNCTION(odbc_sql_prepare);
S48_EXPORT_FUNCTION(odbc_sql_bind_parameter_exec_out);
S48_EXPORT_FUNCTION(odbc_sql_get_cursor_name);
S48_EXPORT_FUNCTION(odbc_sql_set_cursor_name);
/* PART 6 */
S48_EXPORT_FUNCTION(odbc_sql_execute);
S48_EXPORT_FUNCTION(odbc_sql_execute_direct);
S48_EXPORT_FUNCTION(odbc_sql_native_sql);
S48_EXPORT_FUNCTION(odbc_sql_describe_param);
S48_EXPORT_FUNCTION(odbc_sql_num_params);
/* PART 7 */
S48_EXPORT_FUNCTION(odbc_sql_row_count);
S48_EXPORT_FUNCTION(odbc_sql_get_data);
S48_EXPORT_FUNCTION(odbc_sql_set_pos);
S48_EXPORT_FUNCTION(odbc_sql_bulk_operations);
S48_EXPORT_FUNCTION(odbc_sql_more_results);
S48_EXPORT_FUNCTION(odbc_sql_fetch);
S48_EXPORT_FUNCTION(odbc_sql_num_result_cols);
S48_EXPORT_FUNCTION(odbc_sql_describe_col);
S48_EXPORT_FUNCTION(odbc_sql_col_attribute);
/* PART 8 */
S48_EXPORT_FUNCTION(odbc_sql_column_privileges);
S48_EXPORT_FUNCTION(odbc_sql_columns);
S48_EXPORT_FUNCTION(odbc_sql_foreign_keys);
S48_EXPORT_FUNCTION(odbc_sql_primary_keys);
S48_EXPORT_FUNCTION(odbc_sql_procedure_columns);
S48_EXPORT_FUNCTION(odbc_sql_procedures);
S48_EXPORT_FUNCTION(odbc_sql_special_columns);
S48_EXPORT_FUNCTION(odbc_sql_statistics);
S48_EXPORT_FUNCTION(odbc_sql_table_privileges);
S48_EXPORT_FUNCTION(odbc_sql_tables);
/* PART 9 */
S48_EXPORT_FUNCTION(odbc_sql_free_statement);
S48_EXPORT_FUNCTION(odbc_sql_close_cursor);
S48_EXPORT_FUNCTION(odbc_sql_cancel);
S48_EXPORT_FUNCTION(odbc_sql_endtran);
/* PART 10 */
S48_EXPORT_FUNCTION(odbc_sql_disconnect);
S48_EXPORT_FUNCTION(odbc_sql_free_handle);
/* PART 11 */
S48_EXPORT_FUNCTION(odbc_sql_get_diag_recs);
/* misc functions */
S48_EXPORT_FUNCTION(bindcol_finalize_bindcols);
}