#include "scheme48.h" #include /* ODBC header files */ #include #include #include /* darwin 6.1 sql header files do not define SQLLEN */ #ifndef SQLLEN #define SQLLEN SQLINTEGER #endif #define ERROR_MSG_BUFFER_LEN 255 #define ODBC_MAX_STR_LEN 255 #define ODBC_MAX_DRIVER_NAME_LEN ODBC_MAX_STR_LEN #define ODBC_GET_INFO_MAX_LEN ODBC_MAX_STR_LEN #define ODBC_GET_CONNECT_ATTR_MAX_LEN ODBC_MAX_STR_LEN #define ODBC_GET_STMT_ATTR_MAX_LEN ODBC_MAX_STR_LEN #define ODBC_GET_DATA_MAX_STR_LEN ODBC_MAX_STR_LEN #define ODBC_DESCRIBE_COL_MAX_STR_LEN ODBC_MAX_STR_LEN #define ODBC_MAX_CURSOR_NAME_STR_LEN ODBC_MAX_STR_LEN #define ODBC_MAX_NATIVE_SQL_STR_LEN ODBC_MAX_STR_LEN #define ODBC_MAX_GET_DESC_FIELD_STR_LEN ODBC_MAX_STR_LEN #define ODBC_RETVAL_BUFFER_INITIAL_SIZE 3 #define ODBC_DEBUG_MSGS 1 #define ODBC_RAISE_EXCEPTION(MSG) s48_raise_string_os_error(MSG) #ifdef ODBC_DEBUG_MSGS #define ODBC_DEBUG_DIAGREC(ht, h) odbc_debug_msgs(ht, h); #else #define ODBC_DEBUG_DIAGREC(ht, h) ; #endif #ifdef ODBC_DEBUG_MSGS #define ODBC_DEBUG_PRINTF_1(str) printf(str); #define ODBC_DEBUG_PRINTF_2(str, arg) printf(str, arg); #define ODBC_DEBUG_PRINTF_3(str, arg1, arg2) printf(str, arg1, arg2); #define ODBC_DEBUG_PRINTF_4(str, arg1, arg2, arg3) printf(str, arg1, arg2, arg3); #define ODBC_DEBUG_PRINTF_5(str, arg1, arg2, arg3, arg4) printf(str, arg1, arg2, arg3, arg4); #else #define ODBC_DEBUG_PRINTF_1(str) ; #define ODBC_DEBUG_PRINTF_2(str, arg) ; #define ODBC_DEBUG_PRINTF_3(str, arg1, arg2) ; #define ODBC_DEBUG_PRINTF_4(str, arg1, arg2, arg3) ; #define ODBC_DEBUG_PRINTF_5(str, arg1, arg2, arg3, arg4) ; #endif /* offsets for scheme records */ /* some useful macros */ #define ODBC_SUCCESS(retval) ((retval == SQL_SUCCESS) || (retval == SQL_SUCCESS_WITH_INFO)) /* corresponds to sql-date */ static s48_value sql_date_record_type = S48_FALSE; #define SR_SQL_DATE_YEAR 0 #define SR_SQL_DATE_MONTH 1 #define SR_SQL_DATE_DAY 2 /* corresponds to sql-time */ static s48_value sql_time_record_type = S48_FALSE; #define SR_SQL_TIME_HOUR 0 #define SR_SQL_TIME_MINUTE 1 #define SR_SQL_TIME_SECOND 2 /* corresponds to sql-timestamp */ static s48_value sql_timestamp_record_type = S48_FALSE; #define SR_SQL_TIMESTAMP_YEAR 0 #define SR_SQL_TIMESTAMP_MONTH 1 #define SR_SQL_TIMESTAMP_DAY 2 #define SR_SQL_TIMESTAMP_HOUR 3 #define SR_SQL_TIMESTAMP_MINUTE 4 #define SR_SQL_TIMESTAMP_SECOND 5 #define SR_SQL_TIMESTAMP_FRACTION 6 /* corresponds to sql-numeric */ #define SR_SQL_NUMERIC_PRECISION 0 #define SR_SQL_NUMERIC_SCALE 1 #define SR_SQL_NUMERIC_SIGN 2 #define SR_SQL_NUMERIC_VALUE 3 /* corresponds to odbc-column */ static s48_value odbc_column_record_type = S48_FALSE; #define SR_ODBC_COLUMN_NAME 0 #define SR_ODBC_COLUMN_TYPE 1 #define SR_ODBC_COLUMN_SIZE 2 #define SR_ODBC_COLUMN_DIGITS 3 #define SR_ODBC_COLUMN_NULLABLE 4 /* corresponds to odbc-diag */ static s48_value odbc_diag_record_type = S48_FALSE; #define SR_ODBC_DIAG_SQL_STATE 0 #define SR_ODBC_DIAG_NATIVE_ERROR 1 #define SR_ODBC_DIAG_MESSAGE 2 /* corresponds to odbc-parameter */ static s48_value odbc_parameter_record_type = S48_FALSE; #define SR_ODBC_PARAMETER_TYPE 0 #define SR_ODBC_PARAMETER_SIZE 1 #define SR_ODBC_PARAMETER_DIGITS 2 #define SR_ODBC_PARAMETER_NULLABLE 3 /* stuff needed for SQLBindCol() */ /* correspons to bindcol-buffer */ static s48_value bindcol_buffer_record_type = S48_FALSE; #define SR_BINDCOL_BUFFER_POINTER 0 #define SR_BINDCOL_BUFFER_LENGTH 1 #define SR_BINDCOL_BUFFER_TARGET_TYPE 2 static s48_value signal_unbound_column = S48_FALSE; static s48_value signal_buffer_exceeded = S48_FALSE; typedef struct bindcol_col_rec *ColumnRecPtr; typedef struct bindcol_col_rec { SQLUSMALLINT col_no; void *col_buffer; SQLSMALLINT target_type; SQLLEN buffer_len; SQLLEN buffer_needed; ColumnRecPtr next; } ColumnRec; typedef struct bindcol_stmt_rec *StmtRecPtr; typedef struct bindcol_stmt_rec { SQLHSTMT stmt_handle; ColumnRecPtr col_recs; StmtRecPtr next; } StmtRec; /* global variables */ StmtRecPtr global_bindcol_list = NULL; /* helper functions needed for SQLBindCol() */ ColumnRecPtr bindcol_lookup_binding(SQLHSTMT stmt_handle, SQLUSMALLINT column_no); s48_value bindcol_lookup_binding_scheme(s48_value stmt_handle, s48_value column_no); void bindcol_bind_column(SQLHSTMT stmt_handle, SQLUSMALLINT column_no, ColumnRecPtr new_col); void bindcol_unbind_colum(SQLHSTMT stmt_handle, SQLUSMALLINT column_no); s48_value bindcol_finalize_bindcols(s48_value stmt_handle); s48_value odbc_sql_bindcol(s48_value stmt_handle, s48_value column_no, s48_value target_type, s48_value buffer_len); /* * * 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(); /* 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); /* Given a valid environment handle get a connection handle */ s48_value odbc_alloc_connection_handle(s48_value env_handle); /* Given a valid connection handle get a statement handle */ s48_value odbc_alloc_statement_handle(s48_value stmt_handle); /* for ODBC 1.0 compatibility */ s48_value odbc_sql_alloc_env(); s48_value odbc_sql_alloc_connect(s48_value env_handle); s48_value odbc_sql_alloc_stmt(s48_value conn_handle); /* Connect to a server */ s48_value odbc_sql_connect(s48_value connection_handle, s48_value ds_name, s48_value user_name, s48_value authentication); s48_value odbc_sql_browse_connect(s48_value conn_handle, s48_value conn_string); /* * * 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); /* Returns the list of installed drivers and their attributes. */ s48_value odbc_sql_drivers(s48_value env_handle); /* 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); /* 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); /* Returns supported driver functions. */ s48_value odbc_sql_get_func_exists(s48_value conn_handle, s48_value fun_id); /* Returns information about supported data types. */ s48_value odbc_sql_get_type_info(s48_value stmt_handle, s48_value data_type); /* * * 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); s48_value odbc_sql_set_connect_attr_string(s48_value conn_handle, s48_value attribute, s48_value value); s48_value odbc_sql_get_connect_attr_string(s48_value conn_handle, s48_value attribute); s48_value odbc_sql_get_connect_attr_int(s48_value conn_handle, s48_value attribute); s48_value odbc_sql_set_env_attr_int(s48_value env_handle, s48_value attribute, s48_value value); s48_value odbc_sql_get_env_attr_int(s48_value env_handle, s48_value attribute, s48_value value); s48_value odbc_sql_set_stmt_attr_int(s48_value stmt_handle, s48_value attribute, s48_value value); s48_value odbc_sql_set_stmt_attr_string(s48_value stmt_handle, s48_value attribute, s48_value value); s48_value odbc_sql_get_stmt_attr_int(s48_value stmt_handle, s48_value attribute); s48_value odbc_sql_get_stmt_attr_string(s48_value stmt_handle, s48_value attribute); /* * * 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); /* 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); /* * * PART 5 * * Preparing SQL requests * */ /* Prepare a SQL statement for execution */ s48_value odbc_sql_prepare(s48_value stmt_handle, s48_value stmt_txt); s48_value odbc_sql_bind_parameter_exec_out(s48_value stmt_handle, s48_value param_vals); s48_value odbc_sql_get_cursor_name(s48_value stmt_handle); void odbc_sql_set_cursor_name(s48_value stmt_handle, s48_value cursorname); /* * * PART 6 * * Submitting requests * */ s48_value odbc_sql_execute(s48_value stmt_handle); s48_value odbc_sql_execute_direct(s48_value stmt_handle, s48_value stmt); /* 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); /* Returns the description for a specific parameter in a statement */ s48_value odbc_sql_describe_param(s48_value stmt_handle, s48_value parameter_no); /* Returns the number of parameters in a statement */ s48_value odbc_sql_num_params(s48_value stmt_handle); /* * * PART 7 * * Retrieving results and information about results * */ s48_value odbc_sql_row_count(s48_value stmt_handle); s48_value odbc_sql_get_data(s48_value stmt_handle, s48_value column_number, s48_value target_type, s48_value buffer_size); /* 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); /* 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); /* 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); s48_value odbc_sql_fetch(s48_value stmt_handle); s48_value odbc_sql_num_result_cols(s48_value stmt_handle); s48_value odbc_sql_describe_col(s48_value stmt_handle, s48_value column_number); /* 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); /* * * PART 8 * * Obtaining information about the data source's * system tables (catalog functions) * */ /* 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); /* 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); /* 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); /* 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); /* 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); /* 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); /* 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); /* 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); /* 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); /* 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); /* * * 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); /* Closes a cursor that has been opened on a statement handle */ s48_value odbc_sql_close_cursor(s48_value stmt_handle); /* Cancels an SQL statement */ s48_value odbc_sql_cancel(s48_value stmt_handle); /* Commits or rolls back a transaction */ s48_value odbc_sql_endtran(s48_value handle_type, s48_value handle, s48_value completion_type); /* * * PART 10 * * Terminating a connection * */ /* Closes the connection */ s48_value odbc_sql_disconnect(s48_value conn_handle); /* Free a handle */ s48_value odbc_sql_free_handle(s48_value handle_type, s48_value handle); /* * * PART 11 * * misc. functions * */ s48_value odbc_sql_get_diag_recs(s48_value handle_type, s48_value handle); #ifdef ODBC_DEBUG_MSGS /* print detailed debug information */ void odbc_debug_msgs(SQLSMALLINT handle_type, SQLHANDLE handle); #endif /* convert Scheme sql-date record to SQL_DATE_STRUCT */ void sql_date_record_to_struct(s48_value sql_date, SQL_DATE_STRUCT *ds); /* convert SQL_DATE_STRUCT to Scheme sql-date record */ s48_value struct_to_sql_date_record(SQL_DATE_STRUCT *ds); /* convert Scheme sql-time record to SQL_TIME_STRUCT */ void sql_time_record_to_struct(s48_value sql_time, SQL_TIME_STRUCT *ts); /* convert SQL_TIME_STRUCT to Scheme sql-time record */ s48_value struct_to_sql_time_record(SQL_TIME_STRUCT *ts); /* convert SQL_TIME_STRUCT to Scheme sql-time record */ s48_value struct_to_sql_time_record(SQL_TIME_STRUCT *ts); /* convert Scheme sql-timestamp record to SQL_TIMESTAMP_STRUCT */ void sql_timestamp_record_to_struct(s48_value sql_timestamp, SQL_TIMESTAMP_STRUCT *ts); void odbc_sql_alloc(void **buffer, size_t buffer_len, size_t type_len); size_t sizeof_sql_c_type_identifier(SQLSMALLINT ctypeid); s48_value buffer_to_s48_value(void *buffer, SQLSMALLINT ctypeid); void s48_init_odbc(void);