#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; #if (ODBCVER >= 0x300) retval = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv); ODBC_DEBUG_PRINTF_2("SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, ...): %x\n", henv); #else retval = SQLAllocEnv(&henv); ODBC_DEBUG_PRINTF_2("SQLAllocEnv(...): %x\n", henv); #endif /* (ODBCVER >= 0x300) */ return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer((long)henv) : S48_UNSPECIFIC); } /* 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); #if (ODBCVER >= 0x300) retval = SQLAllocHandle(SQL_HANDLE_DBC, envh, &hdbc); ODBC_DEBUG_PRINTF_3("SQLAllocHandle(SQL_HANDLE_DBC, %x, ...): %x\n", envh, hdbc); #else retval = SQLAllocConnect(envh, &hdbc); ODBC_DEBUG_PRINTF_3("SQLAllocConnect(%x, ...): %x\n", envh, hdbc); #endif /* ODBCVER >= 0x300 */ return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer((long)hdbc) : S48_UNSPECIFIC); } /* 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); #if (ODBCVER >= 0x300) retval = SQLAllocHandle(SQL_HANDLE_STMT, ch, &hstmt); ODBC_DEBUG_PRINTF_3("SQLAllocHandle() %x %x\n", ch, hstmt); #else retval = SQLAllocStmt(ch, &hstmt); ODBC_DEBUG_PRINTF_3("SQLAllocStmt() %x %x\n", ch, hstmt); #endif /* ODBCVER >= 0x300 */ return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer((long)hstmt) : S48_UNSPECIFIC); } /* 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, S48_STRING_LENGTH(ds_name), user, S48_STRING_LENGTH(user_name), auth, S48_STRING_LENGTH(authentication)); return s48_enter_integer(retval); } 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; s48_value res = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(1); S48_GC_PROTECT_1(res); 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_initial_retval_buffer_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 (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) buffer_len = buffer_needed+1; else break; } res = s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_string(buffer) : S48_UNSPECIFIC); free(buffer); S48_GC_UNPROTECT(); return res; } /* * * 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; int first; SQLSMALLINT server_name_len, driver_descr_len; SQLSMALLINT server_name_needed, driver_descr_needed; SQLCHAR *server_name = NULL; SQLCHAR *driver_descr = NULL; s48_value res_list = S48_NULL; s48_value res = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(res_list, res); eh = (SQLHENV) s48_extract_integer(env_handle); ODBC_DEBUG_PRINTF_1("odbc_sql_data_sources\n"); server_name_len = driver_descr_len = odbc_initial_retval_buffer_size; first = 1; for (;;) { for (;;) { odbc_sql_alloc((void **) &server_name, server_name_len, sizeof(SQLCHAR)); odbc_sql_alloc((void **) &driver_descr, driver_descr_len, sizeof(SQLCHAR)); 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 (SQL_SUCCEEDED(retval) && ((server_name_needed > server_name_len) || (driver_descr_needed > driver_descr_len))) { if (server_name_needed > server_name_len) server_name_len = server_name_needed + 1; if (driver_descr_needed > driver_descr_len) driver_descr_len = driver_descr_needed + 1; } else break; } if (SQL_SUCCEEDED(retval)) res_list = s48_cons(s48_cons(s48_enter_string(server_name), s48_enter_string(driver_descr)), res_list); else res_list = S48_UNSPECIFIC; if (retval == SQL_NO_DATA) { res = s48_list_2(s48_enter_integer(retval), res_list); free(server_name); free(driver_descr); S48_GC_UNPROTECT(); return res; } first = 0; } /* never reached */ S48_GC_UNPROTECT(); return s48_list_2(s48_enter_integer(retval), S48_UNSPECIFIC); } /* Returns the list of installed drivers and their attributes. */ s48_value odbc_sql_drivers(s48_value env_handle) { #if (ODBCVER >= 0x0200) SQLHENV eh; SQLRETURN retval; int first; SQLSMALLINT driver_descr_len, driver_attr_len; SQLSMALLINT driver_descr_needed, driver_attr_needed; SQLCHAR *driver_attr = NULL; SQLCHAR *driver_descr = NULL; s48_value res_list = S48_NULL; s48_value res = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(res, res_list); eh = (SQLHENV) s48_extract_integer(env_handle); ODBC_DEBUG_PRINTF_1("odbc_sql_drivers\n"); driver_descr_len = driver_attr_len = odbc_initial_retval_buffer_size; first = 0; for (;;) { for (;;) { odbc_sql_alloc((void **) &driver_descr, driver_descr_len, sizeof(SQLCHAR)); odbc_sql_alloc((void **) &driver_attr, driver_attr_len, sizeof(SQLCHAR)); retval = SQLDrivers(eh, (SQLUSMALLINT) (first ? SQL_FETCH_FIRST : SQL_FETCH_NEXT), driver_descr, driver_descr_len, &driver_descr_needed, driver_attr, driver_attr_len, &driver_attr_needed); if (SQL_SUCCEEDED(retval) && ((driver_descr_needed > driver_descr_len) || (driver_attr_needed > driver_attr_len))) { if (driver_descr_needed > driver_descr_len) driver_descr_len = driver_descr_needed + 1; if (driver_attr_needed > driver_attr_len) driver_attr_len = driver_attr_needed + 1; } else break; } if (SQL_SUCCEEDED(retval)) res_list = s48_cons(s48_cons(s48_enter_string(driver_descr), s48_enter_string(driver_attr)), res_list); if (retval == SQL_NO_DATA) { res = s48_list_2(s48_enter_integer(retval), res_list); free(driver_descr); free(driver_attr); S48_GC_UNPROTECT(); return res; } first = 1; } /* not reached */ S48_GC_UNPROTECT(); return res; #else RAISE_API_VERSION_MISMATCH("SQLDrivers", ODBCVER, 0x200); #endif /* ODBCVER >= 0x200 */ } /* 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); return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer(info) : S48_UNSPECIFIC); } /* 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; s48_value res = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(1); S48_GC_PROTECT_1(res); 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_initial_retval_buffer_size; for (;;) { odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR)); retval = SQLGetInfo(ch, ik, buffer, buffer_len, &buffer_needed); if (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) buffer_len = buffer_needed+1; else break; } res = s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_string(buffer) : S48_UNSPECIFIC); free(buffer); S48_GC_UNPROTECT(); return res; } /* 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; 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); if (SQL_SUCCEEDED(retval)) return s48_list_2(s48_enter_integer(retval), SQL_FUNC_EXISTS(supported, fi) == SQL_TRUE ? S48_TRUE : S48_FALSE); else return s48_list_2(s48_enter_integer(retval), S48_UNSPECIFIC); } /* 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); return s48_enter_integer(retval); } /* * * 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) { #if (ODBCVER >= 0x300) 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, (SQLPOINTER) &val, 0); return s48_enter_integer(retval); #else RAISE_API_VERSION_MISMATCH("SQLSetConnectAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } s48_value odbc_sql_set_connect_attr_string(s48_value conn_handle, s48_value attribute, s48_value value) { #if (ODBCVER >= 0x300) 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)); return s48_enter_integer(retval); #else RAISE_API_VERSION_MISMATCH("SQLSetConnectAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } s48_value odbc_sql_get_connect_attr_string(s48_value conn_handle, s48_value attribute) { #if (ODBCVER >= 0x300) SQLHDBC ch; SQLINTEGER attr; SQLCHAR *buffer = NULL; SQLINTEGER buffer_needed, buffer_len; SQLRETURN retval; s48_value res = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(1); S48_GC_PROTECT_1(res); ODBC_DEBUG_PRINTF_1("odbc_sql_get_connect_attr_string\n"); buffer_len = odbc_initial_retval_buffer_size; for (;;) { odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR)); retval = SQLGetConnectAttr(ch, attr, buffer, buffer_len, &buffer_needed); if (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) buffer_needed = buffer_len; else break; } res = s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_string(buffer) : S48_UNSPECIFIC); free(buffer); S48_GC_UNPROTECT(); return res; #else RAISE_API_VERSION_MISMATCH("SQLGetConnectAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } s48_value odbc_sql_get_connect_attr_int(s48_value conn_handle, s48_value attribute) { #if (ODBCVER >= 0x300) 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); return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer(buffer) : S48_UNSPECIFIC); #else RAISE_API_VERSION_MISMATCH("SQLGetConnectAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } s48_value odbc_sql_set_env_attr_int(s48_value env_handle, s48_value attribute, s48_value value) { #if (ODBCVER >= 0x300) SQLHENV eh; SQLINTEGER attr; SQLUINTEGER val; SQLRETURN retval; eh = (SQLHENV) s48_extract_integer(env_handle); attr = (SQLINTEGER) s48_extract_integer(attribute); val = (SQLUINTEGER) s48_extract_integer(value); ODBC_DEBUG_PRINTF_4("odbc_sql_set_env_attr_int eh %x attr %d value %d\n", eh, attr, val); retval = SQLSetEnvAttr(eh, attr, (SQLPOINTER) val, sizeof(SQLUINTEGER)); return s48_enter_integer(retval); #else RAISE_API_VERSION_MISMATCH("SQLSetConnectAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } s48_value odbc_sql_get_env_attr_int(s48_value env_handle, s48_value attribute, s48_value value) { #if (ODBCVER >= 0x300) SQLHENV eh; SQLINTEGER attr; SQLUINTEGER val, str_len; SQLRETURN retval; eh = (SQLHENV) s48_extract_integer(env_handle); attr = (SQLINTEGER) s48_extract_integer(attribute); val = (SQLUINTEGER) s48_extract_integer(value); ODBC_DEBUG_PRINTF_4("odbc_sql_get_env_attr_int eh %x attr %d value %d\n", eh, attr, val); retval = SQLGetEnvAttr(eh, attr, &val, sizeof(SQLUINTEGER), &str_len); return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer(val) : S48_UNSPECIFIC); #else RAISE_API_VERSION_MISMATCH("SQLGetEnvAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } /* Sets a statement attribute */ s48_value odbc_sql_set_stmt_attr_int(s48_value stmt_handle, s48_value attribute, s48_value value) { #if (ODBCVER >= 0x300) 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); return s48_enter_integer(retval); #else RAISE_API_VERSION_MISMATCH("SQLSetStmtAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } s48_value odbc_sql_set_stmt_attr_string(s48_value stmt_handle, s48_value attribute, s48_value value) { #if (ODBCVER >= 0x300) 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)); return s48_enter_integer(retval); #else RAISE_API_VERSION_MISMATCH("SQLSetStmtAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } s48_value odbc_sql_get_stmt_attr_int(s48_value stmt_handle, s48_value attribute) { #if (ODBCVER >= 0x300) 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); return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer(val) : S48_UNSPECIFIC); #else RAISE_API_VERSION_MISMATCH("SQLGetStmtAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } s48_value odbc_sql_get_stmt_attr_string(s48_value stmt_handle, s48_value attribute) { #if (ODBCVER >= 0x300) SQLHSTMT sh; SQLINTEGER attr, buffer_len, buffer_needed; SQLCHAR *buffer = NULL; SQLRETURN retval; s48_value res = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(1); S48_GC_PROTECT_1(res); ODBC_DEBUG_PRINTF_1("odbc_sql_get_stmt_attr_string\n"); buffer_len = odbc_initial_retval_buffer_size; for (;;) { odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR)); retval = SQLGetStmtAttr(sh, attr, &buffer, buffer_len, &buffer_needed); if (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) buffer_len = buffer_needed+1; else break; } res = s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_string(buffer) : S48_UNSPECIFIC); free(buffer); S48_GC_UNPROTECT(); return res; #else RAISE_API_VERSION_MISMATCH("SQLGetStmtAttr", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } /* * * 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) { #if (ODBCVER >= 0x300) SQLHDESC dh; SQLSMALLINT rn, fi; SQLINTEGER value, buffer_len; SQLRETURN retval; s48_value res = S48_UNSPECIFIC; s48_value scheme_int = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(res, scheme_int); 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); if (SQL_SUCCEEDED(retval)) switch (buffer_len) { case SQL_IS_INTEGER: scheme_int = s48_enter_integer((SQLINTEGER) value); break; case SQL_IS_UINTEGER: scheme_int = s48_enter_integer((SQLUINTEGER) value); break; case SQL_IS_SMALLINT: scheme_int = s48_enter_integer((SQLSMALLINT) value); break; case SQL_IS_USMALLINT: scheme_int = s48_enter_integer((SQLUSMALLINT) value); break; default: RAISE_UNKNOWN_INTEGER_TYPE_ERROR("SQLGetDescField", buffer_len); } res = s48_list_2(s48_enter_integer(retval), scheme_int); S48_GC_UNPROTECT(); return res; #else RAISE_API_VERSION_MISMATCH("SQLGetDescField", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } /* 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) { #if (ODBCVER >= 0x300) SQLHDESC dh; SQLSMALLINT rn, fi; SQLCHAR *buffer = NULL; SQLINTEGER buffer_len, buffer_needed; SQLRETURN retval; s48_value res = S48_UNSPECIFIC; s48_value scheme_str = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(res, scheme_str); 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_initial_retval_buffer_size; for (;;) { odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR)); retval = SQLGetDescField(dh, rn, fi, (SQLPOINTER) buffer, buffer_len, &buffer_needed); if (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) buffer_len = buffer_needed+1; else break; } if (SQL_SUCCEEDED(retval)) scheme_str = s48_enter_string(buffer); free(buffer); res = s48_list_2(s48_enter_integer(retval), scheme_str); S48_GC_UNPROTECT(); return res; #else RAISE_API_VERSION_MISMATCH("SQLGetDescField", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } /* * * 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)); return s48_enter_integer(retval); } s48_value odbc_sql_bind_parameter(s48_value bind_parameter_rec) { SQLHSTMT sh; SQLUSMALLINT param_no; SQLSMALLINT in_out_type, value_type, param_type, decimal_digits; SQLUINTEGER column_size; SQLPOINTER parameter_value_input_ptr, parameter_value_output_ptr; SQLINTEGER buffer_length; SQLRETURN retval; S48_DECLARE_GC_PROTECT(1); S48_GC_PROTECT_1(bind_parameter_rec); sh = (SQLHSTMT) s48_extract_integer(S48_RECORD_REF(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_STATEMENT_HANDLE)); param_no = (SQLUSMALLINT) s48_extract_integer(S48_RECORD_REF(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_PARAM_NO)); in_out_type = (SQLSMALLINT) s48_extract_integer(S48_RECORD_REF(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_INPUT_OUTPUT_TYPE)); value_type = (SQLSMALLINT) s48_extract_integer(S48_RECORD_REF(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_VALUE_TYPE)); param_type = (SQLSMALLINT) s48_extract_integer(S48_RECORD_REF(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_PARAMETER_TYPE)); column_size = (SQLUINTEGER) s48_extract_integer(S48_RECORD_REF(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_COLUMN_SIZE)); decimal_digits = (SQLSMALLINT) s48_extract_integer(S48_RECORD_REF(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_DECIMAL_DIGITS)); buffer_length = (SQLINTEGER) s48_extract_integer(S48_RECORD_REF(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_BUFFER_LENGTH)); parameter_value_input_ptr = (SQLPOINTER) s48_extract_integer(S48_RECORD_REF(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_PARAMETER_VALUE_INPUT_PTR)); if ((in_out_type == SQL_PARAM_INPUT_OUTPUT) || (in_out_type == SQL_PARAM_OUTPUT)) parameter_value_output_ptr = (SQLPOINTER) malloc(buffer_length); else parameter_value_output_ptr = NULL; S48_RECORD_SET(bind_parameter_rec, SR_ODBC_BIND_PARAMETER_PARAMETER_VALUE_OUTPUT_PTR, s48_enter_integer((long) parameter_value_output_ptr)); /* retval = SQLBindParameter(sh, param_no, in_out_type, value_type, */ /* param_type, column_size, decimal_digits, */ /* param_type); */ S48_GC_UNPROTECT(); } s48_value bind_parameter_set_buffer(s48_value bind_parameter_rec, s48_value value) { return S48_UNSPECIFIC; } s48_value bind_parameter_get_buffer(s48_value bind_parameter_rec) { return S48_UNSPECIFIC; } s48_value odbc_sql_get_cursor_name(s48_value stmt_handle) { SQLHSTMT sh; SQLRETURN retval; SQLCHAR *buffer = NULL; SQLSMALLINT buffer_len, buffer_needed; s48_value res = S48_UNSPECIFIC; s48_value scheme_str = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(res, scheme_str); ODBC_DEBUG_PRINTF_1("odbc_sql_get_cursor_name\n"); sh = (SQLHSTMT) s48_extract_integer(stmt_handle); buffer_len = odbc_initial_retval_buffer_size; for (;;) { odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR)); retval = SQLGetCursorName(sh, buffer, buffer_len, &buffer_needed); if (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) buffer_len = buffer_needed+1; else break; } if (SQL_SUCCEEDED(retval)) scheme_str = s48_enter_string(buffer); free(buffer); res = s48_list_2(s48_enter_integer(retval), scheme_str); S48_GC_UNPROTECT(); return res; } s48_value 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)); return s48_enter_integer(retval); } /* * * 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); return s48_enter_integer(retval); } 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)); return s48_enter_integer(retval); } /* 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; s48_value res = S48_UNSPECIFIC; s48_value scheme_str = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(res, scheme_str); 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_initial_retval_buffer_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 (SQL_SUCCEEDED(retval) && buffer_needed > buffer_len) buffer_len = buffer_needed+1; else break; } if (SQL_SUCCEEDED(retval)) scheme_str = s48_enter_string(stmt_out); free(stmt_out); res = s48_list_2(s48_enter_integer(retval), scheme_str); S48_GC_UNPROTECT(); return res; } /* 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 res = S48_UNSPECIFIC; s48_value scheme_rec = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(res, scheme_rec); 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); if (SQL_SUCCEEDED(retval)) { scheme_rec = s48_make_record(odbc_parameter_record_type); S48_RECORD_SET(scheme_rec, SR_ODBC_PARAMETER_TYPE, s48_enter_integer(dt)); S48_RECORD_SET(scheme_rec, SR_ODBC_PARAMETER_SIZE, s48_enter_integer(ps)); S48_RECORD_SET(scheme_rec, SR_ODBC_PARAMETER_DIGITS, s48_enter_integer(dd)); S48_RECORD_SET(scheme_rec, SR_ODBC_PARAMETER_NULLABLE, s48_enter_integer(n)); } res = s48_list_2(s48_enter_integer(retval), scheme_rec); S48_GC_UNPROTECT(); return res; } /* 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); return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer(params) : S48_UNSPECIFIC); } /* * * 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); return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer(rowcount) : S48_UNSPECIFIC); } s48_value odbc_sql_get_data(s48_value stmt_handle, s48_value column_number, s48_value target_type) { SQLHSTMT sh; SQLUSMALLINT cn; SQLSMALLINT tt, buffer_len; SQLINTEGER buffer_needed; SQLRETURN retval; void *buffer = NULL; s48_value result = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(1); S48_GC_PROTECT_1(result); sh = (SQLHSTMT) s48_extract_integer(stmt_handle); cn = (SQLUSMALLINT) s48_extract_integer(column_number); tt = (SQLSMALLINT) s48_extract_integer(target_type); ODBC_DEBUG_PRINTF_4("odbc_sql_get_data() sh:%x cn:%d tt:%d\n", sh, cn, tt); buffer_len = odbc_initial_retval_buffer_size; for (;;) { odbc_sql_alloc((void **) &buffer, buffer_len, sizeof_sql_c_type_identifier(tt)); retval = SQLGetData(sh, cn, tt, buffer, buffer_len, &buffer_needed); if (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) buffer_len = buffer_needed+1; else break; } if (SQL_SUCCEEDED(retval)) { result = s48_list_2(s48_enter_integer(retval), buffer_to_s48_value(buffer, tt)); free(buffer); } else result = s48_list_2(s48_enter_integer(retval), S48_UNSPECIFIC); S48_GC_UNPROTECT(); return result; } /* 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); return s48_enter_integer(retval); } /* 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) { #if (ODBCVER >= 0x300) 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); return s48_enter_integer(retval); #else RAISE_API_VERSION_MISMATCH("SQLBulkOperations", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } /* 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); return s48_enter_integer(retval); } 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); return s48_enter_integer(retval); } 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); return s48_list_2(s48_enter_integer(retval), SQL_SUCCEEDED(retval) ? s48_enter_integer(numcols) : S48_UNSPECIFIC); } 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 res = S48_UNSPECIFIC; s48_value col_rec = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(2); S48_GC_PROTECT_2(res, 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_initial_retval_buffer_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 (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) buffer_len = buffer_needed+1; else break; } if (SQL_SUCCEEDED(retval)) { 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)); } res = s48_list_2(s48_enter_integer(retval), col_rec); free(buffer); S48_GC_UNPROTECT(); return res; } /* 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) { #if (ODBCVER >= 0x300) SQLHSTMT sh; SQLUSMALLINT cn, fi; SQLCHAR *buffer = NULL; SQLSMALLINT buffer_len, buffer_needed; SQLINTEGER intbuffer; SQLRETURN retval; s48_value res_string = S48_UNSPECIFIC; s48_value res_pair = S48_UNSPECIFIC; s48_value res = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(3); S48_GC_PROTECT_3(res, res_pair, res_string); 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_initial_retval_buffer_size; for (;;) { odbc_sql_alloc((void **) &buffer, buffer_len, sizeof(SQLCHAR)); retval = SQLColAttribute(sh, cn, fi, buffer, buffer_len, &buffer_needed, &intbuffer); if (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) buffer_len = buffer_needed+1; else break; } if (SQL_SUCCEEDED(retval)) { res_string = s48_enter_string(buffer); res_pair = s48_cons(res_string, s48_enter_integer(intbuffer)); } free(buffer); res = s48_list_2(s48_enter_integer(retval), res_pair); S48_GC_UNPROTECT(); return res; #else RAISE_API_VERSION_MISMATCH("SQLColAttribute", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } 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) RAISE_ODBC_BINDCOL_UNBOUND_COLUMN_ERROR((long)sh, cn) 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) RAISE_ODBC_BUFFER_ALLOC_ERROR(sizeof(ColumnRec)); /* 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) RAISE_ODBC_BUFFER_ALLOC_ERROR(sizeof_sql_c_type_identifier(tt)*bl); /* 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) RAISE_ODBC_BINDCOL_REBINDING_ERROR("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) RAISE_ODBC_BUFFER_ALLOC_ERROR(sizeof_sql_c_type_identifier(tt)*bl); } /* 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); return s48_enter_integer(retval); } 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) RAISE_ODBC_BUFFER_ALLOC_ERROR(sizeof(StmtRec)); 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) RAISE_ODBC_BINDCOL_UNBOUND_COLUMN_ERROR((long)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; } RAISE_ODBC_BINDCOL_UNBOUND_COLUMN_ERROR((long)stmt_handle, 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)); return s48_enter_integer(retval); } /* 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)); return s48_enter_integer(retval); } /* 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)); return s48_enter_integer(retval); } /* 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)); return s48_enter_integer(retval); } /* 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)); return s48_enter_integer(retval); } /* 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)); return s48_enter_integer(retval); } /* 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); return s48_enter_integer(retval); } /* 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); return s48_enter_integer(retval); } /* 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)); return s48_enter_integer(retval); } /* 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)); return s48_enter_integer(retval); } /* * * 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); return s48_enter_integer(retval); } /* Closes a cursor that has been opened on a statement handle */ s48_value odbc_sql_close_cursor(s48_value stmt_handle) { #if (ODBCVER >= 0x300) SQLHSTMT sh; SQLRETURN retval; ODBC_DEBUG_PRINTF_1("odbc_sql_close_cursor\n"); sh = (SQLHSTMT) s48_extract_integer(stmt_handle); retval = SQLCloseCursor(sh); return s48_enter_integer(retval); #else RAISE_API_VERSION_MISMATCH("SQLCloseCursor", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } /* 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); return s48_enter_integer(retval); } /* Commits or rolls back a transaction */ s48_value odbc_sql_endtran(s48_value handle_type, s48_value handle, s48_value completion_type) { #if (ODBCVER >= 0x300) 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); return s48_enter_integer(retval); #else RAISE_API_VERSION_MISMATCH("SQLEndTran", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } /* * * 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); return s48_enter_integer(retval); } /* Free a handle */ s48_value odbc_sql_free_handle(s48_value handle_type, s48_value handle) { #if (ODBCVER >= 0x300) 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); return s48_enter_integer(retval); #else RAISE_API_VERSION_MISMATCH("SQLFreeHandle", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } /* * * PART 11 * * misc. functions * */ s48_value odbc_sql_get_diag_recs(s48_value handle_type, s48_value handle) { #if (ODBCVER >= 0x300) 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 rec_list = S48_NULL; s48_value diag_rec = S48_UNSPECIFIC; S48_DECLARE_GC_PROTECT(3); S48_GC_PROTECT_3(res, rec_list, diag_rec); ht = (SQLSMALLINT) s48_extract_integer(handle_type); h = (SQLHANDLE) s48_extract_integer(handle); ODBC_DEBUG_PRINTF_4("SQLGetDiagRec(%d, %x, %i)\n", ht, h, i); i = more_recs = 1; buffer_len = odbc_initial_retval_buffer_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 (SQL_SUCCEEDED(retval) && (buffer_needed > buffer_len)) { ODBC_DEBUG_PRINTF_3("buffer_needed %d buffer_len %d\n", 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)); rec_list = s48_cons(diag_rec, rec_list); free(buffer); buffer = NULL; break; } case SQL_NO_DATA: { more_recs = 0; break; } default: { free(buffer); res = s48_list_2(s48_enter_integer(retval), S48_UNSPECIFIC); S48_GC_UNPROTECT(); return res; } } i++; } res = s48_list_2(s48_enter_integer(retval), rec_list); free(buffer); S48_GC_UNPROTECT(); return res; #else RAISE_API_VERSION_MISMATCH("SQLGetDiagRec", ODBCVER, 0x300); #endif /* ODBCVER >= 0x300 */ } #if 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: RAISE_ODBC_UNKNOWN_C_TYPE_IDENTIFIER_ERROR(0, ctypeid); 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+1)*type_len); } if (*buffer == NULL) RAISE_ODBC_BUFFER_ALLOC_ERROR((buffer_len+1)*type_len); } void copy_scheme_value_to_buffer(s48_value schemeval, void **buffer, SQLSMALLINT ctypeid) { ODBC_DEBUG_PRINTF_3("s48_value_to_buffer(): ctypeid %d buffer %x\n", ctypeid, buffer); switch (ctypeid) { case SQL_C_CHAR: *buffer = (void *)calloc(S48_STRING_LENGTH(schemeval)+1, sizeof(SQLCHAR)); if (*buffer == NULL) RAISE_ODBC_BUFFER_ALLOC_ERROR((S48_STRING_LENGTH(schemeval)+1)*sizeof(SQLCHAR)); strcpy(*buffer, s48_extract_string(schemeval)); break; case SQL_C_SSHORT: case SQL_C_SHORT: case SQL_C_USHORT: /* SQL_C_SHORT has no default conversion, treat it like SQL_C_SHORT */ *buffer = (void *)malloc(sizeof(SQLSMALLINT)); if (*buffer == NULL) RAISE_ODBC_BUFFER_ALLOC_ERROR(sizeof(SQLSMALLINT)); if (ctypeid == SQL_C_USHORT) *((SQLSMALLINT *) *buffer) = (SQLUSMALLINT) s48_extract_unsigned_integer(schemeval); else *((SQLSMALLINT *) *buffer) = (SQLSMALLINT) s48_extract_integer(schemeval); break; case SQL_C_SLONG: case SQL_C_LONG: case SQL_C_ULONG: /* SQL_C_LONG has no default conversion, treat it like SQL_C_LONG */ *buffer = (void *)malloc(sizeof(SQLINTEGER)); if (*buffer == NULL) RAISE_ODBC_BUFFER_ALLOC_ERROR(sizeof(SQLINTEGER)); if (ctypeid == SQL_C_ULONG) *((SQLUINTEGER *) *buffer) = (SQLUINTEGER) s48_extract_unsigned_integer(schemeval); else *((SQLINTEGER *) *buffer) = (SQLINTEGER) s48_extract_integer(schemeval); break; case SQL_C_FLOAT: *buffer = (void *)malloc(sizeof(SQLREAL)); if (*buffer == NULL) RAISE_ODBC_BUFFER_ALLOC_ERROR(sizeof(SQLREAL)); *((SQLREAL *) *buffer) = (SQLREAL) s48_extract_double(schemeval); break; case SQL_C_DOUBLE: *buffer = (void *)malloc(sizeof(SQLDOUBLE)); if (*buffer == NULL) RAISE_ODBC_BUFFER_ALLOC_ERROR(sizeof(SQLDOUBLE)); *((SQLDOUBLE *) *buffer) = (SQLDOUBLE) s48_extract_double(schemeval); break; /* case SQL_C_TINYINT: case SQL_C_STINYINT: case SQL_C_UTINYINT: */ /* SQL_C_TINYINT has no default conversion, treat it like SQL_C_STINYINT */ /* *buffer = (void *)malloc(sizeof(SQLTINYINT)); */ /* if (*buffer == NULL) */ /* RAISE_ODBC_BUFFER_ALLOC_ERROR(sizeof(SQLTINYINT)); */ /* if (ctypeid == SQL_C_UTINYINT) */ /* *((SQLUTINYINT *) *buffer) = (SQLUTINYINT) s48_extract_unsigned_integer(schemeval); */ /* else */ /* *((SQLSTINYINT *) *buffer) = (SQLSTINYINT) s48_extract_integer(schemeval); */ /* break; */ default: RAISE_ODBC_UNKNOWN_C_TYPE_IDENTIFIER_ERROR(NULL, ctypeid); } } 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: RAISE_ODBC_UNKNOWN_C_TYPE_IDENTIFIER_ERROR((long)buffer, ctypeid); break; } } /* set initial return value buffer size */ s48_value odbc_set_initial_retval_buffer_size(s48_value nobytes) { odbc_initial_retval_buffer_size = (SQLUSMALLINT) s48_extract_integer(nobytes); } /* get initial return value buffer size */ s48_value odbc_get_intial_retval_buffer_size() { return s48_enter_integer((int) odbc_initial_retval_buffer_size); } 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_parameter_record_type = s48_get_imported_binding("odbc-parameter"); S48_GC_PROTECT_GLOBAL(odbc_bind_parameter_record_type); odbc_bind_parameter_record_type = s48_get_imported_binding("odbc-bind-parameter"); S48_GC_PROTECT_GLOBAL(bindcol_buffer_record_type); bindcol_buffer_record_type = s48_get_imported_binding("bindcol-buffer"); /* import conditions */ S48_GC_PROTECT_GLOBAL(raise_odbc_api_version_mismatch_error); raise_odbc_api_version_mismatch_error = s48_get_imported_binding("raise-odbc-api-version-mismatch-error"); S48_GC_PROTECT_GLOBAL(raise_odbc_unknown_integer_type_error); raise_odbc_unknown_integer_type_error = s48_get_imported_binding("raise-odbc-unknown-integer-type-error"); S48_GC_PROTECT_GLOBAL(raise_odbc_buffer_alloc_error); raise_odbc_buffer_alloc_error = s48_get_imported_binding("raise-odbc-buffer-alloc-error"); S48_GC_PROTECT_GLOBAL(raise_odbc_unknown_c_type_identifier_error); raise_odbc_unknown_c_type_identifier_error = s48_get_imported_binding("raise-odbc-unknown-c-type-identifier-error"); S48_GC_PROTECT_GLOBAL(raise_odbc_bindcol_unbound_column_error); raise_odbc_bindcol_unbound_column_error = s48_get_imported_binding("raise-odbc-bindcol-unbound-column-error"); S48_GC_PROTECT_GLOBAL(raise_odbc_bindcol_rebinding_error); raise_odbc_bindcol_rebinding_error = s48_get_imported_binding("raise-odbc-bindcol-rebinding-error"); /* 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); S48_EXPORT_FUNCTION(bind_parameter_set_buffer); S48_EXPORT_FUNCTION(bind_parameter_get_buffer); 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); S48_EXPORT_FUNCTION(odbc_set_initial_retval_buffer_size); S48_EXPORT_FUNCTION(odbc_get_intial_retval_buffer_size); }