#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; ODBC_DEBUG_PRINTF_1("odbc_alloc_environment\n"); retval = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); switch (retval) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: { odbc_sql_set_env_attr(henv); return s48_enter_integer((long)henv); } case SQL_ERROR: { ODBC_RAISE_EXCEPTION("SQLAllocHandle returned SQL_ERROR"); break; } default: { ODBC_RAISE_EXCEPTION("SQLAllocHandle unknown return value"); break; } } } /* 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; ODBC_DEBUG_PRINTF_1("odbc_set_environment\n"); retval = SQLSetEnvAttr(env_handle, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0); 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; ODBC_DEBUG_PRINTF_1("odbc_alloc_connection_handle\n"); envh = (SQLHENV) s48_extract_integer(env_handle); retval = SQLAllocHandle(SQL_HANDLE_DBC, 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; ODBC_DEBUG_PRINTF_1("odbc_alloc_statement_handle\n"); ch = (SQLHANDLE) s48_extract_integer(conn_handle); retval = SQLAllocHandle(SQL_HANDLE_STMT, 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; } } } /* 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; ODBC_DEBUG_PRINTF_1("odbc_sql_connect\n"); 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); retval = SQLConnect(ch, dsn, SQL_NTS, user, SQL_NTS, auth, SQL_NTS); switch (retval) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: { return S48_TRUE; } 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; } } /* * * 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) { 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, 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_1("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_1("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; switch (retval) { 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); 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)); 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: { 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_TRUE; } 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_TRUE; } 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_TRUE; } 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_TRUE; } 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_extract_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_TRUE; } 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_TRUE; } 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_TRUE; } 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_TRUE; } 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_TRUE; } 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: { return S48_TRUE; } case SQL_ERROR: { ODBC_RAISE_EXCEPTION("SQLExecDirect returned SQL_ERROR"); break; } case SQL_NEED_DATA: { return SQL_NEED_DATA; } case SQL_STILL_EXECUTING: { ODBC_RAISE_EXCEPTION("SQLExecDirect returned SQL_STILL_EXECUTING, not implemented yet"); break; } case SQL_NO_DATA: { return SQL_NO_DATA; } 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, ¶ms); 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) { SQLHSTMT sh; SQLUSMALLINT cn; SQLSMALLINT tt; SQLRETURN retval; ODBC_DEBUG_PRINTF_1("odbc_sql_get_data\n"); sh = (SQLHSTMT) s48_extract_integer(stmt_handle); cn = (SQLUSMALLINT) s48_extract_integer(column_number); tt = (SQLSMALLINT) s48_extract_integer(target_type); switch (tt) { case SQL_C_CHAR: case SQL_C_BINARY: { 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); res = s48_enter_string(buffer); free(buffer); return res; } case SQL_C_SSHORT: case SQL_C_USHORT: case SQL_C_SLONG: case SQL_C_ULONG: { long int i; SQLINTEGER rest; retval = SQLGetData(sh, cn, tt, &i, sizeof(long int), &rest); check_sql_get_data_result(retval, sh); return s48_enter_integer(i); } } } void check_sql_get_data_result(SQLRETURN retval, SQLHSTMT stmt_handle) { switch (retval) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: { return; } case SQL_NO_DATA: { ODBC_RAISE_EXCEPTION("SQLGetData returned SQL_NO_DATA"); break; } case SQL_STILL_EXECUTING: { ODBC_RAISE_EXCEPTION("SQLGetData returned SQL_STILL_EXECUTING, not yet implemented"); break; } case SQL_ERROR: { ODBC_RAISE_EXCEPTION("SQLGetData returned SQL_ERROR"); break; } case SQL_INVALID_HANDLE: { ODBC_RAISE_EXCEPTION("SQLGetData got invalid handle"); break; } } } /* 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; ODBC_DEBUG_PRINTF_1("odbc_sql_set_pos\n"); 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); retval = SQLSetPos(sh, rn, op, lt); switch (retval) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: { return S48_TRUE; } case SQL_NEED_DATA: { return s48_enter_integer(SQL_NEED_DATA); } 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: { return S48_TRUE; } case SQL_NEED_DATA: { return s48_enter_integer(SQL_NEED_DATA); } 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: { return S48_TRUE; } case SQL_NO_DATA: { return SQL_NO_DATA; } 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; ODBC_DEBUG_PRINTF_1("odbc_sql_fetch\n"); sh = (SQLHSTMT) s48_extract_integer(stmt_handle); retval = SQLFetch(sh); switch (retval) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: { return S48_TRUE; } case SQL_NO_DATA: { return SQL_NO_DATA; } 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_int(s48_value stmt_handle, s48_value column_no) { SQLHSTMT sh; SQLSMALLINT cn; ColumnRecPtr col; sh = (SQLHSTMT) s48_extract_integer(stmt_handle); cn = (SQLSMALLINT) s48_extract_integer(column_no); ODBC_DEBUG_PRINTF_3("bindcol_lookup_binding_int() %x %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_3("bindcol_lookup_binding_int(): %x %d\n", col->col_buffer, *((SQLINTEGER *) col->col_buffer)); return s48_enter_integer(*((SQLINTEGER *) col->col_buffer)); } } s48_value bindcol_lookup_binding_char(s48_value stmt_handle, s48_value column_no) { ColumnRecPtr col; ODBC_DEBUG_PRINTF_3("bindcol_lookup_binding_char(): %x %d\n", stmt_handle, column_no); col = bindcol_lookup_binding((SQLHSTMT) s48_extract_integer(stmt_handle), (SQLUSMALLINT) s48_extract_integer(column_no)); if (col == NULL) s48_call_scheme(S48_SHARED_BINDING_REF(signal_unbound_column), 2, stmt_handle, column_no); else { ODBC_DEBUG_PRINTF_3("bindcol_lookup_binding_char(): %x %d\n", col->col_buffer, (SQLCHAR *) col->col_buffer); if (col->buffer_needed > col->buffer_len) s48_call_scheme(S48_SHARED_BINDING_REF(signal_buffer_exceeded), 2, s48_enter_integer(col->buffer_needed), s48_enter_string((SQLCHAR *) col->col_buffer)); else return s48_enter_string((SQLCHAR *) col->col_buffer); } } /* 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; 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); 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, stmt_handle, column_no); } void bindcol_finalize_bindcols(SQLHSTMT stmt_handle) { StmtRecPtr stmt, prev_stmt; ColumnRecPtr col, prev_col, first_col; SQLRETURN retval; ODBC_DEBUG_PRINTF_2("bindcol_finalize_bindcols() %x\n", stmt_handle); prev_stmt = stmt = global_bindcol_list; while (stmt != NULL) { if (stmt->stmt_handle == stmt_handle) { /* 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(stmt_handle, 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; } } /* * * 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 */ void 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; } 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 */ void 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; } 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 */ void 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; } 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 */ void 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; } 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 */ void 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; } 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. */ void 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; } 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 */ void 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; } 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 */ void 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; } 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 */ void 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; } 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 */ void 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; } 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_TRUE; } 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_TRUE; } 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_TRUE; } 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_TRUE; } 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; ODBC_DEBUG_PRINTF_1("odbc_sql_disconnect\n"); ch = (SQLHDBC) s48_extract_integer(conn_handle); retval = SQLDisconnect(ch); switch (retval) { case SQL_SUCCESS: case SQL_SUCCESS_WITH_INFO: { return S48_TRUE; } 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; ODBC_DEBUG_PRINTF_1("odbc_free_handle\n"); ht = (SQLSMALLINT) s48_extract_integer(handle_type); h = (SQLHANDLE) s48_extract_integer(handle); retval = SQLFreeHandle(ht, h); switch (retval) { case SQL_SUCCESS: { return S48_TRUE; } 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; 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)); 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; 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)); 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; 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)); 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: 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) { 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 */ 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_int); S48_EXPORT_FUNCTION(bindcol_lookup_binding_char); 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); /* 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); }