From 1a593a24b416c2be201273fa884ee9b8ea5ce797 Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Sat, 24 Dec 2011 08:10:41 +0000 Subject: [PATCH] Revert r3979, move imported mysql_* functions from TDBConnection to a global var scope. Fixes issue #2647. Also, move MySQL related structures out of dbconnection.pas into mysql_structures.pas and const.inc. --- source/const.inc | 89 +++++++++++ source/dbconnection.pas | 296 ++++++++---------------------------- source/mysql_structures.pas | 255 ++++++++++++++++++++----------- 3 files changed, 320 insertions(+), 320 deletions(-) diff --git a/source/const.inc b/source/const.inc index 6a547f63..e5b1bedc 100644 --- a/source/const.inc +++ b/source/const.inc @@ -344,6 +344,10 @@ const MSG_NOGRIDEDITING = 'Selected columns don''t contain a sufficient set of key columns to allow editing. Please select primary or unique key columns, or just all columns.'; SIdle = 'Idle.'; SUnsupported = 'Not supported by this server'; + MsgSQLError: String = 'SQL Error (%d): %s'; + MsgUnhandledNetType: String = 'Unhandled connection type (%d)'; + MsgDisconnect: String = 'Connection to %s closed at %s'; + MsgInvalidColumn: String = 'Column #%d not available. Query returned %d columns and %d rows.'; PKEY = 'PRIMARY'; KEY = 'KEY'; @@ -366,3 +370,88 @@ const // A set of characters which need not to be quoted IDENTCHARS = ['A'..'Z', 'a'..'z', '0'..'9', '_']; + + // General declarations + MYSQL_ERRMSG_SIZE = 512; + SQLSTATE_LENGTH = 5; + SCRAMBLE_LENGTH = 20; + MYSQL_PORT = 3306; + LOCAL_HOST = 'localhost'; + NAME_LEN = 64; + PROTOCOL_VERSION = 10; + FRM_VER = 6; + + // Field's flags + NOT_NULL_FLAG = 1; + PRI_KEY_FLAG = 2; + UNIQUE_KEY_FLAG = 4; + MULTIPLE_KEY_FLAG = 8; + BLOB_FLAG = 16; + UNSIGNED_FLAG = 32; + ZEROFILL_FLAG = 64; + BINARY_FLAG = 128; + ENUM_FLAG = 256; + AUTO_INCREMENT_FLAG = 512; + TIMESTAMP_FLAG = 1024; + SET_FLAG = 2048; + NUM_FLAG = 32768; + PART_KEY_FLAG = 16384; + GROUP_FLAG = 32768; + UNIQUE_FLAG = 65536; + BINCMP_FLAG = 131072; + + // Client connection options + CLIENT_LONG_PASSWORD = 1; + CLIENT_FOUND_ROWS = 2; // Found instead of affected rows + CLIENT_LONG_FLAG = 4; + CLIENT_CONNECT_WITH_DB = 8; + CLIENT_NO_SCHEMA = 16; // Don't allow database.table.column + CLIENT_COMPRESS = 32; + CLIENT_ODBC = 64; + CLIENT_LOCAL_FILES = 128; + CLIENT_IGNORE_SPACE = 256; // Ignore spaces before '(' + CLIENT_PROTOCOL_41 = 512; + CLIENT_INTERACTIVE = 1024; + CLIENT_SSL = 2048; // Switch to SSL after handshake + CLIENT_IGNORE_SIGPIPE = 4096; + CLIENT_TRANSACTIONS = 8192; + CLIENT_RESERVED = 16384; + CLIENT_SECURE_CONNECTION = 32768; + CLIENT_MULTI_STATEMENTS = 65536; + CLIENT_MULTI_RESULTS = 131072; + CLIENT_SSL_VERIFY_SERVER_CERT = 67108864; + CLIENT_REMEMBER_OPTIONS = 134217728; + + // Enum Field Types + FIELD_TYPE_DECIMAL = 0; + FIELD_TYPE_TINY = 1; + FIELD_TYPE_SHORT = 2; + FIELD_TYPE_LONG = 3; + FIELD_TYPE_FLOAT = 4; + FIELD_TYPE_DOUBLE = 5; + FIELD_TYPE_NULL = 6; + FIELD_TYPE_TIMESTAMP = 7; + FIELD_TYPE_LONGLONG = 8; + FIELD_TYPE_INT24 = 9; + FIELD_TYPE_DATE = 10; + FIELD_TYPE_TIME = 11; + FIELD_TYPE_DATETIME = 12; + FIELD_TYPE_YEAR = 13; + FIELD_TYPE_NEWDATE = 14; + FIELD_TYPE_VARCHAR = 15; + FIELD_TYPE_BIT = 16; + FIELD_TYPE_NEWDECIMAL = 246; + FIELD_TYPE_ENUM = 247; + FIELD_TYPE_SET = 248; + FIELD_TYPE_TINY_BLOB = 249; + FIELD_TYPE_MEDIUM_BLOB = 250; + FIELD_TYPE_LONG_BLOB = 251; + FIELD_TYPE_BLOB = 252; + FIELD_TYPE_VAR_STRING = 253; + FIELD_TYPE_STRING = 254; + FIELD_TYPE_GEOMETRY = 255; + + COLLATION_BINARY = 63; + // Equivalent to COLLATION_BINARY, this is what a new driver returns when connected to a pre-4.1 server. + COLLATION_NONE = 0; + diff --git a/source/dbconnection.pas b/source/dbconnection.pas index 4e1d992c..1dd78d7e 100644 --- a/source/dbconnection.pas +++ b/source/dbconnection.pas @@ -8,175 +8,6 @@ uses type - PUSED_MEM=^USED_MEM; - USED_MEM = packed record - next: PUSED_MEM; - left: Integer; - size: Integer; - end; - - PERR_PROC = ^ERR_PROC; - ERR_PROC = procedure; - - PMEM_ROOT = ^MEM_ROOT; - MEM_ROOT = packed record - free: PUSED_MEM; - used: PUSED_MEM; - pre_alloc: PUSED_MEM; - min_malloc: Integer; - block_size: Integer; - block_num: Integer; - first_block_usage: Integer; - error_handler: PERR_PROC; - end; - - NET = record - vio: Pointer; - buff: PAnsiChar; - buff_end: PAnsiChar; - write_pos: PAnsiChar; - read_pos: PAnsiChar; - fd: Integer; - max_packet: Cardinal; - max_packet_size: Cardinal; - pkt_nr: Cardinal; - compress_pkt_nr: Cardinal; - write_timeout: Cardinal; - read_timeout: Cardinal; - retry_count: Cardinal; - fcntl: Integer; - compress: Byte; - remain_in_buf: LongInt; - length: LongInt; - buf_length: LongInt; - where_b: LongInt; - return_status: Pointer; - reading_or_writing: Char; - save_char: Char; - no_send_ok: Byte; - last_error: array[1..MYSQL_ERRMSG_SIZE] of Char; - sqlstate: array[1..SQLSTATE_LENGTH + 1] of Char; - last_errno: Cardinal; - error: Char; - query_cache_query: Pointer; - report_error: Byte; - return_errno: Byte; - end; - - PMYSQL_FIELD = ^MYSQL_FIELD; - MYSQL_FIELD = record - name: PAnsiChar; // Name of column - org_name: PAnsiChar; // Original column name, if an alias - table: PAnsiChar; // Table of column if column was a field - org_table: PAnsiChar; // Org table name if table was an alias - db: PAnsiChar; // Database for table - catalog: PAnsiChar; // Catalog for table - def: PAnsiChar; // Default value (set by mysql_list_fields) - length: LongInt; // Width of column - max_length: LongInt; // Max width of selected set - name_length: Cardinal; - org_name_length: Cardinal; - table_length: Cardinal; - org_table_length: Cardinal; - db_length: Cardinal; - catalog_length: Cardinal; - def_length: Cardinal; - flags: Cardinal; // Div flags - decimals: Cardinal; // Number of decimals in field - charsetnr: Cardinal; // Character set - _type: Cardinal; // Type of field. Se mysql_com.h for types - end; - - MYSQL_ROW = array[0..$ffff] of PAnsiChar; - PMYSQL_ROW = ^MYSQL_ROW; - - PMYSQL_ROWS = ^MYSQL_ROWS; - MYSQL_ROWS = record - next: PMYSQL_ROWS; - data: PMYSQL_ROW; - end; - - MYSQL_DATA = record - Rows: Int64; - Fields: Cardinal; - Data: PMYSQL_ROWS; - Alloc: MEM_ROOT; - end; - PMYSQL_DATA = ^MYSQL_DATA; - - PMYSQL = ^MYSQL; - MYSQL = record - _net: NET; - connector_fd: Pointer; - host: PAnsiChar; - user: PAnsiChar; - passwd: PAnsiChar; - unix_socket: PAnsiChar; - server_version: PAnsiChar; - host_info: PAnsiChar; - info: PAnsiChar; - db: PAnsiChar; - charset: PAnsiChar; - fields: PMYSQL_FIELD; - field_alloc: MEM_ROOT; - affected_rows: Int64; - insert_id: Int64; - extra_info: Int64; - thread_id: LongInt; - packet_length: LongInt; - port: Cardinal; - client_flag: LongInt; - server_capabilities: LongInt; - protocol_version: Cardinal; - field_count: Cardinal; - server_status: Cardinal; - server_language: Cardinal; - warning_count: Cardinal; - options: Cardinal; - status: Byte; - free_me: Byte; - reconnect: Byte; - scramble: array[1..SCRAMBLE_LENGTH+1] of Char; - rpl_pivot: Byte; - master: PMYSQL; - next_slave: PMYSQL; - last_used_slave: PMYSQL; - last_used_con: PMYSQL; - stmts: Pointer; - methods: Pointer; - thd: Pointer; - unbuffered_fetch_owner: PByte; - end; - - MYSQL_RES = record - row_count: Int64; - fields: PMYSQL_FIELD; - data: PMYSQL_DATA; - data_cursor: PMYSQL_ROWS; - lengths: PLongInt; - handle: PMYSQL; - field_alloc: MEM_ROOT; - field_count: Integer; - current_field: Integer; - row: PMYSQL_ROW; - current_row: PMYSQL_ROW; - eof: Byte; - unbuffered_fetch_cancelled: Byte; - methods: PAnsiChar; - end; - PMYSQL_RES = ^MYSQL_RES; - - TMySQLOption = (MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE, - MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, - MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE, - MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT, - MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, - MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, - MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, - MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, - MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH); - - { TDBObjectList and friends } TListNodeType = (lntNone, lntDb, lntTable, lntView, lntFunction, lntProcedure, lntTrigger, lntEvent, lntColumn); @@ -443,33 +274,6 @@ type procedure SetObjectNamesInSelectedDB; procedure SetLockedByThread(Value: TThread); virtual; public - mysql_affected_rows: function(Handle: PMYSQL): Int64; stdcall; - mysql_character_set_name: function(Handle: PMYSQL): PAnsiChar; stdcall; - mysql_close: procedure(Handle: PMYSQL); stdcall; - mysql_data_seek: procedure(Result: PMYSQL_RES; Offset: Int64); stdcall; - mysql_errno: function(Handle: PMYSQL): Cardinal; stdcall; - mysql_error: function(Handle: PMYSQL): PAnsiChar; stdcall; - mysql_fetch_field_direct: function(Result: PMYSQL_RES; FieldNo: Cardinal): PMYSQL_FIELD; stdcall; - mysql_fetch_lengths: function(Result: PMYSQL_RES): PLongInt; stdcall; - mysql_fetch_row: function(Result: PMYSQL_RES): PMYSQL_ROW; stdcall; - mysql_free_result: procedure(Result: PMYSQL_RES); stdcall; - mysql_get_client_info: function: PAnsiChar; stdcall; - mysql_get_server_info: function(Handle: PMYSQL): PAnsiChar; stdcall; - mysql_init: function(Handle: PMYSQL): PMYSQL; stdcall; - mysql_num_fields: function(Result: PMYSQL_RES): Integer; stdcall; - mysql_num_rows: function(Result: PMYSQL_RES): Int64; stdcall; - mysql_options: function(Handle: PMYSQL; Option: TMySQLOption; arg: PAnsiChar): Integer; stdcall; - mysql_ping: function(Handle: PMYSQL): Integer; stdcall; - mysql_real_connect: function(Handle: PMYSQL; const Host, User, Passwd, Db: PAnsiChar; Port: Cardinal; const UnixSocket: PAnsiChar; ClientFlag: Cardinal): PMYSQL; stdcall; - mysql_real_query: function(Handle: PMYSQL; const Query: PAnsiChar; Length: Cardinal): Integer; stdcall; - mysql_ssl_set: function(Handle: PMYSQL; const key, cert, CA, CApath, cipher: PAnsiChar): Byte; stdcall; - mysql_stat: function(Handle: PMYSQL): PAnsiChar; stdcall; - mysql_store_result: function(Handle: PMYSQL): PMYSQL_RES; stdcall; - mysql_thread_id: function(Handle: PMYSQL): Cardinal; stdcall; - mysql_next_result: function(Handle: PMYSQL): Integer; stdcall; - mysql_set_character_set: function(Handle: PMYSQL; csname: PAnsiChar): Integer; stdcall; - mysql_thread_init: function: Byte; stdcall; - mysql_thread_end: procedure; stdcall; constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); virtual; abstract; @@ -551,8 +355,6 @@ type TMySQLConnection = class(TDBConnection) private FHandle: PMYSQL; - FLibraryHandle: HMODULE; - FLibraryPath: String; FLastRawResults: TMySQLRawResults; FPlinkProcInfo: TProcessInformation; procedure SetActive(Value: Boolean); override; @@ -572,7 +374,6 @@ type procedure SetLockedByThread(Value: TThread); override; public constructor Create(AOwner: TComponent); override; - destructor Destroy; override; procedure Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TDBLogCategory=lcSQL); override; function ConvertServerVersion(Version: Integer): String; override; function Ping(Reconnect: Boolean): Boolean; override; @@ -740,11 +541,39 @@ function mysql_authentication_dialog_ask( exports mysql_authentication_dialog_ask; -const - MsgSQLError: String = 'SQL Error (%d): %s'; - MsgUnhandledNetType: String = 'Unhandled connection type (%d)'; - MsgDisconnect: String = 'Connection to %s closed at %s'; - MsgInvalidColumn: String = 'Column #%d not available. Query returned %d columns and %d rows.'; +{$I const.inc} + +var + LibMysqlPath: String = 'libmysql.dll'; + LibMysqlHandle: HMODULE; // Shared module handle + + mysql_affected_rows: function(Handle: PMYSQL): Int64; stdcall; + mysql_character_set_name: function(Handle: PMYSQL): PAnsiChar; stdcall; + mysql_close: procedure(Handle: PMYSQL); stdcall; + mysql_data_seek: procedure(Result: PMYSQL_RES; Offset: Int64); stdcall; + mysql_errno: function(Handle: PMYSQL): Cardinal; stdcall; + mysql_error: function(Handle: PMYSQL): PAnsiChar; stdcall; + mysql_fetch_field_direct: function(Result: PMYSQL_RES; FieldNo: Cardinal): PMYSQL_FIELD; stdcall; + mysql_fetch_lengths: function(Result: PMYSQL_RES): PLongInt; stdcall; + mysql_fetch_row: function(Result: PMYSQL_RES): PMYSQL_ROW; stdcall; + mysql_free_result: procedure(Result: PMYSQL_RES); stdcall; + mysql_get_client_info: function: PAnsiChar; stdcall; + mysql_get_server_info: function(Handle: PMYSQL): PAnsiChar; stdcall; + mysql_init: function(Handle: PMYSQL): PMYSQL; stdcall; + mysql_num_fields: function(Result: PMYSQL_RES): Integer; stdcall; + mysql_num_rows: function(Result: PMYSQL_RES): Int64; stdcall; + mysql_options: function(Handle: PMYSQL; Option: TMySQLOption; arg: PAnsiChar): Integer; stdcall; + mysql_ping: function(Handle: PMYSQL): Integer; stdcall; + mysql_real_connect: function(Handle: PMYSQL; const Host, User, Passwd, Db: PAnsiChar; Port: Cardinal; const UnixSocket: PAnsiChar; ClientFlag: Cardinal): PMYSQL; stdcall; + mysql_real_query: function(Handle: PMYSQL; const Query: PAnsiChar; Length: Cardinal): Integer; stdcall; + mysql_ssl_set: function(Handle: PMYSQL; const key, cert, CA, CApath, cipher: PAnsiChar): Byte; stdcall; + mysql_stat: function(Handle: PMYSQL): PAnsiChar; stdcall; + mysql_store_result: function(Handle: PMYSQL): PMYSQL_RES; stdcall; + mysql_thread_id: function(Handle: PMYSQL): Cardinal; stdcall; + mysql_next_result: function(Handle: PMYSQL): Integer; stdcall; + mysql_set_character_set: function(Handle: PMYSQL; csname: PAnsiChar): Integer; stdcall; + mysql_thread_init: function: Byte; stdcall; + mysql_thread_end: procedure; stdcall; implementation @@ -905,7 +734,6 @@ var begin inherited; FQuoteChar := '`'; - FLibraryPath := 'libmysql.dll'; // The compiler complains that dynamic and static arrays are incompatible, so this does not work: // FDatatypes := MySQLDatatypes SetLength(FDatatypes, Length(MySQLDatatypes)); @@ -944,16 +772,6 @@ begin end; -destructor TMySQLConnection.Destroy; -begin - // Release libmysql.dll handle - inherited; - if FLibraryHandle <> 0 then - FreeLibrary(FLibraryHandle); - FLibraryHandle := 0; -end; - - function TDBConnection.GetDatatypeByName(Datatype: String): TDBDatatype; var i: Integer; @@ -971,10 +789,10 @@ procedure TMySQLConnection.AssignProc(var Proc: FARPROC; Name: PAnsiChar); begin // Map library procedure to internal procedure Log(lcDebug, 'Assign procedure "'+Name+'"'); - Proc := GetProcAddress(FLibraryHandle, Name); + Proc := GetProcAddress(LibMysqlHandle, Name); if Proc = nil then begin - FLibraryHandle := 0; - raise EDatabaseError.Create('Your '+FLibraryPath+' is out-dated or somehow incompatible to '+APPNAME+'. Please use the one from the installer, or just reinstall '+APPNAME+'.'); + LibMysqlHandle := 0; + raise EDatabaseError.Create('Your '+LibMysqlPath+' is out-dated or somehow incompatible to '+APPNAME+'. Please use the one from the installer, or just reinstall '+APPNAME+'.'); end; end; @@ -1292,11 +1110,11 @@ procedure TMySQLConnection.DoBeforeConnect; begin // Init libmysql before actually connecting. // Each connection has its own library handle - if FLibraryHandle = 0 then begin - Log(lcDebug, 'Loading library file '+FLibraryPath+' ...'); - FLibraryHandle := LoadLibrary(PWideChar(FLibraryPath)); - if FLibraryHandle = 0 then - raise EDatabaseError.Create('Can''t find a usable '+FLibraryPath+'. Please launch '+ExtractFileName(ParamStr(0))+' from the directory where you have installed it.') + if LibMysqlHandle = 0 then begin + Log(lcDebug, 'Loading library file '+LibMysqlPath+' ...'); + LibMysqlHandle := LoadLibrary(PWideChar(LibMysqlPath)); + if LibMysqlHandle = 0 then + raise EDatabaseError.Create('Can''t find a usable '+LibMysqlPath+'. Please launch '+ExtractFileName(ParamStr(0))+' from the directory where you have installed it.') else begin AssignProc(@mysql_affected_rows, 'mysql_affected_rows'); AssignProc(@mysql_character_set_name, 'mysql_character_set_name'); @@ -1325,7 +1143,7 @@ begin AssignProc(@mysql_set_character_set, 'mysql_set_character_set'); AssignProc(@mysql_thread_init, 'mysql_thread_init'); AssignProc(@mysql_thread_end, 'mysql_thread_end'); - Log(lcDebug, FLibraryPath + ' v' + DecodeApiString(mysql_get_client_info) + ' loaded.'); + Log(lcDebug, LibMysqlPath + ' v' + DecodeApiString(mysql_get_client_info) + ' loaded.'); end; end; inherited; @@ -3299,7 +3117,7 @@ var i: Integer; begin if HasResult then for i:=Low(FResultList) to High(FResultList) do - FConnection.mysql_free_result(FResultList[i]); + mysql_free_result(FResultList[i]); SetLength(FResultList, 0); inherited; end; @@ -3341,7 +3159,7 @@ begin NumResults := Length(FResultList)+1 else begin for i:=Low(FResultList) to High(FResultList) do - FConnection.mysql_free_result(FResultList[i]); + mysql_free_result(FResultList[i]); NumResults := 1; FRecordCount := 0; FEditingPrepared := False; @@ -3356,14 +3174,14 @@ begin if HasResult then begin // FCurrentResults is normally done in SetRecNo, but never if result has no rows FCurrentResults := LastResult; - NumFields := FConnection.mysql_num_fields(LastResult); + NumFields := mysql_num_fields(LastResult); SetLength(FColumnTypes, NumFields); SetLength(FColumnLengths, NumFields); SetLength(FColumnFlags, NumFields); FColumnNames.Clear; FColumnOrgNames.Clear; for i:=0 to NumFields-1 do begin - Field := FConnection.mysql_fetch_field_direct(LastResult, i); + Field := mysql_fetch_field_direct(LastResult, i); FColumnNames.Add(Connection.DecodeAPIString(Field.name)); if Connection.ServerVersionInt >= 40100 then FColumnOrgNames.Add(Connection.DecodeAPIString(Field.org_name)) @@ -3573,11 +3391,11 @@ begin // Do not seek if FCurrentRow points to the previous row of the wanted row WantedLocalRecNo := FCurrentResults.row_count-(NumRows-Value); if (WantedLocalRecNo = 0) or (FRecNo+1 <> Value) or (FCurrentRow = nil) then - FConnection.mysql_data_seek(FCurrentResults, WantedLocalRecNo); - FCurrentRow := FConnection.mysql_fetch_row(FCurrentResults); + mysql_data_seek(FCurrentResults, WantedLocalRecNo); + FCurrentRow := mysql_fetch_row(FCurrentResults); FCurrentUpdateRow := nil; // Remember length of column contents. Important for Col() so contents of cells with #0 chars are not cut off - LengthPointer := FConnection.mysql_fetch_lengths(FCurrentResults); + LengthPointer := mysql_fetch_lengths(FCurrentResults); for j:=Low(FColumnLengths) to High(FColumnLengths) do FColumnLengths[j] := PInteger(Integer(LengthPointer) + j * SizeOf(Integer))^; break; @@ -4248,7 +4066,7 @@ var begin // Return first available Field.db property, or just the current database as fallback for i:=0 to ColumnCount-1 do begin - Field := FConnection.mysql_fetch_field_direct(FCurrentResults, i); + Field := mysql_fetch_field_direct(FCurrentResults, i); if Field.db <> '' then begin Result := Connection.DecodeAPIString(Field.db); break; @@ -4276,7 +4094,7 @@ var begin IsView := False; for i:=0 to ColumnCount-1 do begin - Field := FConnection.mysql_fetch_field_direct(FCurrentResults, i); + Field := mysql_fetch_field_direct(FCurrentResults, i); if Connection.DecodeAPIString(Field.table) <> Connection.DecodeAPIString(Field.org_table) then begin // Probably a VIEW, in which case we rely on the first column's table name. @@ -4804,4 +4622,16 @@ begin end; +initialization + + +finalization + +// Release libmysql.dll handle +if LibMysqlHandle <> 0 then begin + FreeLibrary(LibMysqlHandle); + LibMysqlHandle := 0; +end; + + end. diff --git a/source/mysql_structures.pas b/source/mysql_structures.pas index 3a4432d3..fec33a71 100644 --- a/source/mysql_structures.pas +++ b/source/mysql_structures.pas @@ -11,94 +11,175 @@ uses {$I const.inc} -const - - // General declarations - MYSQL_ERRMSG_SIZE = 512; - SQLSTATE_LENGTH = 5; - SCRAMBLE_LENGTH = 20; - MYSQL_PORT = 3306; - LOCAL_HOST = 'localhost'; - NAME_LEN = 64; - PROTOCOL_VERSION = 10; - FRM_VER = 6; - - // Field's flags - NOT_NULL_FLAG = 1; - PRI_KEY_FLAG = 2; - UNIQUE_KEY_FLAG = 4; - MULTIPLE_KEY_FLAG = 8; - BLOB_FLAG = 16; - UNSIGNED_FLAG = 32; - ZEROFILL_FLAG = 64; - BINARY_FLAG = 128; - ENUM_FLAG = 256; - AUTO_INCREMENT_FLAG = 512; - TIMESTAMP_FLAG = 1024; - SET_FLAG = 2048; - NUM_FLAG = 32768; - PART_KEY_FLAG = 16384; - GROUP_FLAG = 32768; - UNIQUE_FLAG = 65536; - BINCMP_FLAG = 131072; - - // Client connection options - CLIENT_LONG_PASSWORD = 1; - CLIENT_FOUND_ROWS = 2; // Found instead of affected rows - CLIENT_LONG_FLAG = 4; - CLIENT_CONNECT_WITH_DB = 8; - CLIENT_NO_SCHEMA = 16; // Don't allow database.table.column - CLIENT_COMPRESS = 32; - CLIENT_ODBC = 64; - CLIENT_LOCAL_FILES = 128; - CLIENT_IGNORE_SPACE = 256; // Ignore spaces before '(' - CLIENT_PROTOCOL_41 = 512; - CLIENT_INTERACTIVE = 1024; - CLIENT_SSL = 2048; // Switch to SSL after handshake - CLIENT_IGNORE_SIGPIPE = 4096; - CLIENT_TRANSACTIONS = 8192; - CLIENT_RESERVED = 16384; - CLIENT_SECURE_CONNECTION = 32768; - CLIENT_MULTI_STATEMENTS = 65536; - CLIENT_MULTI_RESULTS = 131072; - CLIENT_SSL_VERIFY_SERVER_CERT = 67108864; - CLIENT_REMEMBER_OPTIONS = 134217728; - - // Enum Field Types - FIELD_TYPE_DECIMAL = 0; - FIELD_TYPE_TINY = 1; - FIELD_TYPE_SHORT = 2; - FIELD_TYPE_LONG = 3; - FIELD_TYPE_FLOAT = 4; - FIELD_TYPE_DOUBLE = 5; - FIELD_TYPE_NULL = 6; - FIELD_TYPE_TIMESTAMP = 7; - FIELD_TYPE_LONGLONG = 8; - FIELD_TYPE_INT24 = 9; - FIELD_TYPE_DATE = 10; - FIELD_TYPE_TIME = 11; - FIELD_TYPE_DATETIME = 12; - FIELD_TYPE_YEAR = 13; - FIELD_TYPE_NEWDATE = 14; - FIELD_TYPE_VARCHAR = 15; - FIELD_TYPE_BIT = 16; - FIELD_TYPE_NEWDECIMAL = 246; - FIELD_TYPE_ENUM = 247; - FIELD_TYPE_SET = 248; - FIELD_TYPE_TINY_BLOB = 249; - FIELD_TYPE_MEDIUM_BLOB = 250; - FIELD_TYPE_LONG_BLOB = 251; - FIELD_TYPE_BLOB = 252; - FIELD_TYPE_VAR_STRING = 253; - FIELD_TYPE_STRING = 254; - FIELD_TYPE_GEOMETRY = 255; - - COLLATION_BINARY = 63; - // Equivalent to COLLATION_BINARY, this is what a new driver returns when connected to a pre-4.1 server. - COLLATION_NONE = 0; - - type + PUSED_MEM=^USED_MEM; + USED_MEM = packed record + next: PUSED_MEM; + left: Integer; + size: Integer; + end; + + PERR_PROC = ^ERR_PROC; + ERR_PROC = procedure; + + PMEM_ROOT = ^MEM_ROOT; + MEM_ROOT = packed record + free: PUSED_MEM; + used: PUSED_MEM; + pre_alloc: PUSED_MEM; + min_malloc: Integer; + block_size: Integer; + block_num: Integer; + first_block_usage: Integer; + error_handler: PERR_PROC; + end; + + NET = record + vio: Pointer; + buff: PAnsiChar; + buff_end: PAnsiChar; + write_pos: PAnsiChar; + read_pos: PAnsiChar; + fd: Integer; + max_packet: Cardinal; + max_packet_size: Cardinal; + pkt_nr: Cardinal; + compress_pkt_nr: Cardinal; + write_timeout: Cardinal; + read_timeout: Cardinal; + retry_count: Cardinal; + fcntl: Integer; + compress: Byte; + remain_in_buf: LongInt; + length: LongInt; + buf_length: LongInt; + where_b: LongInt; + return_status: Pointer; + reading_or_writing: Char; + save_char: Char; + no_send_ok: Byte; + last_error: array[1..MYSQL_ERRMSG_SIZE] of Char; + sqlstate: array[1..SQLSTATE_LENGTH + 1] of Char; + last_errno: Cardinal; + error: Char; + query_cache_query: Pointer; + report_error: Byte; + return_errno: Byte; + end; + + PMYSQL_FIELD = ^MYSQL_FIELD; + MYSQL_FIELD = record + name: PAnsiChar; // Name of column + org_name: PAnsiChar; // Original column name, if an alias + table: PAnsiChar; // Table of column if column was a field + org_table: PAnsiChar; // Org table name if table was an alias + db: PAnsiChar; // Database for table + catalog: PAnsiChar; // Catalog for table + def: PAnsiChar; // Default value (set by mysql_list_fields) + length: LongInt; // Width of column + max_length: LongInt; // Max width of selected set + name_length: Cardinal; + org_name_length: Cardinal; + table_length: Cardinal; + org_table_length: Cardinal; + db_length: Cardinal; + catalog_length: Cardinal; + def_length: Cardinal; + flags: Cardinal; // Div flags + decimals: Cardinal; // Number of decimals in field + charsetnr: Cardinal; // Character set + _type: Cardinal; // Type of field. Se mysql_com.h for types + end; + + MYSQL_ROW = array[0..$ffff] of PAnsiChar; + PMYSQL_ROW = ^MYSQL_ROW; + + PMYSQL_ROWS = ^MYSQL_ROWS; + MYSQL_ROWS = record + next: PMYSQL_ROWS; + data: PMYSQL_ROW; + end; + + MYSQL_DATA = record + Rows: Int64; + Fields: Cardinal; + Data: PMYSQL_ROWS; + Alloc: MEM_ROOT; + end; + PMYSQL_DATA = ^MYSQL_DATA; + + PMYSQL = ^MYSQL; + MYSQL = record + _net: NET; + connector_fd: Pointer; + host: PAnsiChar; + user: PAnsiChar; + passwd: PAnsiChar; + unix_socket: PAnsiChar; + server_version: PAnsiChar; + host_info: PAnsiChar; + info: PAnsiChar; + db: PAnsiChar; + charset: PAnsiChar; + fields: PMYSQL_FIELD; + field_alloc: MEM_ROOT; + affected_rows: Int64; + insert_id: Int64; + extra_info: Int64; + thread_id: LongInt; + packet_length: LongInt; + port: Cardinal; + client_flag: LongInt; + server_capabilities: LongInt; + protocol_version: Cardinal; + field_count: Cardinal; + server_status: Cardinal; + server_language: Cardinal; + warning_count: Cardinal; + options: Cardinal; + status: Byte; + free_me: Byte; + reconnect: Byte; + scramble: array[1..SCRAMBLE_LENGTH+1] of Char; + rpl_pivot: Byte; + master: PMYSQL; + next_slave: PMYSQL; + last_used_slave: PMYSQL; + last_used_con: PMYSQL; + stmts: Pointer; + methods: Pointer; + thd: Pointer; + unbuffered_fetch_owner: PByte; + end; + + MYSQL_RES = record + row_count: Int64; + fields: PMYSQL_FIELD; + data: PMYSQL_DATA; + data_cursor: PMYSQL_ROWS; + lengths: PLongInt; + handle: PMYSQL; + field_alloc: MEM_ROOT; + field_count: Integer; + current_field: Integer; + row: PMYSQL_ROW; + current_row: PMYSQL_ROW; + eof: Byte; + unbuffered_fetch_cancelled: Byte; + methods: PAnsiChar; + end; + PMYSQL_RES = ^MYSQL_RES; + + TMySQLOption = (MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE, + MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, + MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE, + MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT, + MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, + MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, + MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, + MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, + MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH); + // MySQL data types TDBDatatypeIndex = (dtTinyint, dtSmallint, dtMediumint, dtInt, dtBigint, dtFloat, dtDouble, dtDecimal, dtNumeric, dtReal, dtMoney, dtSmallmoney,