h2odbc.h 18.4 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
/*
 * 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"