/* * Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html). */ #include <winsock.h> #include <windows.h> #include <odbcinst.h> #include <sqlext.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include <string> #include <vector> #include "resource.h" using namespace std; const int MAX_STRING_LEN=511; void initSockets(); void trace(char* message,...); void setString(char* dest, int dest_len, SQLCHAR *source, SQLSMALLINT source_len); void returnString(SQLCHAR* dest, SQLSMALLINT dest_len, SQLSMALLINT* dest_pt, const char* source); void returnString(SQLPOINTER dest, SQLINTEGER dest_len, SQLINTEGER* dest_pt, const char* source); void returnInt(SQLPOINTER InfoValue, SQLINTEGER* LengthPtr, SQLUINTEGER value); void returnInt(SQLPOINTER NumericPtr, int value); void returnInt(SQLPOINTER InfoValue, SQLSMALLINT* LengthPtr, SQLUINTEGER value); void returnSmall(SQLPOINTER InfoValue, SQLSMALLINT* LengthPtr, SQLUSMALLINT value); void returnSmall(SQLPOINTER InfoValue, SQLINTEGER* LengthPtr, SQLUSMALLINT value); void returnPointer(SQLPOINTER pointer, void* value); int getDefaultCType(int sqlType); extern HINSTANCE m_dll; extern bool m_socket_init; class Socket { SOCKET m_socket; private: void setError(char* where); void read(char* buffer, int len); void write(const char* buffer, int len); public: Socket(const char* host,int port); void close(); int readByte(); int readInt(); bool readBool(); string readString(); Socket* writeByte(int byte); Socket* writeBool(bool x); Socket* writeInt(int x); Socket* writeString(const char* string); bool isClosed() { return m_socket != 0; } }; class Environment; class Connection; class Statement; class Descriptor; class DescriptorRecord; enum DescriptorState {D_ACTIVE,D_FREE}; enum DescriptorType {DT_DEFAULT,DT_SHARED}; enum ConnectionState {C_INIT,C_OPEN,C_CLOSED}; enum StatementState {S_PREPARED,S_EXECUTED,S_POSITIONED,S_CLOSED}; enum Send {S_EXECUTE}; const int MAGIC_ENVIRONMENT=0xABC0; const int MAGIC_CONNECTION=0xABC1; const int MAGIC_STATEMENT=0xABC2; const int MAGIC_DESCRIPTOR=0xABC3; const int MAGIC_DESCRIPTOR_RECORD=0xABC4; class Descriptor { int m_magic; Connection* m_connection; int m_id; int m_type; int m_arraySize; int m_count; SQLUSMALLINT* m_statusPointer; SQLUINTEGER* m_rowsProcessedPointer; DescriptorState m_state; vector<Statement*> m_bound; vector<DescriptorRecord*> m_records; char* m_error; bool m_rowWiseBinding; int m_rowSize; public: static Descriptor* cast(void* pointer); // create a shared descriptor Descriptor(Connection* c); // create a default descriptor (not shared) Descriptor(); ~Descriptor(); void init(); bool isFreed() { return m_state==D_FREE; } void clearRecords() { m_records.clear(); } void addRecord(DescriptorRecord* rec) { m_records.push_back(rec); } void readData(int i, Socket* s); DescriptorRecord* getRecord(int i) { return m_records[i]; } int getRecordCount() { return m_records.size(); } void setStatusPointer(SQLUSMALLINT* newPointer) { m_statusPointer = newPointer; } SQLUSMALLINT* getStatusPointer() { return m_statusPointer; } void setRowsProcessedPointer(SQLUINTEGER* rowsProcessedPointer) { m_rowsProcessedPointer = rowsProcessedPointer; } void setRowsProcessed(int rows) { if(m_rowsProcessedPointer != 0) { *m_rowsProcessedPointer = rows; } } void setStatus(SQLUSMALLINT value) { if(m_statusPointer != 0) { *m_statusPointer = value; } } void setError(char* error) { m_error = error; } char* getError() { return m_error; } void setBindingType(bool rowWiseBinding, int rowSize); }; /* Header: SQL_DESC_ALLOC_TYPE (readonly) SQL_DESC_BIND_TYPE (read/write) SQL_DESC_ARRAY_SIZE (read/write) SQL_DESC_COUNT (readonly) SQL_DESC_ARRAY_STATUS_PTR (read/write) SQL_DESC_ROWS_PROCESSED_PTR (read/write) SQL_DESC_BIND_OFFSET_PTR (read/write) Record: SQL_DESC_AUTO_UNIQUE_VALUE SQL_DESC_LOCAL_TYPE_NAME SQLCHAR* TypeName SQL_DESC_BASE_COLUMN_NAME SQLCHAR* TableName SQL_DESC_NAME SQLCHAR* ColumnName / DisplayName SQL_DESC_BASE_TABLE_NAME SQLCHAR* TableName SQL_DESC_NULLABLE SQL_DESC_CASE_SENSITIVE SQL_DESC_OCTET_LENGTH SQL_DESC_CATALOG_NAME SQLCHAR* CatalogName SQL_DESC_OCTET_LENGTH_PTR SQL_DESC_CONCISE_TYPE SQLSMALLINT DataType SQL_DESC_PARAMETER_TYPE SQL_DESC_DATA_PTR SQL_DESC_PRECISION SQL_DESC_DATETIME_INTERVAL_CODE SQL_DESC_SCALE SQL_DESC_DATETIME_INTERVAL_PRECISION SQL_DESC_SCHEMA_NAME SQLCHAR* SchemaName SQL_DESC_DISPLAY_SIZE SQL_DESC_SEARCHABLE SQL_DESC_FIXED_PREC_SCALE SQL_DESC_TABLE_NAME SQLCHAR* TableName SQL_DESC_INDICATOR_PTR SQL_DESC_TYPE SQL_DESC_LABEL SQLCHAR* SQL_DESC_TYPE_NAME SQLCHAR* SQL_DESC_LENGTH SQL_DESC_UNNAMED SQL_DESC_LITERAL_PREFIX SQLCHAR* SQL_DESC_UNSIGNED SQL_DESC_LITERAL_SUFFIX SQLCHAR* SQL_DESC_UPDATABLE */ class DescriptorRecord { int m_magic; Descriptor* m_descriptor; int m_sqlDataType; int m_cDataType; string m_name; string m_columnName; string m_tableName; SQLPOINTER m_pointer; SQLINTEGER* m_statusPointer; int m_targetBufferLength; int m_dataInt; string m_dataString; int m_precision; int m_scale; int m_displaySize; bool m_wasNull; public: static DescriptorRecord* cast(void* pointer); DescriptorRecord(Descriptor* d) { m_magic=MAGIC_DESCRIPTOR_RECORD; m_descriptor=d; m_sqlDataType = 0; m_cDataType = 0; m_pointer = 0; m_statusPointer = 0; m_targetBufferLength = 0; m_dataInt = 0; m_precision = 0; m_scale = 0; m_displaySize = 0; m_wasNull = false; } ~DescriptorRecord() { if(m_magic==MAGIC_DESCRIPTOR_RECORD) { m_magic=0; } else { trace("~DescriptorRecord %d",m_magic); return; } } void setSqlDataType(int sqlDataType) { m_sqlDataType = sqlDataType; } void setCDataType(int cDataType) { m_cDataType = cDataType; } void setTargetBufferLength(int len) { m_targetBufferLength = len; } void setTargetPointer(SQLPOINTER pointer) { m_pointer = pointer; } void setTargetStatusPointer(SQLINTEGER* statusPointer) { m_statusPointer = statusPointer; } int getSqlDataType() { return m_sqlDataType; } bool hasFixedPrecisionScale(); int getDisplaySize() { return m_displaySize; } int getPrecision() { return m_precision; } int getScale() { return m_scale; } string getColumnName() { return m_columnName; } string getTableName() { return m_tableName; } char* getString(); int getInt(); void readMeta(Socket* s); void sendParameterValue(Socket* s); void readData(Socket* s); void copyData(DescriptorRecord* ar); bool wasNull() { return m_wasNull; } void setNull(); int getLength(); const char* getPrefix(); const char* getSuffix(); }; class Environment { int m_magic; int m_id; int m_openConnections; int m_behavior; char* m_error; public: static Environment* cast(void* pointer); Environment(); ~Environment(); Connection* createConnection(); void closeConnection(Connection* conn); int getOpenConnectionCount() { return m_openConnections; } void setBehavior(int behavior) { m_behavior=behavior; } int getBehavior() { return m_behavior; } void setError(char* error) { m_error = error; } char* getError() { return m_error; } }; class Connection { int m_magic; friend class Environment; Environment* m_environment; ConnectionState m_state; int m_id; string m_name; string m_user; string m_password; bool m_readOnly; bool m_autoCommit; vector<Statement*> m_stats; Socket* m_socket; char* m_error; string m_dataSourceName; private: Connection(Environment* e); void appendStatement(); void removeStatement(int i); ~Connection(); public: static Connection* cast(void* pointer); Environment* getEnvironment() { return m_environment; } void open(string name,string user,string password); bool isClosed() { return m_state==C_CLOSED; } void close(); void setReadOnly(bool readonly) { m_readOnly=readonly; } bool getReadOnly() { return m_readOnly; } void setAutoCommit(bool autocommit); void commit(); void rollback(); bool getAutoCommit() { return m_autoCommit; } Socket* getSocket() { return m_socket; } void setError(char* error) { m_error = error; } char* getError() { return m_error; } string getNativeSQL(const char* sql); void setDataSourceName(string dataSourceName) { m_dataSourceName = dataSourceName; } string getDataSourceName() { return m_dataSourceName; } }; class Statement { int m_magic; Connection* m_connection; int m_id; Descriptor m_appRowDefault; Descriptor m_impRowDefault; Descriptor m_appParamDefault; Descriptor m_impParamDefault; Descriptor* m_appRow; Descriptor* m_impRow; Descriptor* m_appParam; Descriptor* m_impParam; StatementState m_state; string m_sql; int m_columnCount; int m_updateCount; int m_resultSetId; int m_preparedId; int m_rowId; bool m_hasResultSet; int m_parameterCount; bool m_useBookmarks; char* m_error; private: void processResultSet(Socket* s); public: static Statement* cast(void* pointer); Statement(Connection* c); ~Statement(); bool prepare(char* sql); bool execute(char* sql); bool executePrepared(); void getMetaTables(char* catalog, char* schema, char* table, char* tabletypes); void getMetaColumns(char* catalog, char* schema, char* table, char* column); void getMetaVersionColumns(char* catalog, char* schema, char* table); void getMetaBestRowIdentifier(char* catalog, char* schema, char* table, int scope, bool nullable); void getMetaIndexInfo(char* catalog, char* schema, char* table, bool unique, bool approximate); void getMetaTypeInfoAll(); void getMetaTypeInfo(int sqlType); Descriptor* getAppRowDesc(); Descriptor* getImpRowDesc(); Descriptor* getAppParamDesc(); Descriptor* getImpParamDesc(); int getColumnCount() { return m_columnCount; } bool next(); int getParametersCount() { return m_parameterCount; } int getUpdateCount() { return m_updateCount; } const char* getSQL(); void closeCursor(); void setUseBookmarks(bool bookmarks) { m_useBookmarks = bookmarks; } bool getUseBookmarks() { return m_useBookmarks; } int getRowId() { return m_rowId; } void setError(char* error) { m_error = error; } char* getError() { return m_error; } void addParameter(); }; #define E_01000 "01000 General warning" #define E_01001 "01001 Cursor operation conflict" #define E_01002 "01002 Disconnect error" #define E_01003 "01003 NULL value eliminated in set function" #define E_01004 "01004 String data, right-truncated" #define E_01006 "01006 Privilege not revoked" #define E_01007 "01007 Privilege not granted" #define E_01S00 "01S00 Invalid connection string attribute" #define E_01S01 "01S01 Error in row" #define E_01S02 "01S02 Option value changed" #define E_01S06 "01S06 Attempt to fetch before the result set returned the first rowset" #define E_01S07 "01S07 Fractional truncation" #define E_01S08 "01S08 Error saving File DSN" #define E_01S09 "01S09 Invalid keyword" #define E_07001 "07001 Wrong number of parameters" #define E_07002 "07002 COUNT field incorrect" #define E_07005 "07005 Prepared statement not a cursor-specification" #define E_07006 "07006 Restricted data type attribute violation" #define E_07009 "07009 Invalid descriptor index" #define E_07S01 "07S01 Invalid use of default parameter" #define E_08001 "08001 Client unable to establish connection" #define E_08002 "08002 Connection name in use" #define E_08003 "08003 Connection does not exist" #define E_08004 "08004 Server rejected the connection" #define E_08007 "08007 Connection failure during transaction" #define E_08S01 "08S01 Communication link failure" #define E_21S01 "21S01 Insert value list does not match column list" #define E_21S02 "21S02 Degree of derived table does not match column list" #define E_22001 "22001 String data, right-truncated" #define E_22002 "22002 Indicator variable required but not supplied" #define E_22003 "22003 Numeric value out of range" #define E_22007 "22007 Invalid datetime format" #define E_22008 "22008 Datetime field overflow" #define E_22012 "22012 Division by zero" #define E_22015 "22015 Interval field overflow" #define E_22018 "22018 Invalid character value for cast specification" #define E_22019 "22019 Invalid escape character" #define E_22025 "22025 Invalid escape sequence" #define E_22026 "22026 String data, length mismatch" #define E_23000 "23000 Integrity constraint violation" #define E_24000 "24000 Invalid cursor state" #define E_25000 "25000 Invalid transaction state" #define E_25S01 "25S01 Transaction state" #define E_25S02 "25S02 Transaction is still active" #define E_25S03 "25S03 Transaction is rolled back" #define E_28000 "28000 Invalid authorization specification" #define E_34000 "34000 Invalid cursor name" #define E_3C000 "3C000 Duplicate cursor name" #define E_3D000 "3D000 Invalid catalog name" #define E_3F000 "3F000 Invalid schema name" #define E_40001 "40001 Serialization failure" #define E_40002 "40002 Integrity constraint violation" #define E_40003 "40003 Statement completion unknown" #define E_42000 "42000 Syntax error or access violation" #define E_42S01 "42S01 Base table or view already exists" #define E_42S02 "42S02 Base table or view not found" #define E_42S11 "42S11 Index already exists" #define E_42S12 "42S12 Index not found" #define E_42S21 "42S21 Column already exists" #define E_42S22 "42S22 Column not found" #define E_44000 "44000 WITH CHECK OPTION violation" #define E_HY000 "HY000 General error" #define E_HY001 "HY001 Memory allocation error" #define E_HY003 "HY003 Invalid application buffer type" #define E_HY004 "HY004 Invalid SQL data type" #define E_HY007 "HY007 Associated statement is not prepared" #define E_HY008 "HY008 Operation canceled" #define E_HY009 "HY009 Invalid use of null pointer" #define E_HY010 "HY010 Function sequence error" #define E_HY011 "HY011 Attribute cannot be set now" #define E_HY012 "HY012 Invalid transaction operation code" #define E_HY013 "HY013 Memory management error" #define E_HY014 "HY014 Limit on the number of handles exceeded" #define E_HY015 "HY015 No cursor name available" #define E_HY016 "HY016 Cannot modify an implementation row descriptor" #define E_HY017 "HY017 Invalid use of an automatically allocated descriptor handle" #define E_HY018 "HY018 Server declined cancel request" #define E_HY019 "HY019 Non-character and non-binary data sent in pieces" #define E_HY020 "HY020 Attempt to concatenate a null value" #define E_HY021 "HY021 Inconsistent descriptor information" #define E_HY024 "HY024 Invalid attribute value" #define E_HY090 "HY090 Invalid string or buffer length" #define E_HY091 "HY091 Invalid descriptor field identifier" #define E_HY092 "HY092 Invalid attribute/option identifier" #define E_HY095 "HY095 Function type out of range" #define E_HY096 "HY096 Invalid information type" #define E_HY097 "HY097 Column type out of range" #define E_HY098 "HY098 Scope type out of range" #define E_HY099 "HY099 Nullable type out of range" #define E_HY100 "HY100 Uniqueness option type out of range" #define E_HY101 "HY101 Accuracy option type out of range" #define E_HY103 "HY103 Invalid retrieval code" #define E_HY104 "HY104 Invalid precision or scale value" #define E_HY105 "HY105 Invalid parameter type" #define E_HY106 "HY106 Fetch type out of range" #define E_HY107 "HY107 Row value out of range" #define E_HY109 "HY109 Invalid cursor position" #define E_HY110 "HY110 Invalid driver completion" #define E_HY111 "HY111 Invalid bookmark value" #define E_HYC00 "HYC00 Optional feature not implemented" #define E_HYT00 "HYT00 Timeout expired" #define E_HYT01 "HYT01 Connection timeout expired" #define E_IM001 "IM001 Driver does not support this function" #define E_IM002 "IM002 Data source name not found and no default driver specified" #define E_IM003 "IM003 Specified driver could not be loaded" #define E_IM004 "IM004 Driver's SQLAllocHandle on SQL_HANDLE_ENV failed" #define E_IM005 "IM005 Driver's SQLAllocHandle on SQL_HANDLE_DBC failed" #define E_IM006 "IM006 Driver's SQLSetConnectAttr failed" #define E_IM007 "IM007 No data source or driver specified; dialog prohibited" #define E_IM008 "IM008 Dialog failed" #define E_IM009 "IM009 Unable to load translation DLL" #define E_IM010 "IM010 Data source name too long" #define E_IM011 "IM011 Driver name too long" #define E_IM012 "IM012 DRIVER keyword syntax error" #define E_IM013 "IM013 Trace file error" #define E_IM014 "IM014 Invalid name of File DSN" #define E_IM015 "IM015 Corrupt file data source"