diff --git a/extra/mysql_dataset/mysqldataset.pas b/extra/mysql_dataset/mysqldataset.pas
deleted file mode 100644
index c94eefb9..00000000
--- a/extra/mysql_dataset/mysqldataset.pas
+++ /dev/null
@@ -1,1077 +0,0 @@
-unit mysqldataset;
-
-{$M+} // Needed to add published properties
-
-interface
-
-uses
- Classes, db, SysUtils, windows, mysql_api;
-
-type
-
- { **************** }
- { TMySQLConnection }
- { **************** }
-
- TMySQLLogCategory = (lcStats, lcSQL, lcError, lcInternal);
- TMySQLLogEvent = procedure (Category: TMySQLLogCategory; Msg: String) of object;
-
- TMySQLServerCapability = (
- cpShowEngines, // SHOW ENGINES
- cpShowTableStatus, // SHOW TABLE STATUS
- cpShowFullTables, // SHOW FULL TABLES
- cpShowCreateTable, // SHOW CREATE TABLE foo
- cpShowCreateDatabase, // SHOW CREATE DATABASE foo
- cpHelpSystem, // HELP "foo"
- cpSetNames, // SET NAMES
- cpCalcFoundRows, // SELECT SQL_CALC_FOUND_ROWS ...
- cpLoadFile, // LOAD DATA LOCAL INFILE ...
- cpTableComment, // CREATE TABLE ... COMMENT = "foo"
- cpFieldComment, // ALTER TABLE ADD ... COMMENT = "foo"
- cpColumnMoving, // ALTER TABLE CHANGE ... FIRST|AFTER foo
- cpTruncateTable, // TRUNCATE TABLE foo
- cpBackticks, // `identifier`
- cpAlterDatabase, // ALTER DATABASE
- cpRenameDatabase // RENAME DATABASE
- );
- TMySQLServerCapabilities = set of TMySQLServerCapability;
-
- TMySQLClientOption = (
- opCompress, // CLIENT_COMPRESS
- opConnectWithDb, // CLIENT_CONNECT_WITH_DB
- opFoundRows, // CLIENT_FOUND_ROWS
- opIgnoreSigpipe, // CLIENT_IGNORE_SIGPIPE
- opIgnoreSpace, // CLIENT_IGNORE_SPACE
- opInteractive, // CLIENT_INTERACTIVE
- opLocalFiles, // CLIENT_LOCAL_FILES
- opLongFlag, // CLIENT_LONG_FLAG
- opLongPassword, // CLIENT_LONG_PASSWORD
- opMultiResults, // CLIENT_MULTI_RESULTS
- opMultiStatements, // CLIENT_MULTI_STATEMENTS
- opNoSchema, // CLIENT_NO_SCHEMA
- opODBC, // CLIENT_ODBC
- opProtocol41, // CLIENT_PROTOCOL_41
- opRememberOptions, // CLIENT_REMEMBER_OPTIONS
- opReserved, // CLIENT_RESERVED
- opSecureConnection, // CLIENT_SECURE_CONNECTION
- opSSL, // CLIENT_SSL
- opTransactions // CLIENT_TRANSACTIONS
- );
- TMySQLClientOptions = set of TMySQLClientOption;
-
-const
- DEFAULT_MYSQLOPTIONS = [opCompress, opLocalFiles, opInteractive, opProtocol41];
-
-type
- TMySQLConnection = class(TComponent)
- private
- FHandle: PMYSQL;
- FActive: Boolean;
- FHostname: String;
- FPort: Cardinal;
- FUsername: String;
- FPassword: String;
- FTimeout: Cardinal;
- FDatabase: String;
- FOnLog: TMySQLLogEvent;
- FOptions: TMySQLClientOptions;
- FCapabilities: TMySQLServerCapabilities;
- FRowsFound: Int64;
- FRowsAffected: Int64;
- procedure SetActive( Value: Boolean );
- procedure SetDatabase( Value: String );
- function GetThreadId: Cardinal;
- function GetCharacterSet: String;
- function GetLastError: String;
- function GetServerVersionStr: String;
- function GetServerVersionInt: Integer;
- procedure Log(Category: TMySQLLogCategory; Msg: String);
- procedure DetectCapabilities;
- public
- constructor Create(AOwner: TComponent); override;
- function Query( SQL: String ): PMYSQL_RES;
- function EscapeString( Text: String; DoQuote: Boolean = True ): String;
- function QuoteIdent( Identifier: String ): String;
- function GetRow( SQL: String; RowOffset: Int64 = 0 ): TStringList;
- function GetVar( SQL: String; Column: Integer = 0 ): String; overload;
- function GetVar( SQL: String; Column: String ): String; overload;
-
- property ThreadId: Cardinal read GetThreadId;
- property Handle: PMYSQL read FHandle;
- property CharacterSet: String read GetCharacterSet;
- property LastError: String read GetLastError;
- property ServerVersionStr: String read GetServerVersionStr;
- property ServerVersionInt: Integer read GetServerVersionInt;
- property Capabilities: TMySQLServerCapabilities read FCapabilities;
- property RowsFound: Int64 read FRowsFound;
- property RowsAffected: Int64 read FRowsAffected;
-
- published
- property Active: Boolean read FActive write SetActive default False;
- property Hostname: String read FHostname write FHostname;
- property Port: Cardinal read FPort write FPort default MYSQL_PORT;
- property Username: String read FUsername write FUsername;
- property Password: String read FPassword write FPassword;
- property Timeout: Cardinal read FTimeout write FTimeout default NET_READ_TIMEOUT;
- property Database: String read FDatabase write SetDatabase;
- property Options: TMySQLClientOptions read FOptions write FOptions default DEFAULT_MYSQLOPTIONS;
-
- // Events
- property OnLog: TMySQLLogEvent read FOnLog write FOnLog;
- end;
-
-
- { *********** }
- { TMySQLQuery }
- { *********** }
-
- TMySQLQuery = class(TDataSet)
- private
- FSQL: TStrings;
- FConnection: TMySQLConnection;
- FRowsAffected: Int64;
- FLastResult: PMYSQL_RES;
- FRecNo: Int64;
- FCurrentRow: PMYSQL_ROW;
- procedure SetQuery(Value: TStrings);
- protected
- function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
- procedure SetFieldData(Field: TField; Buffer: Pointer); override;
- function GetRecordSize: Word; override;
- function GetCanModify: Boolean; override;
- procedure InternalOpen; override;
- procedure InternalClose; override;
- procedure InternalInitFieldDefs; override;
- procedure InternalHandleException; override;
- procedure InternalInitRecord(Buffer: PChar); override;
- function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
- procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
- procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
- procedure InternalSetToRecord(Buffer: PChar); override;
- function IsCursorOpen: Boolean; override;
- procedure InternalFirst; override;
- procedure InternalLast; override;
- procedure InternalEdit; override;
- procedure InternalInsert; override;
- procedure InternalPost; override;
- procedure InternalDelete; override;
- function GetRecNo: Integer; override;
- function GetRecordCount: Integer; override;
- procedure SetRecNo(Value: Integer); override;
-
- public
- constructor Create(AOwner: TComponent); override;
- procedure ExecSQL;
- property RowsAffected: Int64 read FRowsAffected;
- function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;
- published
- property SQL: TStrings read FSQL write SetQuery;
- property Connection: TMySQLConnection read FConnection write FConnection;
-
- property AutoCalcFields;
- property BeforeOpen;
- property AfterOpen;
- property BeforeClose;
- property AfterClose;
- property BeforeRefresh;
- property AfterRefresh;
- property BeforeScroll;
- property AfterScroll;
- property OnCalcFields;
- property OnFilterRecord;
- property Filter;
- property Filtered;
- end;
-
- procedure Register;
-
- // Should be removed when this baby is running
- procedure debug(txt: String);
-
-
-implementation
-
-
-procedure debug(txt: String);
-begin
- txt := 'mds '+txt;
- OutputDebugString(PChar(txt));
-end;
-
-procedure Register;
-begin
- RegisterComponents('MySQL Dataset', [TMySQLConnection, TMySQLQuery]);
-end;
-
-
-
-{ **************** }
-{ TMySQLConnection }
-{ **************** }
-
-constructor TMySQLConnection.Create(AOwner: TComponent);
-begin
- inherited Create(AOwner);
- FOptions := DEFAULT_MYSQLOPTIONS;
- FTimeout := NET_READ_TIMEOUT;
- FPort := MYSQL_PORT;
- FRowsFound := -1;
- FRowsAffected := -1;
-end;
-
-
-{**
- (Dis-)Connect to/from server
- Parts copied from MySQL-Front or revision 1 of HeidiSQL's childwin.pas
-}
-procedure TMySQLConnection.SetActive( Value: Boolean );
-var
- connected : PMYSQL;
- ClientFlags : Integer;
- error : String;
-begin
- FActive := Value;
-
- if Value and (FHandle = nil) then
- begin
- // Get handle
- FHandle := mysql_init(nil);
- // timeout
- mysql_options(FHandle, MYSQL_OPT_CONNECT_TIMEOUT, @FTimeout);
-
- // read ini-file
- // mysql_options(FHandle, MYSQL_READ_DEFAULT_FILE, pchar(ExtractFilePath(paramstr(0)) + 'my.ini'));
- // read [Client]-section from ini-file
- mysql_options(FHandle, MYSQL_READ_DEFAULT_GROUP, pchar('Client'));
-
- // Gather client options
- ClientFlags := 0;
- if opRememberOptions in FOptions then ClientFlags := ClientFlags or CLIENT_REMEMBER_OPTIONS;
- if opLongPassword in FOptions then ClientFlags := ClientFlags or CLIENT_LONG_PASSWORD;
- if opFoundRows in FOptions then ClientFlags := ClientFlags or CLIENT_FOUND_ROWS;
- if opLongFlag in FOptions then ClientFlags := ClientFlags or CLIENT_LONG_FLAG;
- if opConnectWithDb in FOptions then ClientFlags := ClientFlags or CLIENT_CONNECT_WITH_DB;
- if opNoSchema in FOptions then ClientFlags := ClientFlags or CLIENT_NO_SCHEMA;
- if opCompress in FOptions then ClientFlags := ClientFlags or CLIENT_COMPRESS;
- if opODBC in FOptions then ClientFlags := ClientFlags or CLIENT_ODBC;
- if opLocalFiles in FOptions then ClientFlags := ClientFlags or CLIENT_LOCAL_FILES;
- if opIgnoreSpace in FOptions then ClientFlags := ClientFlags or CLIENT_IGNORE_SPACE;
- if opProtocol41 in FOptions then ClientFlags := ClientFlags or CLIENT_PROTOCOL_41;
- if opInteractive in FOptions then ClientFlags := ClientFlags or CLIENT_INTERACTIVE;
- if opSSL in FOptions then ClientFlags := ClientFlags or CLIENT_SSL;
- if opIgnoreSigpipe in FOptions then ClientFlags := ClientFlags or CLIENT_IGNORE_SIGPIPE;
- if opTransactions in FOptions then ClientFlags := ClientFlags or CLIENT_TRANSACTIONS;
- if opReserved in FOptions then ClientFlags := ClientFlags or CLIENT_RESERVED;
- if opSecureConnection in FOptions then ClientFlags := ClientFlags or CLIENT_SECURE_CONNECTION;
- if opMultiStatements in FOptions then ClientFlags := ClientFlags or CLIENT_MULTI_STATEMENTS;
- if opMultiResults in FOptions then ClientFlags := ClientFlags or CLIENT_MULTI_RESULTS;
- if opRememberOptions in FOptions then ClientFlags := ClientFlags or CLIENT_REMEMBER_OPTIONS;
-
- // Connect
- connected := mysql_real_connect(FHandle,
- pChar(FHostname),
- pChar(FUsername),
- pChar(FPassword),
- nil,
- FPort,
- nil,
- ClientFlags
- );
- if connected = nil then
- begin
- error := LastError;
- Log( lcError, error );
- FActive := False;
- FHandle := nil;
- raise Exception.Create( error );
- end
- else begin
- DetectCapabilities;
- Log( lcStats, 'Connection established with host "'+Hostname+'" on port '+IntToStr(Port)+' as user "'+Username+'"' );
- Log( lcStats, 'Connection-ID: '+IntToStr(ThreadId) );
- Log( lcStats, 'Characterset: '+CharacterSet );
- Log( lcStats, 'Server version: '+ServerVersionStr+' ('+IntToStr(ServerVersionInt)+')' );
- SetDatabase( FDatabase );
- end;
- end
-
- else if (not Value) and (FHandle <> nil) then
- begin
- mysql_close(FHandle);
- FHandle := nil;
- FCapabilities := [];
- Log( lcStats, 'Connection closed' );
- end;
-
-end;
-
-
-{**
- Executes a query
-}
-function TMySQLConnection.Query(SQL: string): PMYSQL_RES;
-var
- querystatus : Integer;
-begin
- if Not FActive then
- SetActive( True );
- Log( lcSQL, Trim(Copy(SQL, 1, 1024)) );
- querystatus := mysql_real_query(FHandle, pChar(SQL), length(SQL));
- if querystatus <> 0 then
- begin
- Log( lcError, GetLastError );
- raise Exception.Create(GetLastError);
- end
- else begin
- FRowsAffected := mysql_affected_rows( FHandle );
- Log( lcStats, IntToStr(RowsAffected)+' rows affected.' );
- Result := mysql_store_result( FHandle );
- try
- FRowsFound := mysql_num_rows( Result );
- Log( lcStats, IntToStr(RowsFound)+' rows found.' );
- except
- // mysql_num_rows caused an exception.
- // Now we know that the query was a non-result-query.
- Log( lcInternal, 'Query returned empty resultset.' );
- mysql_free_result( Result );
- Result := nil;
- end;
- end;
-end;
-
-
-{**
- Set "Database" property and select that db if connected
-}
-procedure TMySQLConnection.SetDatabase( Value: String );
-var
- oldValue : String;
-begin
- if Value = '' then
- Exit;
-
- oldValue := FDatabase;
- FDatabase := Value;
-
- // Switch to DB if connected.
- // If not connected, SetDatabase() should be called by SetActive()
- if FActive then
- try
- Query( 'USE '+QuoteIdent(Value) );
- Log( lcStats, 'Database "'+Value+'" selected' )
- except
- On E:Exception do
- begin
- FDatabase := oldValue;
- raise Exception.Create(e.Message);
- end;
- end;
-end;
-
-
-{**
- Return current thread id
-}
-function TMySQLConnection.GetThreadId: Cardinal;
-begin
- Result := mysql_thread_id( FHandle );
-end;
-
-
-{**
- Return currently used character set
-}
-function TMySQLConnection.GetCharacterSet: String;
-begin
- Result := mysql_character_set_name( FHandle );
-end;
-
-
-{**
- Return the last error nicely formatted
-}
-function TMySQLConnection.GetLastError: String;
-begin
- Result := Format('SQL Error (%d): %s', [mysql_errno(FHandle), mysql_error(FHandle)] );
-end;
-
-
-{**
- Return the untouched server version string
-}
-function TMySQLConnection.GetServerVersionStr: String;
-begin
- Result := mysql_get_server_info(FHandle);
-end;
-
-
-{**
- Get version string as normalized integer
- "5.1.12-beta-community-123" => 50112
-}
-function TMySQLConnection.GetServerVersionInt: Integer;
-var
- i, dots: Byte;
- fullversion, v1, v2, v3: String;
-begin
- Result := -1;
-
- dots := 0;
- // Avoid calling GetServerVersionStr too often
- fullversion := ServerVersionStr;
- v1 := '';
- v2 := '';
- v3 := '';
- for i := 1 to Length(fullversion) do
- begin
- if fullversion[i] = '.' then
- begin
- inc(dots);
- // We expect exactly 2 dots.
- if dots > 2 then
- break;
- end
- else if fullversion[i] in ['0'..'9'] then
- begin
- if dots = 0 then
- v1 := v1 + fullversion[i]
- else if dots = 1 then
- v2 := v2 + fullversion[i]
- else if dots = 2 then
- v3 := v3 + fullversion[i];
- end
- else // Don't include potential numbers of trailing string
- break;
- end;
-
- // Concat tokens
- if (Length(v1)>0) and (Length(v2)>0) and (Length(v3)>0) then
- begin
- Result := StrToIntDef(v1, 0) *10000 +
- StrToIntDef(v2, 0) *100 +
- StrToIntDef(v3, 0);
- end;
-
-end;
-
-
-{**
- Call log event if assigned to object
-}
-procedure TMySQLConnection.Log(Category: TMySQLLogCategory; Msg: String);
-begin
- if Assigned(FOnLog) then
- FOnLog( Category, Msg);
-end;
-
-
-{**
- Escapes a string for usage in SQL queries
-}
-function TMySQLConnection.EscapeString( Text: String; DoQuote: Boolean ): String;
-var
- BufferLen: Integer;
- Buffer: PChar;
-begin
- BufferLen := Length(Text) * 2 + 1;
- GetMem(Buffer, BufferLen);
- BufferLen := mysql_real_escape_string(FHandle, Buffer, PChar(Text), Length(Text));
- SetString(Result, Buffer, BufferLen);
- FreeMem(Buffer);
-
- if DoQuote then
- Result := '''' + Result + '''';
-end;
-
-
-{**
- Add backticks to identifier
- Todo: Support ANSI style
-}
-function TMySQLConnection.QuoteIdent( Identifier: String ): String;
-begin
- if cpBackticks in Capabilities then
- begin
- Result := StringReplace(Identifier, '`', '``', [rfReplaceAll]);
- Result := '`' + Result + '`';
- end
- else
- Result := Identifier;
-end;
-
-
-{**
- Detect various capabilities of the server
- for easy feature-checks in client-applications.
-}
-procedure TMySQLConnection.DetectCapabilities;
-var
- ver : Integer;
- procedure addCap( c: TMySQLServerCapability; addit: Boolean );
- begin
- if addit then
- Include( FCapabilities, c )
- else
- Exclude( FCapabilities, c );
- end;
-begin
- // Avoid calling GetServerVersionInt too often
- ver := ServerVersionInt;
-
- addCap( cpShowEngines, ver >= 40102 );
- addCap( cpShowTableStatus, ver >= 32300 );
- addCap( cpShowFullTables, ver >= 50002 );
- addCap( cpShowCreateTable, ver >= 32320 );
- addCap( cpShowCreateDatabase, ver >= 50002 );
- addCap( cpHelpSystem, ver >= 40100 );
- addCap( cpSetNames, ver >= 40100 );
- addCap( cpCalcFoundRows, ver >= 40000 );
- addCap( cpLoadFile, ver >= 32206 );
- addCap( cpTableComment, ver >= 32300 );
- addCap( cpFieldComment, ver >= 40100 );
- addCap( cpColumnMoving, ver >= 40001 );
- addCap( cpTruncateTable, ver >= 50003 );
- addCap( cpBackticks, ver >= 32300 );
- addCap( cpAlterDatabase, ver >= 50002 );
- addCap( cpRenameDatabase, ver >= 50107 );
-
-end;
-
-
-{**
- Get one row via SQL query as TStringList
- Todo: free res after raising exception
-}
-function TMySQLConnection.GetRow( SQL: String; RowOffset: Int64 = 0 ): TStringList;
-var
- res : PMYSQL_RES;
- row : PMYSQL_ROW;
- field : PMYSQL_FIELD;
- i : Integer;
-begin
- Result := TStringList.Create;
- res := Query( SQL );
- if RowsFound < RowOffset+1 then
- raise Exception.Create( 'Error ('+Self.ClassName+'): Query returned not enough rows: '+IntToStr(RowsFound)+', wanted offset: '+IntToStr(RowOffset) );
- mysql_data_seek( res, RowOffset );
- row := mysql_fetch_row( res );
- for i := 0 to mysql_num_fields(res) - 1 do
- begin
- field := mysql_fetch_field_direct( res, i );
- Result.Values[field.name] := row[i];
- end;
- mysql_free_result(res);
-end;
-
-
-{**
- Get single cell value via SQL query, identified by column number
- Todo: free row after raising exception
-}
-function TMySQLConnection.GetVar( SQL: String; Column: Integer = 0 ): String;
-var
- row : TStringList;
-begin
- row := GetRow( SQL );
- if row.Count < Column+1 then
- raise Exception.Create( 'Error ('+Self.ClassName+'): Fetching field nr. '+IntToStr(Column)+' not possible - query returned '+IntToStr(row.Count)+' fields.' );
- Result := row.ValueFromIndex[Column];
- FreeAndNil(row);
-end;
-
-
-{**
- Get single cell value via SQL query, identified by column name
- Todo: free row after raising exception
-}
-function TMySQLConnection.GetVar( SQL: String; Column: String ): String;
-var
- row : TStringList;
- i : Integer;
- colexists : Boolean;
-begin
- row := GetRow( SQL );
- colexists := False;
- for i := 0 to row.Count - 1 do
- begin
- if LowerCase(row.Names[i]) = LowerCase(Column) then
- begin
- colexists := True;
- break;
- end;
- end;
- if not colexists then
- raise Exception.Create( 'Error ('+Self.ClassName+'): Field "'+Column+'" does not exist in resultset.' );
- Result := row.Values[Column];
- FreeAndNil(row);
-end;
-
-
-
-
-{ *********** }
-{ TMySQLQuery }
-{ *********** }
-
-constructor TMySQLQuery.Create(AOwner: TComponent);
-begin
- inherited Create(AOwner);
- FSQL := TStringList.Create;
- FRowsAffected := -1;
- FRecNo := -1;
-end;
-
-
-{**
- Executes a query without handling the resultset
-}
-procedure TMySQLQuery.ExecSQL;
-var
- res: PMYSQL_RES;
-begin
- res := FConnection.Query( FSQL.Text );
- // Important to temporary store the number of affected rows now
- // because the connection object is free to execute further queries now.
- FRowsAffected := Connection.RowsAffected;
- // Free result, we don't do anything with it in ExecSQL
- mysql_free_result( res );
-end;
-
-
-{**
- Set SQL TStringList
-}
-procedure TMySQLQuery.SetQuery(Value: TStrings);
-begin
- if FSQL.Text <> Value.Text then
- begin
- FSQL.BeginUpdate;
- try
- FSQL.Assign(Value);
- finally
- FSQL.EndUpdate;
- end;
- end;
-end;
-
-
-{**
- The most important method for a TDataset:
- Navigate to and fetch the current, next or prior row
-}
-function TMySQLQuery.GetRecord(Buffer: PChar; GetMode: TGetMode;
- DoCheck: Boolean): TGetResult;
-begin
- Result := grOK;
-
- case GetMode of
- gmCurrent:
- begin
- if (RecNo < 0) or (RecNo >= RecordCount) then
- Result := grError
- else
- Result := grOK;
- end;
-
- gmNext:
- if RecNo >= RecordCount then
- Result := grEOF
- else
- begin
- RecNo := RecNo + 1;
- Result := grOK;
- end;
-
- gmPrior:
- if RecNo <= 0 then
- Result := grBOF
- else
- begin
- RecNo := RecNo - 1;
- Result := grOK;
- end;
- end;
-
- if Result = grOK then
- begin
- FCurrentRow := mysql_fetch_row( FLastResult );
- System.Move(
- FCurrentRow,
- Buffer,
- SizeOf(FCurrentRow)
- );
- end;
-
-end;
-
-function TMySQLQuery.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
-begin
- {
- The Field parameter is the field for which the value needs to be retrieved.
- The Field parameter is only passed for reference and should never be altered by this routine.
-
- The Buffer parameter is where the field value needs to be copied to.
- Looking at the buffer parameter results in a question that doesn't have an
- obvious answer at first glance. That question is "What size is that buffer
- and what needs to be copied into it?". The only way of determining this is
- by looking at the various TField types in DB.pas and examining their GetValue
- and GetDataSize methods.
-
- Here is a partial table with some values used in the base dataset we will create later on:
- Field Type Buffer Result
- ftInteger,ftDate,ftTime Integer
- ftBoolean Boolean
- ftDateTime TDateTimeRec
- ftFloat,ftCurrency Double
- ftString PChar
-
- As we can see, most types map pretty cleanly with the noteable exception of TDateTime
- which requires some translation into a TDateTimeRec.
-
- GetFieldData function returns True if a value was copied into the buffer by the
- method and False if no value was copied.
-
- That covers the GetFieldData method.
- }
- FConnection.Log(lcInternal, 'GetFieldData called for RecNo '+inttostr(RecNo)+' field "'+Field.Name+'" ('+inttostr(field.FieldNo)+')');
- if Field.DataType = ftString then
- begin
- System.Move(
- FCurrentRow[Field.FieldNo-1]^,
- //ZEOS: RowAccessor.GetColumnData(ColumnIndex, Result)^,
- Buffer,
- //ZEOS: RowAccessor.GetColumnDataSize(ColumnIndex)
- SizeOf(FCurrentRow[Field.FieldNo-1])
- );
- Result := True;
- end
- else
- Result := False;
-end;
-
-
-{**
- Tell dataset the contents of a field
-}
-procedure TMySQLQuery.SetFieldData(Field: TField; Buffer: Pointer);
-begin
- { SetFieldData is the exact reverse operation
- of GetFieldData. It is passed a buffer with some field value in the buffer that
- must then be copied back into your record buffer.
- }
- if Field.DataType = ftString then
- begin
- System.Move(
- Buffer^,
- FCurrentRow,
- SizeOf(FCurrentRow)
- );
- end;
-end;
-
-
-{**
- ??
-}
-function TMySQLQuery.GetRecordSize: Word;
-begin
- Result := 1;
-end;
-
-
-{**
- Dataset is editable?
- Should be True for simple SELECTs and False for not parsable SELECTs
-}
-function TMySQLQuery.GetCanModify: Boolean;
-begin
- Result := True;
-end;
-
-
-{**
- Send query and fetch resultset
-}
-procedure TMySQLQuery.InternalOpen;
-begin
- FLastResult := FConnection.Query( FSQL.Text );
- FieldDefs.Clear;
- FieldDefs.Update; // Calls InternalInitFieldDefs
-
- if DefaultFields then CreateFields;
- BindFields(True);
-end;
-
-
-{**
- Close resultset
-}
-procedure TMySQLQuery.InternalClose;
-begin
- mysql_free_result(FLastResult);
-end;
-
-
-{**
- Fetch field types of recent resultset
-}
-procedure TMySQLQuery.InternalInitFieldDefs;
-var
- def: TFieldDef;
- i, numfields: Cardinal;
- field: PMYSQL_FIELD;
- fType: TFieldType;
-
- // Detect signed flag of a field
- function Signed: Boolean;
- begin
- Result := (UNSIGNED_FLAG and field.flags) = 0;
- end;
-
-begin
- numfields := mysql_num_fields(FLastResult);
-
- for i := 0 to numfields-1 do
- begin
- field := mysql_fetch_field_direct(FLastResult, i);
-
- // Create a new field
- def := FieldDefs.AddFieldDef;
- def.FieldNo := i;
- def.Name := field.name;
-
- // Map field type to delphi-types
- // see TFieldType in DB.pas
- case field._type of
- FIELD_TYPE_TINY:
- fType := ftSmallint;
-
- FIELD_TYPE_YEAR, FIELD_TYPE_SHORT:
- fType := ftInteger;
-
- FIELD_TYPE_INT24, FIELD_TYPE_LONG:
- begin
- if Signed then
- fType := ftInteger
- else
- fType := ftFloat;
- end;
-
- FIELD_TYPE_LONGLONG:
- fType := ftString;
-
- FIELD_TYPE_FLOAT:
- fType := ftFloat;
-
- FIELD_TYPE_DECIMAL, FIELD_TYPE_NEWDECIMAL:
- begin
- if (field.decimals = 0) and (field.length < 11) then
- fType := ftInteger
- else
- fType := ftFloat;
- end;
-
- FIELD_TYPE_DOUBLE:
- fType := ftFloat;
-
- FIELD_TYPE_DATE:
- fType := ftString;
-
- FIELD_TYPE_TIME:
- fType := ftString;
-
- FIELD_TYPE_DATETIME, FIELD_TYPE_TIMESTAMP:
- fType := ftString;
-
- FIELD_TYPE_TINY_BLOB, FIELD_TYPE_MEDIUM_BLOB,
- FIELD_TYPE_LONG_BLOB, FIELD_TYPE_BLOB:
- if (field.flags and BINARY_FLAG) = 0 then
- fType := ftMemo
- else
- fType := ftBlob;
-
- FIELD_TYPE_BIT:
- fType := ftBlob;
-
- FIELD_TYPE_VARCHAR:
- fType := ftString;
-
- FIELD_TYPE_VAR_STRING:
- fType := ftString;
-
- FIELD_TYPE_STRING:
- fType := ftString;
-
- FIELD_TYPE_ENUM:
- fType := ftString;
-
- FIELD_TYPE_SET:
- fType := ftString;
-
- FIELD_TYPE_NULL:
- // Example: SELECT NULL FROM DUAL
- // Todo: Find out if it is possible to get real data in a
- // TYPE_NULL field, perhaps adjust to binary or some such?
- fType := ftString;
-
- FIELD_TYPE_GEOMETRY:
- // Todo: Would be nice to show as WKT.
- fType := ftBlob;
-
- else
- raise Exception.Create('Unknown MySQL data type!'+IntToStr(field._type));
- end;
-
- def.DataType := fType;
- if fType in [ftString, ftWidestring, ftBytes] then
- def.Size := field.length
- else
- def.Size := 0;
-
- def.Required := (field.flags and NOT_NULL_FLAG) = NOT_NULL_FLAG;
- def.Precision := field.length;
-
- end;
-end;
-
-
-procedure TMySQLQuery.InternalHandleException;
-begin
- // Application.HandleException(Self); ?
-end;
-
-
-{**
- ??
-}
-procedure TMySQLQuery.InternalInitRecord(Buffer: PChar);
-begin
-end;
-
-
-{**
- ??
-}
-function TMySQLQuery.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
-begin
-end;
-
-
-{**
- ??
-}
-procedure TMySQLQuery.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
-begin
-end;
-
-
-{**
- ??
-}
-procedure TMySQLQuery.GetBookmarkData(Buffer: PChar; Data: Pointer);
-begin
-end;
-
-
-{**
- ??
-}
-procedure TMySQLQuery.InternalSetToRecord(Buffer: PChar);
-begin
-end;
-
-
-{**
- ??
-}
-function TMySQLQuery.IsCursorOpen: Boolean;
-begin
- // Result := Handle <> nil; ?
-end;
-
-
-{**
- Called by DataSet.First
-}
-procedure TMySQLQuery.InternalFirst;
-begin
- FRecNo := 0;
- mysql_data_seek( FLastResult, FRecNo );
-end;
-
-
-{**
- Called by DataSet.Last
-}
-procedure TMySQLQuery.InternalLast;
-begin
- FRecNo := mysql_num_rows( FLastResult )-1;
- mysql_data_seek( FLastResult, FRecNo );
-end;
-
-
-{**
- ??
-}
-procedure TMySQLQuery.InternalEdit;
-begin
-end;
-
-
-{**
- Fill default values?
-}
-procedure TMySQLQuery.InternalInsert;
-begin
-end;
-
-
-{**
- Generate UPDATE or INSERT statement?
-}
-procedure TMySQLQuery.InternalPost;
-begin
- inherited;
-end;
-
-
-{**
- Generate DELETE statement?
-}
-procedure TMySQLQuery.InternalDelete;
-begin
-end;
-
-
-{**
- Called by DataSet.RecNo
-}
-function TMySQLQuery.GetRecNo: Integer;
-begin
- Result := FRecNo;
-end;
-
-
-{**
- Called by DataSet.RecordCount
-}
-function TMySQLQuery.GetRecordCount: Integer;
-begin
- Result := mysql_num_rows( FLastResult );
-end;
-
-
-{**
- Navigate to record
-}
-procedure TMySQLQuery.SetRecNo(Value: Integer);
-begin
- if Value > RecordCount then
- Value := RecordCount-1;
- FRecNo := Value;
- mysql_data_seek( FLastResult, FRecNo );
-end;
-
-
-
-end.
diff --git a/packages/delphi11/heidisql.dpr b/packages/delphi11/heidisql.dpr
index 58793d58..9fff450f 100644
--- a/packages/delphi11/heidisql.dpr
+++ b/packages/delphi11/heidisql.dpr
@@ -17,14 +17,7 @@ uses
insertfiles in '..\..\source\insertfiles.pas' {frmInsertFiles},
insertfiles_progress in '..\..\source\insertfiles_progress.pas' {frmInsertFilesProgress},
helpers in '..\..\source\helpers.pas',
- synchronization in '..\..\source\synchronization.pas',
- communication in '..\..\source\communication.pas',
- threading in '..\..\source\threading.pas',
sqlhelp in '..\..\source\sqlhelp.pas' {frmSQLhelp},
- queryprogress in '..\..\source\queryprogress.pas' {frmQueryProgress},
- mysqlquery in '..\..\source\mysqlquery.pas',
- mysqlquerythread in '..\..\source\mysqlquerythread.pas',
- mysqlconn in '..\..\source\mysqlconn.pas',
mysql_structures in '..\..\source\mysql_structures.pas',
column_selection in '..\..\source\column_selection.pas' {ColumnSelectionForm},
data_sorting in '..\..\source\data_sorting.pas' {DataSortingForm},
@@ -40,7 +33,9 @@ uses
uVistaFuncs in '..\..\source\uVistaFuncs.pas',
dataviewsave in '..\..\source\dataviewsave.pas' {FrmDataViewSave},
routine_editor in '..\..\source\routine_editor.pas' {frmRoutineEditor},
- table_editor in '..\..\source\table_editor.pas' {frmTableEditor};
+ table_editor in '..\..\source\table_editor.pas' {frmTableEditor},
+ mysql_api in '..\..\source\mysql_api.pas',
+ mysql_connection in '..\..\source\mysql_connection.pas';
{$R ..\..\res\icon.RES}
{$R ..\..\res\version.RES}
@@ -54,26 +49,6 @@ begin
Application.CreateForm(TMainForm, MainForm);
Application.OnMessage := Mainform.OnMessageHandler;
debug('perf: Main created.');
-
- try
- try
- InitializeSync(MainForm.Handle);
- SetWindowName(main.discname);
- InitializeThreading(MainForm.Handle);
- InitializeComm(
- MainForm.Handle,
- MainForm.ExecuteRemoteNonQuery,
- MainForm.ExecuteRemoteQuery
- );
- debug('perf: Running.');
- MainForm.Startup;
- Application.Run;
- finally
- DeInitializeSync;
- end;
- except
- on e: Exception do begin
- ShowMessage(e.ClassName + ': ' + e.Message);
- end;
- end;
+ MainForm.Startup;
+ Application.Run;
end.
diff --git a/packages/delphi11/heidisql.dproj b/packages/delphi11/heidisql.dproj
index ee40dad3..235b3d84 100644
--- a/packages/delphi11/heidisql.dproj
+++ b/packages/delphi11/heidisql.dproj
@@ -155,10 +155,9 @@
+
+
-
-
-
@@ -168,9 +167,6 @@
-
-
-
@@ -183,7 +179,6 @@
-
diff --git a/source/column_selection.pas b/source/column_selection.pas
index 94af9acb..003c9c27 100644
--- a/source/column_selection.pas
+++ b/source/column_selection.pas
@@ -4,7 +4,7 @@ interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls, CheckLst, ExtCtrls, TntCheckLst, WideStrings, DB;
+ Dialogs, StdCtrls, CheckLst, ExtCtrls, TntCheckLst, WideStrings, mysql_connection;
type
TColumnSelectionForm = class(TForm)
@@ -52,13 +52,13 @@ end;
}
procedure TColumnSelectionForm.FormShow(Sender: TObject);
var
- ds: TDataSet;
+ Results: TMySQLQuery;
begin
- ds := Mainform.SelectedTableColumns;
- ds.First;
- while not ds.Eof do begin
- chklistColumns.Items.Add(ds.Fields[0].AsWideString);
- ds.Next;
+ Results := Mainform.SelectedTableColumns;
+ Results.First;
+ while not Results.Eof do begin
+ chklistColumns.Items.Add(Results.Col(0));
+ Results.Next;
end;
// Check items!
@@ -153,7 +153,7 @@ procedure TColumnSelectionForm.chkSortClick(Sender: TObject);
var
checkedfields : TStringList;
i: Integer;
- ds: TDataSet;
+ Results: TMySQLQuery;
begin
// Memorize checked items in a list
checkedfields := TStringList.Create;
@@ -170,11 +170,11 @@ begin
// Add all fieldnames again
chklistColumns.Items.BeginUpdate;
chklistColumns.Clear;
- ds := Mainform.SelectedTableColumns;
- ds.First;
- while not ds.Eof do begin
- chklistColumns.Items.Add(ds.Fields[0].AsWideString);
- ds.Next;
+ Results := Mainform.SelectedTableColumns;
+ Results.First;
+ while not Results.Eof do begin
+ chklistColumns.Items.Add(Results.Col(0));
+ Results.Next;
end;
chklistColumns.Items.EndUpdate;
end;
diff --git a/source/communication.pas b/source/communication.pas
deleted file mode 100644
index 97b2224d..00000000
--- a/source/communication.pas
+++ /dev/null
@@ -1,514 +0,0 @@
-unit communication;
-
-(*
- Functions for Inter-Process Communication.
-
- Note about WM_COPYDATA:
- This message must be sent synchronously with SendMessage,
- cannot be sent asynchronously using PostMessage. I think
- the reason is related to the idea behind WM_COPYDATA causing
- Windows to do a context switch to the receiving application..
-*)
-
-
-interface
-
-uses
- Db,
- Windows,
- Threading,
- Classes,
- Messages;
-
-const
- // Our custom message types.
- WM_COMPLETED = WM_APP + 1;
- WM_PROCESSLOG = WM_APP + 2;
- WM_MYSQL_THREAD_NOTIFY = WM_APP + 3;
- WM_CLEAR_RIGHTCLICK_POINTER = WM_APP + 4;
- WM_REFILL_SPAREBUF = WM_APP + 5;
- // Our message subtypes for WM_COPYDATA messages.
- CMD_EXECUTEQUERY_NORESULTS = 1; { Slightly faster - Fire-and-forget, no results }
- CMD_EXECUTEQUERY_RESULTS = 2; { Normal - Wait for completion, fetch results }
- RES_QUERYDATA = 257;
- RES_EXCEPTION = 258;
- RES_NONQUERY = 259;
- // Our custom return codes.
- ERR_NOERROR = 0;
- ERR_UNSPECIFIED = 1;
-
-type
- TNonQueryRunner = procedure(sendingApp: THandle; query: string) of object;
- TQueryRunner = function(sendingApp: THandle; query: string): TDataSet of object;
-
-
-(*
- Run this procedure at application startup.
-*)
-procedure InitializeComm(myWindow: THandle; nonQueryRunner: TNonQueryRunner; queryRunner: TQueryRunner);
-
-(*
- Execute a query on another window, request results but don't wait for them.
-*)
-function RemoteExecSqlAsync(handler: TCompletionHandler; timeout: Cardinal; window: THandle; query: String; method: DWORD; waitControl: TObject = nil): Cardinal;
-
-(*
- Execute a query on another window, showing a wait dialog while processing
- and calling a completion handler via messaging when done.
-*)
-function RemoteExecSql(handler: TCompletionHandler; timeout: Cardinal; window: THandle; query: String; info: String; method: DWORD): Cardinal;
-
-(*
- Execute a query on another window, showing a wait dialog while processing
- and returning results or raising an exception when done.
-*)
-function RemoteExecQuery(window: THandle; query: String; info: String): TDataSet;
-
-(*
- Execute a query on a window.
-*)
-procedure RemoteExecNonQuery(window: THandle; query: string; info: string = '');
-
-(*
- Execute a USE query on a window,
- given the version of the mysql server that window is connected to.
-*)
-procedure RemoteExecUseNonQuery(window: THandle; mysqlVersion: integer; dbName: string; info: string = '');
-
-(*
- Fill in resulting data and return waiting thread to caller.
- Call from message handler when a query has finished executing and results are ready.
-*)
-procedure FinishRemoteExecution(msg: TWMCopyData);
-
-(*
- Slightly lame wrapper: Call to release a RemoteXXX SendMessage call on the "other side".
-*)
-procedure ReleaseRemoteCaller(errCode: integer);
-
-(*
- Extract a SQL query from a WM_COPYDATA message.
-*)
-function GetQueryFromMsg(msg: TWMCopyData): string;
-
-(*
- Extract a request id from a WM_COPYDATA message.
-*)
-function GetRequestIdFromMsg(msg: TWMCopyData): Cardinal;
-
-(*
- Helper which will handle WM_COMPLETED messages received.
-*)
-procedure HandleWMCompleteMessage(var msg: TMessage);
-
-(*
- Helper which will handle WM_COPYDATA messages received.
-*)
-procedure HandleWMCopyDataMessage(var msg: TWMCopyData);
-
-
-implementation
-
-uses
- Forms,
- Dialogs,
- AdoDb,
- AdoInt,
- ActiveX,
- Helpers,
- SysUtils;
-
-type
- TCopyDataStruct = packed record
- dwData: LongWord; // up to 32 bits of data to be passed to the receiving application.
- cbData: LongWord; // the size, in bytes, of the data pointed to by the lpData member.
- lpData: Pointer; // points to data to be passed to the receiving application. This member can be nil.
- end;
-
-var
- sender: THandle;
- nqRunner: TNonQueryRunner;
- qRunner: TQueryRunner;
-
-
-function CopyDataSetToAdoDataSet(src: TDataSet): TAdoDataSet;
-var
- dst: TAdoDataSet;
- i: Integer;
-begin
- dst := TAdoDataSet.Create(nil);
- dst.FieldDefs.Assign(src.FieldDefs);
- dst.CreateDataSet;
- src.First;
- while not src.Eof do begin
- dst.Append;
- for i := 0 to dst.FieldCount - 1 do begin
- dst.Fields[i].Assign(src.Fields[i]);
- end;
- dst.Post;
- src.Next;
- end;
- result := dst;
-end;
-
-
-procedure SendDatasetToRemote(window: THandle; request: Cardinal; resType: integer; ds: TDataSet);
-var
- adods: TAdoDataSet;
- data: TCopyDataStruct;
- ms: TMemoryStream;
- sa: TStreamAdapter;
- olevar: OleVariant;
-begin
- ms := TMemoryStream.Create;
- try
- ms.Write(request, sizeof(Cardinal));
- if resType <> RES_NONQUERY then begin
- adods := CopyDataSetToAdoDataSet(ds);
- sa := TStreamAdapter.Create(ms);
- olevar := adods.Recordset;
- olevar.Save(sa as IStream, 0);
- end;
- debug(Format('ipc: Sending data set to window %d, request id %d, size %d', [window, request, ms.Size]));
- data.dwData := resType;
- data.cbData := ms.Size;
- data.lpData := ms.Memory;
- SendMessage(window, WM_COPYDATA, sender, integer(@data));
- finally
- ms.free;
- end;
-end;
-
-
-procedure SendErrorStringToRemote(window: THandle; request: Cardinal; resType: integer; error: string);
-var
- data: TCopyDataStruct;
- ms: TMemoryStream;
- pcerr: PChar;
-begin
- ms := TMemoryStream.Create;
- try
- ms.Write(request, sizeof(Cardinal));
- pcerr := PChar(error);
- ms.Write(pcerr^, StrLen(pcerr) + 1);
- debug(Format('ipc: Sending error message to window %d, request id %d, size %d', [window, request, ms.Size]));
- data.dwData := resType;
- data.cbData := ms.Size;
- data.lpData := ms.Memory;
- SendMessage(window, WM_COPYDATA, sender, integer(@data));
- finally
- ms.free;
- end;
-end;
-
-
-function GetStringFromMsgInternal(msg: TWMCopyData): string;
-var
- pcsql: PChar;
- ms: TMemoryStream;
-begin
- ms := TMemoryStream.Create;
- try
- with msg.CopyDataStruct^ do begin
- ms.Write(lpData^, cbData);
- ms.Position := sizeof(Cardinal);
- pcsql := StrAlloc(ms.Size - sizeof(Cardinal));
- ms.Read(pcsql^, ms.Size - sizeof(Cardinal));
- result := pcsql;
- end;
- finally
- ms.free;
- end;
-end;
-
-
-function GetQueryFromMsg(msg: TWMCopyData): string;
-begin
- result := GetStringFromMsgInternal(msg);
-end;
-
-
-function GetExceptionTextFromMsg(msg: TWMCopyData): string;
-begin
- result := GetStringFromMsgInternal(msg);
-end;
-
-
-function GetRequestIdFromMsg(msg: TWMCopyData): Cardinal;
-var
- req: Cardinal;
- ms: TMemoryStream;
-begin
- ms := TMemoryStream.Create;
- try
- with msg.CopyDataStruct^ do begin
- ms.Write(lpData^, cbData);
- ms.Position := 0;
- ms.Read(req, sizeof(Cardinal));
- result := req;
- end;
- finally
- ms.free;
- end;
-end;
-
-
-function GetDataSetFromMsg(msg: TWMCopyData): TDataSet;
-var
- adods: TAdoDataSet;
- ms: TMemoryStream;
- sa: TStreamAdapter;
- olevar: OleVariant;
-begin
- ms := TMemoryStream.Create;
- try
- with msg.CopyDataStruct^ do begin
- ms.Write(lpData^, cbData);
- ms.Position := sizeof(Cardinal);
- sa := TStreamAdapter.Create(ms);
- olevar := CoRecordset.Create;
- olevar.Open(sa as IStream);
- adods := TAdoDataSet.Create(nil);
- adods.Recordset := IUnknown(olevar) as _Recordset;
- result := adods;
- end;
- finally
- ms.free;
- end;
-end;
-
-
-procedure RemoteExecSqlInternal(method: DWORD; req: Cardinal; window: THandle; query: String);
-var
- ms: TMemoryStream;
- pcsql: PChar;
- data: TCopyDataStruct;
- err: integer;
-begin
- ms := TMemoryStream.Create;
- try
- debug(Format('ipc: Remote query being requested, id %d.', [req]));
- ms.Write(req, sizeof(Cardinal));
- pcsql := PChar(query);
- ms.Write(pcsql^, StrLen(pcsql) + 1);
- data.dwData := method;
- data.cbData := ms.Size;
- data.lpData := ms.Memory;
- err := SendMessage(window, WM_COPYDATA, sender, integer(@data));
- if err <> 0 then Exception.CreateFmt('Remote returned error %d when asked to execute query', [err]);
- finally
- ms.free;
- end;
-end;
-
-
-function RemoteExecSqlAsync(handler: TCompletionHandler; timeout: Cardinal; window: THandle; query: String; method: DWORD; waitControl: TObject = nil): Cardinal;
-var
- req: Cardinal;
-begin
- req := SetCompletionHandler(handler, timeout, waitControl);
- RemoteExecSqlInternal(method, req, window, query);
- result := req;
-end;
-
-
-function RemoteExecSql(handler: TCompletionHandler; timeout: Cardinal; window: THandle; query: String; info: String; method: DWORD): Cardinal;
-var
- cancelDialog: TForm;
- requestId: Cardinal;
-begin
- if Length(info) = 0 then info := 'Waiting for remote session to execute query...';
- cancelDialog := CreateMessageDialog(info, mtCustom, [mbCancel]);
- requestId := RemoteExecSqlAsync(handler, timeout, window, query, method, cancelDialog);
- // The callback method shouldn't be activated before messages has been processed,
- // so we can safely touch the wait control (a cancel dialog) here.
- cancelDialog.ShowModal;
- // We just cancel in any case.
- // If the query was completed before the cancel dialog closed,
- // the notification code won't accept the cancel, so it's OK.
- NotifyInterrupted(requestId, Exception.Create('User cancelled.'));
- result := RequestId;
-end;
-
-
-function RemoteExecQuery(window: THandle; query: String; info: String): TDataSet;
-var
- requestId: Cardinal;
-begin
- // Call with no handler (= no completion message) and no timeout.
- requestId := RemoteExecSql(nil, INFINITE_TIMEOUT, window, query, info, CMD_EXECUTEQUERY_RESULTS);
- // Take care of results since there's no handler.
- result := TDataSet(ExtractResultObject(requestId));
-end;
-
-
-procedure RemoteExecNonQuery(window: THandle; query: string; info: string);
-var
- requestId: Cardinal;
-begin
- // Call with no handler (= no completion message) and no timeout.
- requestId := RemoteExecSql(nil, INFINITE_TIMEOUT, window, query, info, CMD_EXECUTEQUERY_NORESULTS);
- // Take care of results since there's no handler.
- ExtractResultObject(requestId);
-end;
-
-
-{***
- Note: Broken, will not work as intended.
- Remote window needs to set TemporaryDatabase (and reset it afterwards)
- for this to work. Also, queries are fired asynchronously, so the user
- may change the active database at any point. It is safest to just add
- the database name explicitly in the SQL rather than to run USE remotely.
-}
-procedure RemoteExecUseNonQuery(window: THandle; mysqlVersion: integer; dbName: string; info: string);
-begin
- RemoteExecNonQuery(window, 'USE ' + maskSql(mysqlVersion, dbName), info);
-end;
-
-
-procedure SwitchWaitControlInternal(waitControl: TObject);
-var
- cancelDialog: TForm;
-begin
- // Hide the cancel dialog if it's still showing.
- cancelDialog := TForm(waitControl);
- if (cancelDialog <> nil) and cancelDialog.Visible then cancelDialog.Close;
-end;
-
-
-procedure FinishRemoteExecution(msg: TWMCopyData);
-var
- res: TDataSet;
- req: Cardinal;
- s: string;
-begin
- req := GetRequestIdFromMsg(msg);
- debug(Format('ipc: Remote execute query call finished for request id %d.', [req]));
- case msg.CopyDataStruct^.dwData of
- RES_QUERYDATA: begin
- res := GetDataSetFromMsg(msg);
- NotifyComplete(req, res);
- end;
- RES_EXCEPTION: begin
- s := GetExceptionTextFromMsg(msg);
- NotifyFailed(req, Exception.Create('Error from remote: ' + s));
- end;
- RES_NONQUERY: begin
- // Uses a blank object to indicate completed queries with no result data..
- NotifyComplete(req, TObject.Create());
- end;
- end;
-end;
-
-
-procedure ReleaseRemoteCaller(errCode: integer);
-begin
- // reply to the message so the clients thread is unblocked
- ReplyMessage(errCode);
-end;
-
-
-procedure ReportFinishedQuery(method: DWORD; window: THandle; request: Cardinal; ds: TDataSet);
-var
- resType: DWORD;
-begin
- if method = CMD_EXECUTEQUERY_NORESULTS then resType := RES_NONQUERY
- else resType := RES_QUERYDATA;
- SendDataSetToRemote(window, request, resType, ds);
-end;
-
-
-procedure ReportFailedQuery(method: DWORD; window: THandle; request: Cardinal; error: string); overload;
-begin
- SendErrorStringToRemote(window, request, RES_EXCEPTION, error);
-end;
-
-
-procedure HandleWMCompleteMessage(var msg: TMessage);
-var
- req: Cardinal;
- res: TNotifyStructure;
- callback: TCompletionHandler;
-begin
- debug('ipc: Handling WM_COMPLETED.');
- try
- // Extract results.
- req := msg.LParam;
- res := ExtractResults(req, true);
- // Switch wait control to non-waiting state.
- SwitchWaitControlInternal(res.GetWaitControl);
- // Perform rest of completion via callback, if any.
- callback := res.GetHandler;
- if @callback <> nil then begin
- // Clear results.
- ExtractResults(req);
- // Perform callback.
- callback(res);
- end;
- // Otherwise just assume that completion will be handled
- // by some thread which were waiting for the wait control.
- //
- // In the future, we could explicitly sound an event for
- // this purpose, in case it's not possible to wait on the
- // wait control..
- finally
- ReleaseRemoteCaller(ERR_NOERROR);
- end;
-end;
-
-
-procedure HandleWMCopyDataMessage(var msg: TWMCopyData);
-var
- method: DWORD;
- query: string;
- remoteReqId: integer;
- data: TDataSet;
- //tab: THandle;
-begin
- debug('ipc: Handling WM_COPYDATA.');
- method := msg.CopyDataStruct^.dwData;
- if
- (method = CMD_EXECUTEQUERY_NORESULTS) or
- (method = CMD_EXECUTEQUERY_RESULTS)
- then begin
- try
- remoteReqId := GetRequestIdFromMsg(msg);
- query := GetQueryFromMsg(msg);
- finally
- ReleaseRemoteCaller(ERR_NOERROR);
- end;
- try
- if method = CMD_EXECUTEQUERY_NORESULTS then begin
- nqRunner(msg.From, query);
- ReportFinishedQuery(method, msg.From, remoteReqId, nil);
- end else begin
- data := qRunner(msg.From, query);
- ReportFinishedQuery(method, msg.From, remoteReqId, data);
- end;
- except
- on e: Exception do begin
- ReportFailedQuery(method, msg.From, remoteReqId, e.Message);
- end;
- end;
- end;
- if
- (method = RES_QUERYDATA) or
- (method = RES_EXCEPTION) or
- (method = RES_NONQUERY)
- then begin
- ReleaseRemoteCaller(ERR_NOERROR);
- FinishRemoteExecution(msg);
- end;
-end;
-
-
-procedure InitializeComm(myWindow: THandle; nonQueryRunner: TNonQueryRunner; queryRunner: TQueryRunner);
-begin
- sender := myWindow;
- nqRunner := nonQueryRunner;
- qRunner := queryRunner;
-end;
-
-
-end.
-
diff --git a/source/copytable.pas b/source/copytable.pas
index b88fdf2e..5975186a 100644
--- a/source/copytable.pas
+++ b/source/copytable.pas
@@ -10,8 +10,8 @@ interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- StdCtrls, Buttons, CheckLst, ZDataSet, ComCtrls, WideStrings,
- TntStdCtrls, TntCheckLst;
+ StdCtrls, Buttons, CheckLst, ComCtrls, WideStrings,
+ TntStdCtrls, TntCheckLst, mysql_connection;
type
TCopyTableForm = class(TForm)
@@ -111,7 +111,6 @@ procedure TCopyTableForm.FormShow(Sender: TObject);
var
i : Integer;
struc_data : Byte;
- ds: TDataSet;
NodeData: PVTreeData;
begin
if Mainform.DBtree.Focused then
@@ -132,15 +131,7 @@ begin
comboSelectDatabase.ItemIndex := 0;
// fill columns:
- CheckListBoxFields.Items.Clear;
- ds := Mainform.GetResults( 'SHOW FIELDS FROM ' + mainform.mask(oldTableName) );
- for i:=1 to ds.RecordCount do
- begin
- CheckListBoxFields.Items.Add( ds.Fields[0].AsWideString );
- ds.Next;
- end;
- ds.Close;
- FreeAndNil(ds);
+ CheckListBoxFields.Items.Text := Mainform.Connection.GetCol('SHOW FIELDS FROM ' + mainform.mask(oldTableName)).Text;
// select all:
for i:=0 to CheckListBoxFields.Items.Count-1 do
@@ -174,7 +165,7 @@ var
keystr : WideString;
notnull,
default : WideString;
- zq : TDataSet;
+ Results : TMySQLQuery;
isFulltext : Boolean;
struc_data : Byte;
Fixes : TWideStringlist;
@@ -194,17 +185,17 @@ begin
// keys >
if CheckBoxWithIndexes.Checked then begin
- zq := Mainform.GetResults( 'SHOW KEYS FROM ' + mainform.mask(oldtablename) );
+ Results := Mainform.Connection.GetResults('SHOW KEYS FROM ' + mainform.mask(oldtablename));
setLength(keylist, 0);
keystr := '';
- for i:=1 to zq.RecordCount do
+ for i:=1 to Results.RecordCount do
begin
which := -1;
for k:=0 to length(keylist)-1 do
begin
- if keylist[k].Name = zq.Fields[2].AsString then // keyname exists!
+ if keylist[k].Name = Results.Col(2) then // keyname exists!
which := k;
end;
if which = -1 then
@@ -213,30 +204,27 @@ begin
which := high(keylist);
keylist[which].Columns := TWideStringList.Create;
keylist[which].SubParts := TWideStringList.Create;
- with keylist[which] do // set properties for new key
- begin
- if Mainform.mysql_version < 40002 then
- isFulltext := (zq.FieldByName('Comment').AsString = 'FULLTEXT')
- else
- isFulltext := (zq.FieldByName('Index_type').AsString = 'FULLTEXT');
- Name := zq.Fields[2].AsString;
- if zq.Fields[2].AsString = 'PRIMARY' then
- _type := 'PRIMARY'
- else if isFulltext then
- _type := 'FULLTEXT'
- else if zq.Fields[1].AsString = '1' then
- _type := ''
- else if zq.Fields[1].AsString = '0' then
- _type := 'UNIQUE';
- end;
+ // set properties for new key
+ if Mainform.Connection.ServerVersionInt < 40002 then
+ isFulltext := Results.Col('Comment') = 'FULLTEXT'
+ else
+ isFulltext := Results.Col('Index_type') = 'FULLTEXT';
+ keylist[which].Name := Results.Col(2);
+ if Results.Col(2) = 'PRIMARY' then
+ keylist[which]._type := 'PRIMARY'
+ else if isFulltext then
+ keylist[which]._type := 'FULLTEXT'
+ else if Results.Col(1) = '1' then
+ keylist[which]._type := ''
+ else if Results.Col(1) = '0' then
+ keylist[which]._type := 'UNIQUE';
end;
// add column
- keylist[which].Columns.add( zq.FieldByName('Column_Name').AsWideString );
- keylist[which].SubParts.add( zq.FieldByName('Sub_part').AsWideString );
- zq.Next;
+ keylist[which].Columns.add(Results.Col('Column_Name'));
+ keylist[which].SubParts.add(Results.Col('Sub_part'));
+ Results.Next;
end;
- zq.Close;
- FreeAndNil(zq);
+ FreeAndNil(Results);
for k:=0 to high(keylist) do
begin
if k > 0 then
@@ -261,16 +249,16 @@ begin
// < keys
// Add collation and engine clauses
- zq := Mainform.FetchActiveDbTableList;
- while not zq.Eof do begin
- if zq.FieldByName(DBO_NAME).AsWideString = oldTableName then begin
- if (zq.FindField(DBO_COLLATION) <> nil) and (zq.FieldByName(DBO_COLLATION).AsString <> '') then
- strquery := strquery + ' COLLATE ' + zq.FieldByName(DBO_COLLATION).AsString;
- if (zq.FindField(DBO_ENGINE) <> nil) and (zq.FieldByName(DBO_ENGINE).AsString <> '') then
- strquery := strquery + ' ENGINE=' + zq.FieldByName(DBO_ENGINE).AsString;
+ Results := Mainform.FetchActiveDbTableList;
+ while not Results.Eof do begin
+ if Results.Col(DBO_NAME) = oldTableName then begin
+ if Results.ColExists(DBO_COLLATION) and (Results.Col(DBO_COLLATION) <> '') then
+ strquery := strquery + ' COLLATE ' + Results.Col(DBO_COLLATION);
+ if Results.ColExists(DBO_ENGINE) and (Results.Col(DBO_ENGINE) <> '') then
+ strquery := strquery + ' ENGINE=' + Results.Col(DBO_ENGINE);
break;
end;
- zq.Next;
+ Results.Next;
end;
strquery := strquery + ' SELECT';
@@ -291,40 +279,39 @@ begin
if radioStructure.Checked then
strquery := strquery + ' WHERE 1 = 0';
- Mainform.ExecUpdateQuery(strquery);
+ Mainform.Connection.Query(strquery, False);
// Fix missing auto_increment property and CURRENT_TIMESTAMP defaults in new table
- zq := Mainform.GetResults('SHOW FIELDS FROM ' + mainform.mask(oldtablename));
+ Results := Mainform.Connection.GetResults('SHOW FIELDS FROM ' + mainform.mask(oldtablename));
Fixes := TWideStringlist.Create;
- while not zq.Eof do begin
+ while not Results.Eof do begin
notnull := '';
- if zq.FieldByName('Null').AsString = '' then
+ if Results.Col('Null') = '' then
notnull := 'NOT NULL';
default := '';
- if zq.FieldByName('Default').AsWideString <> '' then begin
+ if Results.Col('Default') <> '' then begin
default := 'DEFAULT ';
- if zq.FieldByName('Default').AsWideString = 'CURRENT_TIMESTAMP' then
- default := default + zq.FieldByName('Default').AsWideString
+ if Results.Col('Default') = 'CURRENT_TIMESTAMP' then
+ default := default + Results.Col('Default')
else
- default := default + esc(zq.FieldByName('Default').AsWideString);
+ default := default + esc(Results.Col('Default'));
end;
- if (CheckBoxWithIndexes.Checked and (zq.FieldByName('Extra').AsString = 'auto_increment'))
- or (zq.FieldByName('Default').AsString = 'CURRENT_TIMESTAMP') then begin
- Fixes.Add('CHANGE '+Mainform.mask(zq.FieldByName('Field').AsWideString)+' '+
- Mainform.mask(zq.FieldByName('Field').AsWideString)+' '+
- zq.FieldByName('Type').AsWideString+' '+default+' '+notnull+' '+zq.FieldByName('Extra').AsString);
+ if (CheckBoxWithIndexes.Checked and (Results.Col('Extra') = 'auto_increment'))
+ or (Results.Col('Default') = 'CURRENT_TIMESTAMP') then begin
+ Fixes.Add('CHANGE '+Mainform.mask(Results.Col('Field'))+' '+
+ Mainform.mask(Results.Col('Field'))+' '+
+ Results.Col('Type')+' '+default+' '+notnull+' '+Results.Col('Extra'));
end;
- zq.Next;
+ Results.Next;
end;
if Fixes.Count > 0 then begin
- Mainform.ExecUpdateQuery('ALTER TABLE '+Mainform.mask(ComboSelectDatabase.Text) + '.'+Mainform.mask(editNewTablename.Text)+ ' '+
+ Mainform.Connection.Query('ALTER TABLE '+Mainform.mask(ComboSelectDatabase.Text) + '.'+Mainform.mask(editNewTablename.Text)+ ' '+
ImplodeStr(', ', Fixes)
);
end;
- zq.Close;
- FreeAndNil(zq);
+ Results.Free;
FreeAndNil(Fixes);
Mainform.actRefresh.Execute;
diff --git a/source/createdatabase.pas b/source/createdatabase.pas
index 98d11e21..7c1f0c62 100644
--- a/source/createdatabase.pas
+++ b/source/createdatabase.pas
@@ -4,7 +4,7 @@ interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls, db, SynEdit, SynMemo, TntStdCtrls, WideStrings;
+ Dialogs, StdCtrls, mysql_connection, SynEdit, SynMemo, TntStdCtrls, WideStrings;
type
TCreateDatabaseForm = class(TForm)
@@ -29,7 +29,7 @@ type
function GetCreateStatement: WideString;
private
{ Private declarations }
- dsCollations : TDataSet;
+ dsCollations : TMySQLQuery;
defaultCharset : String;
currentCollation : String;
public
@@ -55,9 +55,9 @@ begin
InheritFont(Font);
try
- dsCollations := Mainform.GetResults('SHOW COLLATION');
+ dsCollations := Mainform.Connection.GetResults('SHOW COLLATION');
// Detect servers default charset
- defaultCharset := Mainform.GetVar( 'SHOW VARIABLES LIKE '+esc('character_set_server'), 1 );
+ defaultCharset := Mainform.Connection.GetVar( 'SHOW VARIABLES LIKE '+esc('character_set_server'), 1 );
except
// Ignore it when the above statements don't work on pre 4.1 servers.
// If the list(s) are nil, disable the combobox(es), so we create the db without charset.
@@ -70,9 +70,8 @@ begin
begin
comboCharset.Items.BeginUpdate;
dsCollations.First;
- while not dsCollations.Eof do
- begin
- charset := dsCollations.FieldByName('Charset').AsString;
+ while not dsCollations.Eof do begin
+ charset := dsCollations.Col('Charset');
if comboCharset.Items.IndexOf(charset) = -1 then
comboCharset.Items.Add(charset);
dsCollations.Next;
@@ -90,7 +89,6 @@ end;
procedure TCreateDatabaseForm.FormDestroy(Sender: TObject);
begin
- if dsCollations <> nil then dsCollations.Close;
FreeAndNil(dsCollations);
end;
@@ -118,7 +116,7 @@ begin
editDBName.SelectAll;
// Detect current charset and collation to be able to preselect them in the pulldowns
- sql_create := Mainform.GetVar('SHOW CREATE DATABASE '+Mainform.mask(modifyDB), 1);
+ sql_create := Mainform.Connection.GetVar('SHOW CREATE DATABASE '+Mainform.mask(modifyDB), 1);
currentCharset := Copy( sql_create, pos('CHARACTER SET', sql_create)+14, Length(sql_create));
currentCharset := GetFirstWord( currentCharset );
if currentCharset <> '' then
@@ -166,13 +164,12 @@ begin
comboCollation.Items.BeginUpdate;
comboCollation.Items.Clear;
dsCollations.First;
- while not dsCollations.Eof do
- begin
- if dsCollations.FieldByName('Charset').AsString = comboCharset.Text then
+ while not dsCollations.Eof do begin
+ if dsCollations.Col('Charset') = comboCharset.Text then
begin
- comboCollation.Items.Add( dsCollations.FieldByName('Collation').AsString );
- if dsCollations.FieldByName('Default').AsString = 'Yes' then
- defaultCollation := dsCollations.FieldByName('Collation').AsString;
+ comboCollation.Items.Add( dsCollations.Col('Collation'));
+ if dsCollations.Col('Default') = 'Yes' then
+ defaultCollation := dsCollations.Col('Collation');
end;
dsCollations.Next;
end;
@@ -224,12 +221,12 @@ procedure TCreateDatabaseForm.btnOKClick(Sender: TObject);
var
sql : WideString;
AllDatabases, Unions, ObjectsLeft: TWideStringList;
- ObjectsInNewDb, ObjectsInOldDb: TDataset;
+ ObjectsInNewDb, ObjectsInOldDb: TMySQLQuery;
OldObjType, NewObjType: TListNodeType;
begin
if modifyDB = '' then try
sql := GetCreateStatement;
- Mainform.ExecUpdateQuery( sql );
+ Mainform.Connection.Query(sql);
// Close form
ModalResult := mrOK;
except
@@ -246,25 +243,25 @@ begin
end;
if modifyDB = editDBName.Text then begin
// Alter database
- Mainform.ExecUpdateQuery(sql);
+ Mainform.Connection.Query(sql);
end else begin
// Rename database
ObjectsInOldDb := MainForm.RefreshDbTableList(modifyDB);
- AllDatabases := Mainform.GetCol('SHOW DATABASES');
+ AllDatabases := Mainform.Connection.GetCol('SHOW DATABASES');
if AllDatabases.IndexOf(editDBName.Text) = -1 then begin
// Target db does not exist - create it
- Mainform.ExecUpdateQuery(GetCreateStatement);
+ Mainform.Connection.Query(GetCreateStatement);
end else begin
// Target db exists - warn if there are tables with same names
ObjectsInNewDb := MainForm.RefreshDbTableList(editDBName.Text);
while not ObjectsInNewDb.Eof do begin
- NewObjType := GetDBObjectType(ObjectsInNewDb.Fields);
+ NewObjType := GetDBObjectType(ObjectsInNewDb);
ObjectsInOldDb.First;
while not ObjectsInOldDb.Eof do begin
- OldObjType := GetDBObjectType(ObjectsInOldDb.Fields);
+ OldObjType := GetDBObjectType(ObjectsInOldDb);
if not (OldObjType in [lntTable, lntCrashedTable, lntView]) then
Raise Exception.Create('Database "'+modifyDB+'" contains stored routine(s), which cannot be moved.');
- if (ObjectsInOldDb.FieldByName(DBO_NAME).AsWideString = ObjectsInNewDb.FieldByName(DBO_NAME).AsWideString)
+ if (ObjectsInOldDb.Col(DBO_NAME) = ObjectsInNewDb.Col(DBO_NAME))
and (OldObjType = NewObjType) then begin
// One or more objects have a naming conflict
Raise Exception.Create('Database "'+editDBName.Text+'" exists and has objects with same names as in "'+modifyDB+'"');
@@ -282,12 +279,12 @@ begin
ObjectsInOldDb.First;
sql := 'RENAME TABLE ';
while not ObjectsInOldDb.Eof do begin
- sql := sql + Mainform.mask(modifyDb)+'.'+Mainform.mask(ObjectsInOldDb.FieldByName(DBO_NAME).AsWideString)+' TO '+
- Mainform.mask(editDBName.Text)+'.'+Mainform.mask(ObjectsInOldDb.FieldByName(DBO_NAME).AsWideString)+', ';
+ sql := sql + Mainform.mask(modifyDb)+'.'+Mainform.mask(ObjectsInOldDb.Col(DBO_NAME))+' TO '+
+ Mainform.mask(editDBName.Text)+'.'+Mainform.mask(ObjectsInOldDb.Col(DBO_NAME))+', ';
ObjectsInOldDb.Next;
end;
Delete(sql, Length(sql)-1, 2);
- Mainform.ExecUpdateQuery(sql);
+ Mainform.Connection.Query(sql);
Mainform.ClearDbTableList(modifyDB);
Mainform.ClearDbTableList(editDBName.Text);
// Last step for renaming: drop source database
@@ -302,12 +299,12 @@ begin
if Mainform.InformationSchemaTables.IndexOf('TRIGGERS') > -1 then
Unions.Add('SELECT 1 FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.TRIGGERS WHERE TRIGGER_SCHEMA='+esc(modifyDB));
if Unions.Count = 1 then
- ObjectsLeft := Mainform.GetCol(Unions[0])
+ ObjectsLeft := Mainform.Connection.GetCol(Unions[0])
else if Unions.Count > 1 then
- ObjectsLeft := Mainform.GetCol('(' + implodestr(') UNION (', Unions) + ')');
+ ObjectsLeft := Mainform.Connection.GetCol('(' + implodestr(') UNION (', Unions) + ')');
end;
if ObjectsLeft.Count = 0 then begin
- Mainform.ExecUpdateQuery('DROP DATABASE '+modifyDB);
+ Mainform.Connection.Query('DROP DATABASE '+modifyDB);
end;
FreeAndNil(ObjectsLeft);
end;
diff --git a/source/data_sorting.pas b/source/data_sorting.pas
index f7265422..2bc411d4 100644
--- a/source/data_sorting.pas
+++ b/source/data_sorting.pas
@@ -5,7 +5,7 @@ interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls, Buttons,
- WideStrings, TntStdCtrls, helpers, Db;
+ WideStrings, TntStdCtrls, helpers, mysql_connection;
type
@@ -60,15 +60,15 @@ end;
}
procedure TDataSortingForm.FormShow(Sender: TObject);
var
- ds: TDataset;
+ Results: TMySQLQuery;
begin
// Take column names from listColumns and add here
ColumnNames.Clear;
- ds := Mainform.SelectedTableColumns;
- ds.First;
- while not ds.Eof do begin
- ColumnNames.Add(ds.Fields[0].AsWideString);
- ds.Next;
+ Results := Mainform.SelectedTableColumns;
+ Results.First;
+ while not Results.Eof do begin
+ ColumnNames.Add(Results.Col(0));
+ Results.Next;
end;
OrderColumns := Mainform.FDataGridSort;
diff --git a/source/dataviewsave.pas b/source/dataviewsave.pas
index 16204692..af7b0675 100644
--- a/source/dataviewsave.pas
+++ b/source/dataviewsave.pas
@@ -67,7 +67,7 @@ begin
HiddenCols.StrictDelimiter := True;
Mainform.SelectedTableColumns.First;
for i := 0 to Mainform.SelectedTableColumns.RecordCount - 1 do begin
- Col := Mainform.SelectedTableColumns.Fields[0].AsWideString;
+ Col := Mainform.SelectedTableColumns.Col(0);
if Mainform.FDataGridSelect.IndexOf(Col) = -1 then
HiddenCols.Add(Col);
Mainform.SelectedTableColumns.Next;
diff --git a/source/editvar.pas b/source/editvar.pas
index b030c5bd..327cd3fe 100644
--- a/source/editvar.pas
+++ b/source/editvar.pas
@@ -70,9 +70,10 @@ begin
// Set the value and keep the form open in any error case
try
- Mainform.ExecUpdateQuery(sql, False, True);
+ Mainform.Connection.Query(sql);
except
ModalResult := mrNone;
+ Raise;
end;
end;
diff --git a/source/exportsql.dfm b/source/exportsql.dfm
index e8fdf0b2..b6e0e516 100644
--- a/source/exportsql.dfm
+++ b/source/exportsql.dfm
@@ -148,13 +148,13 @@ object ExportSQLForm: TExportSQLForm
Left = 235
Top = 0
Width = 376
- Height = 200
+ Height = 161
Anchors = [akLeft, akTop, akRight]
Caption = 'Output'
TabOrder = 0
DesignSize = (
376
- 200)
+ 161)
object btnFileBrowse: TPngSpeedButton
Left = 344
Top = 42
@@ -218,40 +218,7 @@ object ExportSQLForm: TExportSQLForm
Color = clBtnFace
Enabled = False
ItemHeight = 13
- TabOrder = 6
- end
- object radioOtherHost: TRadioButton
- Left = 9
- Top = 152
- Width = 256
- Height = 17
- Caption = 'Another host and optionally another database'
- TabOrder = 8
- OnClick = radioOtherHostClick
- end
- object comboOtherHost: TComboBox
- Left = 26
- Top = 169
- Width = 137
- Height = 21
- Style = csDropDownList
- Color = clBtnFace
- Enabled = False
- ItemHeight = 13
TabOrder = 5
- OnSelect = comboOtherHostSelect
- end
- object comboOtherHostDatabase: TTntComboBox
- Left = 168
- Top = 169
- Width = 198
- Height = 21
- Style = csDropDownList
- Anchors = [akLeft, akTop, akRight]
- Color = clBtnFace
- Enabled = False
- ItemHeight = 13
- TabOrder = 7
end
object radioDirectory: TRadioButton
Left = 9
@@ -278,9 +245,9 @@ object ExportSQLForm: TExportSQLForm
end
object groupExampleSql: TGroupBox
Left = 235
- Top = 206
+ Top = 167
Width = 376
- Height = 107
+ Height = 146
Anchors = [akLeft, akTop, akRight, akBottom]
Caption = 'Example SQL'
TabOrder = 1
@@ -288,7 +255,7 @@ object ExportSQLForm: TExportSQLForm
Left = 2
Top = 15
Width = 372
- Height = 90
+ Height = 129
SingleLineMode = False
Align = alClient
Color = clBtnFace
diff --git a/source/exportsql.pas b/source/exportsql.pas
index 199e232b..00123031 100644
--- a/source/exportsql.pas
+++ b/source/exportsql.pas
@@ -9,7 +9,6 @@ unit exportsql;
interface
uses
- Threading,
Windows,
Messages,
SysUtils,
@@ -24,11 +23,9 @@ uses
Buttons,
comctrls,
ToolWin,
- DB,
SynEdit,
SynMemo,
- ZDataSet,
- PngSpeedButton, StdActns, WideStrings, TntCheckLst, TntStdCtrls, Menus;
+ PngSpeedButton, StdActns, WideStrings, TntCheckLst, TntStdCtrls, Menus, mysql_connection, mysql_structures;
type
TExportSQLForm = class(TForm)
@@ -52,9 +49,6 @@ type
radioOtherDatabase: TRadioButton;
radioFile: TRadioButton;
comboOtherDatabase: TTNTComboBox;
- radioOtherHost: TRadioButton;
- comboOtherHost: TComboBox;
- comboOtherHostDatabase: TTNTComboBox;
groupExampleSql: TGroupBox;
SynMemoExampleSQL: TSynMemo;
groupOptions: TGroupBox;
@@ -72,7 +66,6 @@ type
btnDirectoryBrowse: TPngSpeedButton;
procedure FormCreate(Sender: TObject);
procedure comboTargetCompatChange(Sender: TObject);
- procedure comboOtherHostSelect(Sender: TObject);
procedure comboDataChange(Sender: TObject);
procedure comboTablesChange(Sender: TObject);
procedure comboDatabaseChange(Sender: TObject);
@@ -91,7 +84,6 @@ type
procedure validateRadioControls(Sender: TObject);
procedure validateControls(Sender: TObject);
procedure cbxStructureClick(Sender: TObject);
- procedure radioOtherHostClick(Sender: TObject);
procedure cbxDataClick(Sender: TObject);
procedure checkListTablesKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
@@ -113,9 +105,7 @@ implementation
uses
Main,
- Helpers,
- Synchronization,
- Communication;
+ Helpers;
{$R *.DFM}
@@ -136,7 +126,6 @@ const
// Order of radiobutton group "Output"
OUTPUT_FILE = 1;
OUTPUT_DB = 2;
- OUTPUT_HOST = 3;
OUTPUT_DIR = 4;
// Default output compatibility
@@ -148,8 +137,6 @@ const
var
appHandles: array of THandle;
cancelDialog: TForm = nil;
- remote_version: integer;
- remote_max_allowed_packet : Int64;
target_versions : TStringList;
@@ -167,7 +154,6 @@ end;
procedure TExportSQLForm.FormShow(Sender: TObject);
var
i, OutputTo : Integer;
- list: TWindowDataArray;
begin
barProgress.Position := 0;
lblProgress.Caption := '';
@@ -189,7 +175,7 @@ begin
with target_versions do
begin
Add( IntToStr( SQL_VERSION_ANSI ) + '=ANSI SQL' );
- Add( IntToStr( Mainform.mysql_version ) + '=Same as source (' + ConvertServerVersion(Mainform.mysql_version) + ')');
+ Add( IntToStr( Mainform.Connection.ServerVersionInt ) + '=Same as source (' + Mainform.Connection.ServerVersionStr + ')');
Add( '50100=HeidiSQL w/ MySQL Server 5.1' );
Add( '50000=HeidiSQL w/ MySQL Server 5.0' );
Add( '40100=HeidiSQL w/ MySQL Server 4.1' );
@@ -227,35 +213,11 @@ begin
FilenameEdited := False;
comboSelectDatabaseChange(self);
editDirectory.Text := GetRegValue(REGNAME_EXP_OUTDIR, '');
- OutputTo := GetRegValue(REGNAME_EXP_TARGET, -1);
- if OutputTo > -1 then
- begin
-
- {***
- @note ansgarbecker, 2007-02-24
- If OutputTo is now OUTPUT_HOST and there are no other windows
- to export to, reset OutputTo to OUTPUT_FILE to avoid the error-popup
- "You need at least 2 windows...", which should not be fired in
- FormShow rather than only when the user has really clicked that
- radiobutton.
- As a benefit, the OUTPUT_FILE won't be saved to registry here
- so the OUTPUT_HOST is still enabled in registry and will be used
- the next time if we have more than 1 window
- @see bug #1666054
- }
- // Check if all the heidisql windows are still alive.
- CheckForCrashedWindows;
- // Fetch list of heidisql windows.
- list := GetWindowList;
- if (Length(list) < 2) and (OutputTo = OUTPUT_HOST) then
- OutputTo := OUTPUT_FILE;
-
- case OutputTo of
- OUTPUT_FILE : radioFile.Checked := true;
- OUTPUT_DIR : radioDirectory.Checked := true;
- OUTPUT_DB : radioOtherDatabase.Checked := true;
- OUTPUT_HOST : radioOtherHost.Checked := true;
- end;
+ OutputTo := GetRegValue(REGNAME_EXP_TARGET, OUTPUT_FILE);
+ case OutputTo of
+ OUTPUT_FILE : radioFile.Checked := true;
+ OUTPUT_DIR : radioDirectory.Checked := true;
+ OUTPUT_DB : radioOtherDatabase.Checked := true;
end;
Width := GetRegValue(REGNAME_EXP_WINWIDTH, Width);
Height := GetRegValue(REGNAME_EXP_WINHEIGHT, Height);
@@ -281,77 +243,20 @@ begin
generateExampleSQL;
end;
-procedure TExportSQLForm.comboOtherHostSelect(Sender: TObject);
-var
- data: TDataSet;
- j: integer;
- versions : TWideStringList;
-begin
- // Get both databases and version right when the radio
- // is clicked, so we can switch to the 'file' radio
- // immediately when something goes wrong.
- try
- data := RemoteExecQuery(
- appHandles[comboOtherHost.ItemIndex],
- 'SHOW DATABASES',
- 'Fetching remote list of databases...'
- );
- comboOtherHostDatabase.Clear;
- for j:=0 to data.RecordCount - 1 do begin
- comboOtherHostDatabase.Items.Add(data.FieldByName('Database').AsWideString);
- data.Next;
- end;
- data.Free;
-
- data := RemoteExecQuery(
- appHandles[comboOtherHost.ItemIndex],
- 'SELECT VERSION()',
- 'Probing for remote version...'
- );
- versions := explode('.', data.Fields[0].AsWideString);
- remote_version := MakeInt(versions[0]) * 10000 + MakeInt(versions[1]) * 100 + MakeInt(versions[2]);
- data.Free;
-
- // Fetch the max_allowed_packet variable to be sure not to
- // overload the server when using "Extended Insert"
- data := RemoteExecQuery(
- appHandles[comboOtherHost.ItemIndex],
- 'SHOW VARIABLES LIKE ' + esc('max_allowed_packet'),
- 'Checking for maximum allowed SQL-packet size on server '+comboOtherHost.Text+'...'
- );
- remote_max_allowed_packet := MakeInt( data.FieldByName('Value').AsString );
- data.Free;
- except
- on E: Exception do begin
- ShowMessage(E.Message);
- radioFile.Checked := true;
- E.Free;
- end;
- end;
-
- // Select remote database with the same name as the source db if available
- if comboOtherHostDatabase.Items.IndexOf( comboSelectDatabase.Text ) > -1 then
- comboOtherHostDatabase.ItemIndex := comboOtherHostDatabase.Items.IndexOf( comboSelectDatabase.Text )
- // Otherwise, select first database if available
- else if comboOtherHostDatabase.Items.Count > 0 then
- comboOtherHostDatabase.ItemIndex := 0;
-
-end;
-
procedure TExportSQLForm.comboSelectDatabaseChange(Sender: TObject);
var
i : Integer;
CheckThisItem: Boolean;
- ds: TDataset;
+ Results: TMySQLQuery;
dir: WideString;
begin
// read tables from db
checkListTables.Items.Clear;
- ds := Mainform.FetchDbTableList(comboSelectDatabase.Text);
- while not ds.Eof do begin
- if GetDBObjectType(ds.Fields) = lntTable then
- checkListTables.Items.Add(ds.FieldByName(DBO_NAME).AsWideString);
- ds.Next;
+ Results := Mainform.FetchDbTableList(comboSelectDatabase.Text);
+ while not Results.Eof do begin
+ if GetDBObjectType(Results) = lntTable then
+ checkListTables.Items.Add(Results.Col(DBO_NAME));
+ Results.Next;
end;
// select all/some:
@@ -482,11 +387,8 @@ var
keystr : WideString;
sourceDb, destDb : WideString;
which : Integer;
- tofile,todb,tohost : boolean;
- samehost : boolean;
- sameuuid : TGuid;
+ tofile,todb : boolean;
tcount,tablecounter : Integer;
- win2export : THandle;
StrProgress : String;
value : WideString;
Escaped,fullvalue : PChar;
@@ -504,13 +406,13 @@ var
RecordCount_all, RecordCount_one, RecordNo_all,
offset, limit : Int64;
sql_select : WideString;
- query : TDataSet;
+ query : TMySQLQuery;
OldActualDatabase : WideString;
function sourceMask(sql: WideString): WideString;
begin
// Same as mask(sql).
- Result := maskSql(Mainform.mysql_version, sql);
+ Result := maskSql(Mainform.Connection.ServerVersionInt, sql);
end;
function destMask(sql: WideString): WideString;
@@ -540,7 +442,6 @@ begin
// to where?
tofile := radioFile.Checked or radioDirectory.Checked;
todb := radioOtherDatabase.Checked;
- tohost := radioOtherHost.Checked;
// export!
pageControl1.ActivePageIndex := 0;
@@ -549,7 +450,6 @@ begin
// Initialize default-variables
target_version := SQL_VERSION_DEFAULT;
target_cliwa := false;
- win2export := 0;
max_allowed_packet := 1024*1024;
// export what?
@@ -571,7 +471,7 @@ begin
// Extract name part of selected target version
target_version := MakeInt(target_versions.Names[comboTargetCompat.ItemIndex]);
target_cliwa := Pos('mysqldump', target_versions.Names[comboTargetCompat.ItemIndex]) > 0;
- max_allowed_packet := MakeInt( Mainform.GetVar( 'SHOW VARIABLES LIKE ' + esc('max_allowed_packet'), 1 ) );
+ max_allowed_packet := MakeInt( Mainform.Connection.GetVar( 'SHOW VARIABLES LIKE ' + esc('max_allowed_packet'), 1 ) );
f := InitFileStream('header');
if f = nil then
begin
@@ -586,27 +486,12 @@ begin
// Export to other database in the same window
if todb then begin
- target_version := Mainform.mysql_version;
- max_allowed_packet := MakeInt( Mainform.GetVar( 'SHOW VARIABLES LIKE ' + esc('max_allowed_packet'), 1 ) );
+ target_version := Mainform.Connection.ServerVersionInt;
+ max_allowed_packet := MakeInt( Mainform.Connection.GetVar( 'SHOW VARIABLES LIKE ' + esc('max_allowed_packet'), 1 ) );
sourceDb := comboSelectDatabase.Text;
destDb := comboOtherDatabase.Text;
end;
- // Export to other window/host
- if tohost then begin
- target_version := remote_version;
- max_allowed_packet := remote_max_allowed_packet;
- win2export := appHandles[comboOtherHost.ItemIndex];
- sourceDb := comboSelectDatabase.Text;
- if exportdb then begin
- // Use original DB-name from source-server
- destDb := comboSelectDatabase.Text;
- end else begin
- // Use existing DB-name on target-server
- destDb := comboOtherHostDatabase.Items[comboOtherHostDatabase.ItemIndex];
- end;
- end;
-
// MySQL has supported extended insert since 3.23.
extended_insert := not (target_version = SQL_VERSION_ANSI);
@@ -620,10 +505,10 @@ begin
if tofile then
begin
wfs(f, '# --------------------------------------------------------');
- wfs(f, WideFormat('# %-30s%s', ['Host:', Mainform.MysqlConn.Connection.HostName]));
+ wfs(f, WideFormat('# %-30s%s', ['Host:', Mainform.Connection.HostName]));
wfs(f, WideFormat('# %-30s%s', ['Database:', sourceDb]));
- wfs(f, WideFormat('# %-30s%s', ['Server version:', Mainform.GetVar('SELECT VERSION()')]));
- wfs(f, WideFormat('# %-30s%s', ['Server OS:', Mainform.GetVar('SHOW VARIABLES LIKE ' + esc('version_compile_os'), 1)]));
+ wfs(f, WideFormat('# %-30s%s', ['Server version:', Mainform.Connection.GetVar('SELECT VERSION()')]));
+ wfs(f, WideFormat('# %-30s%s', ['Server OS:', Mainform.Connection.GetVar('SHOW VARIABLES LIKE ' + esc('version_compile_os'), 1)]));
wfs(f, WideFormat('# %-30s%s', ['Target compatibility:', comboTargetCompat.Text]));
if extended_insert then
begin
@@ -638,71 +523,27 @@ begin
{***
Set characterset to current one
}
- if Mainform.mysql_version > 40100 then
- current_characterset := Mainform.GetVar( 'SHOW VARIABLES LIKE ' + esc('character_set_connection'), 1 )
- else if Mainform.mysql_version > 40000 then
+ if Mainform.Connection.ServerVersionInt > 40100 then
+ current_characterset := Mainform.Connection.GetVar( 'SHOW VARIABLES LIKE ' + esc('character_set_connection'), 1 )
+ else if Mainform.Connection.ServerVersionInt > 40000 then
// todo: test this, add charolation --> charset conversion table from 4.0 to 4.1+
- current_characterset := Mainform.GetVar( 'SHOW VARIABLES LIKE ' + esc('character_set'), 1 )
+ current_characterset := Mainform.Connection.GetVar( 'SHOW VARIABLES LIKE ' + esc('character_set'), 1 )
else
// todo: test this
current_characterset := 'binary';
- {***
- Check if source and destination session is connected to the same server.
- }
- samehost := todb;
- if tohost then begin
- i := CreateGuid(sameuuid);
- if i <> 0 then raise Exception.Create('Could not create a GUID.');
- sql := esc(appName + '_' + GuidToString(sameuuid));
- try
- i := StrToInt(Mainform.GetVar('SELECT GET_LOCK(' + sql + ', 0)'));
- if i <> 1 then raise Exception.Create('Could not create a server lock.');
- query := RemoteExecQuery(
- win2export,
- 'SELECT GET_LOCK(' + sql + ', 0)',
- 'Checking for same server...'
- );
- i := query.Fields[0].AsInteger;
- query.Free;
- if i <> 1 then samehost := true
- else begin
- query := RemoteExecQuery(
- win2export,
- 'SELECT RELEASE_LOCK(' + sql + ')',
- 'Releasing remote lock...'
- );
- end;
- finally
- Mainform.ExecuteNonQuery('SELECT RELEASE_LOCK(' + sql + ')');
- end;
- end;
-
- {***
- Avoid destructive actions (DROP before CREATE) on same host and database.
- }
- if tohost and samehost then begin
- if exportdb and (comboDatabase.ItemIndex = DB_DROP_CREATE) then raise Exception.Create('Aborted: selected action "database recreate" on same source/destination host would drop source database.');
- if exporttables and (comboTables.ItemIndex = TAB_DROP_CREATE) then begin
- if sourceDb = destDb then raise Exception.Create('Aborted: selected action "tables recreate" on same source/destination host and database would drop source tables.');
- end;
- end;
-
{***
Some actions which are only needed if we're not in OtherDatabase-mode:
Set character set, create and use database.
}
- if tofile or tohost then
+ if tofile then
begin
// Switch to correct SQL_MODE so MySQL doesn't reject ANSI SQL
if target_version = SQL_VERSION_ANSI then
begin
sql := makeConditionalStmt('SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=''ANSI,NO_BACKSLASH_ESCAPES''', 40101, tofile);
sql := fixSQL( sql, target_version, target_cliwa );
- if tofile then
- wfs(f, sql)
- else if tohost then
- RemoteExecNonQuery(win2export, sql );
+ wfs(f, sql)
end;
{***
@@ -711,10 +552,7 @@ begin
}
sql := makeConditionalStmt('SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0', 40014, tofile);
sql := fixSQL( sql, target_version, target_cliwa );
- if tofile then
- wfs(f, sql)
- else if tohost then
- RemoteExecNonQuery(win2export, sql );
+ wfs(f, sql);
if exportdb then
begin
@@ -735,14 +573,12 @@ begin
sql := 'DROP DATABASE IF EXISTS ' + destMask(destDb);
if tofile then
wfs(f, sql + ';')
- else if tohost then
- RemoteExecNonQuery(win2export, sql );
end;
{***
CREATE statement for database plus database-switching
}
- if Mainform.mysql_version < 50002 then
+ if Mainform.Connection.ServerVersionInt < 50002 then
begin
sql := 'CREATE DATABASE ';
if comboDatabase.ItemIndex = DB_CREATE_IGNORE then
@@ -753,7 +589,7 @@ begin
end
else
begin
- sql := Mainform.GetVar( 'SHOW CREATE DATABASE ' + sourceMask(sourceDb), 1 );
+ sql := Mainform.Connection.GetVar( 'SHOW CREATE DATABASE ' + sourceMask(sourceDb), 1 );
sql := fixNewlines(sql);
if target_version = SQL_VERSION_ANSI then
sql := StringReplace(sql, '`', '"', [rfReplaceAll]);
@@ -764,9 +600,7 @@ begin
end;
sql := fixSQL( sql, target_version, target_cliwa );
if tofile then
- wfs(f, sql + ';')
- else if tohost then
- RemoteExecNonQuery(win2export, sql);
+ wfs(f, sql + ';');
if exporttables then
begin
if tofile then
@@ -829,93 +663,10 @@ begin
createquery := createquery + '#' + crlf + crlf;
end;
- {***
- Let the server generate the CREATE TABLE statement if the version allows that
- }
- if Mainform.mysql_version >= 32320 then
- begin
- Query := Mainform.GetResults('SHOW CREATE TABLE ' + sourceMask(checkListTables.Items[i]));
- sql := Query.Fields[1].AsWideString;
- Query.Close;
- FreeAndNil(Query);
- sql := fixNewlines(sql);
- sql := fixSQL( sql, target_version, target_cliwa );
- end
- {***
- Generate CREATE TABLE statement by hand on old servers
- }
- else if Mainform.mysql_version < 32320 then begin
- Query := Mainform.GetResults( 'SHOW COLUMNS FROM ' + sourceMask(checkListTables.Items[i]));
- if tofile then
- sql := 'CREATE TABLE ' + destMask(checkListTables.Items[i]) + ' (' + crlf
- else
- sql := sql + 'CREATE TABLE ' + destMask(destDb) + '.' + sourceMask(checkListTables.Items[i]) + ' (' + crlf;
- for j := 1 to Query.Fieldcount do
- begin
- sql := sql + ' ' + destMask(Query.Fields[0].AsWideString) + ' ' + Query.Fields[1].AsWideString;
- if Query.Fields[2].AsString <> 'YES' then
- sql := sql + ' NOT NULL';
- if Query.Fields[4].AsWideString <> '' then
- sql := sql + ' DEFAULT ''' + Query.Fields[4].AsWideString + '''';
- if Query.Fields[5].AsWideString <> '' then
- sql := sql + ' ' + Query.Fields[5].AsWideString;
- if j < Query.Fieldcount then
- sql := sql + ',' + crlf;
- end;
- Query.Close;
- FreeAndNil(Query);
-
- // Keys:
- Query := Mainform.GetResults( 'SHOW KEYS FROM ' + sourceMask(checkListTables.Items[i]));
- setLength(keylist, 0);
- keystr := '';
- if Query.RecordCount > 0 then
- keystr := ',';
-
- for j := 1 to Query.RecordCount do
- begin
- which := -1;
-
- for k:=0 to length(keylist)-1 do
- begin
- if keylist[k].Name = Query.Fields[2].AsString then // keyname exists!
- which := k;
- end;
- if which = -1 then
- begin
- setlength(keylist, length(keylist)+1);
- which := high(keylist);
- keylist[which].Columns := TWideStringList.Create;
- with keylist[which] do // set properties for new key
- begin
- Name := Query.Fields[2].AsString;
- if Query.Fields[2].AsString = 'PRIMARY' then
- _type := 'PRIMARY'
- else if Query.FieldCount >= 10 then if Query.Fields[9].AsString = 'FULLTEXT' then
- _type := 'FULLTEXT'
- else if Query.Fields[1].AsString = '1' then
- _type := ''
- else if Query.Fields[1].AsString = '0' then
- _type := 'UNIQUE';
- end;
- end;
- keylist[which].Columns.add(destMask(Query.Fields[4].AsWideString)); // add column(s)
- Query.Next;
- end;
- Query.Close;
- FreeAndNil(Query);
- for k:=0 to high(keylist) do
- begin
- if k > 0 then
- keystr := keystr + ',';
- if keylist[k].Name = 'PRIMARY' then
- keystr := keystr + crlf + ' PRIMARY KEY ('
- else
- keystr := keystr + crlf + ' ' + keylist[k]._type + ' KEY ' + destMask(keylist[k].Name) + ' (';
- keystr := keystr + implodestr(',', keylist[k].Columns) + ')';
- end;
- sql := sql + keystr + crlf + ')';
- end; // mysql_version < 32320
+ // Let the server generate the CREATE TABLE statement
+ sql := Mainform.Connection.GetVar('SHOW CREATE TABLE ' + sourceMask(checkListTables.Items[i]), 1);
+ sql := fixNewlines(sql);
+ sql := fixSQL( sql, target_version, target_cliwa );
if not tofile then Insert(destMask(destDb) + '.', sql, Pos('TABLE', sql) + 6);
@@ -939,15 +690,8 @@ begin
// Run CREATE TABLE on another Database
else if todb then begin
if comboTables.ItemIndex = TAB_DROP_CREATE then
- Mainform.ExecUpdateQuery( dropquery );
- Mainform.ExecUpdateQuery( createquery );
- end
-
- // Run CREATE TABLE on another host
- else if tohost then begin
- if comboTables.ItemIndex = TAB_DROP_CREATE then
- RemoteExecNonQuery(win2export, dropquery);
- RemoteExecNonQuery(win2export, createquery);
+ Mainform.Connection.Query( dropquery );
+ Mainform.Connection.Query( createquery );
end;
barProgress.StepIt;
@@ -961,16 +705,15 @@ begin
// Set to mysql-readable char:
DecimalSeparator := '.';
columnnames := ' (';
- Query := Mainform.GetResults( 'SHOW FIELDS FROM ' + sourceMask(checkListTables.Items[i]));
- for k:=1 to Query.RecordCount do
+ Query := Mainform.Connection.GetResults( 'SHOW FIELDS FROM ' + sourceMask(checkListTables.Items[i]));
+ for k:=0 to Query.RecordCount-1 do
begin
if k>1 then
columnnames := columnnames + ', ';
- columnnames := columnnames + destMask(Query.Fields[0].AsWideString);
+ columnnames := columnnames + destMask(Query.Col(0));
Query.Next;
end;
columnnames := columnnames+')';
- Query.Close;
FreeAndNil(Query);
if tofile then
@@ -986,23 +729,15 @@ begin
if comboData.ItemIndex = DATA_TRUNCATE_INSERT then
begin
if tofile then
- begin
- wfs(f, 'TRUNCATE TABLE ' + destMask(checkListTables.Items[i]) + ';');
- end
+ wfs(f, 'TRUNCATE TABLE ' + destMask(checkListTables.Items[i]) + ';')
else if todb then
- begin
- Mainform.ExecUpdateQuery('TRUNCATE TABLE ' + sourceMask(destDb) + '.' + checkListTables.Items[i]);
- end
- else if tohost then
- begin
- RemoteExecNonQuery(win2export, 'TRUNCATE TABLE ' + destMask(destDb) + '.' + checkListTables.Items[i]);
- end;
+ Mainform.Connection.Query('TRUNCATE TABLE ' + sourceMask(destDb) + '.' + checkListTables.Items[i]);
end;
// Set rows per step limit and detect total row count
// Be sure to do this step before the table is locked!
limit := 5000;
- RecordCount_all := MakeInt(Mainform.GetNamedVar('SHOW TABLE STATUS LIKE '+esc(checkListTables.Items[i]), 'Rows'));
+ RecordCount_all := MakeInt(Mainform.Connection.GetVar('SHOW TABLE STATUS LIKE '+esc(checkListTables.Items[i]), 'Rows'));
if RecordCount_all = 0 then begin
if tofile then
@@ -1020,16 +755,10 @@ begin
end
else if todb then
begin
- Mainform.ExecUpdateQuery( 'LOCK TABLES ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i])+ ' WRITE, ' + sourceMask(sourceDb) + '.' + sourceMask(checkListTables.Items[i])+ ' WRITE');
+ Mainform.Connection.Query( 'LOCK TABLES ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i])+ ' WRITE, ' + sourceMask(sourceDb) + '.' + sourceMask(checkListTables.Items[i])+ ' WRITE');
if target_version > 40000 then
- Mainform.ExecUpdateQuery( 'ALTER TABLE ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i])+ ' DISABLE KEYS' );
+ Mainform.Connection.Query( 'ALTER TABLE ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i])+ ' DISABLE KEYS' );
end
- else if tohost then
- begin
- RemoteExecNonQuery(win2export, 'LOCK TABLES ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]) + ' WRITE');
- if target_version > 40000 then
- RemoteExecNonQuery(win2export, 'ALTER TABLE ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]) + ' DISABLE KEYS');
- end;
end;
offset := 0;
@@ -1056,7 +785,7 @@ begin
end;
// Execute SELECT
- Query := Mainform.GetResults( sql_select );
+ Query := Mainform.Connection.GetResults( sql_select );
insertquery := '';
valuescount := 0;
@@ -1087,26 +816,24 @@ begin
end;
thesevalues := '(';
- for k := 0 to Query.fieldcount-1 do
+ for k := 0 to Query.ColumnCount-1 do
begin
- if Query.Fields[k].IsNull then
+ if Query.IsNull(k) then
value := 'NULL'
else
- case Query.Fields[k].DataType of
- ftInteger, ftSmallint, ftWord:
- value := Query.Fields[k].AsWideString;
- ftBoolean:
- value := esc( BoolToStr( Query.Fields[k].AsBoolean ) );
- ftBlob:
- if Query.Fields[k].AsString <> '' then
- value := '0x' + BinToWideHex(Query.Fields[k].AsString)
+ case Query.DataType(k).Category of
+ dtcInteger:
+ value := Query.Col(k);
+ dtcBinary:
+ if Query.Col(k) <> '' then
+ value := '0x' + BinToWideHex(Query.Col(k))
else
value := esc('');
else
- value := esc( Query.Fields[k].AsWideString, False, target_version );
+ value := esc( Query.Col(k), False, target_version );
end;
thesevalues := thesevalues + value;
- if k < Query.Fieldcount-1 then
+ if k < Query.ColumnCount-1 then
thesevalues := thesevalues + ',';
end;
thesevalues := thesevalues + ')';
@@ -1141,15 +868,12 @@ begin
insertquery := insertquery + ';';
wfs(f, insertquery)
end else if todb then
- Mainform.ExecUpdateQuery(insertquery)
- else if tohost then
- RemoteExecNonQuery(win2export, insertquery);
+ Mainform.Connection.Query(insertquery);
if donext then
Query.Next;
donext := true;
insertquery := '';
end;
- Query.Close;
FreeAndNil(Query);
end;
// Set back to local setting:
@@ -1164,14 +888,8 @@ begin
else if todb then
begin
if target_version > 40000 then
- Mainform.ExecUpdateQuery( 'ALTER TABLE ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i]) + ' ENABLE KEYS' );
- Mainform.ExecUpdateQuery( 'UNLOCK TABLES' );
- end
- else if tohost then
- begin
- if target_version > 40000 then
- RemoteExecNonQuery(win2export, 'ALTER TABLE ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]) + ' ENABLE KEYS');
- RemoteExecNonQuery(win2export, 'UNLOCK TABLES');
+ Mainform.Connection.Query( 'ALTER TABLE ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i]) + ' ENABLE KEYS' );
+ Mainform.Connection.Query( 'UNLOCK TABLES' );
end;
end;
barProgress.StepIt;
@@ -1189,14 +907,11 @@ begin
end;
// Restore old value for SQL_MODE
- if (tofile or tohost) and (target_version = SQL_VERSION_ANSI) then
+ if tofile and (target_version = SQL_VERSION_ANSI) then
begin
sql := makeConditionalStmt('SET SQL_MODE=@OLD_SQL_MODE', 40101, tofile);
sql := fixSql(sql, target_version, target_cliwa);
- if tofile then
- wfs(f, sql)
- else if tohost then
- RemoteExecNonQuery(win2export, sql );
+ wfs(f, sql);
end;
{***
@@ -1206,9 +921,7 @@ begin
sql := makeConditionalStmt('SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS', 40014, tofile);
sql := fixSQL( sql, target_version, target_cliwa );
if tofile then
- wfs(f, sql)
- else if tohost then
- RemoteExecNonQuery(win2export, sql );
+ wfs(f, sql);
FINALLY
Mainform.TemporaryDatabase := '';
@@ -1328,10 +1041,6 @@ begin
btnDirectoryBrowse.Enabled := False;
comboOtherDatabase.Enabled := False;
comboOtherDatabase.Color := DisabledColor;
- comboOtherHost.Enabled := False;
- comboOtherHost.Color := DisabledColor;
- comboOtherHostDatabase.Enabled := False;
- comboOtherHostDatabase.Color := DisabledColor;
// Silence compiler warning
ControlToFocus := EditFileName;
@@ -1350,11 +1059,6 @@ begin
comboOtherDatabase.Enabled := True;
comboOtherDatabase.Color := EnabledColor;
ControlToFocus := comboOtherDatabase;
- end else if radioOtherHost.Checked then begin
- comboOtherHost.Enabled := True;
- comboOtherHost.Color := EnabledColor;
- comboOtherHostDatabase.Color := EnabledColor;
- ControlToFocus := comboOtherHost;
end;
if ControlToFocus.CanFocus then
ControlToFocus.SetFocus;
@@ -1365,7 +1069,7 @@ end;
procedure TExportSQLForm.validateControls(Sender: TObject);
begin
- cbxDatabase.Enabled := cbxStructure.Checked and (radioFile.Checked or radioDirectory.Checked or radioOtherHost.Checked);
+ cbxDatabase.Enabled := cbxStructure.Checked and (radioFile.Checked or radioDirectory.Checked);
comboDatabase.Enabled := cbxDatabase.Enabled and cbxDatabase.Checked;
cbxTables.Enabled := cbxStructure.Checked;
@@ -1373,9 +1077,6 @@ begin
comboData.Enabled := cbxData.Checked;
- // Should possible be in validateRadioControls() but is dependent on properties decided above.
- comboOtherHostDatabase.Enabled := not (cbxDatabase.Enabled and cbxDatabase.Checked);
-
// Prevent choosing export of db struct + data but no table struct.
if cbxData.Checked then begin
if Sender = cbxTables then cbxDatabase.Checked := cbxDatabase.Checked and cbxTables.Checked
@@ -1473,55 +1174,6 @@ begin
end;
-procedure TExportSQLForm.radioOtherHostClick(Sender: TObject);
-var
- list: TWindowDataArray;
- i, k: integer;
-begin
- // Check if all the heidisql windows are still alive.
- CheckForCrashedWindows;
-
- // Fetch list of heidisql windows.
- list := GetWindowList;
-
- // Fill list of hosts.
- comboOtherHost.Items.Clear;
- SetLength(appHandles, High(list));
- k := 0;
- for i := 0 to High(list) do with list[i] do begin
- // Do not include current window.
- if appHandle <> MainForm.Handle then begin
- // Do not include non-connected windows.
- if connected then begin
- if namePostfix <> 0 then name := name + Format(' (%d)', [namePostFix]);
- comboOtherHost.Items.Add(name);
- appHandles[k] := appHandle;
- k := k + 1;
- end;
- end;
- end;
-
- // Abort if no other windows.
- if comboOtherHost.Items.Count = 0 then begin
- MessageDLG('You need at least two open connection-windows to enable this option.', mtError, [mbOK], 0);
- radioFile.Checked := true;
- abort;
- end;
-
- // Select first host and call change event
- comboOtherHost.ItemIndex := 0;
- comboOtherHost.OnSelect(comboOtherHost);
-
- // De-select database structure to enable database dropdown box.
- cbxDatabase.Checked := false;
-
- validateRadioControls(Sender);
- validateControls(Sender);
- generateExampleSql;
-end;
-
-
-
{***
Save settings in registry, should be called just before closing
the form, but not when Cancel was pressed.
@@ -1547,9 +1199,7 @@ begin
if radioDirectory.checked then
OutputTo := OUTPUT_DIR
else if radioOtherDatabase.checked then
- OutputTo := OUTPUT_DB
- else if radioOtherHost.checked then
- OutputTo := OUTPUT_HOST;
+ OutputTo := OUTPUT_DB;
WriteInteger(REGNAME_EXP_TARGET, OutputTo );
WriteString(REGNAME_EXP_DESTDB, Utf8Encode(comboOtherDatabase.Text));
WriteInteger(REGNAME_EXP_WINWIDTH, Width );
diff --git a/source/helpers.pas b/source/helpers.pas
index fc284fe2..d59c0c41 100644
--- a/source/helpers.pas
+++ b/source/helpers.pas
@@ -9,9 +9,9 @@ unit helpers;
interface
uses Classes, SysUtils, Graphics, db, clipbrd, dialogs,
- forms, controls, ShellApi, checklst, windows, ZDataset, ZAbstractDataset,
+ forms, controls, ShellApi, checklst, windows,
shlobj, ActiveX, WideStrUtils, VirtualTrees, SynRegExpr, Messages, WideStrings,
- TntCheckLst, Registry, SynEditHighlighter, mysql_structures, DateUtils;
+ TntCheckLst, Registry, SynEditHighlighter, mysql_connection, mysql_structures, DateUtils;
type
@@ -45,7 +45,7 @@ type
property AsWideString: WideString read GetAsWideString write SetAsWideString;
end;
- // Structures for result grids, mapped from a TDataset to some handy VirtualTree structure
+ // Structures for result grids, mapped from a TMySQLQuery to some handy VirtualTree structure
TGridCell = record
Text: WideString;
NewText: WideString; // Used to create UPDATE clauses with needed columns
@@ -103,23 +103,6 @@ type
// General purpose editing status flag
TEditingStatus = (esUntouched, esModified, esDeleted, esAddedUntouched, esAddedModified, esAddedDeleted);
- TDeferDataSet = class;
- TAsyncPostRunner = procedure(ds: TDeferDataSet) of object;
-
- TDeferDataSet = class(TZQuery)
- private
- callback: TAsyncPostRunner;
- kind: Integer;
- protected
- procedure InternalPost; override;
- procedure InternalRefresh; override;
- public
- constructor Create(AOwner: TComponent; PostCallback: TAsyncPostRunner); reintroduce;
- procedure ExecSQL; override;
- procedure DoAsync;
- procedure DoAsyncExecSql;
- end;
-
{$I const.inc}
function implodestr(seperator: WideString; a: TWideStringList) :WideString;
@@ -175,7 +158,6 @@ type
function getFirstWord( text: String ): String;
function ConvertWindowsCodepageToMysqlCharacterSet(codepage: Cardinal): string;
function LastPos(needle: WideChar; haystack: WideString): Integer;
- function ConvertServerVersion( Version: Integer ): String;
function FormatByteNumber( Bytes: Int64; Decimals: Byte = 1 ): String; Overload;
function FormatByteNumber( Bytes: String; Decimals: Byte = 1 ): String; Overload;
function FormatTimeNumber( Seconds: Cardinal ): String;
@@ -184,7 +166,7 @@ type
procedure SetVTSelection( VT: TVirtualStringTree; Selected: TWideStringList );
function Pos2(const Needle, HayStack: string; const StartPos: Integer) : Integer;
function GetTempDir: String;
- function GetDBObjectType( TableStatus: TFields ): TListNodeType;
+ function GetDBObjectType(TableStatus: TMySQLQuery): TListNodeType;
procedure SetWindowSizeGrip(hWnd: HWND; Enable: boolean);
procedure SaveUnicodeFile(Filename: String; Text: WideString);
function CreateUnicodeFileStream(Filename: String): TFileStream;
@@ -213,8 +195,7 @@ type
procedure SelectNode(VT: TVirtualStringTree; Node: PVirtualNode); overload;
function DateBackFriendlyCaption(d: TDateTime): String;
procedure InheritFont(AFont: TFont);
- function FieldContent(ds: TDataSet; ColName: WideString): WideString;
- function GetTableSize(ds: TDataSet): Int64;
+ function GetTableSize(Results: TMySQLQuery): Int64;
var
MainReg : TRegistry;
@@ -931,7 +912,7 @@ end;
{***
- Converts a TDataSet to CSV-values.
+ Converts grid contents to CSV-values.
@param Grid Object which holds data to export
@param string Field-separator
@param string Field-encloser
@@ -1022,7 +1003,7 @@ end;
{***
- Converts a TDataSet to XML.
+ Converts grid contents to XML.
@param Grid Object which holds data to export
@param string Text used as root-element
}
@@ -1099,7 +1080,7 @@ end;
{***
- Converts a TDataSet to XML.
+ Converts grid contents to XML.
@param Grid Object which holds data to export
@param string Text used as tablename in INSERTs
}
@@ -2172,21 +2153,6 @@ begin
end;
-{**
- Convert integer version to real version string
-}
-function ConvertServerVersion( Version: Integer ): String;
-var
- v : String;
- v1, v2 : Byte;
-begin
- v := IntToStr( Version );
- v1 := StrToIntDef( v[2]+v[3], 0 );
- v2 := StrToIntDef( v[4]+v[5], 0 );
- Result := v[1] + '.' + IntToStr(v1) + '.' + IntToStr(v2);
-end;
-
-
{**
Format a filesize to automatically use the best fitting expression
16 100 000 Bytes -> 16,1 MB
@@ -2325,7 +2291,7 @@ end;
// Tell type of db object (table|view) by a given row from a SHOW TABLE STATUS result
-function GetDBObjectType( TableStatus: TFields ): TListNodeType;
+function GetDBObjectType(TableStatus: TMySQLQuery): TListNodeType;
var
t: String;
begin
@@ -2338,8 +2304,8 @@ begin
"Views bla references invalid..."
}
Result := lntTable;
- if TableStatus.FindField('Type') <> nil then begin
- t := TableStatus.FindField('Type').AsString;
+ if TableStatus.ColExists('Type') then begin
+ t := TableStatus.Col('Type');
if t = 'BASE TABLE' then
Result := lntTable
else if t = 'VIEW' then
@@ -2350,14 +2316,14 @@ begin
Result := lntProcedure;
end else begin
if
- TableStatus[1].IsNull and // Engine column is NULL for views
- TableStatus[2].IsNull and
- (Pos('VIEW', UpperCase(TableStatus.FieldByName(DBO_COMMENT).AsWideString)) > 0)
+ TableStatus.IsNull(1) and // Engine column is NULL for views
+ TableStatus.IsNull(2) and
+ (Pos('VIEW', UpperCase(TableStatus.Col(DBO_COMMENT))) > 0)
then Result := lntView;
if
- TableStatus[1].IsNull and
- TableStatus[2].IsNull and
- (Pos('MARKED AS CRASHED', UpperCase(TableStatus.FieldByName(DBO_COMMENT).AsWideString)) > 0)
+ TableStatus.IsNull(1) and
+ TableStatus.IsNull(2) and
+ (Pos('MARKED AS CRASHED', UpperCase(TableStatus.Col(DBO_COMMENT))) > 0)
then Result := lntCrashedTable;
end;
end;
@@ -3080,68 +3046,17 @@ begin
end;
-// Fetch content from a row cell, avoiding NULLs to cause AVs
-function FieldContent(ds: TDataSet; ColName: WideString): WideString;
-begin
- Result := '';
- if (ds.FindField(colName) <> nil) and (not ds.FindField(ColName).IsNull) then
- Result := ds.FieldByName(ColName).AsWideString;
-end;
-
-
-function GetTableSize(ds: TDataSet): Int64;
+function GetTableSize(Results: TMySQLQuery): Int64;
var
d, i: String;
begin
- d := FieldContent(ds, 'Data_length');
- i := FieldContent(ds, 'Index_length');
+ d := Results.Col('Data_length', True);
+ i := Results.Col('Index_length', True);
if (d = '') or (i = '') then Result := -1
else Result := MakeInt(d) + MakeInt(i);
end;
-procedure TDeferDataSet.InternalPost;
-begin
- kind := 1;
- if @callback = nil then DoAsync
- else callback(self);
-end;
-
-procedure TDeferDataSet.InternalRefresh;
-begin
- kind := 3;
- if @callback = nil then DoAsync
- else callback(self);
-end;
-
-procedure TDeferDataSet.ExecSql;
-begin
- kind := 2;
- if @callback = nil then DoAsync
- else callback(self);
-end;
-
-constructor TDeferDataSet.Create(AOwner: TComponent; PostCallback: TAsyncPostRunner);
-begin
- callback := PostCallback;
- inherited Create(AOwner);
-end;
-
-procedure TDeferDataSet.DoAsync;
-begin
- case kind of
- 1: inherited InternalPost;
- 2: inherited ExecSQL;
- 3: inherited InternalRefresh;
- end;
-end;
-
-procedure TDeferDataSet.DoAsyncExecSql;
-begin
- inherited ExecSql;
-end;
-
-
end.
diff --git a/source/insertfiles.pas b/source/insertfiles.pas
index 6261acd0..6f820d1a 100644
--- a/source/insertfiles.pas
+++ b/source/insertfiles.pas
@@ -4,7 +4,8 @@ interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- StdCtrls, ComCtrls, ImgList, Buttons, ShellApi, Math, insertfiles_progress;
+ StdCtrls, ComCtrls, ImgList, Buttons, ShellApi, Math, insertfiles_progress,
+ mysql_connection;
type TCol = record
Name : String; // for displaying in lists
@@ -105,15 +106,15 @@ end;
{ Read tables from selected DB }
procedure TfrmInsertFiles.ComboBoxDBsChange(Sender: TObject);
var
- ds: TDataset;
+ Results: TMySQLQuery;
begin
// read tables from db
ComboBoxTables.Items.Clear;
- ds := Mainform.FetchDbTableList(ComboBoxDBs.Text);
- while not ds.Eof do begin
- if GetDBObjectType(ds.Fields) in [lntTable, lntView] then
- ComboBoxTables.Items.Add(ds.FieldByName(DBO_NAME).AsString);
- ds.Next;
+ Results := Mainform.FetchDbTableList(ComboBoxDBs.Text);
+ while not Results.Eof do begin
+ if GetDBObjectType(Results) in [lntTable, lntView] then
+ ComboBoxTables.Items.Add(Results.Col(DBO_NAME));
+ Results.Next;
end;
if ComboBoxTables.Items.Count > 0 then
ComboBoxTables.ItemIndex := 0;
@@ -123,22 +124,20 @@ end;
{ Show Columns from selected table }
procedure TfrmInsertFiles.ComboBoxTablesChange(Sender: TObject);
var
- i : Integer;
- ds : TDataSet;
+ Results: TMySQLQuery;
begin
setlength(cols, 0);
if ComboBoxTables.ItemIndex > -1 then begin
- ds := Mainform.GetResults('SHOW FIELDS FROM '+mainform.mask(ComboBoxDBs.Text)+'.'+mainform.mask(ComboBoxTables.Text));
- for i:=1 to ds.RecordCount do begin
+ Results := Mainform.Connection.GetResults('SHOW FIELDS FROM '+mainform.mask(ComboBoxDBs.Text)+'.'+mainform.mask(ComboBoxTables.Text));
+ while not Results.Eof do begin
setlength(cols, length(cols)+1);
- cols[length(cols)-1].Name := ds.Fields[0].AsString;
- cols[length(cols)-1].isBLOB := (pos('blob', lowercase(ds.Fields[1].AsString)) > 0) or (pos('text', lowercase(ds.Fields[1].AsString)) > 0);
+ cols[length(cols)-1].Name := Results.Col(0);
+ cols[length(cols)-1].isBLOB := (pos('blob', lowercase(Results.Col(1))) > 0) or (pos('text', lowercase(Results.Col(1))) > 0);
cols[length(cols)-1].Value := 'NULL';
cols[length(cols)-1].Quote := false;
- ds.Next;
+ Results.Next;
end;
- ds.Close;
- FreeAndNil(ds);
+ FreeAndNil(Results);
DisplayColumns(self);
end;
end;
diff --git a/source/insertfiles_progress.pas b/source/insertfiles_progress.pas
index 3a2d7757..0c498690 100644
--- a/source/insertfiles_progress.pas
+++ b/source/insertfiles_progress.pas
@@ -4,7 +4,7 @@ interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- StdCtrls, ComCtrls, ExtCtrls, Db, ZDataset;
+ StdCtrls, ComCtrls, ExtCtrls, mysql_connection;
type
TfrmInsertFilesProgress = class(TForm)
@@ -59,17 +59,13 @@ var
dt: TDateTime;
y, m, d, h, mi, s, ms: Word;
FileStream: TFileStream;
- zq: TDeferDataSet;
- zqSqlIdx: Integer;
readBuf: String;
bytesRead: Integer;
- data: WideString;
+ sql, data: WideString;
begin
Timer1.Enabled := false;
screen.Cursor := crHourglass;
ProgressBar1.Max := TfrmInsertFiles(FInsertFilesForm).ListViewFiles.Items.Count;
- zq := TDeferDataSet.Create(nil, Mainform.RunAsyncPost);
- zq.Connection := Mainform.Conn.MysqlConn;
TRY
@@ -83,44 +79,16 @@ begin
filename := ListViewFiles.Items[i].Caption;
lblFilename.Caption := mince(filename, 30) + ' ('+FormatNumber(ListViewFiles.Items[i].SubItems[0])+' KB)';
lblFilename.Repaint;
- zq.ParamCheck := true;
- zq.SQL.Clear;
- zq.SQL.Add( 'INSERT INTO '+mainform.mask(ComboBoxDBs.Text)+'.'+mainform.mask(ComboBoxTables.Text) +
- ' (' + mainform.mask(ComboBoxColumns.Text) );
+ sql := 'INSERT INTO '+mainform.mask(ComboBoxDBs.Text)+'.'+mainform.mask(ComboBoxTables.Text) +
+ ' (' + mainform.mask(ComboBoxColumns.Text);
lblOperation.caption := 'Inserting data ...';
lblOperation.Repaint;
for j:=0 to length(cols)-1 do
begin
if cols[j].Name = ComboBoxColumns.Text then
continue;
- zq.SQL.Add( ', ' + mainform.mask(cols[j].Name) );
+ sql := sql + ', ' + mainform.mask(cols[j].Name);
end;
- zqSqlIdx := zq.SQL.Add( ') VALUES (:STREAM, ' );
-
- for j:=0 to length(cols)-1 do
- begin
- if cols[j].Name = ComboBoxColumns.Text then
- continue;
- Value := cols[j].Value;
- if pos('%', Value) > 0 then
- begin
- //Value := stringreplace(Value, '%filesize%', inttostr(size), [rfReplaceAll]);
- Value := stringreplace(Value, '%filename%', ExtractFileName(filename), [rfReplaceAll]);
- Value := stringreplace(Value, '%filepath%', ExtractFilePath(filename), [rfReplaceAll]);
- FileAge(filename, dt);
- DecodeDate(dt, y, m, d);
- DecodeTime(dt, h, mi, s, ms);
- Value := stringreplace(Value, '%filedate%', Format('%.4d-%.2d-%.2d', [y,m,d]), [rfReplaceAll]);
- Value := stringreplace(Value, '%filedatetime%', Format('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', [y,m,d,h,mi,s]), [rfReplaceAll]);
- Value := stringreplace(Value, '%filetime%', Format('%.2d:%.2d:%.2d', [h,mi,s]), [rfReplaceAll]);
- end;
- if cols[j].Quote then
- Value := esc(Value);
- zq.SQL.Add( Value + ', ' );
- end;
- // Strip last komma + space + CR + LF
- zq.SQL.Text := copy( zq.SQL.Text, 1, length(zq.SQL.Text)-4 );
- zq.SQL.Add( ')' );
try
lblOperation.caption := 'Reading file ...';
lblOperation.Repaint;
@@ -141,7 +109,6 @@ begin
SetLength(readBuf, bytesRead div SizeOf(Char));
data := data + BinToWideHex(readBuf);
end;
- zq.SQL[zqSqlIdx] := StringReplace(zq.SQL[zqSqlIdx], ':STREAM', data, []);
finally
FileStream.Free;
end;
@@ -149,7 +116,33 @@ begin
MessageDlg( 'Error reading file:' + CRLF + filename, mtError, [mbOK], 0 );
break;
end;
- zq.ExecSql;
+ sql := sql + ') VALUES ('+data+', ';
+
+ for j:=0 to length(cols)-1 do
+ begin
+ if cols[j].Name = ComboBoxColumns.Text then
+ continue;
+ Value := cols[j].Value;
+ if pos('%', Value) > 0 then
+ begin
+ //Value := stringreplace(Value, '%filesize%', inttostr(size), [rfReplaceAll]);
+ Value := stringreplace(Value, '%filename%', ExtractFileName(filename), [rfReplaceAll]);
+ Value := stringreplace(Value, '%filepath%', ExtractFilePath(filename), [rfReplaceAll]);
+ FileAge(filename, dt);
+ DecodeDate(dt, y, m, d);
+ DecodeTime(dt, h, mi, s, ms);
+ Value := stringreplace(Value, '%filedate%', Format('%.4d-%.2d-%.2d', [y,m,d]), [rfReplaceAll]);
+ Value := stringreplace(Value, '%filedatetime%', Format('%.4d-%.2d-%.2d %.2d:%.2d:%.2d', [y,m,d,h,mi,s]), [rfReplaceAll]);
+ Value := stringreplace(Value, '%filetime%', Format('%.2d:%.2d:%.2d', [h,mi,s]), [rfReplaceAll]);
+ end;
+ if cols[j].Quote then
+ Value := esc(Value);
+ sql := sql + Value + ', ';
+ end;
+ // Strip last comma + space
+ sql := copy(sql, 1, length(sql)-2);
+ sql := sql + ')';
+ Mainform.Connection.Query(sql);
lblOperation.caption := 'Freeing memory ...';
lblOperation.Repaint;
ProgressBar1.StepIt;
@@ -158,7 +151,6 @@ begin
end;
FINALLY
- FreeAndNil(zq);
screen.Cursor := crDefault;
Close();
END;
diff --git a/source/loaddata.pas b/source/loaddata.pas
index 74473080..40aeebe6 100644
--- a/source/loaddata.pas
+++ b/source/loaddata.pas
@@ -11,7 +11,7 @@ interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, comctrls, Buttons, CheckLst, PngSpeedButton,
- WideStrings, TntCheckLst, TntStdCtrls, db, SynRegExpr;
+ WideStrings, TntCheckLst, TntStdCtrls, mysql_connection, SynRegExpr;
type
Tloaddataform = class(TForm)
@@ -68,7 +68,7 @@ type
procedure btnColDownClick(Sender: TObject);
private
{ Private declarations }
- dsCharsets: TDataset;
+ dsCharsets: TMySQLQuery;
public
{ Public declarations }
end;
@@ -138,7 +138,7 @@ end;
procedure Tloaddataform.comboDatabaseChange(Sender: TObject);
var
count, i, selCharsetIndex, v: Integer;
- ds: TDataset;
+ ds: TMySQLQuery;
seldb, seltable, dbcreate: WideString;
rx: TRegExpr;
DefCharset: String;
@@ -149,8 +149,8 @@ begin
seltable := Mainform.SelectedTable.Text;
ds := Mainform.FetchDbTableList(comboDatabase.Text);
while not ds.Eof do begin
- if GetDBObjectType(ds.Fields) in [lntTable, lntView] then
- comboTable.Items.Add(ds.FieldByName(DBO_NAME).AsWideString);
+ if GetDBObjectType(ds) in [lntTable, lntView] then
+ comboTable.Items.Add(ds.Col(DBO_NAME));
count := comboTable.Items.Count-1;
if (comboDatabase.Text = seldb) and (comboTable.Items[count] = seltable) then
comboTable.ItemIndex := count;
@@ -164,14 +164,14 @@ begin
selCharsetIndex := comboCharset.ItemIndex;
comboCharset.Enabled := False;
comboCharset.Clear;
- v := Mainform.mysql_version;
+ v := Mainform.Connection.ServerVersionInt;
if ((v >= 50038) and (v < 50100)) or (v >= 50117) then begin
if dsCharsets = nil then
- dsCharsets := Mainform.GetResults('SHOW CHARSET');
+ dsCharsets := Mainform.Connection.GetResults('SHOW CHARSET');
comboCharset.Enabled := True;
// Detect db charset
DefCharset := 'Let server/database decide';
- dbcreate := Mainform.GetVar('SHOW CREATE DATABASE '+Mainform.mask(comboDatabase.Text), 1);
+ dbcreate := Mainform.Connection.GetVar('SHOW CREATE DATABASE '+Mainform.mask(comboDatabase.Text), 1);
rx := TRegExpr.Create;
rx.ModifierG := True;
rx.Expression := 'CHARACTER SET (\w+)';
@@ -179,9 +179,10 @@ begin
DefCharset := DefCharset + ' ('+rx.Match[1]+')';
comboCharset.Items.Add(DefCharset);
dsCharsets.First;
- for i:=1 to dsCharsets.RecordCount do begin
- comboCharset.Items.Add(dsCharsets.Fields[1].AsWideString + ' ('+dsCharsets.Fields[0].AsWideString+')');
- if dsCharsets.Fields[0].AsWideString = 'utf8' then begin
+ while not dsCharsets.Eof do begin
+ comboCharset.Items.Add(dsCharsets.Col(1) + ' ('+dsCharsets.Col(0)+')');
+ if dsCharsets.Col(0) = 'utf8' then begin
+ i := comboCharset.Items.Count-1;
comboCharset.Items[i] := comboCharset.Items[i] + ' - '+APPNAME+' output';
if selCharsetIndex = -1 then
selCharsetIndex := i;
@@ -197,22 +198,11 @@ end;
procedure Tloaddataform.comboTableChange(Sender: TObject);
-var
- i : Integer;
- ds : TDataSet;
begin
// fill columns:
chklistColumns.Items.Clear;
- if (comboDatabase.Text <> '') and (comboTable.Text <> '') then begin
- ds := Mainform.GetResults( 'SHOW FIELDS FROM ' + mainform.mask(comboDatabase.Text) + '.' + mainform.mask(comboTable.Text));
- for i:=1 to ds.RecordCount do
- begin
- chklistColumns.Items.Add(ds.Fields[0].AsWideString);
- ds.Next;
- end;
- ds.Close;
- FreeAndNil(ds);
- end;
+ if (comboDatabase.Text <> '') and (comboTable.Text <> '') then
+ chklistColumns.Items.Text := Mainform.Connection.GetCol('SHOW FIELDS FROM ' + mainform.mask(comboDatabase.Text) + '.' + mainform.mask(comboTable.Text)).Text;
// select all:
ToggleCheckListBox( chklistColumns, True );
@@ -267,7 +257,7 @@ begin
if comboCharset.ItemIndex > 0 then begin
dsCharsets.RecNo := comboCharset.ItemIndex;
- query := query + 'CHARACTER SET '+dsCharsets.Fields[0].AsString+' ';
+ query := query + 'CHARACTER SET '+dsCharsets.Col(0)+' ';
end;
// Fields:
@@ -300,7 +290,7 @@ begin
// if col.Count < ColumnsCheckListBox.Items.Count then
query := query + '(' + implodestr(',', col) + ')';
- Mainform.ExecUpdateQuery(query);
+ Mainform.Connection.Query(query);
close;
end;
diff --git a/source/main.dfm b/source/main.dfm
index ab83e20a..6b4c46e3 100644
--- a/source/main.dfm
+++ b/source/main.dfm
@@ -1591,13 +1591,6 @@ object MainForm: TMainForm
Action = actExportData
end
end
- object menuWindow: TMenuItem
- Caption = '&Window'
- OnClick = menuWindowClick
- object miFake: TMenuItem
- Caption = 'fake item - see notes in menuWindowClick()'
- end
- end
object Help1: TMenuItem
Tag = 22
Caption = '&Help'
@@ -6464,7 +6457,6 @@ object MainForm: TMainForm
end
end
object TimerConnected: TTimer
- Enabled = False
OnTimer = TimerConnectedTimer
Left = 103
Top = 269
@@ -6517,13 +6509,6 @@ object MainForm: TMainForm
Left = 40
Top = 200
end
- object ZSQLMonitor1: TZSQLMonitor
- Active = True
- MaxTraceCount = 100
- OnLogTrace = ZSQLMonitor1LogTrace
- Left = 104
- Top = 304
- end
object popupDbGridHeader: TPopupMenu
AutoHotkeys = maManual
AutoLineReduction = maManual
diff --git a/source/main.pas b/source/main.pas
index 22bc1519..0b80dac6 100644
--- a/source/main.pas
+++ b/source/main.pas
@@ -10,20 +10,19 @@ unit Main;
interface
uses
- Synchronization,
- Communication,
Windows, SysUtils, Classes, Graphics, Forms, Controls, Menus,
StdCtrls, Dialogs, Buttons, Messages, ExtCtrls, ComCtrls, StdActns,
- ActnList, ImgList, ShellApi, ToolWin, Clipbrd, db,
- SynMemo, synedit, SynEditTypes, ZDataSet, ZSqlProcessor,
- sqlhelp, MysqlQueryThread, VirtualTrees,
+ ActnList, ImgList, ShellApi, ToolWin, Clipbrd,
+ SynMemo, synedit, SynEditTypes,
+ sqlhelp, VirtualTrees,
DateUtils, PngImageList, TableTools, View, Usermanager,
SelectDBObject, Widestrings, ShlObj, SynEditMiscClasses, SynEditSearch,
- SynCompletionProposal, ZSqlMonitor, SynEditHighlighter, SynHighlighterSQL,
- TntStdCtrls, Tabs, SynUnicode, mysqlconn, EditVar, helpers, queryprogress,
- mysqlquery, createdatabase, table_editor, SynRegExpr,
- WideStrUtils, ZDbcLogging, ExtActns, CommCtrl, routine_editor, options,
- Contnrs, PngSpeedButton, connections, SynEditKeyCmds, exportsql;
+ SynCompletionProposal, SynEditHighlighter, SynHighlighterSQL,
+ TntStdCtrls, Tabs, SynUnicode, EditVar, helpers,
+ createdatabase, table_editor, SynRegExpr,
+ WideStrUtils, ExtActns, CommCtrl, routine_editor, options,
+ Contnrs, PngSpeedButton, connections, SynEditKeyCmds, exportsql,
+ mysql_connection, mysql_api;
type
@@ -136,8 +135,6 @@ type
actLoadSQL: TAction;
ImportSQL1: TMenuItem;
menuConnections: TPopupMenu;
- menuWindow: TMenuItem;
- miFake: TMenuItem;
menuBugtracker: TMenuItem;
menuFeaturetracker: TMenuItem;
menuDownload: TMenuItem;
@@ -309,7 +306,6 @@ type
InsertfilesintoBLOBfields3: TMenuItem;
N19: TMenuItem;
setNULL1: TMenuItem;
- ZSQLMonitor1: TZSQLMonitor;
menuExporttables: TMenuItem;
popupDbGridHeader: TPopupMenu;
SynCompletionProposal: TSynCompletionProposal;
@@ -458,7 +454,6 @@ type
procedure setDefaultWindowConfig;
procedure actCreateTableExecute(Sender: TObject);
procedure actCreateViewExecute(Sender: TObject);
- procedure menuWindowClick(Sender: TObject);
procedure focusWindow(Sender: TObject);
procedure menuConnectionsPopup(Sender: TObject);
procedure actExitApplicationExecute(Sender: TObject);
@@ -518,13 +513,7 @@ type
procedure actSQLhelpExecute(Sender: TObject);
procedure actUpdateCheckExecute(Sender: TObject);
procedure actWebbrowse(Sender: TObject);
- function ExecuteRemoteQuery(sender: THandle; query: string): TDataSet;
- procedure ExecuteRemoteNonQuery(sender: THandle; query: string);
procedure FindDialogQueryFind(Sender: TObject);
- procedure HandleWMComplete(var msg: TMessage); message WM_COMPLETED;
- procedure HandleWMCopyData(var msg: TWMCopyData); message WM_COPYDATA;
- procedure HandleWMProcessLog(var msg: TMessage); message WM_PROCESSLOG;
- procedure HandleWMRefill(var msg: TMessage); message WM_REFILL_SPAREBUF;
procedure ReplaceDialogQueryFind(Sender: TObject);
procedure ReplaceDialogQueryReplace(Sender: TObject);
procedure actCopyAsSQLExecute(Sender: TObject);
@@ -557,7 +546,7 @@ type
procedure EnsureChunkLoaded(Sender: TBaseVirtualTree; Node: PVirtualNode; FullWidth: Boolean = False);
procedure DiscardNodeData(Sender: TVirtualStringTree; Node: PVirtualNode);
procedure viewdata(Sender: TObject);
- procedure LogSQL(msg: WideString = ''; comment: Boolean = true );
+ procedure LogSQL(Msg: WideString; Category: TMySQLLogCategory=lcInfo);
procedure CheckUptime;
procedure KillProcess(Sender: TObject);
procedure ExecSQLClick(Sender: TObject; Selection: Boolean = false;
@@ -585,21 +574,8 @@ type
procedure popupDataGridPopup(Sender: TObject);
procedure InsertDate(Sender: TObject);
procedure setNULL1Click(Sender: TObject);
- function GetNamedVar( SQLQuery: WideString; x: WideString;
- HandleErrors: Boolean = false; DisplayErrors: Boolean = false ) : WideString;
- function GetVar( SQLQuery: WideString; x: Integer = 0;
- HandleErrors: Boolean = false; DisplayErrors: Boolean = false ) : WideString;
- function GetResults( SQLQuery: WideString;
- HandleErrors: Boolean = false; DisplayErrors: Boolean = false; ForceDialog: Boolean = false): TDataSet;
- function GetCol( SQLQuery: WideString; x: Integer = 0;
- HandleErrors: Boolean = false; DisplayErrors: Boolean = false ) : WideStrings.TWideStringList;
- procedure ZSQLMonitor1LogTrace(Sender: TObject; Event: TZLoggingEvent);
procedure MenuTablelistColumnsClick(Sender: TObject);
- procedure CancelQuery;
- procedure CheckConnection();
procedure QueryLoad( filename: String; ReplaceContent: Boolean = true );
- procedure ExecuteNonQuery(SQLQuery: String);
- function ExecuteQuery(query: String): TDataSet;
function CreateOrGetRemoteQueryTab(sender: THandle): THandle;
procedure DataGridChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure DataGridCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode;
@@ -623,7 +599,6 @@ type
procedure menuExploreClick(Sender: TObject);
procedure menuInsertSnippetAtCursorClick(Sender: TObject);
procedure menuLoadSnippetClick(Sender: TObject);
- procedure RunAsyncPost(ds: TDeferDataSet);
procedure vstGetNodeDataSize(Sender: TBaseVirtualTree; var
NodeDataSize: Integer);
procedure vstInitNode(Sender: TBaseVirtualTree; ParentNode, Node:
@@ -663,7 +638,6 @@ type
procedure vstGetHint(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; var LineBreakStyle: TVTTooltipLineBreakStyle; var
HintText: WideString);
- procedure ProcessSqlLog;
procedure ListCommandStatsBeforeCellPaint(Sender: TBaseVirtualTree;
TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
CellPaintMode: TVTCellPaintMode; CellRect: TRect; var ContentRect: TRect);
@@ -739,13 +713,7 @@ type
ReachedEOT : Boolean;
FDelimiter: String;
ServerUptime : Integer;
- time_connected : Cardinal;
viewingdata : Boolean;
- FMysqlConn : TMysqlConn;
- FConn : TOpenConnProf;
- QueryRunningInterlock : Integer;
- UserQueryFired : Boolean;
- UserQueryFiring : Boolean;
CachedTableLists : WideStrings.TWideStringList;
EditVariableForm : TfrmEditVariable;
FileNameSessionLog : String;
@@ -754,10 +722,10 @@ type
SqlMessagesLock : TRtlCriticalSection;
dsShowEngines,
dsHaveEngines,
- dsCollations : TDataset;
- FilterPanelManuallyOpened : Boolean;
+ dsCollations,
FSelectedTableColumns,
- FSelectedTableKeys : TDataset;
+ FSelectedTableKeys : TMySQLQuery;
+ FilterPanelManuallyOpened : Boolean;
DataGridDB, DataGridTable : WideString;
PrevTableColWidths : WideStrings.TWideStringList;
DataGridHasChanges : Boolean;
@@ -770,10 +738,6 @@ type
function GetParamValue(const paramChar: Char; const paramName:
string; var curIdx: Byte; out paramValue: string): Boolean;
procedure SetDelimiter(Value: String);
- function GetQueryRunning: Boolean;
- procedure SetQueryRunning(running: Boolean);
- procedure WaitForQueryCompletion(WaitForm: TfrmQueryProgress; query: TMySqlQuery; ForceDialog: Boolean);
- function RunThreadedQuery(AQuery: WideString; ForceDialog: Boolean): TMysqlQuery;
procedure DisplayRowCountStats(MatchingRows: Int64 = -1);
procedure insertFunction(Sender: TObject);
function GetActiveDatabase: WideString;
@@ -781,15 +745,17 @@ type
procedure SetSelectedDatabase(db: WideString);
procedure SetVisibleListColumns( List: TVirtualStringTree; Columns: WideStrings.TWideStringList );
procedure ToggleFilterPanel(ForceVisible: Boolean = False);
- function GetSelectedTableColumns: TDataset;
- function GetSelectedTableKeys: TDataset;
+ function GetSelectedTableColumns: TMySQLQuery;
+ function GetSelectedTableKeys: TMySQLQuery;
procedure AutoCalcColWidths(Tree: TVirtualStringTree; PrevLayout: Widestrings.TWideStringlist = nil);
procedure PlaceObjectEditor(Which: TListNodeType);
procedure SetTabCaption(PageIndex: Integer; Text: String);
function ConfirmTabClose(PageIndex: Integer): Boolean;
procedure SaveQueryMemo(Filename: String; OnlySelection: Boolean);
procedure UpdateFilterPanel(Sender: TObject);
+ procedure DatabaseChanged(Database: WideString);
public
+ Connection: TMySQLConnection;
cancelling: Boolean;
virtualDesktopName: string;
TableToolsDialog: TfrmTableTools;
@@ -804,7 +770,6 @@ type
TemporaryDatabase : WideString;
dataselected : Boolean;
editing : Boolean;
- mysql_version : Integer;
WindowNumber : Integer;
SessionName : String;
VTRowDataListVariables,
@@ -812,9 +777,6 @@ type
VTRowDataListProcesses,
VTRowDataListCommandStats,
VTRowDataListTables : TVTreeDataArray;
-
- FProgressForm : TFrmQueryProgress;
-
// Variables set by preferences dialog
prefRememberFilters : Boolean;
prefLogsqlnum,
@@ -853,31 +815,22 @@ type
procedure FillPopupQueryLoad;
procedure PopupQueryLoadRemoveAbsentFiles( sender: TObject );
procedure SessionConnect(Sender: TObject);
- function InitConnection(parNetType: Integer; parHost, parPort, parUser, parPass, parCompress, parSession: WideString): Boolean;
- //procedure HandleQueryNotification(ASender : TMysqlQuery; AEvent : Integer);
+ function InitConnection(parHost, parSocketname, parPort, parUser, parPass, parCompress, parSession: WideString): Boolean;
- function ExecUpdateQuery(sql: WideString; HandleErrors: Boolean = false; DisplayErrors: Boolean = false): Int64;
- function ExecSelectQuery(sql: WideString; HandleErrors: Boolean = false; DisplayErrors: Boolean = false; ForceDialog: Boolean = false): TDataSet;
- procedure ExecUseQuery(db: WideString; HandleErrors: Boolean = false; DisplayErrors: Boolean = false);
-
- property FQueryRunning: Boolean read GetQueryRunning write SetQueryRunning;
function ActiveGrid: TVirtualStringTree;
function GridResult(Grid: TBaseVirtualTree): TGridResult; overload;
function GridResult(PageIndex: Integer): TGridResult; overload;
- property MysqlConn : TMysqlConn read FMysqlConn;
- property Conn : TOpenConnProf read FConn;
property ActiveDatabase : WideString read GetActiveDatabase write SetSelectedDatabase;
property SelectedTable : TListNode read GetSelectedTable;
- function FetchActiveDbTableList: TDataSet;
- function RefreshActiveDbTableList: TDataSet;
- function FetchDbTableList(db: WideString): TDataSet;
- function RefreshDbTableList(db: WideString): TDataSet;
+ function FetchActiveDbTableList: TMySQLQuery;
+ function RefreshActiveDbTableList: TMySQLQuery;
+ function FetchDbTableList(db: WideString): TMySQLQuery;
+ function RefreshDbTableList(db: WideString): TMySQLQuery;
procedure ClearDbTableList(db: WideString);
function DbTableListCachedAndValid(db: WideString): Boolean;
procedure ClearAllTableLists;
- procedure EnsureDatabase;
procedure TestVTreeDataArray( P: PVTreeDataArray );
function GetVTreeDataArray( VT: TBaseVirtualTree ): PVTreeDataArray;
procedure ActivateFileLogging;
@@ -899,8 +852,8 @@ type
function CheckUniqueKeyClause: Boolean;
procedure DataGridInsertRow;
procedure DataGridCancel(Sender: TObject);
- property SelectedTableColumns: TDataset read GetSelectedTableColumns write FSelectedTableColumns;
- property SelectedTableKeys: TDataset read GetSelectedTableKeys write FSelectedTableKeys;
+ property SelectedTableColumns: TMySQLQuery read GetSelectedTableColumns write FSelectedTableColumns;
+ property SelectedTableKeys: TMySQLQuery read GetSelectedTableKeys write FSelectedTableKeys;
procedure CalcNullColors;
procedure FillDataViewPopup;
procedure GetDataViews(List: TStrings);
@@ -909,7 +862,7 @@ type
function GetRegKeyTable: String;
procedure SaveListSetup( List: TVirtualStringTree );
procedure RestoreListSetup( List: TVirtualStringTree );
- function GetCollations(Items: TWideStrings = nil): TDataset;
+ function GetCollations(Items: TWideStrings = nil): TMySQLQuery;
procedure SetEditorTabCaption(Editor: TFrame; ObjName: WideString);
procedure ResetSelectedTableStuff;
procedure SetWindowCaption;
@@ -952,7 +905,7 @@ const
implementation
uses
- About, loaddata, printlist, copytable, insertfiles, Threading,
+ About, loaddata, printlist, copytable, insertfiles,
mysql_structures, UpdateCheck, uVistaFuncs, runsqlfile, column_selection,
data_sorting, grideditlinks, dataviewsave;
@@ -960,41 +913,6 @@ uses
{$R *.DFM}
-procedure TMainForm.HandleWMComplete(var msg: TMessage);
-begin
- HandleWMCompleteMessage(msg);
-end;
-
-procedure TMainForm.HandleWMCopyData(var msg: TWMCopyData);
-begin
- HandleWMCopyDataMessage(msg);
-end;
-
-procedure TMainForm.HandleWMProcessLog(var msg: TMessage);
-begin
- ProcessSqlLog;
-end;
-
-function TMainForm.ExecuteRemoteQuery(sender: THandle; query: string): TDataSet;
-//var
- //tab: THandle;
-begin
- // tab := TMDIChild(ActiveMDIChild).CreateOrGetRemoteQueryTab(sender);
- // TQueryTab(tab).AddText(query);
- // tab.ExecOrQueueQuery(query);
- result := ExecuteQuery(query);
-end;
-
-procedure TMainForm.ExecuteRemoteNonQuery(sender: THandle; query: string);
-//var
- //tab: THandle;
-begin
- // tab := TMDIChild(ActiveMDIChild).CreateOrGetRemoteQueryTab(sender);
- // TQueryTab(tab).AddText(query);
- // tab.ExecOrQueueQuery(query);
- ExecuteNonQuery(query);
-end;
-
procedure TMainForm.showstatus(msg: string=''; panel: Integer=6);
begin
// show Message in statusbar
@@ -1096,7 +1014,7 @@ var
begin
flushwhat := UpperCase(TAction(Sender).Caption);
delete(flushwhat, pos('&', flushwhat), 1);
- ExecUpdateQuery('FLUSH ' + flushwhat);
+ Connection.Query('FLUSH ' + flushwhat);
if Sender = actFlushTableswithreadlock then begin
MessageDlg(
'Tables have been flushed and read lock acquired.'#10 +
@@ -1104,7 +1022,7 @@ begin
'Press OK to unlock when done...',
mtInformation, [mbOk], 0
);
- ExecUpdateQuery('UNLOCK TABLES');
+ Connection.Query('UNLOCK TABLES');
end;
end;
@@ -1213,32 +1131,6 @@ begin
end;
-var
- spareMemory: Pointer = nil;
-
-procedure HandleRuntimeError(ErrorCode: Byte; ErrorAddr: Pointer);
-begin
- if spareMemory <> nil then FreeMem(spareMemory);
- debug('mem: released spare block.');
- spareMemory := nil;
- if MainForm <> nil then begin
- PostMessage(MainForm.Handle, WM_REFILL_SPAREBUF, 0, 0);
- end;
- raise Exception.Create('Runtime error ' + IntToStr(ErrorCode) + ' at ' + IntToHex(Cardinal(ErrorAddr), 8) + '.');
-end;
-
-procedure SpareBufRefill;
-begin
- debug('mem: reallocating spare block.');
- if spareMemory = nil then spareMemory := AllocMem(6543210);
-end;
-
-procedure TMainForm.HandleWMRefill(var msg: TMessage);
-begin
- SpareBufRefill;
-end;
-
-
{***
OnCreate Event
Important to set the windowstate here instead of in OnShow
@@ -1265,9 +1157,6 @@ begin
// Use new Vista dialogs per default.
//UseLatestCommonDialogs := True;
- SpareBufRefill;
- ErrorProc := HandleRuntimeError;
-
refreshMonitorConfig;
loadWindowConfig;
@@ -1296,9 +1185,6 @@ begin
// Folder for session logfiles
DirnameSessionLogs := DirnameUserAppData + 'Sessionlogs\';
- QueryRunningInterlock := 0;
- UserQueryFired := False;
- UserQueryFiring := False;
TemporaryDatabase := '';
// SQLFiles-History
@@ -1473,9 +1359,9 @@ end;
}
procedure TMainForm.Startup;
var
- curParam, parNetType: Byte;
+ curParam, NetType: Byte;
sValue,
- parHost, parPort, parUser, parPass,
+ parHost, parSocketname, parPort, parUser, parPass,
parCompress, parSession: String;
LastUpdatecheck, LastStatsCall, LastConnect: TDateTime;
UpdatecheckInterval, i: Integer;
@@ -1556,7 +1442,6 @@ begin
// Check commandline if parameters were passed. Otherwise show connections windows
curParam := 1;
- parNetType := NETTYPE_TCPIP;
while curParam <= ParamCount do begin
// -M and -d are choosen not to conflict with mysql.exe
// http://dev.mysql.com/doc/refman/5.0/en/mysql-command-options.html
@@ -1567,8 +1452,8 @@ begin
parHost := sValue
else if GetParamValue('P', 'port', curParam, sValue) then
parPort := sValue
- else if GetParamValue('T', 'nettype', curParam, sValue) then
- parNetType := StrToIntDef(sValue, NETTYPE_TCPIP)
+ else if GetParamValue('s', 'socket', curParam, sValue) then
+ parSocketname := sValue
else if GetParamValue('C', 'compress', curParam, sValue) then
parCompress := sValue
else if GetParamValue('u', 'user', curParam, sValue) then
@@ -1582,8 +1467,14 @@ begin
// Find stored session if -dSessionName was passed
if (parSession <> '') and MainReg.KeyExists(REGPATH + REGKEY_SESSIONS + parSession) then begin
- parNetType := GetRegValue(REGNAME_NETTYPE, DEFAULT_NETTYPE, parSession);
+ NetType := GetRegValue(REGNAME_NETTYPE, NETTYPE_TCPIP, parSession);
parHost := GetRegValue(REGNAME_HOST, DEFAULT_HOST, parSession);
+ if NetType = NETTYPE_TCPIP then
+ parSocketname := ''
+ else begin
+ parSocketname := parHost;
+ parHost := '.';
+ end;
parUser := GetRegValue(REGNAME_USER, DEFAULT_USER, parSession);
parPass := decrypt(GetRegValue(REGNAME_PASSWORD, DEFAULT_PASSWORD, parSession));
parPort := GetRegValue(REGNAME_PORT, IntToStr(DEFAULT_PORT), parSession);
@@ -1595,7 +1486,7 @@ begin
if CommandLineMode then begin
if parSession = '' then
parSession := parHost;
- Connected := InitConnection(parNetType, parHost, parPort, parUser, parPass, parCompress, parSession);
+ Connected := InitConnection(parHost, parSocketname, parPort, parUser, parPass, parCompress, parSession);
end;
// Auto connection via preference setting
@@ -1603,9 +1494,17 @@ begin
if (not CommandLineMode) and (not Connected) and GetRegValue(REGNAME_AUTORECONNECT, DEFAULT_AUTORECONNECT) then begin
LastSession := GetRegValue(REGNAME_LASTSESSION, '');
if LastSession <> '' then begin
+ parHost := GetRegValue(REGNAME_HOST, '', LastSession);
+ NetType := GetRegValue(REGNAME_NETTYPE, NETTYPE_TCPIP, LastSession);
+ if NetType = NETTYPE_TCPIP then
+ parSocketname := ''
+ else begin
+ parSocketname := parHost;
+ parHost := '.';
+ end;
Connected := InitConnection(
- GetRegValue(REGNAME_NETTYPE, DEFAULT_NETTYPE, LastSession),
- GetRegValue(REGNAME_HOST, '', LastSession),
+ parHost,
+ parSocketname,
GetRegValue(REGNAME_PORT, '', LastSession),
GetRegValue(REGNAME_USER, '', LastSession),
decrypt(GetRegValue(REGNAME_PASSWORD, '', LastSession)),
@@ -1648,9 +1547,6 @@ procedure TMainForm.DoAfterConnect;
var
i, j: Integer;
lastUsedDB: WideString;
- v: String[50];
- v1, v2, v3: String;
- rx: TRegExpr;
functioncats : TStringList;
miGroup,
miFilterGroup,
@@ -1663,28 +1559,12 @@ begin
if GetRegValue(REGNAME_LOGTOFILE, DEFAULT_LOGTOFILE) then
ActivateFileLogging;
- TimerConnected.Enabled := true;
- LogSQL('Connected. Thread-ID: ' + IntToStr( MySQLConn.Connection.GetThreadId ));
-
- // Detect server version
- // Be careful with version suffixes, for example: '4.0.31-20070605_Debian-5-log'
- v := GetVar( 'SELECT VERSION()' );
- rx := TRegExpr.Create;
- rx.ModifierG := True;
- rx.Expression := '^(\d+)\.(\d+)\.(\d+)';
- if rx.Exec(v) then begin
- v1 := rx.Match[1];
- v2 := rx.Match[2];
- v3 := rx.Match[3];
- end;
- rx.Free;
- mysql_version := MakeInt(v1) *10000 + MakeInt(v2) *100 + MakeInt(v3);
- tabHost.Caption := 'Host: '+MySQLConn.Connection.HostName;
- showstatus('MySQL '+v1+'.'+v2+'.'+v3, 3);
+ tabHost.Caption := 'Host: '+Connection.HostName;
+ showstatus('MySQL '+Connection.ServerVersionStr, 3);
// Save server version
OpenRegistry(SessionName);
- Mainreg.WriteInteger(REGNAME_SERVERVERSION, mysql_version);
+ Mainreg.WriteInteger(REGNAME_SERVERVERSION, Connection.ServerVersionInt);
Mainreg.WriteString(REGNAME_LASTCONNECT, DateTimeToStr(Now));
comboOnlyDBs.Items.Text := Utf8Decode(GetRegValue(REGNAME_ONLYDBS, '', SessionName));
@@ -1698,10 +1578,6 @@ begin
CheckUptime;
- // Define window properties
- SetWindowConnected( true );
- WindowNumber := SetWindowName(SessionName);
-
// Reselect last used database
if GetRegValue( REGNAME_RESTORELASTUSEDDB, DEFAULT_RESTORELASTUSEDDB ) then begin
lastUsedDB := Utf8Decode(GetRegValue(REGNAME_LASTUSEDDB, '', SessionName));
@@ -1752,14 +1628,14 @@ begin
miFunction.Caption := '&-';
miFunction.Hint := MySqlFunctions[j].Name + MySqlFunctions[j].Declaration;
// Take care of needed server version
- if MySqlFunctions[j].Version <= mysql_version then begin
+ if MySqlFunctions[j].Version <= Connection.ServerVersionInt then begin
if MySqlFunctions[j].Description <> '' then
miFunction.Hint := miFunction.Hint + ' - ' + Copy(MySqlFunctions[j].Description, 0, 200 );
miFunction.Tag := j;
// Place menuitem on menu
miFunction.OnClick := insertFunction;
end else begin
- miFunction.Hint := miFunction.Hint + ' - ('+STR_NOTSUPPORTED+', needs >= '+ConvertServerVersion(MySqlFunctions[j].Version)+')';
+ miFunction.Hint := miFunction.Hint + ' - ('+STR_NOTSUPPORTED+', needs >= '+Connection.ConvertServerVersion(MySqlFunctions[j].Version)+')';
miFunction.Enabled := False;
end;
// Prevent generating a seperator for ShortHint and LongHint
@@ -1806,11 +1682,8 @@ begin
FreeAndNil(CreateDatabaseForm);
// Closing connection
- if Assigned(FMysqlConn) then begin
- LogSQL('Closing connection to "'+SessionName+'" session (' + FMysqlConn.Connection.hostname + ') ...');
- FMysqlConn.Disconnect;
- FreeAndNil(FMysqlConn);
- end;
+ if Assigned(Connection) then
+ FreeAndNil(Connection);
if prefLogToFile then
DeactivateFileLogging;
@@ -1821,12 +1694,8 @@ begin
ListProcesses.Tag := VTREE_NOTLOADED;
ListCommandstats.Tag := VTREE_NOTLOADED;
- SetWindowConnected( false );
- SetWindowName( main.discname );
Application.Title := APPNAME;
- TimerConnected.Enabled := False;
- time_connected := 0;
TimerHostUptime.Enabled := False;
end;
@@ -1902,43 +1771,6 @@ begin
UserManagerForm.ShowModal;
end;
-procedure TMainForm.menuWindowClick(Sender: TObject);
-var
- i: integer;
- list: TWindowDataArray;
- item: TMenuItem;
-begin
- // Delete dynamically added connection menu items.
- // NOTE: The menu doesn't like having 0 items, so we keep one which we delete later.
- for i := menuWindow.Count - 1 downto 1 do menuWindow.Delete(i);
-
- // Check if all the heidisql windows are still alive.
- CheckForCrashedWindows;
-
- // Fetch the list of windows.
- list := GetWindowList;
-
- // TODO: Load "all" array with all connections
-
- // Re-create dynamic menu items.
- for i := 0 to High(list) do with list[i] do begin
- // TODO: Remove connection with this UID from "all" array
- item := TMenuItem.Create(self);
- if namePostfix <> 0 then name := name + Format(' (%d)', [namePostFix]);
- item.Caption := name;
- if (appHandle = Handle) and (connected) then item.ImageIndex := ICON_MYSELF_CONNECTED
- else if (appHandle = Handle) and (not connected) then item.ImageIndex := ICON_MYSELF_DISCONNECTED
- else if (appHandle <> Handle) and (connected) then item.ImageIndex := ICON_OTHER_CONNECTED
- else if (appHandle <> Handle) and (not connected) then item.ImageIndex := ICON_OTHER_DISCONNECTED;
- item.Tag := appHandle;
- item.OnClick := focusWindow;
- menuWindow.Add(item);
- end;
- // NOTE: The menu breaks if it has 0 items at any point. Therefore we delete item 0 as the last thing.
- // Perhaps later the Window menu will contain more items, for now it's initially filled with a fake menu item.
- menuWindow.Delete(0);
-end;
-
procedure TMainForm.actAboutBoxExecute(Sender: TObject);
begin
// Info-Box
@@ -2030,7 +1862,6 @@ end;
procedure TMainForm.menuConnectionsPopup(Sender: TObject);
var
i: integer;
- list: TWindowDataArray;
item: TMenuItem;
Connections: TStringList;
begin
@@ -2039,32 +1870,6 @@ begin
menuConnections.Items.Delete(i);
end;
- // Check if all the heidisql windows are still alive.
- CheckForCrashedWindows;
-
- // Fetch list of heidisql windows.
- list := GetWindowList;
-
- // Re-create dynamic menu items.
- for i := 0 to High(list) do with list[i] do begin
- // TODO: Remove connection with this UID from "all" array
- item := TMenuItem.Create(self);
- if namePostfix <> 0 then name := name + Format(' (%d)', [namePostFix]);
- item.Caption := name;
- if (appHandle = Handle) and (connected) then item.ImageIndex := ICON_MYSELF_CONNECTED
- else if (appHandle = Handle) and (not connected) then item.ImageIndex := ICON_MYSELF_DISCONNECTED
- else if (appHandle <> Handle) and (connected) then item.ImageIndex := ICON_OTHER_CONNECTED
- else if (appHandle <> Handle) and (not connected) then item.ImageIndex := ICON_OTHER_DISCONNECTED;
- item.Tag := appHandle;
- item.OnClick := focusWindow;
- menuConnections.Items.Add(item);
- end;
-
- // Add separator
- item := TMenuItem.Create(menuConnections);
- item.Caption := '-';
- menuConnections.Items.Add(item);
-
// "Session manager" and "New window" items
item := TMenuItem.Create(menuConnections);
item.Action := actSessionManager;
@@ -2136,7 +1941,7 @@ end;
// Escape database, table, field, index or key name.
function TMainform.mask(str: WideString) : WideString;
begin
- result := maskSql(mysql_version, str);
+ result := Connection.QuoteIdent(str);
end;
@@ -2372,7 +2177,7 @@ end;
procedure TMainForm.actExportTablesExecute(Sender: TObject);
var
- ds: TDataset;
+ Results: TMySQLQuery;
InDBTree: Boolean;
Comp: TComponent;
begin
@@ -2388,10 +2193,10 @@ begin
if SelectedTable.Text <> '' then
ExportSQLForm.SelectedTables.Add(SelectedTable.Text)
else if Mainform.ActiveDatabase <> '' then begin
- ds := Mainform.FetchDbTableList(ActiveDatabase);
- while not ds.Eof do begin
- ExportSQLForm.SelectedTables.Add(ds.FieldByName(DBO_NAME).AsWideString);
- ds.Next;
+ Results := Mainform.FetchDbTableList(ActiveDatabase);
+ while not Results.Eof do begin
+ ExportSQLForm.SelectedTables.Add(Results.Col(DBO_NAME));
+ Results.Next;
end;
end;
end else
@@ -2421,12 +2226,12 @@ var
if (i > 0) and MultiDrops then sql := sql + ', ';
sql := sql + mask(List[i]);
if not MultiDrops then begin
- ExecUpdateQuery(baseSql + sql);
+ Connection.Query(baseSql + sql);
sql := '';
end;
end;
if MultiDrops then
- ExecUpdateQuery(baseSql + sql);
+ Connection.Query(baseSql + sql);
end;
FreeAndNil(List);
end;
@@ -2453,7 +2258,7 @@ begin
Abort;
Screen.Cursor := crHourglass;
try
- ExecUpdateQuery( 'DROP DATABASE ' + mask(activeDB) );
+ Connection.Query('DROP DATABASE ' + mask(activeDB));
ClearDbTableList(activeDB);
DBtree.Selected[DBtree.GetFirst] := true;
RefreshTree(False);
@@ -2564,17 +2369,23 @@ end;
procedure TMainForm.SessionConnect(Sender: TObject);
var
Session: String;
- parNetType: Integer;
- parHost, parPort, parUser, parPass, parCompress: WideString;
+ NetType: Integer;
+ parHost, parSocketname, parPort, parUser, parPass, parCompress: WideString;
begin
Session := (Sender as TMenuItem).Caption;
- parNetType := GetRegValue(REGNAME_NETTYPE, DEFAULT_NETTYPE, Session);
+ NetType := GetRegValue(REGNAME_NETTYPE, NETTYPE_TCPIP, Session);
parHost := GetRegValue(REGNAME_HOST, '', Session);
+ if NetType = NETTYPE_TCPIP then
+ parSocketname := ''
+ else begin
+ parSocketname := parHost;
+ parHost := '.';
+ end;
parUser := GetRegValue(REGNAME_USER, '', Session);
parPass := decrypt(GetRegValue(REGNAME_PASSWORD, '', Session));
parPort := GetRegValue(REGNAME_PORT, '', Session);
parCompress := IntToStr(Integer(GetRegValue(REGNAME_COMPRESSED, DEFAULT_COMPRESSED, Session)));
- if InitConnection(parNetType, parHost, parPort, parUser, parPass, parCompress, Session) then
+ if InitConnection(parHost, parSocketname, parPort, parUser, parPass, parCompress, Session) then
DoAfterConnect;
end;
@@ -2583,66 +2394,43 @@ end;
Receive connection parameters and create the mdi-window
Paremeters are either sent by connection-form or by commandline.
}
-function TMainform.InitConnection(parNetType: Integer; parHost, parPort, parUser, parPass, parCompress, parSession: WideString): Boolean;
+function TMainform.InitConnection(parHost, parSocketname, parPort, parUser, parPass, parCompress, parSession: WideString): Boolean;
var
- MysqlConnection: TMysqlConn;
- Profile: TOpenConnProf;
- UsingPass, NetType: String;
+ ConnectionAttempt: TMySQLConnection;
SessionExists: Boolean;
begin
- // fill structure
- ZeroMemory(@Profile, SizeOf(Profile));
- Profile.MysqlParams.Protocol := 'mysql';
- Profile.MysqlParams.NetType := parNetType;
- Profile.MysqlParams.Host := Trim( parHost );
- Profile.MysqlParams.Port := StrToIntDef(parPort, DEFAULT_PORT);
- Profile.MysqlParams.Database := '';
- Profile.MysqlParams.User := parUser;
- Profile.MysqlParams.Pass := parPass;
- if Integer(parCompress) > 0 then
- Profile.MysqlParams.PrpCompress := 'true'
- else
- Profile.MysqlParams.PrpCompress := 'false';
- Profile.MysqlParams.PrpDbless := 'true';
- Profile.MysqlParams.PrpClientLocalFiles := 'true';
- Profile.MysqlParams.PrpClientInteractive := 'true';
-
- MysqlConnection := TMysqlConn.Create(@Profile);
+ ConnectionAttempt := TMySQLConnection.Create(Self);
+ ConnectionAttempt.OnLog := LogSQL;
+ ConnectionAttempt.OnDatabaseChanged := DatabaseChanged;
+ ConnectionAttempt.Hostname := parHost;
+ ConnectionAttempt.Socketname := parSocketname;
+ ConnectionAttempt.Username := parUser;
+ ConnectionAttempt.Password := parPass;
+ ConnectionAttempt.Port := StrToIntDef(parPort, MYSQL_PORT);
+ ConnectionAttempt.Active := True;
// attempt to establish connection
- if Profile.MysqlParams.Pass <> '' then UsingPass := 'Yes' else UsingPass := 'No';
- case parNetType of
- NETTYPE_TCPIP: NetType := 'TCP/IP';
- NETTYPE_NAMEDPIPE: NetType := 'named pipe';
- else NetType := 'unknown protocol';
- end;
- LogSQL('Connecting to '+Profile.MysqlParams.Host+' via '+NetType+
- ', username '+Profile.MysqlParams.User+
- ', using password: '+UsingPass+' ...');
SessionExists := MainReg.KeyExists(REGPATH + REGKEY_SESSIONS + parSession);
- if MysqlConnection.Connect <> MCR_SUCCESS then begin
+ if not ConnectionAttempt.Active then begin
// attempt failed
if SessionExists then begin
// Save "refused" counter
OpenRegistry(parSession);
MainReg.WriteInteger(REGNAME_REFUSEDCOUNT, GetRegValue(REGNAME_REFUSEDCOUNT, 0, parSession)+1);
end;
- MessageDlg ( 'Could not establish connection! Details:'+CRLF+CRLF+MysqlConnection.LastError, mtError, [mbOK], 0);
Result := False;
- FreeAndNil(MysqlConnection);
+ FreeAndNil(ConnectionAttempt);
end else begin
if SessionExists then begin
// Save "refused" counter
OpenRegistry(parSession);
MainReg.WriteInteger(REGNAME_CONNECTCOUNT, GetRegValue(REGNAME_CONNECTCOUNT, 0, parSession)+1);
end;
+
Result := True;
- Profile.MysqlConn := MysqlConnection.Connection;
- if Assigned(FMysqlConn) then
+ if Assigned(Connection) then
DoDisconnect;
- // Assign global connection objects
- FConn := Profile;
- FMysqlConn := MysqlConnection;
+ Connection := ConnectionAttempt;
SessionName := parSession;
end;
ShowStatus( STATUS_MSG_READY );
@@ -2717,13 +2505,13 @@ begin
@see http://dev.mysql.com/doc/refman/5.0/en/truncate.html
@see https://sourceforge.net/tracker/index.php?func=detail&aid=1644143&group_id=164593&atid=832350
}
- if mysql_version < 50003 then
+ if Connection.ServerVersionInt < 50003 then
sql_pattern := 'DELETE FROM '
else
sql_pattern := 'TRUNCATE ';
for i:=0 to t.count-1 do
- ExecUpdateQuery( sql_pattern + mask(t[i]) );
+ Connection.Query( sql_pattern + mask(t[i]) );
t.Free;
actRefresh.Execute;
Screen.Cursor := crDefault;
@@ -2793,10 +2581,10 @@ end;
procedure TMainForm.actSQLhelpExecute(Sender: TObject);
var
keyword : String;
- ds: TDataset;
+ Results: TMySQLQuery;
begin
// Call SQL Help from various places
- if mysql_version < 40100 then
+ if Connection.ServerVersionInt < 40100 then
exit;
keyword := '';
@@ -2806,9 +2594,9 @@ begin
// Data-Tab
else if (PageControlMain.ActivePage = tabData)
and Assigned(DataGrid.FocusedNode) then begin
- ds := SelectedTableColumns;
- ds.RecNo := DataGrid.FocusedColumn;
- keyword := ds.FieldByName('Type').AsWideString;
+ Results := SelectedTableColumns;
+ Results.RecNo := DataGrid.FocusedColumn;
+ keyword := Results.Col('Type');
end
else if QueryTabActive and ActiveQueryHelpers.Focused then
begin
@@ -3298,105 +3086,44 @@ begin
end;
-function TMainForm.GetQueryRunning: Boolean;
-begin
- Result := ( QueryRunningInterlock = 1 );
-end;
-
-
-procedure TMainForm.SetQueryRunning(running: Boolean);
-var
- newValue : Integer;
- oldValue : Integer;
-begin
- if ( running ) then
- begin
- newValue := 1;
- end
- else
- begin
- newValue := 0;
- end;
-
- oldValue := InterlockedExchange( QueryRunningInterlock, newValue );
- if ( newValue = oldValue ) then
- begin
- case ( newValue ) of
- 1 :
- begin
- raise Exception.Create( 'Error: Default connection is ' +
- 'already executing a query.' );
- end;
- 0 :
- begin
- raise Exception.Create( 'Internal badness: Double reset of running ' +
- 'flag.' );
- end;
- end;
- end;
-end;
-
-
{**
Add a SQL-command or comment to SynMemoSQLLog
}
-procedure TMainForm.LogSQL(msg: WideString = ''; comment: Boolean = true);
+procedure TMainForm.LogSQL(Msg: WideString; Category: TMySQLLogCategory=lcInfo);
var
- snip : boolean;
+ snip, IsSQL: Boolean;
begin
+ if Category = lcDebug then
+ Exit;
// Shorten very long messages
- snip := (prefLogSqlWidth > 0) and (Length(msg) > prefLogSqlWidth);
+ snip := (prefLogSqlWidth > 0) and (Length(Msg) > prefLogSqlWidth);
+ IsSQL := Category = lcSQL;
if snip then begin
- msg :=
- Copy( msg, 0, prefLogSqlWidth ) +
+ Msg :=
+ Copy(Msg, 0, prefLogSqlWidth) +
'/* large SQL query, snipped at ' +
- FormatNumber( prefLogSqlWidth ) +
+ FormatNumber(prefLogSqlWidth) +
' characters */';
- end else if (not snip) and (not comment) then
- msg := msg + Delimiter
- else if comment then
- msg := '/* ' + msg + ' */';
-
- msg := WideStringReplace( msg, #9, ' ', [rfReplaceAll] );
- msg := WideStringReplace( msg, #10, ' ', [rfReplaceAll] );
- msg := WideStringReplace( msg, #13, ' ', [rfReplaceAll] );
- msg := WideStringReplace( msg, ' ', ' ', [rfReplaceAll] );
-
- EnterCriticalSection(SqlMessagesLock);
- try
- SqlMessages.Add(msg);
- finally
- LeaveCriticalSection(SqlMessagesLock);
- end;
- PostMessage(Handle, WM_PROCESSLOG, 0, 0);
-end;
-
-procedure TMainForm.ProcessSqlLog;
-var
- msg: WideString;
-begin
- EnterCriticalSection(SqlMessagesLock);
- try
- if SqlMessages = nil then Exit;
- if SqlMessages.Count < 1 then Exit;
- msg := SqlMessages[0];
- SqlMessages.Delete(0);
- finally
- LeaveCriticalSection(SqlMessagesLock);
- end;
-
- SynMemoSQLLog.Lines.Add( msg );
+ end else if (not snip) and IsSQL then
+ Msg := Msg + Delimiter
+ else if not IsSQL then
+ Msg := '/* ' + Msg + ' */';
+ Msg := WideStringReplace(Msg, #9, ' ', [rfReplaceAll]);
+ Msg := WideStringReplace(Msg, #10, ' ', [rfReplaceAll]);
+ Msg := WideStringReplace(Msg, #13, ' ', [rfReplaceAll]);
+ Msg := WideStringReplace(Msg, ' ', ' ', [rfReplaceAll]);
+ SynMemoSQLLog.Lines.Add(Msg);
TrimSQLLog;
// Scroll to last line and repaint
- SynMemoSQLLog.GotoLineAndCenter( SynMemoSQLLog.Lines.Count );
+ SynMemoSQLLog.GotoLineAndCenter(SynMemoSQLLog.Lines.Count);
SynMemoSQLLog.Repaint;
// Log to file?
if prefLogToFile then
try
- WriteLn( FileHandleSessionLog, Format('[%s] %s', [DateTimeToStr(Now), msg]) );
+ WriteLn(FileHandleSessionLog, Format('[%s] %s', [DateTimeToStr(Now), msg]));
except
DeactivateFileLogging;
MessageDlg('Error writing to session log file:'+CRLF+FileNameSessionLog+CRLF+CRLF+'Logging is disabled now.', mtError, [mbOK], 0);
@@ -3552,8 +3279,8 @@ begin
SelectedTableKeys.First;
for k := 0 to SelectedTableKeys.RecordCount - 1 do begin
- if (SelectedTableKeys.FieldByName('Key_name').AsString = 'PRIMARY')
- and (SelectedTableKeys.FieldByName('Column_name').AsWideString = name) then begin
+ if (SelectedTableKeys.Col('Key_name') = 'PRIMARY')
+ and (SelectedTableKeys.Col('Column_name') = name) then begin
DataGridResult.Columns[idx].IsPriPart := True;
break;
end;
@@ -3646,7 +3373,7 @@ begin
ColExists := False;
SelectedTableColumns.First;
while not SelectedTableColumns.Eof do begin
- if FDataGridSelect[i] = SelectedTableColumns.FieldByName('Field').AsWideString then begin
+ if FDataGridSelect[i] = SelectedTableColumns.Col('Field') then begin
ColExists := True;
break;
end;
@@ -3665,10 +3392,10 @@ begin
debug('mem: initializing browse columns.');
SelectedTableColumns.First;
while not SelectedTableColumns.Eof do begin
- ColName := SelectedTableColumns.FieldByName('Field').AsWideString;
+ ColName := SelectedTableColumns.Col('Field');
ShowIt := (FDataGridSelect.Count=0) or (FDataGridSelect.IndexOf(ColName)>-1);
if ShowIt or (KeyCols.IndexOf(ColName)>-1) then begin
- ColType := SelectedTableColumns.FieldByName('Type').AsString;
+ ColType := SelectedTableColumns.Col('Type');
rx.Expression := '^((tiny|medium|long)?(text|blob)|(var)?(char|binary))\b(\(\d+\))?';
if rx.Exec(ColType) then begin
select_base := select_base + ' ' + 'LEFT(' + Mask(ColName) + ', ' + IntToStr(GridMaxData) + ')' + ',';
@@ -3676,7 +3403,7 @@ begin
select_base := select_base + ' ' + Mask(ColName) + ',';
end;
select_base_full := select_base_full + ' ' + Mask(ColName) + ',';
- InitColumn(ColName, SelectedTableColumns.FieldByName('Type').AsString, ShowIt);
+ InitColumn(ColName, SelectedTableColumns.Col('Type'), ShowIt);
end;
SelectedTableColumns.Next;
end;
@@ -3753,8 +3480,7 @@ procedure TMainForm.DisplayRowCountStats(MatchingRows: Int64);
var
rows_total : Int64; // total rowcount
IsFiltered, IsInnodb: Boolean;
- ds: TDataSet;
- i: Integer;
+ Results: TMySQLQuery;
s: WideString;
begin
lblDataTop.Caption := ActiveDatabase + '.' + SelectedTable.Text;
@@ -3762,14 +3488,14 @@ begin
IsFiltered := self.DataGridCurrentFilter <> '';
if GetFocusedTreeNodeType = lntTable then begin
// Get rowcount from table
- ds := FetchActiveDbTableList;
+ Results := FetchActiveDbTableList;
rows_total := -1;
IsInnodb := False;
- for i := 0 to ds.RecordCount - 1 do begin
- if ds.FieldByName(DBO_NAME).AsWideString = SelectedTable.Text then begin
- s := ds.FieldByName(DBO_ROWS).AsString;
+ while not Results.Eof do begin
+ if Results.Col(DBO_NAME) = SelectedTable.Text then begin
+ s := Results.Col(DBO_ROWS);
if s <> '' then rows_total := MakeInt(s);
- IsInnodb := ds.Fields[1].AsString = 'InnoDB';
+ IsInnodb := Results.Col(1) = 'InnoDB';
break;
end;
end;
@@ -3792,30 +3518,6 @@ begin
end;
-procedure TMainForm.WaitForQueryCompletion(WaitForm: TfrmQueryProgress; query: TMySqlQuery; ForceDialog: Boolean);
-var
- signal: Cardinal;
-begin
- debug( 'Waiting for query to complete.' );
- cancelling := false;
- if ForceDialog then begin
- debug( 'Showing progress form.' );
- WaitForm.ShowModal();
- end else begin
- signal := WaitForSingleObject(query.EventHandle, QueryWaitTime);
- if signal = 0 then debug( 'Query completed within ' + IntToStr(QueryWaitTime) + 'msec.' )
- else begin
- debug( IntToStr(QueryWaitTime) + 'msec passed, showing progress form.' );
- // Hack: Prevent dynamic loading of records in the context of the wait form's message loop.
- DataGrid.Visible := False;
- WaitForm.ShowModal();
- end;
- end;
- CloseHandle(query.EventHandle);
- debug( 'Query complete.' );
-end;
-
-
{***
Occurs when active tab has changed.
}
@@ -3866,39 +3568,19 @@ begin
end;
-{***
- Ensures that we're connected to the currently selected database.
-}
-procedure TMainForm.EnsureDatabase;
-var
- db: WideString;
-begin
- // Some functions temporarily switch away from the database selected by the user, handle that.
- if TemporaryDatabase <> '' then db := TemporaryDatabase
- else db := ActiveDatabase;
- // Blank = database undefined
- if db = '' then Exit;
- if (FMysqlConn.Connection.Database <> db) or (UserQueryFired and not UserQueryFiring) then begin
- ExecUseQuery(db, false, false);
- UserQueryFired := false;
- FMysqlConn.Connection.Database := db;
- end;
-end;
-
-
{***
Look for list of tables for current database in cache.
Retrieve from server if necessary.
- @return TDataSet The cached list of tables for the active database.
+ @return TMySQLQuery The cached list of tables for the active database.
}
-function TMainForm.FetchActiveDbTableList: TDataSet;
+function TMainForm.FetchActiveDbTableList: TMySQLQuery;
begin
Result := FetchDbTableList(ActiveDatabase);
end;
-function TMainForm.FetchDbTableList(db: WideString): TDataSet;
+function TMainForm.FetchDbTableList(db: WideString): TMySQLQuery;
var
- ds: TDataSet;
+ Results: TMySQLQuery;
OldCursor: TCursor;
Unions: TWideStringlist;
ListObjectsSQL: WideString;
@@ -3910,7 +3592,7 @@ begin
ShowStatus('Fetching tables from "' + db + '" ...');
try
if not Assigned(InformationSchemaTables) then
- InformationSchemaTables := GetCol('SHOW TABLES FROM '+mask(DBNAME_INFORMATION_SCHEMA), 0, True, False);
+ InformationSchemaTables := Connection.GetCol('SHOW TABLES FROM '+mask(DBNAME_INFORMATION_SCHEMA));
if InformationSchemaTables.IndexOf('TABLES') > -1 then begin
Unions := TWideStringlist.Create;
@@ -3971,13 +3653,13 @@ begin
// For servers lacking the INFORMATION_SCHEMA or the TABLES table
ListObjectsSQL := 'SHOW TABLE STATUS FROM ' + mask(db);
end;
- ds := GetResults(ListObjectsSQL);
- CachedTableLists.AddObject(db, ds);
+ Results := Connection.GetResults(ListObjectsSQL);
+ CachedTableLists.AddObject(db, Results);
// Add table names to SQL highlighter
SynSQLSyn1.TableNames.BeginUpdate;
- while not ds.Eof do begin
- SynSQLSyn1.TableNames.Add(ds.FieldByName(DBO_NAME).AsWideString);
- ds.Next;
+ while not Results.Eof do begin
+ SynSQLSyn1.TableNames.Add(Results.Col(DBO_NAME));
+ Results.Next;
end;
SynSQLSyn1.TableNames.EndUpdate;
finally
@@ -3985,21 +3667,21 @@ begin
Screen.Cursor := OldCursor;
end;
end;
- Result := TDataSet(CachedTableLists.Objects[CachedTableLists.IndexOf(db)]);
+ Result := TMySQLQuery(CachedTableLists.Objects[CachedTableLists.IndexOf(db)]);
Result.First;
end;
{***
Nukes cached table list for active database, then refreshes it.
- @return TDataSet The newly cached list of tables for the active database.
+ @return TMySQLQuery The newly cached list of tables for the active database.
}
-function TMainForm.RefreshActiveDbTableList: TDataSet;
+function TMainForm.RefreshActiveDbTableList: TMySQLQuery;
begin
Result := RefreshDbTableList(ActiveDatabase);
end;
-function TMainForm.RefreshDbTableList(db: WideString): TDataSet;
+function TMainForm.RefreshDbTableList(db: WideString): TMySQLQuery;
begin
ClearDbTableList(db);
Result := FetchDbTableList(db);
@@ -4025,12 +3707,11 @@ end;
procedure TMainForm.ClearAllTableLists;
var
idx: Integer;
- ds: TDataSet;
+ Results: TMySQLQuery;
begin
for idx := 0 to CachedTableLists.Count - 1 do begin
- ds := TDataSet(CachedTableLists.Objects[idx]);
- ds.Close;
- FreeAndNil(ds);
+ Results := TMySQLQuery(CachedTableLists.Objects[idx]);
+ FreeAndNil(Results);
end;
CachedTableLists.Clear;
end;
@@ -4040,9 +3721,9 @@ procedure TMainForm.LoadDatabaseProperties(db: WideString);
var
i, img : Integer;
bytes : Int64;
- ds : TDataSet;
+ Results : TMySQLQuery;
Cap,
- SelectedCaptions: WideStrings.TWideStringList;
+ SelectedCaptions: TWideStringList;
begin
// DB-Properties
Screen.Cursor := crHourGlass;
@@ -4050,59 +3731,59 @@ begin
// Remember selected nodes
SelectedCaptions := GetVTCaptions(ListTables, True);
- ds := FetchDbTableList(db);
+ Results := FetchDbTableList(db);
ShowStatus( 'Displaying tables from "' + db + '" ...' );
ListTables.BeginUpdate;
ListTables.Clear;
- SetLength(VTRowDataListTables, ds.RecordCount);
- for i := 1 to ds.RecordCount do
- begin
- VTRowDataListTables[i-1].Captions := WideStrings.TWideStringList.Create;
- Cap := VTRowDataListTables[i-1].Captions;
+ SetLength(VTRowDataListTables, Results.RecordCount);
+ i := 0;
+ while not Results.Eof do begin
+ VTRowDataListTables[i].Captions := TWideStringList.Create;
+ Cap := VTRowDataListTables[i].Captions;
// Object name
- Cap.Add( FieldContent(ds, DBO_NAME) );
- if (FieldContent(ds, DBO_ROWS) <> '') then
- Cap.Add( FormatNumber( FieldContent(ds, DBO_ROWS) ) )
+ Cap.Add(Results.Col(DBO_NAME));
+ if Results.Col(DBO_ROWS, True) <> '' then
+ Cap.Add( FormatNumber(Results.Col(DBO_ROWS) ) )
else Cap.Add('');
// Size: Data_length + Index_length
- bytes := GetTableSize(ds);
+ bytes := GetTableSize(Results);
if bytes >= 0 then Cap.Add(FormatByteNumber(bytes))
else Cap.Add('');
- Cap.Add( FieldContent(ds, DBO_CREATED) );
- Cap.Add( FieldContent(ds, DBO_UPDATED) );
- Cap.Add( FieldContent(ds, DBO_ENGINE) );
- Cap.Add( FieldContent(ds, DBO_COMMENT) );
- Cap.Add( FieldContent(ds, DBO_VERSION) );
- Cap.Add( FieldContent(ds, DBO_ROWFORMAT) );
- if (FieldContent(ds, DBO_AVGROWLEN) <> '') then
- Cap.Add( FormatByteNumber(FieldContent(ds, DBO_AVGROWLEN)) )
+ Cap.Add(Results.Col(DBO_CREATED, True));
+ Cap.Add(Results.Col(DBO_UPDATED, True));
+ Cap.Add(Results.Col(DBO_ENGINE, True));
+ Cap.Add(Results.Col(DBO_COMMENT, True));
+ Cap.Add(Results.Col(DBO_VERSION, True));
+ Cap.Add(Results.Col(DBO_ROWFORMAT, True));
+ if Results.Col(DBO_AVGROWLEN, True) <> '' then
+ Cap.Add( FormatByteNumber(Results.Col(DBO_AVGROWLEN)) )
else Cap.Add('');
- if (FieldContent(ds, DBO_MAXDATALEN) <> '') then
- Cap.Add( FormatByteNumber(FieldContent(ds, DBO_MAXDATALEN)) )
+ if Results.Col(DBO_MAXDATALEN, True) <> '' then
+ Cap.Add( FormatByteNumber(Results.Col(DBO_MAXDATALEN)) )
else Cap.Add('');
- if (FieldContent(ds, DBO_INDEXLEN) <> '') then
- Cap.Add( FormatByteNumber(FieldContent(ds, DBO_INDEXLEN)) )
+ if Results.Col(DBO_INDEXLEN, True) <> '' then
+ Cap.Add( FormatByteNumber(Results.Col(DBO_INDEXLEN, True)) )
else Cap.Add('');
- if (FieldContent(ds, DBO_DATAFREE) <> '') then
- Cap.Add( FormatByteNumber(FieldContent(ds, DBO_DATAFREE)) )
+ if Results.Col(DBO_DATAFREE, True) <> '' then
+ Cap.Add( FormatByteNumber(Results.Col(DBO_DATAFREE)) )
else Cap.Add('');
- if (FieldContent(ds, DBO_AUTOINC) <> '') then
- Cap.Add( FormatNumber(FieldContent(ds, DBO_AUTOINC)) )
+ if Results.Col(DBO_AUTOINC, True) <> '' then
+ Cap.Add( FormatNumber(Results.Col(DBO_AUTOINC)) )
else Cap.Add('');
- Cap.Add( FieldContent(ds, DBO_AUTOINC) );
- Cap.Add( FieldContent(ds, DBO_COLLATION) );
- Cap.Add( FieldContent(ds, DBO_CHECKSUM) );
- Cap.Add( FieldContent(ds, DBO_CROPTIONS) );
- if ds.FindField(DBO_TYPE) <> nil then
- Cap.Add(FieldContent(ds, DBO_TYPE))
+ Cap.Add(Results.Col(DBO_AUTOINC));
+ Cap.Add(Results.Col(DBO_COLLATION));
+ Cap.Add(Results.Col(DBO_CHECKSUM));
+ Cap.Add(Results.Col(DBO_CROPTIONS));
+ if Results.ColExists(DBO_TYPE) then
+ Cap.Add(Results.Col(DBO_TYPE))
else
Cap.Add('BASE TABLE');
- VTRowDataListTables[i-1].NodeType := GetDBObjectType( ds.Fields);
+ VTRowDataListTables[i].NodeType := GetDBObjectType(Results);
// Find icon
- case VTRowDataListTables[i-1].NodeType of
+ case VTRowDataListTables[i].NodeType of
lntTable: img := ICONINDEX_TABLE;
lntCrashedTable: img := ICONINDEX_CRASHED_TABLE;
lntView: img := ICONINDEX_VIEW;
@@ -4110,9 +3791,10 @@ begin
lntFunction: img := ICONINDEX_STOREDFUNCTION;
else img := -1;
end;
- VTRowDataListTables[i-1].ImageIndex := img;
+ VTRowDataListTables[i].ImageIndex := img;
- ds.Next;
+ Results.Next;
+ Inc(i);
end;
ListTables.RootNodeCount := Length(VTRowDataListTables);
ListTables.EndUpdate;
@@ -4137,30 +3819,6 @@ begin
end;
-{***
- Execute a query and return a resultset
- The currently active connection is used
-
- @param String The single SQL-query to be executed on the server
-}
-function TMainForm.ExecuteQuery(query: String): TDataSet;
-begin
- result := GetResults(query, false, false);
-end;
-
-
-{***
- Execute a query without returning a resultset
- The currently active connection is used
-
- @param String The single SQL-query to be executed on the server
-}
-procedure TMainForm.ExecuteNonQuery(SQLQuery: String);
-begin
- ExecUpdateQuery(SQLQuery);
-end;
-
-
{***
Selection in ListTables is changing
@@ -4191,8 +3849,8 @@ begin
SelectedNodes := ListTables.GetSortedSelection(False);
- actSQLhelp.Enabled := mysql_version >= 40100;
- actImportCSV.Enabled := mysql_version >= 32206;
+ actSQLhelp.Enabled := Connection.ServerVersionInt >= 40100;
+ actImportCSV.Enabled := Connection.ServerVersionInt >= 32206;
// Data tab - if query results are made editable, these will need
// to be changed to look at which tab is focused.
@@ -4260,7 +3918,7 @@ end;
procedure TMainForm.CheckUptime;
begin
- ServerUptime := MakeInt(GetVar('SHOW STATUS LIKE ''Uptime''', 1));
+ ServerUptime := MakeInt(Connection.GetVar('SHOW STATUS LIKE ''Uptime''', 1));
// Avoid division by zero
ServerUptime := Max(ServerUptime, 1);
TimerHostUptime.Enabled := true;
@@ -4280,10 +3938,10 @@ begin
for i := 0 to ProcessIDs.Count - 1 do
begin
// Don't kill own process
- if ProcessIDs[i] = IntToStr( MySQLConn.Connection.GetThreadId ) then
+ if ProcessIDs[i] = IntToStr(Connection.ThreadId) then
LogSQL('Ignoring own process id '+ProcessIDs[i]+' when trying to kill it.')
else
- ExecUpdateQuery( 'KILL '+ProcessIDs[i] );
+ Connection.Query('KILL '+ProcessIDs[i]);
end;
ListProcesses.Tag := VTREE_NOTLOADED;
ListProcesses.Repaint;
@@ -4302,11 +3960,9 @@ var
SQLscriptstart : Integer;
SQLscriptend : Integer;
SQLTime : Double;
- LastVistaCheck : Cardinal;
- VistaCheck : Boolean;
fieldcount : Integer;
recordcount : Integer;
- ds : TDataSet;
+ Results : TMySQLQuery;
ColName,
Text, LB : WideString;
col : TVirtualTreeColumn;
@@ -4326,66 +3982,45 @@ begin
if LB <> '' then
Text := WideStringReplace(Text, CRLF, LB, [rfReplaceAll]);
SQL := parseSQL(Text);
-
- if ( SQL.Count = 0 ) then
- begin
+ if SQL.Count = 0 then begin
ResultLabel.Caption := '(nothing to do)';
Exit;
end;
- SQLscriptstart := GetTickCount();
- LastVistaCheck := GetTickCount();
+ SQLscriptstart := GetTickCount;
ResultLabel.Caption := '';
- ds := nil;
+ Results := nil;
try
showstatus( 'Initializing SQL...' );
actExecuteQuery.Enabled := false;
actExecuteSelection.Enabled := false;
- // Let EnsureActiveDatabase know that we've fired user queries.
- UserQueryFiring := true;
-
rowsaffected := 0;
fieldcount := 0;
recordcount := 0;
EnableProgressBar(SQL.Count);
- showstatus( 'Executing SQL...' );
- for i := 0 to (SQL.Count - 1) do
- begin
+ showstatus('Executing SQL...');
+ for i:=0 to SQL.Count-1 do begin
ProgressBarStatus.StepIt;
ProgressBarStatus.Repaint;
- if ( sql[i] = '' ) then
- begin
+ if SQL[i] = '' then
continue;
- end;
- // open last query with data-aware:
ResultLabel.Caption := '';
- // ok, let's rock
- SQLstart := GetTickCount();
+ SQLstart := GetTickCount;
try
- VistaCheck := false;
- if GetTickCount() - LastVistaCheck > 2500 then begin
- VistaCheck := true;
- LastVistaCheck := GetTickCount();
- end;
- ds := GetResults( SQL[i], false, false, VistaCheck );
- if ( ds <> nil ) then
- begin
- fieldcount := ds.Fieldcount;
- recordcount := ds.Recordcount;
- rowsaffected := rowsaffected + TZQuery(ds).RowsAffected;
- end
- else
- begin
+ Results := Connection.GetResults(SQL[i]);
+ if Assigned(Results) then begin
+ fieldcount := Results.ColumnCount;
+ recordcount := Results.Recordcount;
+ end else begin
fieldcount := 0;
recordcount := 0;
- rowsaffected := FMysqlConn.Connection.GetAffectedRowsFromLastPost;
+ rowsaffected := Connection.RowsAffected;
end;
except
- on E:Exception do
- begin
+ on E:Exception do begin
if actQueryStopOnErrors.Checked or (i = SQL.Count - 1) then begin
Screen.Cursor := crDefault;
MessageDlg( E.Message, mtError, [mbOK], 0 );
@@ -4397,40 +4032,35 @@ begin
end;
end;
- SQLend := GetTickCount();
+ SQLend := GetTickCount;
SQLTime := (SQLend - SQLstart) / 1000;
ResultLabel.Caption :=
FormatNumber( rowsaffected ) +' row(s) affected, '+
FormatNumber( fieldcount ) +' column(s) x '+
FormatNumber( recordcount ) +' row(s) in last result set.';
- if ( SQL.Count = 1 ) then
- begin
- ResultLabel.Caption := ResultLabel.Caption +
- ' Query time: '+ FormatNumber( SQLTime, 3) +' sec.';
- end;
+ if i < SQL.Count-1 then
+ FreeAndNil(Results);
+ if SQL.Count = 1 then
+ ResultLabel.Caption := ResultLabel.Caption + ' Query time: '+ FormatNumber( SQLTime, 3) +' sec.';
end;
ProgressBarStatus.Hide;
ValidateQueryControls(Sender);
- if ( SQL.Count > 1 ) then
+ if SQL.Count > 1 then
begin
- SQLscriptend := GetTickCount();
+ SQLscriptend := GetTickCount;
SQLTime := (SQLscriptend - SQLscriptstart) / 1000;
ResultLabel.Caption := ResultLabel.Caption +' Batch time: '+
- FormatNumber( SQLTime, 3 ) +' sec.';
+ FormatNumber(SQLTime, 3) +' sec.';
end;
finally
- // Let EnsureActiveDatabase know that we've fired user queries.
- UserQueryFired := true;
- UserQueryFiring := false;
-
// Avoid excessive GridHighlightChanged() when flicking controls.
viewingdata := true;
- if ds <> nil then begin
+ if Assigned(Results) and Results.HasResult then begin
ActiveGrid.BeginUpdate;
ActiveGrid.Header.Options := ActiveGrid.Header.Options + [hoVisible];
ActiveGrid.Header.Columns.BeginUpdate;
@@ -4438,44 +4068,35 @@ begin
debug('mem: clearing and initializing query columns.');
ActiveGridResult := GridResult(ActiveGrid);
SetLength(ActiveGridResult.Columns, 0);
- SetLength(ActiveGridResult.Columns, ds.FieldCount);
- for i:=0 to ds.FieldCount-1 do begin
- ColName := ds.Fields[i].FieldName;
+ SetLength(ActiveGridResult.Columns, Results.ColumnCount);
+ for i:=0 to Results.ColumnCount-1 do begin
+ ColName := Results.ColumnNames[i];
col := ActiveGrid.Header.Columns.Add;
col.Text := ColName;
col.Options := col.Options - [coAllowClick];
ActiveGridResult.Columns[i].Name := ColName;
- if ds.Fields[i].DataType in [ftSmallint, ftInteger, ftWord, ftLargeint] then begin
- ActiveGridResult.Columns[i].DatatypeCat := dtcInteger;
+ ActiveGridResult.Columns[i].DatatypeCat := Results.DataType(i).Category;
+ if ActiveGridResult.Columns[i].DatatypeCat in [dtcInteger, dtcReal] then
col.Alignment := taRightJustify;
- end else if ds.Fields[i].DataType in [ftFloat] then begin
- ActiveGridResult.Columns[i].DatatypeCat := dtcReal;
- col.Alignment := taRightJustify;
- end else if ds.Fields[i].DataType in [ftDate, ftTime, ftDateTime, ftTimeStamp] then
- ActiveGridResult.Columns[i].DatatypeCat := dtcTemporal
- else if ds.Fields[i].DataType in [ftWideString, ftMemo, ftWideMemo] then
- ActiveGridResult.Columns[i].DatatypeCat := dtcText
- else if ds.Fields[i].DataType in [ftBlob] then
- ActiveGridResult.Columns[i].DatatypeCat := dtcBinary;
end;
debug('mem: query column initialization complete.');
debug('mem: clearing and initializing query rows (internal data).');
SetLength(ActiveGridResult.Rows, 0);
- SetLength(ActiveGridResult.Rows, ds.RecordCount);
- ds.First;
- for i:=0 to ds.RecordCount-1 do begin
+ SetLength(ActiveGridResult.Rows, Results.RecordCount);
+ Results.First;
+ for i:=0 to Results.RecordCount-1 do begin
ActiveGridResult.Rows[i].Loaded := True;
- SetLength(ActiveGridResult.Rows[i].Cells, ds.FieldCount);
- for j:=0 to ds.FieldCount-1 do begin
+ SetLength(ActiveGridResult.Rows[i].Cells, Results.ColumnCount);
+ for j:=0 to Results.ColumnCount-1 do begin
if ActiveGridResult.Columns[j].DatatypeCat = dtcBinary then
- ActiveGridResult.Rows[i].Cells[j].Text := '0x' + BinToWideHex(ds.Fields[j].AsString)
+ ActiveGridResult.Rows[i].Cells[j].Text := '0x' + BinToWideHex(Results.Col(j))
else
- ActiveGridResult.Rows[i].Cells[j].Text := ds.Fields[j].AsWideString;
- ActiveGridResult.Rows[i].Cells[j].IsNull := ds.Fields[j].IsNull;
+ ActiveGridResult.Rows[i].Cells[j].Text := Results.Col(j);
+ ActiveGridResult.Rows[i].Cells[j].IsNull := Results.IsNull(j);
end;
- ds.Next;
+ Results.Next;
end;
- ds.Free;
+ Results.Free;
debug('mem: initializing query rows (grid).');
ActiveGrid.RootNodeCount := Length(ActiveGridResult.Rows);
debug('mem: query row initialization complete.');
@@ -4515,7 +4136,7 @@ procedure TMainForm.SynCompletionProposalExecute(Kind: SynCompletionType;
var CanExecute: Boolean);
var
i,j : Integer;
- ds : TDataset;
+ Results : TMySQLQuery;
sql, TableClauses: WideString;
Tables : TStringList;
tablename : WideString;
@@ -4532,14 +4153,14 @@ var
const
ItemPattern: WideString = '\image{%d}\hspace{5}\color{clSilver}%s\column{}\color{clWindowText}%s';
- procedure addTable( Fields: TFields );
+ procedure addTable(Results: TMySQLQuery);
var ObjName, ObjType: WideString; Icon: Integer;
begin
- ObjName := Fields[0].AsWideString;
+ ObjName := Results.Col(0);
ObjType := '';
- if Fields.FindField(DBO_TYPE) <> nil then
- ObjType := LowerCase(Fields.FieldByName(DBO_TYPE).AsString);
- case GetDBObjectType(Fields) of
+ if Results.ColExists(DBO_TYPE) then
+ ObjType := LowerCase(Results.Col(DBO_TYPE));
+ case GetDBObjectType(Results) of
lntTable: Icon := ICONINDEX_TABLE;
lntCrashedTable: Icon := ICONINDEX_CRASHED_TABLE;
lntFunction: Icon := ICONINDEX_STOREDFUNCTION;
@@ -4554,8 +4175,7 @@ const
procedure addColumns( tablename: WideString );
var
dbname : WideString;
- i : Integer;
- ds : TDataSet;
+ Columns: TMySQLQuery;
begin
dbname := ActiveDatabase;
if Pos( '.', tablename ) > -1 then
@@ -4567,16 +4187,17 @@ const
// Rely on what the user typed is already a valid masked/quoted identifier.
if dbname <> '' then
tablename := dbname + '.' + tablename;
- ds := getResults( 'SHOW COLUMNS FROM '+tablename, true, false );
- if ds = nil then exit;
- for i:=0 to ds.RecordCount-1 do
- begin
- Proposal.InsertList.Add( ds.FieldByName( 'Field' ).AsWideString );
- Proposal.ItemList.Add( WideFormat(ItemPattern, [ICONINDEX_FIELD, GetFirstWord(ds.FieldByName('Type').AsString), ds.FieldByName('Field').AsWideString]) );
- ds.Next;
+ try
+ Columns := Connection.GetResults('SHOW COLUMNS FROM '+tablename);
+ except
+ Exit;
end;
- ds.Close;
- FreeAndNil(ds);
+ while not Columns.Eof do begin
+ Proposal.InsertList.Add(Columns.Col('Field'));
+ Proposal.ItemList.Add(WideFormat(ItemPattern, [ICONINDEX_FIELD, GetFirstWord(Columns.Col('Type')), Columns.Col('Field')]) );
+ Columns.Next;
+ end;
+ FreeAndNil(Columns);
end;
begin
@@ -4669,10 +4290,10 @@ begin
if i > -1 then begin
// Only display tables from specified db
Screen.Cursor := crHourGlass;
- ds := FetchDbTableList(Databases[i]);
- while not ds.Eof do begin
- addTable(ds.Fields);
- ds.Next;
+ Results := FetchDbTableList(Databases[i]);
+ while not Results.Eof do begin
+ addTable(Results);
+ Results.Next;
end;
Screen.Cursor := crDefault;
end;
@@ -4687,10 +4308,10 @@ begin
if ActiveDatabase <> '' then begin
// Display tables from current db
- ds := FetchActiveDbTableList;
- while not ds.Eof do begin
- addTable(ds.Fields);
- ds.Next;
+ Results := FetchActiveDbTableList;
+ while not Results.Eof do begin
+ addTable(Results);
+ Results.Next;
end;
if Length(CurrentInput) = 0 then // assume that we have already a dbname in memo
Proposal.Position := Databases.Count;
@@ -4699,7 +4320,7 @@ begin
// Add functions
for i := 0 to Length(MySQLFunctions) - 1 do begin
// Don't display unsupported functions here
- if MySqlFunctions[i].Version > mysql_version then
+ if MySqlFunctions[i].Version > Connection.ServerVersionInt then
continue;
Proposal.InsertList.Add( MySQLFunctions[i].Name + MySQLFunctions[i].Declaration );
Proposal.ItemList.Add( WideFormat(ItemPattern, [ICONINDEX_FUNCTION, 'function', MySQLFunctions[i].Name + '\color{clSilver}' + MySQLFunctions[i].Declaration] ) );
@@ -4781,7 +4402,7 @@ begin
try
ensureValidIdentifier( NewText );
// rename table
- ExecUpdateQuery( 'RENAME TABLE ' + mask(NodeData.Captions[0]) + ' TO ' + mask(NewText), False, False );
+ Connection.Query('RENAME TABLE ' + mask(NodeData.Captions[0]) + ' TO ' + mask(NewText));
if SynSQLSyn1.TableNames.IndexOf( NewText ) = -1 then begin
SynSQLSyn1.TableNames.Add(NewText);
@@ -4803,15 +4424,12 @@ end;
procedure TMainForm.TimerConnectedTimer(Sender: TObject);
begin
- if not TimerConnected.Enabled then begin
+ if Assigned(Connection) and Connection.Active then begin
+ // calculate and display connection-time
+ showstatus('Connected: ' + FormatTimeNumber((GetTickCount-Connection.ConnectionStarted) Div 1000), 2 );
+ end else begin
showstatus('Disconnected.', 2);
- exit;
end;
-
- inc(time_connected);
-
- // calculate and display connection-time
- showstatus( 'Connected: ' + FormatTimeNumber(time_connected), 2 );
end;
@@ -5036,7 +4654,7 @@ procedure TMainForm.popupHostPopup(Sender: TObject);
begin
Kill1.Enabled := (PageControlHost.ActivePage = tabProcessList) and Assigned(ListProcesses.FocusedNode);
menuEditVariable.Enabled := False;
- if mysql_version >= 40003 then
+ if Connection.ServerVersionInt >= 40003 then
menuEditVariable.Enabled := (PageControlHost.ActivePage = tabVariables) and Assigned(ListVariables.FocusedNode)
else
menuEditVariable.Hint := STR_NOTSUPPORTED;
@@ -5110,8 +4728,8 @@ begin
menuShowSizeColumn.Visible := False;
actSelectTreeBackground.Visible := False;
end;
- actCreateView.Enabled := actCreateView.Enabled and (mysql_version >= 50001);
- actCreateRoutine.Enabled := actCreateRoutine.Enabled and (mysql_version >= 50003);
+ actCreateView.Enabled := actCreateView.Enabled and (Connection.ServerVersionInt >= 50001);
+ actCreateRoutine.Enabled := actCreateRoutine.Enabled and (Connection.ServerVersionInt >= 50003);
end;
@@ -5301,315 +4919,6 @@ begin
end;
-procedure TMainForm.ExecUseQuery(db: WideString; HandleErrors: Boolean = false; DisplayErrors: Boolean = false);
-begin
- ExecUpdateQuery('USE ' + mask(db), HandleErrors, DisplayErrors);
- FConn.MysqlParams.Database := db;
-end;
-
-
-{***
- Execute a query without returning a resultset
- The currently active connection is used
-
- @param String The single SQL-query to be executed on the server
-}
-function TMainForm.ExecUpdateQuery(sql: WideString; HandleErrors: Boolean = false; DisplayErrors: Boolean = false): Int64;
-var
- MysqlQuery : TMysqlQuery;
- ds: TDataSet;
-begin
- Result := -1; // Silence compiler warning.
- MysqlQuery := nil;
- try
- try
- // Start query execution
- MysqlQuery := RunThreadedQuery(sql, false);
- Result := FMysqlConn.Connection.GetAffectedRowsFromLastPost;
- // Inspect query result code and log / notify user on failure
- if MysqlQuery.Result in [MQR_CONNECT_FAIL,MQR_QUERY_FAIL] then
- begin
- raise Exception.Create(MysqlQuery.Comment);
- end;
- except
- on E: Exception do begin
- LogSQL( E.Message, True );
- if DisplayErrors then MessageDlg( E.Message, mtError, [mbOK], 0 );
- // Recreate exception, since we free it below the caller
- // won't know what happened otherwise.
- if not HandleErrors then raise THandledSQLError.Create(MysqlQuery.Comment);
- Result := -1;
- end;
- end;
- finally
- // Cleanup the MysqlQuery object, we won't need it anymore
- if MysqlQuery <> nil then begin
- if MysqlQuery.MysqlDataset <> nil then
- MysqlQuery.MysqlDataset.Close;
- ds := MysqlQuery.MysqlDataset;
- FreeAndNil(ds);
- end;
- FreeAndNil (MysqlQuery);
- end;
-end;
-
-
-{***
- Execute a query which may return a resultset. The caller is responsible for
- freeing the MysqlQuery object and its Dataset member, only on returnvalue True.
- The currently active connection is used
-
- @param String The single SQL-query to be executed on the server
- @return TMysqlQuery Containing the dataset and info data availability
-}
-function TMainForm.ExecSelectQuery(sql: WideString; HandleErrors: Boolean = false; DisplayErrors: Boolean = false; ForceDialog: Boolean = false): TDataSet;
-var
- res: TMysqlQuery;
-begin
- res := nil;
- result := nil;
- try
- try
- // Start query execution
- res := RunThreadedQuery(sql, ForceDialog);
- result := res.MysqlDataset;
- // Inspect query result code and log / notify user on failure
- if res.Result in [MQR_CONNECT_FAIL,MQR_QUERY_FAIL] then
- begin
- raise Exception.Create(res.Comment);
- end;
- except
- on E: Exception do begin
- LogSQL( E.Message, True );
- if DisplayErrors then MessageDlg( E.Message, mtError, [mbOK], 0 );
- if not HandleErrors then raise THandledSQLError.Create(E.Message);
- Result := nil;
- end;
- end;
- finally
- FreeAndNil(res);
- end;
-end;
-
-
-{***
- Executes a query.
-}
-function TMainForm.GetResults( SQLQuery: WideString; HandleErrors: Boolean = false; DisplayErrors: Boolean = false; ForceDialog: Boolean = false): TDataSet;
-begin
- result := ExecSelectQuery(SQLQuery, HandleErrors, DisplayErrors, ForceDialog);
-end;
-
-
-{***
- Execute a query and return String from column x
-}
-function TMainForm.GetVar( SQLQuery: WideString; x: Integer = 0; HandleErrors: Boolean = false; DisplayErrors: Boolean = false) : WideString;
-var
- ds: TDataSet;
-begin
- ds := GetResults( SQLQuery, HandleErrors, DisplayErrors );
- if ds = nil then exit;
- Result := ds.Fields[x].AsWideString;
- ds.Close;
- FreeAndNil(ds);
-end;
-
-
-function TMainForm.GetNamedVar( SQLQuery: WideString; x: WideString; HandleErrors: Boolean = false; DisplayErrors: Boolean = false) : WideString;
-var
- ds: TDataSet;
-begin
- ds := GetResults( SQLQuery, HandleErrors, DisplayErrors );
- if ds = nil then exit;
- Result := ds.Fields.FieldByName(x).AsWideString;
- ds.Close;
- FreeAndNil(ds);
-end;
-
-
-{***
- Execute a query and return column x as Stringlist
-
- @param String SQL query String
- @param Integer 0-based column index in the resultset to return
- @return TStringList
-}
-function TMainForm.GetCol( SQLQuery: WideString; x: Integer = 0; HandleErrors: Boolean = false; DisplayErrors: Boolean = false ) : WideStrings.TWideStringList;
-var
- i: Integer;
- ds: TDataSet;
-begin
- ds := GetResults( SQLQuery, HandleErrors, DisplayErrors);
- Result := WideStrings.TWideStringList.Create;
- if ds = nil then exit;
- for i := 0 to ds.RecordCount - 1 do
- begin
- Result.Add( ds.Fields[x].AsWideString );
- ds.Next;
- end;
- ds.Close;
- FreeAndNil(ds);
-end;
-
-
-{***
- Event procedure handler for the ZSQLMonitor1 object
-}
-procedure TMainForm.ZSQLMonitor1LogTrace(Sender: TObject;
- Event: TZLoggingEvent);
-begin
- LogSQL( Event.Message, (Event.Category <> lcExecute) );
-end;
-
-
-procedure TMainForm.RunAsyncPost(ds: TDeferDataSet);
-var
- res: TMysqlQuery;
-begin
- FQueryRunning := true;
- try
- try
- CheckConnection;
- except
- on E: Exception do begin
- raise Exception.Create('Failed to reconnect, giving up. (' + E.Message + ')');
- end;
- end;
- FProgressForm := TFrmQueryProgress.Create(Self);
- debug('RunThreadedQuery(): Launching asynchronous query.');
- res := ExecPostAsync(FConn,FProgressForm.Handle,ds);
- WaitForQueryCompletion(FProgressForm, res, false);
- if res.Result in [MQR_CONNECT_FAIL,MQR_QUERY_FAIL] then
- begin
- raise Exception.Create(res.Comment);
- end;
- finally
- FQueryRunning := false;
- end;
-end;
-
-{***
- Run a query in a separate thread of execution on the current connection.
-}
-function TMainForm.RunThreadedQuery(AQuery: WideString; ForceDialog: Boolean): TMysqlQuery;
-begin
- Result := nil;
- if (Copy(AQuery, 1, 3) <> 'USE') then EnsureDatabase;
- // Indicate a querythread is active (only one thread allow at this moment)
- FQueryRunning := true;
- try
- // Check if the connection of the current window is still alive
- // Otherwise reconnect
- try
- CheckConnection;
- except
- on E: Exception do begin
- // Ensure auto-updating processlist is disabled, see bug #1865305
- if TimerRefresh.Enabled then
- AutoRefreshToggle(nil);
- Screen.Cursor := crDefault;
- raise Exception.Create('Failed to reconnect, giving up. (' + E.Message + ')');
- end;
- end;
-
- // Create instance of the progress form (but don't show it yet)
- FProgressForm := TFrmQueryProgress.Create(Self);
-
- { Launch a thread of execution that passes the query to the server
-
- The progressform serves as receiver of the status
- messages (WM_MYSQL_THREAD_NOTIFY) of the thread:
-
- * After the thread starts it notifies the progressform (MQE_INITED)
- (which calls ShowModal on itself)
- * Waits for a completion message from the thread (MQE_FINISHED) to remove itself
- * Set FQueryRunning to false
- }
- debug('RunThreadedQuery(): Launching asynchronous query.');
- Result := ExecMysqlStatementAsync (AQuery,FConn,FProgressForm.Handle,RunAsyncPost);
-
- { Repeatedly check if the query has finished by inspecting FQueryRunning
- Allow repainting of user interface
- }
- WaitForQueryCompletion(FProgressForm, Result, ForceDialog);
- finally
- FQueryRunning := false;
- end;
- // Hack: Un-prevent dynamic loading of records in the context of the wait form's message loop.
- if not DataGrid.Visible then DataGrid.Visible := True;
-end;
-
-
-procedure TMainForm.CancelQuery;
-begin
- cancelling := true;
- MysqlConn.Connection.CancelQuery;
-end;
-
-
-// Searchbox unfocused
-procedure TMainForm.CheckConnection;
-var
- connected: Boolean;
- choice: Integer;
-begin
- if not FMysqlConn.IsAlive then begin
- LogSQL('Connection failure detected. Trying to reconnect.', true);
- TimerConnected.Enabled := false;
- TimerConnectedTimer(self);
- TimerHostUptime.Enabled := false;
- TimerHostUptimeTimer(self);
- FQueryRunning := false;
- try
- FMysqlConn.Connection.Disconnect;
- connected := True;
- try
- // CheckConnected() doesn't really check anything, it
- // just sees if the driver has disposed of it's connection
- // by means of a Disconnect() or not. In which case there
- // is no point in doing a Reconnect(), it will NOP.
- FMysqlConn.Connection.CheckConnected;
- except
- connected := False;
- end;
- while not FMysqlConn.IsAlive do begin
- try
- if connected then FMysqlConn.Connection.Reconnect
- else FMysqlConn.Connection.Connect;
- except
- on E: Exception do begin
- MainForm.Visible := False;
- choice := MessageDlg(
- 'Connection to the server has been lost.'#10#10 +
- E.Message + #10#10 +
- 'Click Abort to exit this session.',
- mtError,
- [mbRetry, mbAbort], 0
- );
- if choice = mrAbort then begin
- Close;
- Halt(1);
- end;
- end;
- end;
- if FMysqlConn.IsAlive then MainForm.Visible := True;
- end;
-
- time_connected := 0;
- TimerConnected.Enabled := true;
- LogSQL('Connected. Thread-ID: ' + IntToStr( MySQLConn.Connection.GetThreadId ));
- CheckUptime;
- // Try to restore active database
- if ActiveDatabase <> '' then
- ExecUseQuery(ActiveDatabase)
- finally
- FQueryRunning := true;
- end;
- end;
-end;
-
-
function TMainForm.GetActiveDatabase: WideString;
var
s: PVirtualNode;
@@ -5640,15 +4949,15 @@ end;
function TMainForm.GetTreeNodeType(Node: PVirtualNode): TListNodeType;
var
- ds: TDataset;
+ Results: TMySQLQuery;
begin
Result := lntNone;
if Assigned(Node) then case DBtree.GetNodeLevel(Node) of
1: Result := lntDb;
2: begin
- ds := FetchDbTableList(DBTree.Text[Node.Parent, 0]);
- ds.RecNo := Node.Index+1;
- Result := GetDBObjectType(ds.Fields);
+ Results := FetchDbTableList(DBTree.Text[Node.Parent, 0]);
+ Results.RecNo := Node.Index;
+ Result := GetDBObjectType(Results);
end;
end;
end;
@@ -5786,7 +5095,7 @@ begin
if (SelectedTable.Text <> '') and Assigned(SelectedTableColumns) then begin
SelectedTableColumns.First;
while not SelectedTableColumns.Eof do begin
- ActiveQueryHelpers.Items.Add(SelectedTableColumns.Fields[0].AsWideString);
+ ActiveQueryHelpers.Items.Add(SelectedTableColumns.Col(0));
SelectedTableColumns.Next;
end;
end;
@@ -5799,7 +5108,7 @@ begin
for i := 0 to Length(MySQLFunctions) - 1 do
begin
// Don't display unsupported functions here
- if MySqlFunctions[i].Version > mysql_version then
+ if MySqlFunctions[i].Version > Connection.ServerVersionInt then
continue;
ActiveQueryHelpers.Items.Add( MySQLFunctions[i].Name + MySQLFunctions[i].Declaration );
end;
@@ -6529,21 +5838,20 @@ begin
Combobox.Items.Clear;
// Cache datasets
- if ((dsShowEngines = nil) or (dsShowEngines.State = dsInactive)) and
- ((dsHaveEngines = nil) or (dsHaveEngines.State = dsInactive)) then
- begin
+ if dsShowEngines = nil then begin
FreeAndNil(dsShowEngines);
+ dsShowEngines := Connection.GetResults('SHOW ENGINES');
+ end;
+ if dsHaveEngines = nil then begin
FreeAndNil(dsHaveEngines);
- dsShowEngines := GetResults('SHOW ENGINES', True);
- if dsShowEngines = nil then
- dsHaveEngines := GetResults('SHOW VARIABLES LIKE ''have%''');
+ dsHaveEngines := Connection.GetResults('SHOW VARIABLES LIKE ''have%''');
end;
- if dsShowEngines <> nil then begin
+ if Assigned(dsShowEngines) then begin
dsShowEngines.First;
while not dsShowEngines.Eof do begin
- engineName := dsShowEngines.FieldByName('Engine').AsString;
- engineSupport := LowerCase(dsShowEngines.FieldByName('Support').AsString);
+ engineName := dsShowEngines.Col('Engine');
+ engineSupport := LowerCase(dsShowEngines.Col('Support'));
// Add to dropdown if supported
if engineSupport <> 'no' then
Combobox.Items.Add(engineName);
@@ -6566,14 +5874,14 @@ begin
HaveEngineList.CommaText := 'ARCHIVE,BDB,BLACKHOLE,CSV,EXAMPLE,FEDERATED,INNODB,ISAM';
dsHaveEngines.First;
while not dsHaveEngines.Eof do begin
- engineName := copy(dsHaveEngines.Fields[0].AsString, 6, Length(dsHaveEngines.Fields[0].AsString) );
+ engineName := copy(dsHaveEngines.Col(0), 6, Length(dsHaveEngines.Col(0)) );
// Strip additional "_engine" suffix, fx from "have_blackhole_engine"
if Pos('_', engineName) > 0 then
engineName := copy(engineName, 0, Pos('_', engineName)-1);
engineName := UpperCase(engineName);
// Add engine to dropdown if it's a) in HaveEngineList and b) activated
if (HaveEngineList.IndexOf(engineName) > -1)
- and (LowerCase(dsHaveEngines.Fields[1].AsString) = 'yes') then
+ and (LowerCase(dsHaveEngines.Col(1)) = 'yes') then
Combobox.Items.Add(engineName);
dsHaveEngines.Next;
end;
@@ -6711,7 +6019,7 @@ begin
EditVariableForm.VarValue := NodeData.Captions[1];
// Refresh relevant list node
if EditVariableForm.ShowModal = mrOK then
- NodeData.Captions[1] := GetVar('SHOW VARIABLES LIKE '+esc(NodeData.Captions[0]), 1);
+ NodeData.Captions[1] := Connection.GetVar('SHOW VARIABLES LIKE '+esc(NodeData.Captions[0]), 1);
end;
@@ -6732,7 +6040,7 @@ procedure TMainForm.DBtreeGetText(Sender: TBaseVirtualTree; Node:
PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText:
WideString);
var
- ds: TDataset;
+ Results: TMySQLQuery;
db, eng: WideString;
i: Integer;
Bytes: Int64;
@@ -6740,12 +6048,12 @@ var
begin
case Column of
0: case Sender.GetNodeLevel(Node) of
- 0: CellText := FConn.MysqlParams.User + '@' + FConn.MysqlParams.Host;
+ 0: CellText := Connection.Username + '@' + Connection.Hostname;
1: CellText := Databases[Node.Index];
2: begin
- ds := FetchDbTableList(Databases[Node.Parent.Index]);
- ds.RecNo := Node.Index+1;
- CellText := ds.FieldByName(DBO_NAME).AsWideString;
+ Results := FetchDbTableList(Databases[Node.Parent.Index]);
+ Results.RecNo := Node.Index;
+ CellText := Results.Col(DBO_NAME);
end;
end;
1: case GetTreeNodeType(Node) of
@@ -6763,10 +6071,10 @@ begin
if AllListsCached then begin
Bytes := 0;
for i := 0 to Databases.Count - 1 do begin
- ds := FetchDbTableList(Databases[i]);
- while not ds.Eof do begin
- Bytes := Bytes + GetTableSize(ds);
- ds.Next;
+ Results := FetchDbTableList(Databases[i]);
+ while not Results.Eof do begin
+ Bytes := Bytes + GetTableSize(Results);
+ Results.Next;
end;
end;
end;
@@ -6780,13 +6088,13 @@ begin
CellText := ''
else begin
Bytes := 0;
- ds := FetchDbTableList(db);
- while not ds.Eof do begin
- if ds.FindField('Type') <> nil then eng := FieldContent(ds, 'Type')
- else eng := FieldContent(ds, 'Engine');
+ Results := FetchDbTableList(db);
+ while not Results.Eof do begin
+ if Results.ColExists(DBO_TYPE) then eng := Results.Col(DBO_TYPE)
+ else eng := Results.Col('Engine');
if UpperCase(eng) <> 'MRG_MYISAM' then
- Bytes := Bytes + GetTableSize(ds);
- ds.Next;
+ Bytes := Bytes + GetTableSize(Results);
+ Results.Next;
end;
if Bytes >= 0 then CellText := FormatByteNumber(Bytes)
else CellText := '';
@@ -6794,9 +6102,9 @@ begin
end;
lntTable: begin
db := DBtree.Text[Node.Parent, 0];
- ds := FetchDbTableList(db);
- ds.RecNo := Node.Index + 1;
- Bytes := GetTableSize(ds);
+ Results := FetchDbTableList(db);
+ Results.RecNo := Node.Index + 1;
+ Bytes := GetTableSize(Results);
CellText := FormatByteNumber(Bytes);
end
else CellText := ''; // Applies for views and crashed tables
@@ -6812,7 +6120,7 @@ procedure TMainForm.DBtreeGetImageIndex(Sender: TBaseVirtualTree; Node:
PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted:
Boolean; var ImageIndex: Integer);
var
- ds: TDataset;
+ Results: TMySQLQuery;
begin
if Column > 0 then
Exit;
@@ -6822,9 +6130,9 @@ begin
ImageIndex := ICONINDEX_DB_HIGHLIGHT
else ImageIndex := ICONINDEX_DB;
2: begin
- ds := FetchDbTableList(Databases[Node.Parent.Index]);
- ds.RecNo := Node.Index+1;
- case GetDBObjectType(ds.Fields) of
+ Results := FetchDbTableList(Databases[Node.Parent.Index]);
+ Results.RecNo := Node.Index;
+ case GetDBObjectType(Results) of
lntTable:
if Kind = ikSelected then
ImageIndex := ICONINDEX_TABLE_HIGHLIGHT
@@ -6854,7 +6162,7 @@ procedure TMainForm.DBtreeInitChildren(Sender: TBaseVirtualTree; Node:
PVirtualNode; var ChildCount: Cardinal);
var
VT: TVirtualStringTree;
- ds: TDataset;
+ Results: TMySQLQuery;
i, j: Integer;
DatabasesWanted: TWideStringList;
rx: TRegExpr;
@@ -6868,7 +6176,7 @@ begin
try
if not Assigned(AllDatabases) then begin
Showstatus( 'Reading Databases...' );
- AllDatabases := GetCol('SHOW DATABASES');
+ AllDatabases := Connection.GetCol('SHOW DATABASES');
end;
if not Assigned(Databases) then
Databases := TWideStringList.Create;
@@ -6917,8 +6225,8 @@ begin
Screen.Cursor := crHourglass;
Showstatus( 'Reading Tables...' );
try
- ds := FetchDbTableList(Databases[Node.Index]);
- ChildCount := ds.RecordCount;
+ Results := FetchDbTableList(Databases[Node.Index]);
+ ChildCount := Results.RecordCount;
finally
ShowStatus( STATUS_MSG_READY );
Screen.Cursor := crDefault;
@@ -6969,10 +6277,12 @@ begin
0: ShowHost;
1: begin
newDb := Databases[Node.Index];
+ Connection.Database := newDb;
ShowDatabase( newDb );
end;
2: begin
newDb := Databases[Node.Parent.Index];
+ Connection.Database := newDb;
newDbObject := SelectedTable.Text;
tabEditor.TabVisible := True;
tabData.TabVisible := SelectedTable.NodeType in [lntTable, lntCrashedTable, lntView];
@@ -7005,6 +6315,13 @@ begin
end;
+procedure TMainForm.DatabaseChanged(Database: WideString);
+begin
+ if Database <> ActiveDatabase then
+ ActiveDatabase := Database;
+end;
+
+
procedure TMainForm.DBtreeDblClick(Sender: TObject);
var
Node: PVirtualNode;
@@ -7177,21 +6494,8 @@ end;
function TMainForm.DbTableListCachedAndValid(db: WideString): Boolean;
-var
- ds: TDataSet;
begin
Result := CachedTableLists.IndexOf(db) > -1;
- if Result then begin
- ds := TDataSet(CachedTableLists.Objects[CachedTableLists.IndexOf(db)]);
- // Delphi's RTL (TDataSet in DB.pas) throws exceptions right and left
- // if the database the dataset(-derivate, aka TZDataSet) came from is
- // currently, or has been earlier been, disconnected. Therefore, nuke
- // these datasets, they'll have to be reloaded.
- if ds.State = dsInactive then begin
- ClearDbTableList(db);
- Result := False;
- end;
- end;
end;
procedure TMainForm.editFilterSearchChange(Sender: TObject);
@@ -7208,7 +6512,7 @@ begin
for i := 0 to SelectedTableColumns.RecordCount - 1 do begin
if i > 0 then
Add := Add + ' OR ';
- Add := Add + mask(SelectedTableColumns.Fields[0].AsWideString) + ' LIKE ' + esc('%'+ed.Text+'%');
+ Add := Add + mask(SelectedTableColumns.Col(0)) + ' LIKE ' + esc('%'+ed.Text+'%');
if Length(Add) > 45 then begin
Clause := Clause + Add + CRLF;
Add := '';
@@ -7261,7 +6565,7 @@ procedure TMainForm.EnsureNodeLoaded(Sender: TBaseVirtualTree; Node: PVirtualNod
var
res: TGridResult;
query: WideString;
- ds: TDataSet;
+ Results: TMySQLQuery;
i, j: LongInt;
begin
res := GridResult(Sender);
@@ -7276,9 +6580,9 @@ begin
// start query
ShowStatus('Retrieving data...');
- ds := GetResults(query);
+ Results := Connection.GetResults(query);
// If new data does not match current filter, remove from tree.
- if Cardinal(ds.RecordCount) < 1 then begin
+ if Results.RecordCount < 1 then begin
// Remove entry from dynamic array.
for i := Node.Index to Length(res.Rows) - 1 do begin
if i < Length(res.Rows) - 1 then res.Rows[i] := res.Rows[i + 1];
@@ -7290,21 +6594,21 @@ begin
// fill in data
ShowStatus('Filling grid with record-data...');
- if Cardinal(ds.RecordCount) > 0 then begin
- SetLength(res.Rows[Node.Index].Cells, ds.Fields.Count);
+ if Results.RecordCount > 0 then begin
+ SetLength(res.Rows[Node.Index].Cells, Results.ColumnCount);
i := Node.Index;
- for j := 0 to ds.Fields.Count - 1 do begin
+ for j := 0 to Results.ColumnCount - 1 do begin
if res.Columns[j].DatatypeCat = dtcBinary then
- res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(ds.Fields[j].AsString)
+ res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(Results.Col(j))
else
- res.Rows[i].Cells[j].Text := ds.Fields[j].AsWideString;
- res.Rows[i].Cells[j].IsNull := ds.Fields[j].IsNull;
+ res.Rows[i].Cells[j].Text := Results.Col(j);
+ res.Rows[i].Cells[j].IsNull := Results.IsNull(j);
end;
res.Rows[Node.Index].Loaded := True;
end;
ShowStatus( STATUS_MSG_READY );
- FreeAndNil(ds);
+ FreeAndNil(Results);
end;
end;
@@ -7313,7 +6617,7 @@ var
res: TGridResult;
start, limit: Cardinal;
query: WideString;
- ds: TDataSet;
+ Results: TMySQLQuery;
i, j: LongInt;
hi: LongInt;
regCrashIndicName: String;
@@ -7340,7 +6644,7 @@ begin
ShowStatus('Retrieving data...');
debug(Format('mem: loading data chunk from row %d to %d', [start, limit]));
try
- ds := GetResults(query);
+ Results := Connection.GetResults(query);
except
// if something bad happened, nuke cache, reset cursor and display error.
TVirtualStringTree(Sender).RootNodeCount := 0;
@@ -7350,8 +6654,8 @@ begin
Screen.Cursor := crDefault;
raise;
end;
- if Cardinal(ds.RecordCount) < limit then begin
- limit := ds.RecordCount;
+ if Cardinal(Results.RecordCount) < limit then begin
+ limit := Results.RecordCount;
TVirtualStringTree(Sender).RootNodeCount := start + limit;
SetLength(res.Rows, start + limit);
ReachedEOT := true;
@@ -7372,17 +6676,17 @@ begin
// fill in data
ShowStatus('Filling grid with record-data...');
- for i := start to start + limit - 1 do begin
- SetLength(res.Rows[i].Cells, ds.Fields.Count);
- for j := 0 to ds.Fields.Count - 1 do begin
+ for i:=start to start+limit-1 do begin
+ SetLength(res.Rows[i].Cells, Results.ColumnCount);
+ for j:=0 to Results.ColumnCount-1 do begin
if res.Columns[j].DatatypeCat = dtcBinary then
- res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(ds.Fields[j].AsString)
+ res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(Results.Col(j))
else
- res.Rows[i].Cells[j].Text := ds.Fields[j].AsWideString;
- res.Rows[i].Cells[j].IsNull := ds.Fields[j].IsNull;
+ res.Rows[i].Cells[j].Text := Results.Col(j);
+ res.Rows[i].Cells[j].IsNull := Results.IsNull(j);
end;
res.Rows[i].Loaded := True;
- ds.Next;
+ Results.Next;
end;
if res = DataGridResult then begin
@@ -7391,7 +6695,7 @@ begin
end;
ShowStatus( STATUS_MSG_READY );
- FreeAndNil(ds);
+ FreeAndNil(Results);
end;
end;
@@ -7676,7 +6980,8 @@ begin
sql := sql + ' WHERE ' + GetWhereClause(Row, @DataGridResult.Columns);
try
// Send UPDATE query
- if (ExecUpdateQuery(sql, False, True) = 0) then begin
+ Connection.Query(sql);
+ if Connection.RowsAffected = 0 then begin
MessageDlg('Your change did not affect any row! This can have several causes:' + CRLF + CRLF +
'a) Your changes were silently converted by the server. For instance, if you tried to ' +
'update an unsigned TINYINT field from its maximum value 255 to a higher value.' + CRLF + CRLF +
@@ -7776,8 +7081,8 @@ var
Result.Clear;
SelectedTableKeys.First;
while not SelectedTableKeys.Eof do begin
- if SelectedTableKeys.FieldByName('Key_name').AsWideString = KeyName then
- Result.Add(SelectedTableKeys.FieldByName('Column_name').AsWideString);
+ if SelectedTableKeys.Col('Key_name') = KeyName then
+ Result.Add(SelectedTableKeys.Col('Column_name'));
SelectedTableKeys.Next;
end;
end;
@@ -7788,8 +7093,8 @@ begin
SelectedTableKeys.First;
// 1. round: find a primary key
while not SelectedTableKeys.Eof do begin
- if SelectedTableKeys.FieldByName('Key_name').AsWideString = 'PRIMARY' then begin
- FindColumns(SelectedTableKeys.FieldByName('Key_name').AsWideString);
+ if SelectedTableKeys.Col('Key_name') = 'PRIMARY' then begin
+ FindColumns(SelectedTableKeys.Col('Key_name'));
Exit;
end;
SelectedTableKeys.Next;
@@ -7797,16 +7102,16 @@ begin
// no primary key available -> 2. round: find a unique key
SelectedTableKeys.First;
while not SelectedTableKeys.Eof do begin
- if SelectedTableKeys.FieldByName('Non_unique').AsInteger = 0 then begin
+ if MakeInt(SelectedTableKeys.Col('Non_unique')) = 0 then begin
// We found a UNIQUE key - better than nothing. Check if one of the key
// columns allows NULLs which makes it dangerous to use in UPDATES + DELETES.
- FindColumns(SelectedTableKeys.FieldByName('Key_name').AsWideString);
+ FindColumns(SelectedTableKeys.Col('Key_name'));
SelectedTableColumns.First;
AllowsNull := False;
- for i := 0 to Result.Count - 1 do begin
+ for i:=0 to Result.Count-1 do begin
while (not SelectedTableColumns.Eof) and (not AllowsNull) do begin
- if SelectedTableColumns.FieldByName('Field').AsWideString = Result[i] then
- AllowsNull := UpperCase(SelectedTableColumns.FieldByName('Null').AsString) = 'YES';
+ if SelectedTableColumns.Col('Field') = Result[i] then
+ AllowsNull := UpperCase(SelectedTableColumns.Col('Null')) = 'YES';
SelectedTableColumns.Next;
end;
if AllowsNull then break;
@@ -7892,9 +7197,9 @@ begin
Cols := Copy(Cols, 1, Length(Cols)-2);
sql := 'INSERT INTO '+mask(DataGridDB)+'.'+mask(DataGridTable)+' ('+Cols+') VALUES ('+Vals+')';
// Send INSERT query
- if (ExecUpdateQuery(sql) = 0) then begin
+ Connection.Query(sql);
+ if Connection.RowsAffected = 0 then
MessageBox(Self.Handle, 'Server failed to insert row.', 'Error', 0);
- end;
Result := True;
Row.Loaded := false;
EnsureNodeLoaded(Sender, Node, GetWhereClause(Row, @DataGridResult.Columns));
@@ -7928,7 +7233,7 @@ begin
try
// Send DELETE query
- ExecUpdateQuery(sql, False, True);
+ Connection.Query(sql);
Result := True;
except
Result := False;
@@ -7936,7 +7241,7 @@ begin
if Result then begin
// Remove deleted row nodes out of the grid
- Affected := FMysqlConn.Connection.GetAffectedRowsFromLastPost;
+ Affected := Connection.RowsAffected;
Selected := Sender.SelectedCount;
if Affected = Selected then begin
// Fine. Number of deleted rows equals the selected node count.
@@ -8016,7 +7321,7 @@ var
Col: PGridColumn;
sql: WideString;
len: Int64;
- ds: TDataSet;
+ Results: TMySQLQuery;
begin
Result := True;
@@ -8038,10 +7343,10 @@ begin
' FROM ' + mask(SelectedTable.Text) +
' WHERE ' + GetWhereClause(Row, @DataGridResult.Columns)
;
- ds := GetResults(sql);
- if Col.DatatypeCat = dtcBinary then Cell.Text := '0x' + BinToWideHex(ds.Fields[0].AsString)
- else Cell.Text := ds.Fields[0].AsWideString;
- Cell.IsNull := ds.Fields[0].IsNull;
+ Results := Connection.GetResults(sql);
+ if Col.DatatypeCat = dtcBinary then Cell.Text := '0x' + BinToWideHex(Results.Col(0))
+ else Cell.Text := Results.Col(0);
+ Cell.IsNull := Results.IsNull(0);
end else
Result := False;
end;
@@ -8127,27 +7432,25 @@ begin
end;
-function TMainForm.GetSelectedTableColumns: TDataset;
+function TMainForm.GetSelectedTableColumns: TMySQLQuery;
begin
- if (FSelectedTableColumns = nil) or (FSelectedTableColumns.State = dsInactive) then begin
- FreeAndNil(FSelectedTableColumns);
- // Avoid SQL error on routines
+ if not Assigned(FSelectedTableColumns) then begin
+ // Avoid SQL error on routines
if GetFocusedTreeNodeType in [lntTable, lntView] then begin
ShowStatus('Reading table columns ...');
- FSelectedTableColumns := GetResults( 'SHOW /*!32332 FULL */ COLUMNS FROM ' + mask(SelectedTable.Text), false );
+ FSelectedTableColumns := Connection.GetResults('SHOW /*!32332 FULL */ COLUMNS FROM ' + mask(SelectedTable.Text));
end;
end;
Result := FSelectedTableColumns;
end;
-function TMainForm.GetSelectedTableKeys: TDataset;
+function TMainForm.GetSelectedTableKeys: TMySQLQuery;
begin
- if (FSelectedTableKeys = nil) or (FSelectedTableKeys.State = dsInactive) then begin
- FreeAndNil(FSelectedTableKeys);
- // Avoid SQL error on routines
+ if not Assigned(FSelectedTableKeys) then begin
+ // Avoid SQL error on routines
if GetFocusedTreeNodeType in [lntTable, lntView] then begin
ShowStatus('Reading table keys ...');
- FSelectedTableKeys := GetResults( 'SHOW KEYS FROM ' + mask(SelectedTable.Text) );
+ FSelectedTableKeys := Connection.GetResults('SHOW KEYS FROM ' + mask(SelectedTable.Text));
end;
end;
Result := FSelectedTableKeys;
@@ -8370,7 +7673,7 @@ end;
procedure TMainForm.LoadDataView(ViewName: String);
var
rx: TRegExpr;
- idx, i: Integer;
+ idx: Integer;
Col: WideString;
HiddenCols: TWideStringList;
begin
@@ -8383,8 +7686,8 @@ begin
HiddenCols.DelimitedText := Utf8Decode(MainReg.ReadString(REGNAME_HIDDENCOLUMNS));
SelectedTableColumns.First;
FDataGridSelect.Clear;
- for i := 0 to SelectedTableColumns.RecordCount - 1 do begin
- Col := SelectedTableColumns.Fields[0].AsWideString;
+ while not SelectedTableColumns.Eof do begin
+ Col := SelectedTableColumns.Col(0);
if HiddenCols.IndexOf(Col) = -1 then
FDataGridSelect.Add(Col);
SelectedTableColumns.Next;
@@ -8462,7 +7765,7 @@ procedure TMainForm.ListVariablesBeforePaint(Sender: TBaseVirtualTree; TargetCan
var
i : Integer;
vt: TVirtualStringTree;
- ds: TDataSet;
+ Results: TMySQLQuery;
Sel: TWideStringList;
begin
// Display server variables
@@ -8473,17 +7776,16 @@ begin
DeInitializeVTNodes(vt);
Screen.Cursor := crHourglass;
try
- ds := GetResults('SHOW VARIABLES');
- SetLength(VTRowDataListVariables, ds.RecordCount);
- for i:=1 to ds.RecordCount do begin
- VTRowDataListVariables[i-1].ImageIndex := 25;
- VTRowDataListVariables[i-1].Captions := WideStrings.TWideStringList.Create;
- VTRowDataListVariables[i-1].Captions.Add( ds.Fields[0].AsWideString );
- VTRowDataListVariables[i-1].Captions.Add( ds.Fields[1].AsWideString );
- ds.Next;
+ Results := Connection.GetResults('SHOW VARIABLES');
+ SetLength(VTRowDataListVariables, Results.RecordCount);
+ for i:=0 to Results.RecordCount-1 do begin
+ VTRowDataListVariables[i].ImageIndex := 25;
+ VTRowDataListVariables[i].Captions := TWideStringList.Create;
+ VTRowDataListVariables[i].Captions.Add(Results.Col(0));
+ VTRowDataListVariables[i].Captions.Add(Results.Col(1));
+ Results.Next;
end;
- ds.Close;
- FreeAndNil(ds);
+ FreeAndNil(Results);
vt.RootNodeCount := Length(VTRowDataListVariables);
vt.SortTree(vt.Header.SortColumn, vt.Header.SortDirection);
SetVTSelection(vt, Sel);
@@ -8504,7 +7806,7 @@ var
i: Integer;
valcount: Int64;
tmpval: Double;
- ds: TDataSet;
+ Results: TMySQLQuery;
val, avg_perhour, avg_persec: WideString;
valIsBytes, valIsNumber: Boolean;
vt: TVirtualStringTree;
@@ -8518,19 +7820,19 @@ begin
DeInitializeVTNodes(vt);
Screen.Cursor := crHourglass;
try
- ds := GetResults( 'SHOW /*!50002 GLOBAL */ STATUS' );
- SetLength(VTRowDataListStatus, ds.RecordCount);
- for i:=1 to ds.RecordCount do begin
- VTRowDataListStatus[i-1].ImageIndex := 25;
- VTRowDataListStatus[i-1].Captions := WideStrings.TWideStringList.Create;
- VTRowDataListStatus[i-1].Captions.Add( ds.Fields[0].AsWideString );
- val := ds.Fields[1].AsWideString;
+ Results := Connection.GetResults('SHOW /*!50002 GLOBAL */ STATUS');
+ SetLength(VTRowDataListStatus, Results.RecordCount);
+ for i:=0 to Results.RecordCount-1 do begin
+ VTRowDataListStatus[i].ImageIndex := 25;
+ VTRowDataListStatus[i].Captions := TWideStringList.Create;
+ VTRowDataListStatus[i].Captions.Add(Results.Col(0));
+ val := Results.Col(1);
avg_perhour := '';
avg_persec := '';
// Detect value type
valIsNumber := IntToStr(MakeInt(val)) = val;
- valIsBytes := valIsNumber and (Copy(ds.Fields[0].AsWideString, 1, 6) = 'Bytes_');
+ valIsBytes := valIsNumber and (Copy(Results.Col(0), 1, 6) = 'Bytes_');
// Calculate average values ...
if valIsNumber then begin
@@ -8551,13 +7853,12 @@ begin
else if valIsNumber then
val := FormatNumber(val);
- VTRowDataListStatus[i-1].Captions.Add( val );
- VTRowDataListStatus[i-1].Captions.Add(avg_perhour);
- VTRowDataListStatus[i-1].Captions.Add(avg_persec);
- ds.Next;
+ VTRowDataListStatus[i].Captions.Add( val );
+ VTRowDataListStatus[i].Captions.Add(avg_perhour);
+ VTRowDataListStatus[i].Captions.Add(avg_persec);
+ Results.Next;
end;
- ds.Close;
- FreeAndNil(ds);
+ FreeAndNil(Results);
// Tell VirtualTree the number of nodes it will display
vt.RootNodeCount := Length(VTRowDataListStatus);
vt.SortTree(vt.Header.SortColumn, vt.Header.SortDirection);
@@ -8576,7 +7877,7 @@ end;
procedure TMainForm.ListProcessesBeforePaint(Sender: TBaseVirtualTree; TargetCanvas: TCanvas);
var
i, j: Integer;
- ds: TDataSet;
+ Results: TMySQLQuery;
vt: TVirtualStringTree;
Sel: TWideStringList;
begin
@@ -8588,25 +7889,24 @@ begin
DeInitializeVTNodes(vt);
Screen.Cursor := crHourglass;
try
- ds := GetResults('SHOW FULL PROCESSLIST', false, false);
- SetLength(VTRowDataListProcesses, ds.RecordCount);
- for i:=1 to ds.RecordCount do begin
- VTRowDataListProcesses[i-1].Captions := WideStrings.TWideStringList.Create;
- VTRowDataListProcesses[i-1].Captions.Add( ds.Fields[0].AsWideString );
- if AnsiCompareText( ds.Fields[4].AsString, 'Killed') = 0 then
- VTRowDataListProcesses[i-1].ImageIndex := 26 // killed
+ Results := Connection.GetResults('SHOW FULL PROCESSLIST');
+ SetLength(VTRowDataListProcesses, Results.RecordCount);
+ for i:=0 to Results.RecordCount-1 do begin
+ VTRowDataListProcesses[i].Captions := TWideStringList.Create;
+ VTRowDataListProcesses[i].Captions.Add(Results.Col(0));
+ if AnsiCompareText(Results.Col(4), 'Killed') = 0 then
+ VTRowDataListProcesses[i].ImageIndex := 26 // killed
else begin
- if ds.FindField('Info').AsString = '' then
- VTRowDataListProcesses[i-1].ImageIndex := 55 // idle
+ if Results.Col('Info') = '' then
+ VTRowDataListProcesses[i].ImageIndex := 55 // idle
else
- VTRowDataListProcesses[i-1].ImageIndex := 57 // running query
+ VTRowDataListProcesses[i].ImageIndex := 57 // running query
end;
for j := 1 to 7 do
- VTRowDataListProcesses[i-1].Captions.Add(ds.Fields[j].AsWideString);
- ds.Next;
+ VTRowDataListProcesses[i].Captions.Add(Results.Col(j));
+ Results.Next;
end;
- ds.Close;
- FreeAndNil(ds);
+ FreeAndNil(Results);
vt.RootNodeCount := Length(VTRowDataListProcesses);
vt.SortTree(vt.Header.SortColumn, vt.Header.SortDirection);
SetVTSelection(vt, Sel);
@@ -8655,7 +7955,7 @@ procedure TMainForm.ListCommandStatsBeforePaint(Sender: TBaseVirtualTree; Target
var
i: Integer;
questions: Int64;
- ds: TDataSet;
+ Results: TMySQLQuery;
vt: TVirtualStringTree;
Sel: TWideStringList;
begin
@@ -8668,18 +7968,17 @@ begin
DeInitializeVTNodes(vt);
Screen.Cursor := crHourglass;
try
- ds := GetResults('SHOW /*!50002 GLOBAL */ STATUS LIKE ''Com\_%''' );
- questions := MakeInt(GetVar('SHOW /*!50002 GLOBAL */ STATUS LIKE ''Questions''', 1));
+ Results := Connection.GetResults('SHOW /*!50002 GLOBAL */ STATUS LIKE ''Com\_%''' );
+ questions := MakeInt(Connection.GetVar('SHOW /*!50002 GLOBAL */ STATUS LIKE ''Questions''', 1));
if questions = 0 then
Raise Exception.Create('Could not detect value of "Questions" status. Command statistics are not available.');
- SetLength(VTRowDataListCommandStats, ds.RecordCount+1);
+ SetLength(VTRowDataListCommandStats, Results.RecordCount+1);
addLVitem(0, ' All commands', questions, questions );
- for i:=1 to ds.RecordCount do begin
- addLVitem(i, ds.Fields[0].AsWideString, MakeInt(ds.Fields[1].AsString), questions );
- ds.Next;
+ for i:=0 to Results.RecordCount-1 do begin
+ addLVitem(i, Results.Col(0), MakeInt(Results.Col(1)), questions );
+ Results.Next;
end;
- ds.Close;
- FreeAndNil(ds);
+ FreeAndNil(Results);
// Tell VirtualTree the number of nodes it will display
vt.RootNodeCount := Length(VTRowDataListCommandStats);
vt.SortTree(vt.Header.SortColumn, vt.Header.SortDirection);
@@ -8929,7 +8228,7 @@ begin
query := 'SELECT COUNT(*)' + DataGridCurrentFrom;
if DataGridCurrentFilter <> '' then query := query + ' WHERE ' + DataGridCurrentFilter;
try
- count := MakeInt(GetVar(query));
+ count := MakeInt(Connection.GetVar(query));
// Work around a memory allocation bug in VirtualTree.
if count > prefMaxTotalRows then count := prefMaxTotalRows;
except
@@ -8970,18 +8269,16 @@ begin
end;
-function TMainform.GetCollations(Items: TWideStrings = nil): TDataset;
+function TMainform.GetCollations(Items: TWideStrings = nil): TMySQLQuery;
begin
// Return cached collation list, used in several places, e.g. table editor
- if (dsCollations = nil) or (dsCollations.State = dsInactive) then begin
- FreeAndNil(dsCollations);
- dsCollations := GetResults('SHOW COLLATION', True);
- end;
+ if dsCollations = nil then
+ dsCollations := Connection.GetResults('SHOW COLLATION');
if Assigned(dsCollations) then begin
dsCollations.First;
if Assigned(Items) then begin
while not dsCollations.Eof do begin
- Items.Add(dsCollations.FieldByName('Collation').AsWideString);
+ Items.Add(dsCollations.Col('Collation'));
dsCollations.Next;
end;
dsCollations.First;
@@ -9640,7 +8937,6 @@ begin
MakeVisible := Sender <> btnCloseFilterPanel;
pnlFilterVT.Visible := MakeVisible;
pnlFilterVT.Tag := Integer(MakeVisible);
- ValidateControls(Sender);
// On startup, we cannot SetFocus, throws exceptons. Call with nil in that special case - see FormCreate
if Assigned(Sender) and MakeVisible then
editFilterVT.SetFocus;
diff --git a/extra/mysql_dataset/mysql_api.pas b/source/mysql_api.pas
similarity index 97%
rename from extra/mysql_dataset/mysql_api.pas
rename to source/mysql_api.pas
index 186ef7e8..1b716d8a 100644
--- a/extra/mysql_dataset/mysql_api.pas
+++ b/source/mysql_api.pas
@@ -195,7 +195,10 @@ type
MYSQL_OPT_USE_EMBEDDED_CONNECTION,
MYSQL_OPT_GUESS_CONNECTION,
MYSQL_SET_CLIENT_IP,
- MYSQL_SECURE_AUTH
+ MYSQL_SECURE_AUTH,
+ MYSQL_REPORT_DATA_TRUNCATION,
+ MYSQL_OPT_RECONNECT,
+ MYSQL_OPT_SSL_VERIFY_SERVER_CERT
);
TMySQLRplType = (
diff --git a/source/mysql_connection.pas b/source/mysql_connection.pas
new file mode 100644
index 00000000..e07b2e24
--- /dev/null
+++ b/source/mysql_connection.pas
@@ -0,0 +1,728 @@
+unit mysql_connection;
+
+{$M+} // Needed to add published properties
+
+interface
+
+uses
+ Classes, SysUtils, windows, mysql_api, mysql_structures, WideStrings, WideStrUtils;
+
+type
+
+ { TMySQLConnection }
+
+ TMySQLLogCategory = (lcInfo, lcSQL, lcError, lcWarning, lcDebug);
+ TMySQLLogEvent = procedure(Msg: WideString; Category: TMySQLLogCategory=lcInfo) of object;
+ TMySQLDatabaseChangedEvent = procedure(Database: WideString) of object;
+
+ TMySQLServerCapability = (
+ cpShowEngines, // SHOW ENGINES
+ cpShowTableStatus, // SHOW TABLE STATUS
+ cpShowFullTables, // SHOW FULL TABLES
+ cpShowCreateTable, // SHOW CREATE TABLE foo
+ cpShowCreateDatabase, // SHOW CREATE DATABASE foo
+ cpHelpSystem, // HELP "foo"
+ cpSetNames, // SET NAMES
+ cpCalcFoundRows, // SELECT SQL_CALC_FOUND_ROWS ...
+ cpLoadFile, // LOAD DATA LOCAL INFILE ...
+ cpTableComment, // CREATE TABLE ... COMMENT = "foo"
+ cpFieldComment, // ALTER TABLE ADD ... COMMENT = "foo"
+ cpColumnMoving, // ALTER TABLE CHANGE ... FIRST|AFTER foo
+ cpTruncateTable, // TRUNCATE TABLE foo
+ cpAlterDatabase, // ALTER DATABASE
+ cpRenameDatabase // RENAME DATABASE
+ );
+ TMySQLServerCapabilities = set of TMySQLServerCapability;
+
+ TMySQLClientOption = (
+ opCompress, // CLIENT_COMPRESS
+ opConnectWithDb, // CLIENT_CONNECT_WITH_DB
+ opFoundRows, // CLIENT_FOUND_ROWS
+ opIgnoreSigpipe, // CLIENT_IGNORE_SIGPIPE
+ opIgnoreSpace, // CLIENT_IGNORE_SPACE
+ opInteractive, // CLIENT_INTERACTIVE
+ opLocalFiles, // CLIENT_LOCAL_FILES
+ opLongFlag, // CLIENT_LONG_FLAG
+ opLongPassword, // CLIENT_LONG_PASSWORD
+ opMultiResults, // CLIENT_MULTI_RESULTS
+ opMultiStatements, // CLIENT_MULTI_STATEMENTS
+ opNoSchema, // CLIENT_NO_SCHEMA
+ opODBC, // CLIENT_ODBC
+ opProtocol41, // CLIENT_PROTOCOL_41
+ opRememberOptions, // CLIENT_REMEMBER_OPTIONS
+ opReserved, // CLIENT_RESERVED
+ opSecureConnection, // CLIENT_SECURE_CONNECTION
+ opSSL, // CLIENT_SSL
+ opTransactions // CLIENT_TRANSACTIONS
+ );
+ TMySQLClientOptions = set of TMySQLClientOption;
+
+const
+ DEFAULT_MYSQLOPTIONS = [opCompress, opLocalFiles, opInteractive, opProtocol41];
+
+type
+ TMySQLQuery = class;
+ TMySQLConnection = class(TComponent)
+ private
+ FHandle: PMYSQL;
+ FActive: Boolean;
+ FConnectionStarted: Cardinal;
+ FHostname: String;
+ FSocketname: String;
+ FPort: Integer;
+ FUsername: String;
+ FPassword: String;
+ FDatabase: WideString;
+ FOnLog: TMySQLLogEvent;
+ FOnDatabaseChanged: TMySQLDatabaseChangedEvent;
+ FOptions: TMySQLClientOptions;
+ FCapabilities: TMySQLServerCapabilities;
+ FRowsFound: Int64;
+ FRowsAffected: Int64;
+ FServerVersionUntouched: String;
+ function GetActive: Boolean;
+ procedure SetActive(Value: Boolean);
+ procedure SetDatabase(Value: WideString);
+ function GetThreadId: Cardinal;
+ function GetCharacterSet: String;
+ procedure SetCharacterSet(CharsetName: String);
+ function GetLastError: WideString;
+ function GetServerVersionStr: String;
+ function GetServerVersionInt: Integer;
+ procedure Log(Category: TMySQLLogCategory; Msg: WideString);
+ procedure DetectCapabilities;
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ function Query(SQL: WideString; DoStoreResult: Boolean=False): PMYSQL_RES;
+ function EscapeString(Text: WideString; DoQuote: Boolean=True): WideString;
+ function QuoteIdent(Identifier: WideString): WideString;
+ function DeQuoteIdent(Identifier: WideString): WideString;
+ function ConvertServerVersion(Version: Integer): String;
+ function GetResults(SQL: WideString): TMySQLQuery;
+ function GetCol(SQL: WideString; Column: Integer=0): TWideStringList;
+ function GetVar(SQL: WideString; Column: Integer=0): WideString; overload;
+ function GetVar(SQL: WideString; Column: WideString): WideString; overload;
+ property ThreadId: Cardinal read GetThreadId;
+ property ConnectionStarted: Cardinal read FConnectionStarted;
+ property CharacterSet: String read GetCharacterSet write SetCharacterSet;
+ property LastError: WideString read GetLastError;
+ property ServerVersionUntouched: String read FServerVersionUntouched;
+ property ServerVersionStr: String read GetServerVersionStr;
+ property ServerVersionInt: Integer read GetServerVersionInt;
+ property Capabilities: TMySQLServerCapabilities read FCapabilities;
+ property RowsFound: Int64 read FRowsFound;
+ property RowsAffected: Int64 read FRowsAffected;
+ published
+ property Active: Boolean read GetActive write SetActive default False;
+ property Hostname: String read FHostname write FHostname;
+ property Socketname: String read FSocketname write FSocketname;
+ property Port: Integer read FPort write FPort default MYSQL_PORT;
+ property Username: String read FUsername write FUsername;
+ property Password: String read FPassword write FPassword;
+ property Database: WideString read FDatabase write SetDatabase;
+ property Options: TMySQLClientOptions read FOptions write FOptions default [opCompress, opLocalFiles, opInteractive, opProtocol41];
+ // Events
+ property OnLog: TMySQLLogEvent read FOnLog write FOnLog;
+ property OnDatabaseChanged: TMySQLDatabaseChangedEvent read FOnDatabaseChanged write FOnDatabaseChanged;
+ end;
+
+
+ { TMySQLQuery }
+
+ TMySQLQuery = class(TComponent)
+ private
+ FSQL: WideString;
+ FConnection: TMySQLConnection;
+ FRecNo,
+ FRecordCount: Int64;
+ FColumnNames: TWideStringList;
+ FLastResult: PMYSQL_RES;
+ FCurrentRow: PMYSQL_ROW;
+ FEof: Boolean;
+ procedure SetSQL(Value: WideString);
+ procedure SetRecNo(Value: Int64);
+ public
+ constructor Create(AOwner: TComponent); override;
+ destructor Destroy; override;
+ procedure Execute;
+ procedure First;
+ procedure Next;
+ function ColumnCount: Integer;
+ function Col(Column: Integer; IgnoreErrors: Boolean=False): WideString; overload;
+ function Col(ColumnName: WideString; IgnoreErrors: Boolean=False): WideString; overload;
+ function DataType(Column: Integer): TDataType;
+ function ColExists(Column: WideString): Boolean;
+ function IsNull(Column: Integer): Boolean;
+ function HasResult: Boolean;
+ property RecNo: Int64 read FRecNo write SetRecNo;
+ property Eof: Boolean read FEof;
+ property RecordCount: Int64 read FRecordCount;
+ property ColumnNames: TWideStringList read FColumnNames;
+ published
+ property SQL: WideString read FSQL write SetSQL;
+ property Connection: TMySQLConnection read FConnection write FConnection;
+ end;
+
+
+implementation
+
+
+{ TMySQLConnection }
+
+constructor TMySQLConnection.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+ FOptions := DEFAULT_MYSQLOPTIONS;
+ FPort := MYSQL_PORT;
+ FRowsFound := 0;
+ FRowsAffected := 0;
+ FConnectionStarted := 0;
+end;
+
+
+destructor TMySQLConnection.Destroy;
+begin
+ if Active then Active := False;
+ inherited Destroy;
+end;
+
+
+{**
+ (Dis-)Connect to/from server
+}
+procedure TMySQLConnection.SetActive( Value: Boolean );
+var
+ Connected: PMYSQL;
+ ClientFlags: Integer;
+ Error, tmpdb: WideString;
+ UsingPass, Protocol: String;
+begin
+ FActive := Value;
+
+ if Value and (FHandle = nil) then begin
+ // Get handle
+ FHandle := mysql_init(nil);
+
+ // Gather client options
+ ClientFlags := 0;
+ if opRememberOptions in FOptions then ClientFlags := ClientFlags or CLIENT_REMEMBER_OPTIONS;
+ if opLongPassword in FOptions then ClientFlags := ClientFlags or CLIENT_LONG_PASSWORD;
+ if opFoundRows in FOptions then ClientFlags := ClientFlags or CLIENT_FOUND_ROWS;
+ if opLongFlag in FOptions then ClientFlags := ClientFlags or CLIENT_LONG_FLAG;
+ if opConnectWithDb in FOptions then ClientFlags := ClientFlags or CLIENT_CONNECT_WITH_DB;
+ if opNoSchema in FOptions then ClientFlags := ClientFlags or CLIENT_NO_SCHEMA;
+ if opCompress in FOptions then ClientFlags := ClientFlags or CLIENT_COMPRESS;
+ if opODBC in FOptions then ClientFlags := ClientFlags or CLIENT_ODBC;
+ if opLocalFiles in FOptions then ClientFlags := ClientFlags or CLIENT_LOCAL_FILES;
+ if opIgnoreSpace in FOptions then ClientFlags := ClientFlags or CLIENT_IGNORE_SPACE;
+ if opProtocol41 in FOptions then ClientFlags := ClientFlags or CLIENT_PROTOCOL_41;
+ if opInteractive in FOptions then ClientFlags := ClientFlags or CLIENT_INTERACTIVE;
+ if opSSL in FOptions then ClientFlags := ClientFlags or CLIENT_SSL;
+ if opIgnoreSigpipe in FOptions then ClientFlags := ClientFlags or CLIENT_IGNORE_SIGPIPE;
+ if opTransactions in FOptions then ClientFlags := ClientFlags or CLIENT_TRANSACTIONS;
+ if opReserved in FOptions then ClientFlags := ClientFlags or CLIENT_RESERVED;
+ if opSecureConnection in FOptions then ClientFlags := ClientFlags or CLIENT_SECURE_CONNECTION;
+ if opMultiStatements in FOptions then ClientFlags := ClientFlags or CLIENT_MULTI_STATEMENTS;
+ if opMultiResults in FOptions then ClientFlags := ClientFlags or CLIENT_MULTI_RESULTS;
+ if opRememberOptions in FOptions then ClientFlags := ClientFlags or CLIENT_REMEMBER_OPTIONS;
+
+ // Prepare connection
+ if FHostname = '.' then Protocol := 'named pipe' else Protocol := 'TCP/IP';
+ if Password <> '' then UsingPass := 'Yes' else UsingPass := 'No';
+ Log(lcInfo, 'Connecting to '+Hostname+' via '+Protocol+
+ ', username '+Username+
+ ', using password: '+UsingPass+' ...');
+ Connected := mysql_real_connect(
+ FHandle,
+ PChar(FHostname),
+ PChar(FUsername),
+ PChar(FPassword),
+ nil,
+ FPort,
+ PChar(FSocketname),
+ ClientFlags
+ );
+ if Connected = nil then begin
+ Error := LastError;
+ Log(lcError, Error);
+ FActive := False;
+ FConnectionStarted := 0;
+ FHandle := nil;
+ raise Exception.Create(Error);
+ end else begin
+ Log(lcInfo, 'Connected. Thread-ID: '+IntToStr(ThreadId));
+ CharacterSet := 'utf8';
+ Log(lcInfo, 'Characterset: '+CharacterSet);
+ FConnectionStarted := GetTickCount;
+ FServerVersionUntouched := mysql_get_server_info(FHandle);
+ DetectCapabilities;
+ tmpdb := FDatabase;
+ FDatabase := '';
+ SetDatabase(tmpdb);
+ end;
+ end
+
+ else if (not Value) and (FHandle <> nil) then begin
+ mysql_close(FHandle);
+ FConnectionStarted := 0;
+ FHandle := nil;
+ FCapabilities := [];
+ Log(lcInfo, 'Connection to '+FHostname+' closed');
+ end;
+
+end;
+
+
+function TMySQLConnection.GetActive: Boolean;
+begin
+ if FActive and (mysql_ping(FHandle) <> 0) then
+ Active := False;
+ Result := FActive;
+end;
+
+
+{**
+ Executes a query
+}
+function TMySQLConnection.Query(SQL: WideString; DoStoreResult: Boolean=False): PMYSQL_RES;
+var
+ querystatus: Integer;
+ NativeSQL: String;
+begin
+ if not Active then
+ Active := True;
+ Log(lcSQL, SQL);
+ NativeSQL := UTF8Encode(SQL);
+ querystatus := mysql_real_query(FHandle, PChar(NativeSQL), Length(NativeSQL));
+ if querystatus <> 0 then begin
+ Log(lcError, GetLastError);
+ raise Exception.Create(GetLastError);
+ end else begin
+ Result := nil;
+ // Affected rows are -1 for SELECT queries, 0 for UPDATE queries including
+ // admin commands e.g. FLUSH PRIVILEGES
+ FRowsAffected := mysql_affected_rows(FHandle);
+ if FRowsAffected = -1 then begin
+ FRowsAffected := 0;
+ if DoStoreResult then begin
+ Result := mysql_store_result(FHandle);
+ FRowsFound := mysql_num_rows(Result);
+ Log(lcDebug, IntToStr(RowsFound)+' rows found.');
+ end;
+ end else begin
+ // Query did not return a result
+ FRowsFound := 0;
+ Log(lcDebug, IntToStr(RowsAffected)+' rows affected.');
+ if UpperCase(Copy(SQL, 1, 3)) = 'USE' then begin
+ FDatabase := Trim(Copy(SQL, 4, Length(SQL)-3));
+ FDatabase := DeQuoteIdent(FDatabase);
+ Log(lcDebug, 'Database "'+FDatabase+'" selected');
+ if Assigned(FOnDatabaseChanged) then
+ FOnDatabaseChanged(Database);
+ end;
+ end;
+ end;
+end;
+
+
+{**
+ Set "Database" property and select that db if connected
+}
+procedure TMySQLConnection.SetDatabase(Value: WideString);
+begin
+ if (Value = '') or (Value = FDatabase) then
+ Exit;
+ Query('USE '+QuoteIdent(Value), False);
+end;
+
+
+{**
+ Return current thread id
+}
+function TMySQLConnection.GetThreadId: Cardinal;
+begin
+ Result := mysql_thread_id(FHandle);
+end;
+
+
+{**
+ Return currently used character set
+}
+function TMySQLConnection.GetCharacterSet: String;
+begin
+ Result := mysql_character_set_name(FHandle);
+end;
+
+
+{**
+ Switch character set
+}
+procedure TMySQLConnection.SetCharacterSet(CharsetName: String);
+begin
+ mysql_set_character_set(FHandle, PAnsiChar(CharsetName));
+end;
+
+
+{**
+ Return the last error nicely formatted
+}
+function TMySQLConnection.GetLastError: WideString;
+begin
+ Result := WideFormat('SQL Error (%d): %s', [mysql_errno(FHandle), Utf8Decode(mysql_error(FHandle))]);
+end;
+
+
+{**
+ Get version string as normalized integer
+ "5.1.12-beta-community-123" => 50112
+}
+function TMySQLConnection.GetServerVersionInt: Integer;
+var
+ i, dots: Byte;
+ fullversion, v1, v2, v3: String;
+begin
+ Result := -1;
+
+ dots := 0;
+ // Avoid calling GetServerVersionUntouched too often
+ fullversion := ServerVersionUntouched;
+ v1 := '';
+ v2 := '';
+ v3 := '';
+ for i:=1 to Length(fullversion) do begin
+ if fullversion[i] = '.' then begin
+ inc(dots);
+ // We expect exactly 2 dots.
+ if dots > 2 then
+ break;
+ end else if fullversion[i] in ['0'..'9'] then begin
+ if dots = 0 then
+ v1 := v1 + fullversion[i]
+ else if dots = 1 then
+ v2 := v2 + fullversion[i]
+ else if dots = 2 then
+ v3 := v3 + fullversion[i];
+ end else // Don't include potential numbers of trailing string
+ break;
+ end;
+
+ // Concat tokens
+ if (Length(v1)>0) and (Length(v2)>0) and (Length(v3)>0) then begin
+ Result := StrToIntDef(v1, 0) *10000 +
+ StrToIntDef(v2, 0) *100 +
+ StrToIntDef(v3, 0);
+ end;
+
+end;
+
+
+function TMySQLConnection.GetServerVersionStr: String;
+begin
+ Result := ConvertServerVersion(ServerVersionInt);
+end;
+
+
+{**
+ Convert integer version to real version string
+}
+function TMySQLConnection.ConvertServerVersion(Version: Integer): String;
+var
+ v : String;
+ v1, v2 : Byte;
+begin
+ v := IntToStr( Version );
+ v1 := StrToIntDef( v[2]+v[3], 0 );
+ v2 := StrToIntDef( v[4]+v[5], 0 );
+ Result := v[1] + '.' + IntToStr(v1) + '.' + IntToStr(v2);
+end;
+
+
+function TMySQLConnection.GetResults(SQL: WideString): TMySQLQuery;
+begin
+ Result := TMySQLQuery.Create(Self);
+ Result.Connection := Self;
+ Result.SQL := SQL;
+ try
+ Result.Execute;
+ except
+ FreeAndNil(Result);
+ Raise;
+ end;
+end;
+
+
+{**
+ Call log event if assigned to object
+}
+procedure TMySQLConnection.Log(Category: TMySQLLogCategory; Msg: WideString);
+begin
+ if Assigned(FOnLog) then
+ FOnLog(Msg, Category);
+end;
+
+
+{**
+ Escapes a string for usage in SQL queries
+}
+function TMySQLConnection.EscapeString(Text: WideString; DoQuote: Boolean): WideString;
+var
+ BufferLen: Integer;
+ Buffer: PChar;
+ NativeText: String;
+begin
+ BufferLen := Length(Text) * 2 + 1;
+ GetMem(Buffer, BufferLen);
+ NativeText := UTF8Encode(Text);
+ BufferLen := mysql_real_escape_string(FHandle, Buffer, PChar(NativeText), Length(Text));
+ SetString(Result, Buffer, BufferLen);
+ FreeMem(Buffer);
+
+ if DoQuote then
+ Result := '''' + Result + '''';
+end;
+
+
+{**
+ Add backticks to identifier
+ Todo: Support ANSI style
+}
+function TMySQLConnection.QuoteIdent(Identifier: WideString): WideString;
+begin
+ Result := WideStringReplace(Identifier, '`', '``', [rfReplaceAll]);
+ Result := '`' + Result + '`';
+end;
+
+
+function TMySQLConnection.DeQuoteIdent(Identifier: WideString): WideString;
+begin
+ Result := Identifier;
+ if (Result[1] = '`') and (Result[Length(Identifier)] = '`') then
+ Result := Copy(Result, 2, Length(Result)-2);
+end;
+
+
+{**
+ Detect various capabilities of the server
+ for easy feature-checks in client-applications.
+}
+procedure TMySQLConnection.DetectCapabilities;
+var
+ ver: Integer;
+ procedure addCap(c: TMySQLServerCapability; addit: Boolean);
+ begin
+ if addit then
+ Include(FCapabilities, c)
+ else
+ Exclude(FCapabilities, c);
+ end;
+begin
+ // Avoid calling GetServerVersionInt too often
+ ver := ServerVersionInt;
+
+ addCap(cpShowEngines, ver >= 40102);
+ addCap(cpShowTableStatus, ver >= 32300);
+ addCap(cpShowFullTables, ver >= 50002);
+ addCap(cpShowCreateTable, ver >= 32320);
+ addCap(cpShowCreateDatabase, ver >= 50002);
+ addCap(cpHelpSystem, ver >= 40100);
+ addCap(cpSetNames, ver >= 40100);
+ addCap(cpCalcFoundRows, ver >= 40000);
+ addCap(cpLoadFile, ver >= 32206);
+ addCap(cpTableComment, ver >= 32300);
+ addCap(cpFieldComment, ver >= 40100);
+ addCap(cpColumnMoving, ver >= 40001);
+ addCap(cpTruncateTable, ver >= 50003);
+ addCap(cpAlterDatabase, ver >= 50002);
+ addCap(cpRenameDatabase, ver >= 50107);
+end;
+
+
+function TMySQLConnection.GetCol(SQL: WideString; Column: Integer=0): TWideStringList;
+var
+ Results: TMySQLQuery;
+begin
+ try
+ Results := GetResults(SQL);
+ Result := TWideStringList.Create;
+ while not Results.Eof do begin
+ Result.Add(Results.Col(Column));
+ Results.Next;
+ end;
+ finally
+ FreeAndNil(Results);
+ end;
+end;
+
+
+{**
+ Get single cell value via SQL query, identified by column number
+}
+function TMySQLConnection.GetVar(SQL: WideString; Column: Integer=0): WideString;
+var
+ Results: TMySQLQuery;
+begin
+ try
+ Results := GetResults(SQL);
+ if Results.RecordCount > 0 then
+ Result := Results.Col(Column)
+ else
+ Result := '';
+ finally
+ FreeAndNil(Results);
+ end;
+end;
+
+
+{**
+ Get single cell value via SQL query, identified by column name
+}
+function TMySQLConnection.GetVar(SQL: WideString; Column: WideString): WideString;
+var
+ Results: TMySQLQuery;
+begin
+ try
+ Results := GetResults(SQL);
+ if Results.RecordCount > 0 then
+ Result := Results.Col(Column)
+ else
+ Result := '';
+ finally
+ FreeAndNil(Results);
+ end;
+end;
+
+
+
+
+{ TMySQLQuery }
+
+constructor TMySQLQuery.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+ FRecNo := -1;
+ FRecordCount := 0;
+ FColumnNames := TWideStringlist.Create;
+ FColumnNames.CaseSensitive := True;
+end;
+
+
+destructor TMySQLQuery.Destroy;
+begin
+ inherited Destroy;
+ FreeAndNil(FColumnNames);
+ mysql_free_result(FLastResult);
+end;
+
+
+procedure TMySQLQuery.SetSQL(Value: WideString);
+begin
+ FSQL := Value;
+end;
+
+
+procedure TMySQLQuery.Execute;
+var
+ i: Integer;
+ Field: PMYSQL_FIELD;
+begin
+ FLastResult := Connection.Query(FSQL, True);
+ FRecordCount := Connection.RowsFound;
+ if HasResult then begin
+ for i:=0 to mysql_num_fields(FLastResult)-1 do begin
+ Field := mysql_fetch_field_direct(FLastResult, i);
+ FColumnNames.Add(Utf8Decode(Field.name));
+ end;
+ RecNo := 0;
+ end;
+end;
+
+
+procedure TMySQLQuery.First;
+begin
+ RecNo := 0;
+end;
+
+
+procedure TMySQLQuery.Next;
+begin
+ RecNo := RecNo + 1;
+end;
+
+
+procedure TMySQLQuery.SetRecNo(Value: Int64);
+begin
+ if Value >= RecordCount then begin
+ FRecNo := RecordCount;
+ FEof := True;
+ end else begin
+ FRecNo := Value;
+ FEof := False;
+ mysql_data_seek(FLastResult, FRecNo);
+ FCurrentRow := mysql_fetch_row(FLastResult);
+ end;
+end;
+
+
+function TMySQLQuery.ColumnCount: Integer;
+begin
+ Result := ColumnNames.Count;
+end;
+
+
+function TMySQLQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): WideString;
+begin
+ if (Column > -1) and (Column < ColumnCount) then
+ Result := Utf8Decode(FCurrentRow[Column])
+ else if not IgnoreErrors then
+ Raise Exception.CreateFmt('Column #%d not available. Query returned %d columns and %d rows.', [Column, ColumnCount, RecordCount]);
+end;
+
+
+function TMySQLQuery.Col(ColumnName: WideString; IgnoreErrors: Boolean=False): WideString;
+var
+ idx: Integer;
+begin
+ idx := ColumnNames.IndexOf(ColumnName);
+ if idx > -1 then
+ Result := Col(idx)
+ else if not IgnoreErrors then
+ Raise Exception.CreateFmt('Column "%s" not available.', [ColumnName]);
+end;
+
+
+function TMySQLQuery.DataType(Column: Integer): TDataType;
+var
+ i: Integer;
+ Field: PMYSQL_FIELD;
+begin
+ Field := mysql_fetch_field_direct(FLastResult, Column);
+ Result := Datatypes[Low(Datatypes)];
+ for i:=Low(Datatypes) to High(Datatypes) do begin
+ if Field._type = Datatypes[i].NativeType then begin
+ Result := Datatypes[i];
+ break;
+ end;
+ end;
+end;
+
+
+function TMySQLQuery.ColExists(Column: WideString): Boolean;
+begin
+ Result := (ColumnNames <> nil) and (ColumnNames.IndexOf(Column) > -1);
+end;
+
+
+function TMySQLQuery.IsNull(Column: Integer): Boolean;
+begin
+ Result := FCurrentRow[Column] = nil;
+end;
+
+
+function TMySQLQuery.HasResult: Boolean;
+begin
+ Result := FLastResult <> nil;
+end;
+
+
+end.
diff --git a/source/mysql_structures.pas b/source/mysql_structures.pas
index f9506bcf..a3e15eb1 100644
--- a/source/mysql_structures.pas
+++ b/source/mysql_structures.pas
@@ -7,7 +7,7 @@ unit mysql_structures;
interface
uses
- Classes, Widestrings, Graphics;
+ Classes, Widestrings, Graphics, mysql_api;
{$I const.inc}
@@ -28,6 +28,7 @@ type
// MySQL data type structure
TDatatype = record
Index: TDatatypeIndex;
+ NativeType: Cardinal; // See field types in mysql_api.pas
Name: String[18];
Description: String;
HasLength: Boolean; // Can have Length- or Set-attribute?
@@ -106,6 +107,7 @@ var
(
(
Index: dtTinyint;
+ NativeType: FIELD_TYPE_TINY;
Name: 'TINYINT';
Description: 'TINYINT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A very small integer. The signed range is -128 to 127. ' +
@@ -120,6 +122,7 @@ var
),
(
Index: dtSmallint;
+ NativeType: FIELD_TYPE_SHORT;
Name: 'SMALLINT';
Description: 'SMALLINT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A small integer. The signed range is -32768 to 32767. ' +
@@ -134,6 +137,7 @@ var
),
(
Index: dtMediumint;
+ NativeType: FIELD_TYPE_INT24;
Name: 'MEDIUMINT';
Description: 'MEDIUMINT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A medium-sized integer. The signed range is -8388608 to 8388607. ' +
@@ -148,6 +152,7 @@ var
),
(
Index: dtInt;
+ NativeType: FIELD_TYPE_LONG;
Name: 'INT';
Description: 'INT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A normal-size integer. The signed range is -2147483648 to 2147483647. ' +
@@ -162,6 +167,7 @@ var
),
(
Index: dtBigint;
+ NativeType: FIELD_TYPE_LONGLONG;
Name: 'BIGINT';
Description: 'BIGINT[(M)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A large integer. The signed range is -9223372036854775808 to ' +
@@ -176,6 +182,7 @@ var
),
(
Index: dtFloat;
+ NativeType: FIELD_TYPE_FLOAT;
Name: 'FLOAT';
Description: 'FLOAT[(M,D)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A small (single-precision) floating-point number. Allowable values are '+
@@ -193,6 +200,7 @@ var
),
(
Index: dtDouble;
+ NativeType: FIELD_TYPE_DOUBLE;
Name: 'DOUBLE';
Description: 'DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL]' + CRLF +
'A normal-size (double-precision) floating-point number. Allowable ' +
@@ -210,6 +218,7 @@ var
),
(
Index: dtDecimal;
+ NativeType: FIELD_TYPE_DECIMAL;
Name: 'DECIMAL';
Description: 'DECIMAL[(M[,D])] [UNSIGNED] [ZEROFILL]' + CRLF +
'A packed "exact" fixed-point number. M is the total number of digits ' +
@@ -229,6 +238,7 @@ var
),
(
Index: dtDate;
+ NativeType: FIELD_TYPE_DATE;
Name: 'DATE';
Description: 'DATE' + CRLF +
'A date. The supported range is ''1000-01-01'' to ''9999-12-31''. MySQL ' +
@@ -244,6 +254,7 @@ var
),
(
Index: dtTime;
+ NativeType: FIELD_TYPE_TIME;
Name: 'TIME';
Description: 'TIME' + CRLF +
'A time. The range is ''-838:59:59'' to ''838:59:59''. MySQL displays TIME ' +
@@ -259,6 +270,7 @@ var
),
(
Index: dtYear;
+ NativeType: FIELD_TYPE_YEAR;
Name: 'YEAR';
Description: 'YEAR[(2|4)]' + CRLF +
'A year in two-digit or four-digit format. The default is four-digit ' +
@@ -277,6 +289,7 @@ var
),
(
Index: dtDatetime;
+ NativeType: FIELD_TYPE_DATETIME;
Name: 'DATETIME';
Description: 'DATETIME' + CRLF +
'A date and time combination. The supported range is ''1000-01-01 ' +
@@ -293,6 +306,7 @@ var
),
(
Index: dtTimestamp;
+ NativeType: FIELD_TYPE_TIMESTAMP;
Name: 'TIMESTAMP';
Description: 'TIMESTAMP' + CRLF +
'A timestamp. The range is ''1970-01-01 00:00:01'' UTC to ''2038-01-09 ' +
@@ -311,6 +325,7 @@ var
),
(
Index: dtCHAR;
+ NativeType: FIELD_TYPE_STRING;
Name: 'CHAR';
Description: 'CHAR[(M)]' + CRLF +
'A fixed-length string that is always right-padded with spaces to the ' +
@@ -329,6 +344,7 @@ var
),
(
Index: dtVarchar;
+ NativeType: FIELD_TYPE_VAR_STRING;
Name: 'VARCHAR';
Description: 'VARCHAR(M)' + CRLF +
'A variable-length string. M represents the maximum column length in ' +
@@ -351,6 +367,7 @@ var
),
(
Index: dtTinytext;
+ NativeType: FIELD_TYPE_TINY_BLOB;
Name: 'TINYTEXT';
Description: 'TINYTEXT' + CRLF +
'A TEXT column with a maximum length of 255 (28 - 1) characters. The ' +
@@ -367,6 +384,7 @@ var
),
(
Index: dtText;
+ NativeType: FIELD_TYPE_BLOB;
Name: 'TEXT';
Description: 'TEXT[(M)]' + CRLF +
'A TEXT column with a maximum length of 65,535 (216 - 1) characters. The ' +
@@ -386,6 +404,7 @@ var
),
(
Index: dtMediumtext;
+ NativeType: FIELD_TYPE_MEDIUM_BLOB;
Name: 'MEDIUMTEXT';
Description: 'MEDIUMTEXT' + CRLF +
'A TEXT column with a maximum length of 16,777,215 (224 - 1) characters. ' +
@@ -402,6 +421,7 @@ var
),
(
Index: dtLongtext;
+ NativeType: FIELD_TYPE_LONG_BLOB;
Name: 'LONGTEXT';
Description: 'LONGTEXT' + CRLF +
'A TEXT column with a maximum length of 4,294,967,295 or 4GB (232 - 1) ' +
@@ -421,6 +441,7 @@ var
),
(
Index: dtBinary;
+ NativeType: FIELD_TYPE_STRING;
Name: 'BINARY';
Description: 'BINARY(M)' + CRLF +
'The BINARY type is similar to the CHAR type, but stores binary byte ' +
@@ -437,6 +458,7 @@ var
),
(
Index: dtVarbinary;
+ NativeType: FIELD_TYPE_VAR_STRING;
Name: 'VARBINARY';
Description: 'VARBINARY(M)' + CRLF +
'The VARBINARY type is similar to the VARCHAR type, but stores binary ' +
@@ -453,6 +475,7 @@ var
),
(
Index: dtTinyblob;
+ NativeType: FIELD_TYPE_TINY_BLOB;
Name: 'TINYBLOB';
Description: 'TINYBLOB' + CRLF +
'A BLOB column with a maximum length of 255 (28 - 1) bytes. Each ' +
@@ -468,6 +491,7 @@ var
),
(
Index: dtBlob;
+ NativeType: FIELD_TYPE_BLOB;
Name: 'BLOB';
Description: 'BLOB[(M)]' + CRLF +
'A BLOB column with a maximum length of 65,535 (216 - 1) bytes. Each ' +
@@ -486,6 +510,7 @@ var
),
(
Index: dtMediumblob;
+ NativeType: FIELD_TYPE_MEDIUM_BLOB;
Name: 'MEDIUMBLOB';
Description: 'MEDIUMBLOB' + CRLF +
'A BLOB column with a maximum length of 16,777,215 (224 - 1) bytes. Each ' +
@@ -501,6 +526,7 @@ var
),
(
Index: dtLongblob;
+ NativeType: FIELD_TYPE_LONG_BLOB;
Name: 'LONGBLOB';
Description: 'LONGBLOB' + CRLF +
'A BLOB column with a maximum length of 4,294,967,295 or 4GB (232 - 1) ' +
@@ -518,6 +544,7 @@ var
),
(
Index: dtEnum;
+ NativeType: FIELD_TYPE_ENUM;
Name: 'ENUM';
Description: 'ENUM(''value1'',''value2'',...)' + CRLF +
'An enumeration. A string object that can have only one value, chosen ' +
@@ -535,6 +562,7 @@ var
),
(
Index: dtSet;
+ NativeType: FIELD_TYPE_SET;
Name: 'SET';
Description: 'SET(''value1'',''value2'',...)' + CRLF +
'A set. A string object that can have zero or more values, each of which ' +
@@ -552,6 +580,7 @@ var
),
(
Index: dtBit;
+ NativeType: FIELD_TYPE_BIT;
Name: 'BIT';
Description: 'BIT[(M)]' + CRLF +
'A bit-field type. M indicates the number of bits per value, from 1 to ' +
@@ -566,6 +595,7 @@ var
),
(
Index: dtPoint;
+ NativeType: FIELD_TYPE_GEOMETRY;
Name: 'POINT';
Description: 'POINT(x,y)' + CRLF +
'Constructs a WKB Point using its coordinates.';
@@ -579,6 +609,7 @@ var
),
(
Index: dtLinestring;
+ NativeType: FIELD_TYPE_GEOMETRY;
Name: 'LINESTRING';
Description: 'LINESTRING(pt1,pt2,...)' + CRLF +
'Constructs a WKB LineString value from a number of WKB Point arguments. ' +
@@ -594,6 +625,7 @@ var
),
(
Index: dtPolygon;
+ NativeType: FIELD_TYPE_GEOMETRY;
Name: 'POLYGON';
Description: 'POLYGON(ls1,ls2,...)' + CRLF +
'Constructs a WKB Polygon value from a number of WKB LineString ' +
@@ -609,6 +641,7 @@ var
),
(
Index: dtGeometry;
+ NativeType: FIELD_TYPE_GEOMETRY;
Name: 'GEOMETRY';
Description: '';
HasLength: False;
@@ -621,6 +654,7 @@ var
),
(
Index: dtMultipoint;
+ NativeType: FIELD_TYPE_GEOMETRY;
Name: 'MULTIPOINT';
Description: 'MULTIPOINT(pt1,pt2,...)' + CRLF +
'Constructs a WKB MultiPoint value using WKB Point arguments. If any ' +
@@ -635,6 +669,7 @@ var
),
(
Index: dtMultilinestring;
+ NativeType: FIELD_TYPE_GEOMETRY;
Name: 'MULTILINESTRING';
Description: 'MULTILINESTRING(ls1,ls2,...)' + CRLF +
'Constructs a WKB MultiLineString value using WKB LineString arguments. ' +
@@ -649,6 +684,7 @@ var
),
(
Index: dtMultipolygon;
+ NativeType: FIELD_TYPE_GEOMETRY;
Name: 'MULTIPOLYGON';
Description: 'MULTIPOLYGON(poly1,poly2,...)' + CRLF +
'Constructs a WKB MultiPolygon value from a set of WKB Polygon ' +
@@ -664,6 +700,7 @@ var
),
(
Index: dtGeometrycollection;
+ NativeType: FIELD_TYPE_GEOMETRY;
Name: 'GEOMETRYCOLLECTION';
Description: 'GEOMETRYCOLLECTION(g1,g2,...)' + CRLF +
'Constructs a WKB GeometryCollection. If any argument is not a ' +
diff --git a/source/mysqlconn.pas b/source/mysqlconn.pas
deleted file mode 100644
index 0e838481..00000000
--- a/source/mysqlconn.pas
+++ /dev/null
@@ -1,117 +0,0 @@
-unit MysqlConn;
-
-interface
-
-uses ZConnection, ExtCtrls, MysqlQueryThread;
-
-const
- // connection attemp result codes
- MCR_SUCCESS = 0;
- MCR_FAILED = 1;
-
-{$I const.inc}
-
-type
-
-
- TMysqlConn = class
- private
- FConn : TZConnection;
- FOpenConn : TOpenConnProf;
- FLastError : String;
- function GetIsAlive: Boolean;
- function GetIsConnected: Boolean;
- //FTimer : TTimer;
- public
- constructor Create(AConn : POpenConnProf);
- destructor Destroy(); override;
- function Connect() : Integer;
- procedure Disconnect();
- property IsConnected : Boolean read GetIsConnected;
- property IsAlive : Boolean read GetIsAlive;
- property Connection : TZConnection read FConn;
- property LastError : String read FLastError;
- end;
-
-implementation
-
-uses SysUtils;
-
-{ TMysqlConn }
-
-constructor TMysqlConn.Create;
-begin
- FConn := TZConnection.Create(nil);
- FOpenConn := AConn^;
- FLastError := '';
-end;
-
-function TMysqlConn.Connect(): Integer;
-begin
- FLastError := '';
-
- if FConn.Connected then FConn.Disconnect;
- with FOpenConn.MysqlParams do
- begin
- FConn.Protocol := 'mysql';
- if FOpenConn.MysqlParams.NetType = NETTYPE_TCPIP then begin
- FConn.Hostname := Host;
- FConn.SocketName := '';
- end else begin
- FConn.Hostname := '.';
- FConn.SocketName := Host;
- end;
- FConn.User := User;
- FConn.Password := Pass;
- FConn.Port := Port;
-
- FConn.Properties.Values['compress'] := PrpCompress;
- FConn.Properties.Values['dbless'] := PrpDbless;
- FConn.Properties.Values['CLIENT_LOCAL_FILES'] := PrpClientLocalFiles;
- FConn.Properties.Values['CLIENT_INTERACTIVE'] := PrpClientInteractive;
- // ZConn.Properties.Values['USE_RESULT'] := 'true'; // doesn't work
- // ZConn.Properties.Values['CLIENT_SSL'] := 'true'; // from an mdaems's example
- FConn.Properties.Values['CLIENT_MULTI_RESULTS'] := '1';
- end;
-
- try
- FConn.Connect();
- Result := MCR_SUCCESS;
- except
- // todo: handle exception
- on E : Exception do
- begin
- FLastError := E.Message;
- Result := MCR_FAILED;
- end;
- end;
-end;
-
-
-procedure TMysqlConn.Disconnect;
-begin
- if FConn.Connected then FConn.Disconnect;
-end;
-
-
-destructor TMysqlConn.Destroy;
-begin
- if FConn.Connected then FConn.Disconnect;
- FreeAndNil (FConn);
- inherited;
-end;
-
-function TMysqlConn.GetIsAlive: Boolean;
-begin
- Result := False;
- if IsConnected then Result := FConn.Ping();
-end;
-
-function TMysqlConn.GetIsConnected: Boolean;
-begin
- Result := FConn.Connected;
-end;
-
-
-
-end.
diff --git a/source/mysqlquery.pas b/source/mysqlquery.pas
deleted file mode 100644
index 786c542e..00000000
--- a/source/mysqlquery.pas
+++ /dev/null
@@ -1,201 +0,0 @@
-unit MysqlQuery;
-
-interface
-
-uses Windows, Messages, Classes, Db, ZConnection, ZDataSet, MysqlQueryThread, helpers;
-
-const
- // Thread notification events
- MQE_INITED = 0; // initialized
- MQE_STARTED = 1; // query started
- MQE_FINISHED = 2; // query finished
- MQE_FREED = 3; // object removed from memory
-
- // Query result codes
- MQR_NOTHING = 0; // no result yet
- MQR_SUCCESS = 1; // success
- MQR_CONNECT_FAIL = 2; // done with error
- MQR_QUERY_FAIL = 3; // done with error
-
-{$I const.inc}
-
-type
- TMysqlQuery = class;
-
- TMysqlQueryNotificationEvent = procedure (ASender : TMysqlQuery; AEvent : Integer) of object;
-
- TMysqlQuery = class
- private
- FConn : TOpenConnProf;
- FQueryResult : TThreadResult;
- FMysqlConnection : TZConnection;
- FMysqlConnectionIsOwned : Boolean;
- FMysqlDataset : TDataset;
- FThreadID : Integer;
- FQueryThread : TMysqlQueryThread;
- FEventName : String;
- FEventHandle : THandle;
- FSql : WideString;
- function GetComment: String;
- function GetResult: Integer;
- function GetHasresultSet: Boolean;
- protected
-
- public
- constructor Create (AOwner : TComponent; AConn : POpenConnProf); overload;
- destructor Destroy (); override;
- procedure Query(ASql: WideString; ANotifyWndHandle : THandle; Callback: TAsyncPostRunner; ds: TDeferDataSet);
- procedure SetMysqlDataset(ADataset : TDataset);
- procedure PostNotification (AQueryResult : TThreadResult; AEvent : Integer);
- procedure SetThreadResult(AResult : TThreadResult);
-
- property Result : Integer read GetResult; // Query result code
- property Comment : String read GetComment; // Textual information about the query result, includes error description
- property MysqlConnection : TZConnection read FMysqlConnection;
- property MysqlDataset : TDataset read FMysqlDataset; // Resultset
- property HasResultset : Boolean read GetHasresultSet; // Indicator of resultset availability
- property ThreadID : Integer read FThreadID; // Mysql query thread ID (on the clients os)
- property Sql : WideString read FSql; // Query string
- property EventName : String read FEventName; // Operating system event name used for blocking mode
- property EventHandle : THandle read FEventHandle;
- end;
-
- function ExecMysqlStatementAsync(ASql : WideString; AConn : TOpenConnProf; AWndHandle : THandle; Callback: TAsyncPostRunner) : TMysqlQuery;
- function ExecPostAsync(AConn : TOpenConnProf; AWndHandle : THandle; ds: TDeferDataSet): TMysqlQuery;
-
-
-implementation
-
-uses
- SysUtils,
- Dialogs;
-
-
-{***
- Wrapper function to simplify running a query in asynchronous mode
- This function will end right after the thread is created.
-
- Otherwise status notifications are sent by the WM_MYSQL_THREAD_NOTIFY message;
- * use the WParam member of the AMessage parameter (a TMysqlQuery object)
-
- @param string SQL-statement
- @param TConnParams Connection credentials structure
- @param THandle Window handle to post thread status messages to
-}
-function ExecMysqlStatementAsync(ASql : WideString; AConn : TOpenConnProf; AWndHandle : THandle; Callback: TAsyncPostRunner) : TMysqlQuery;
-begin
- Result := TMysqlQuery.Create(nil,@AConn);
- Result.Query(ASql,AWndHandle,Callback,nil);
-end;
-
-
-function ExecPostAsync(AConn : TOpenConnProf; AWndHandle : THandle; ds: TDeferDataSet): TMysqlQuery;
-begin
- Result := TMysqlQuery.Create(nil,@AConn);
- Result.Query('',AWndHandle,nil,ds);
-end;
-
-
-{ TMysqlQuery }
-
-{***
- Constructor
-
- @param TComponent Owner
- @param PConnParams Used to pass connection credentials. If the MysqlConn member
- (a TZConnection object) <>nil, the query will be run on this connection.
- Otherwise a new connection object is created with the credentials
- in the MysqlParams member
-}
-
-constructor TMysqlQuery.Create(AOwner: TComponent; AConn: POpenConnProf);
-begin
- FConn := AConn^;
- FMysqlConnectionIsOwned := False;
-
- ZeroMemory (@FQueryResult,SizeOf(FQueryResult));
- FSql := '';
-
- if AConn.MysqlConn<>nil then
- FMysqlConnection := AConn.MysqlConn
- else
- begin
- FMysqlConnectionIsOwned := True;
- FMysqlConnection := TZConnection.Create(nil);
- end;
-
- FMysqlDataset := nil;
-end;
-
-
-{***
- Destructor:
- remove created objects from memory
-
- @result
-}
-
-destructor TMysqlQuery.Destroy;
-begin
- //FreeAndNil (FMysqlDataset);
-
- // Only free the connection object if we first created it
- if FMysqlConnectionIsOwned then
- FreeAndNil (FMysqlConnection);
-
- inherited;
-end;
-
-function TMysqlQuery.GetComment: String;
-begin
- Result := FQueryResult.Comment;
-end;
-
-function TMysqlQuery.GetHasresultSet: Boolean;
-begin
- Result := FMysqlDataset <> nil;
-end;
-
-function TMysqlQuery.GetResult: Integer;
-begin
- Result := FQueryResult.Result;
-end;
-
-procedure TMysqlQuery.PostNotification(AQueryResult: TThreadResult; AEvent : Integer);
-begin
- SetThreadResult(AQueryResult);
- debug(Format('qry: Not calling notify function, event type %d occurred.', [AEvent]));
-end;
-
-procedure TMysqlQuery.Query(ASql: WideString; ANotifyWndHandle : THandle; Callback: TAsyncPostRunner; ds: TDeferDataSet);
-begin
- // create thread object
- FQueryThread := TMysqlQueryThread.Create(Self,FConn,ASql,Callback,ds);
- FQueryThread.NotifyWndHandle := ANotifyWndHandle;
- FThreadID := FQueryThread.ThreadID;
- FEventName := APPNAME+'_'+IntToStr(FThreadID);
- FSql := ASql;
-
- FEventHandle := CreateEvent ({*EVENT_MODIFY_STATE + SYNCHRONIZE*}nil, False, False, PChar(FEventName));
-
- // exec query
- debug(Format('qry: Starting query thread %d', [FQueryThread.ThreadID]));
- FQueryThread.Resume();
-end;
-
-
-procedure TMysqlQuery.SetMysqlDataset(ADataset: TDataset);
-begin
- FMysqlDataset := ADataset;
-end;
-
-procedure TMysqlQuery.SetThreadResult(AResult: TThreadResult);
-begin
- try
- FQueryResult := AResult;
- except
- raise Exception.Create('Assertion failed: Internal error in SetThreadResult().');
- end;
-end;
-
-end.
diff --git a/source/mysqlquerythread.pas b/source/mysqlquerythread.pas
deleted file mode 100644
index 6a89c40b..00000000
--- a/source/mysqlquerythread.pas
+++ /dev/null
@@ -1,333 +0,0 @@
-unit MysqlQueryThread;
-
-interface
-
-uses
- Windows, Messages, Forms, Db, Classes, ZConnection, ZDataSet, StdCtrls, SysUtils,
- ZMessages,
- helpers, SynRegExpr, mysql_structures;
-
-{$IFDEF EXAMPLE_APP}
-const
- WM_MYSQL_THREAD_NOTIFY = WM_USER+100;
-{$ENDIF}
-
-type
- // Exception information
- TExceptionData = record
- Msg : String[200];
- HelpContext : Integer;
- end;
-
- // Mysql protocol-relevant connection parameter structure
- TMysqlConnParams = record
- NetType: Integer;
- Host: String;
- Database: WideString;
- Protocol,
- User,
- Pass : String;
- Port : Integer;
- PrpCompress,
- PrpDbless,
- PrpClientLocalFiles,
- PrpClientInteractive : String;
- end;
- PMysqlConnParams = ^TMysqlConnParams;
-
- // Established connection and it's corresponding connection profile.
- // (The actual connection need not necessarily be open, of course, it could in theory be closed or nil,
- // but to keep the name short; this beats "TConnectionProfileDataAndConnectionObject", which I guess would be the proper name.
- TOpenConnProf = record
- MysqlParams : TMysqlConnParams; // stuff that needs to be shipped over to the mysql driver.
- MysqlConn : TZConnection;
- end;
- POpenConnProf = ^TOpenConnProf;
-
- TThreadResult = record
- ThreadID : Integer;
- Action : Integer;
- Sql : WideString;
- Result : Integer;
- Comment : String;
- end;
-
- TMysqlQueryThread = class(TThread)
- private
- FMysqlConn : TZConnection;
- FConn : TOpenConnProf;
- FOwner : TObject; // TMysqlQuery object
- FSql : WideString;
- FCallback: TAsyncPostRunner;
- FPostDataSet: TDeferDataSet;
- FResult : Integer;
- FComment : String;
- FNotifyWndHandle : THandle;
- function GetExceptionData(AException : Exception) : TExceptionData;
- protected
- procedure Execute; override;
- procedure SetState (AResult : Integer; AComment : String);
- procedure SetNotifyWndHandle (Value : THandle);
- procedure NotifyStatus (AEvent : Integer);
- procedure NotifyStatusViaWinMessage (AEvent : Integer);
- function AssembleResult () : TThreadResult;
- function RunDataQuery (ASql : WideString; var ADataset : TDataset; out AExceptionData : TExceptionData; callback: TAsyncPostRunner) : Boolean;
- function RunUpdateQuery (ASql : WideString; var ADataset : TDataset; out AExceptionData : TExceptionData; callback: TAsyncPostRunner) : Boolean;
- function QuerySingleCellAsInteger (ASql : WideString) : Integer;
- public
- constructor Create (AOwner : TObject; AConn : TOpenConnProf; ASql : WideString; Callback: TAsyncPostRunner; APostDataSet: TDeferDataSet);
- destructor Destroy; override;
- property NotifyWndHandle : THandle read FNotifyWndHandle write SetNotifyWndHandle;
- end;
-
-implementation
-
-uses
- MysqlQuery, Dialogs, communication
-{$IFNDEF EXAMPLE_APP}
-, Main
-{$ENDIF}
- ;
-
-function TMysqlQueryThread.AssembleResult: TThreadResult;
-begin
- ZeroMemory (@Result,SizeOf(Result));
-
- Result.ThreadID := ThreadID;
- Result.Action := 1;
- Result.Sql := FSql;
- Result.Result := FResult;
- Result.Comment := FComment;
-end;
-
-constructor TMysqlQueryThread.Create (AOwner : TObject; AConn : TOpenConnProf; ASql : WideString; Callback: TAsyncPostRunner; APostDataSet: TDeferDataSet);
-var
- mc : TZConnection;
-begin
- Inherited Create(True);
-
- FOwner := AOwner;
- FConn := AConn;
- FCallback := Callback;
- FPostDataSet := APostDataSet;
- mc := TMysqlQuery(FOwner).MysqlConnection;
- FMysqlConn := mc;
- FResult := 0;
- FSql := ASql;
-
- if AConn.MysqlParams.NetType = NETTYPE_TCPIP then begin
- mc.HostName := AConn.MysqlParams.Host;
- mc.SocketName := '';
- end else begin
- mc.HostName := '.';
- mc.SocketName := AConn.MysqlParams.Host;
- end;
- mc.Database := AConn.MysqlParams.Database;
- mc.User := AConn.MysqlParams.User;
- mc.Password := AConn.MysqlParams.Pass;
- mc.Protocol := AConn.MysqlParams.Protocol;
- mc.Port := AConn.MysqlParams.Port;
-
- FreeOnTerminate := True;
-end;
-
-destructor TMysqlQueryThread.Destroy;
-begin
- inherited;
-end;
-
-
-procedure TMysqlQueryThread.NotifyStatus(AEvent: Integer);
-var
- h : THandle;
- qr : TThreadResult;
-begin
- if AEvent = MQE_FINISHED then begin
- debug(Format('qry: Setting result', [AEvent]));
- qr := AssembleResult();
- TMysqlQuery(FOwner).SetThreadResult(qr);
- // trigger query finished event
- h := OpenEvent (EVENT_MODIFY_STATE,False,PChar(TMysqlQuery(FOwner).EventName));
- debug('qry: Signalling completion via event.');
- if not SetEvent (h) then raise Exception.Create(Format('Assertion failed: Error %d signaling event', [GetLastError]));
- CloseHandle(h);
- end;
- NotifyStatusViaWinMessage(AEvent);
-end;
-
-procedure TMysqlQueryThread.NotifyStatusViaWinMessage(AEvent: Integer);
-begin
- debug(Format('qry: Posting status %d via WM_MYSQL_THREAD_NOTIFY message', [AEvent]));
- PostMessage(FNotifyWndHandle,WM_MYSQL_THREAD_NOTIFY,Integer(FOwner),AEvent);
-end;
-
-procedure TMysqlQueryThread.Execute;
-var
- q : TDeferDataSet;
- r : Boolean;
- ex : TExceptionData;
-begin
- debug(Format('qry: Thread %d running...', [ThreadID]));
- NotifyStatus(MQE_INITED);
-
- try
- if not FMysqlConn.Connected then FMysqlConn.Connect();
- except
- on E: Exception do begin
- SetState (MQR_CONNECT_FAIL,Format('%s',[E.Message]));
- end;
- end;
-
- if FMysqlConn.Connected then begin
- NotifyStatus (MQE_STARTED);
-
- q := nil;
- if FPostDataSet <> nil then begin
- try
- FPostDataSet.DoAsync;
- SetState (MQR_SUCCESS,'SUCCESS')
- except
- on E: Exception do begin
- SetState (MQR_QUERY_FAIL,Format('%s', [E.Message]));
- end;
- end;
- end else begin
- try
- r := RunDataQuery (FSql,TDataSet(q),ex,FCallback);
- TMysqlQuery(FOwner).SetMysqlDataset(q);
-
- if r then SetState (MQR_SUCCESS,'SUCCESS')
- else SetState (MQR_QUERY_FAIL,ex.Msg);
- except
- on E: Exception do begin
- SetState (MQR_QUERY_FAIL,Format('%s', [E.Message]));
- end;
- end;
- end;
- end;
-
- NotifyStatus (MQE_FINISHED);
- NotifyStatus (MQE_FREED);
- debug(Format('qry: Thread %d suspending.', [ThreadID]));
-end;
-
-
-function TMysqlQueryThread.GetExceptionData(
- AException: Exception): TExceptionData;
-begin
- ZeroMemory (@Result,SizeOf(Result));
- Result.Msg := AException.Message;
- Result.HelpContext := AException.HelpContext;
-end;
-
-function TMysqlQueryThread.QuerySingleCellAsInteger(ASql: WideString): Integer;
-var
- ds : TDataSet;
- e : TExceptionData;
-begin
- Result := 0;
-
- if RunDataQuery(ASql,ds,e, FCallback) then
- begin
- if ds.Fields.Count > 0 then
- Result := ds.Fields[0].AsInteger;
- FreeAndNil (ds);
- end;
-end;
-
-function TMysqlQueryThread.RunDataQuery(ASql: WideString;
- var ADataset: TDataset; out AExceptionData : TExceptionData; callback: TAsyncPostRunner): Boolean;
-var
- q : TDeferDataSet;
-begin
- Result := False;
- q := TDeferDataSet.Create(nil, callback);
- q.Connection := FMysqlConn;
- // Parameter checking is used only in Insert Files, which has it's own TZQuery.
- q.ParamCheck := false;
- q.SQL.Clear;
- q.SQL.Add(ASql);
- ADataset := q;
-
- try
- q.Active := True;
- Result := True;
- except
- on E: Exception do begin
- if E.Message = SCanNotOpenResultSet then begin
- Result := true;
- FreeAndNil(ADataset);
- end else if MainForm.cancelling then begin
- AExceptionData := GetExceptionData(Exception.Create('Cancelled by user.'));
- try
- FMysqlConn.Reconnect;
- except
- end;
- MainForm.cancelling := false;
- end else begin
- AExceptionData := GetExceptionData(E);
- end;
- end;
- end;
-end;
-
-function TMysqlQueryThread.RunUpdateQuery(ASql: WideString; var ADataset: TDataset; out AExceptionData : TExceptionData; callback: TAsyncPostRunner): Boolean;
-var
- q : TDeferDataSet;
-begin
- Result := False;
- q := TDeferDataSet.Create(nil, callback);
- q.Connection := FMysqlConn;
- // Parameter checking is used only in Insert Files, which has it's own TZQuery.
- q.ParamCheck := false;
- q.SQL.Text := ASql;
- ADataSet := q;
-
- try
- q.DoAsyncExecSql();
- Result := True;
- except
- On E: Exception do begin
- if MainForm.cancelling then begin
- AExceptionData := GetExceptionData(Exception.Create('Cancelled by user.'));
- try
- FMysqlConn.Reconnect;
- except
- end;
- MainForm.cancelling := false;
- end else begin
- AExceptionData := GetExceptionData(E);
- end;
- end;
- end;
-
- FreeAndNil (q);
-end;
-
-procedure TMysqlQueryThread.SetNotifyWndHandle(Value: THandle);
-begin
- FNotifyWndHandle := Value;
-end;
-
-procedure TMysqlQueryThread.SetState(AResult: Integer; AComment: String);
-var
- rx: TRegExpr;
- msg: String;
-begin
- debug(Format('qry: Setting status %d with comment %s', [AResult, AComment]));
- FResult := AResult;
- FComment := AComment;
- if FResult <> MQR_SUCCESS then begin
- // Find "(errno: 123)" in message and add more meaningful message from perror.exe
- rx := TRegExpr.Create;
- rx.Expression := '.+\(errno\:\s+(\d+)\)';
- if rx.Exec(FComment) then begin
- msg := MySQLErrorCodes.Values[rx.Match[1]];
- if msg <> '' then
- FComment := FComment + CRLF + CRLF + msg;
- end;
- rx.Free;
- end;
-end;
-
-end.
diff --git a/source/queryprogress.dfm b/source/queryprogress.dfm
deleted file mode 100644
index 5b963998..00000000
--- a/source/queryprogress.dfm
+++ /dev/null
@@ -1,39 +0,0 @@
-object frmQueryProgress: TfrmQueryProgress
- Left = 0
- Top = 0
- BorderIcons = []
- BorderStyle = bsDialog
- Caption = 'Status'
- ClientHeight = 78
- ClientWidth = 222
- Color = clBtnFace
- Font.Charset = DEFAULT_CHARSET
- Font.Color = clWindowText
- Font.Height = -11
- Font.Name = 'Tahoma'
- Font.Style = []
- OldCreateOrder = False
- Position = poScreenCenter
- OnClose = FormClose
- OnCreate = FormCreate
- PixelsPerInch = 96
- TextHeight = 13
- object lblStatusMsg: TLabel
- Left = 24
- Top = 16
- Width = 158
- Height = 13
- Caption = 'Waiting for query to complete ...'
- end
- object btnAbort: TButton
- Left = 72
- Top = 44
- Width = 73
- Height = 25
- Cancel = True
- Caption = 'Cancel'
- Default = True
- TabOrder = 0
- OnClick = btnAbortClick
- end
-end
diff --git a/source/queryprogress.pas b/source/queryprogress.pas
deleted file mode 100644
index 9f04b978..00000000
--- a/source/queryprogress.pas
+++ /dev/null
@@ -1,76 +0,0 @@
-unit queryprogress;
-
-interface
-
-uses
- Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls,MysqlQuery,MysqlQueryThread, ExtCtrls, communication;
-
-type
- TfrmQueryProgress = class(TForm)
- btnAbort: TButton;
- lblStatusMsg: TLabel;
- procedure FormClose(Sender: TObject; var Action: TCloseAction);
- procedure btnAbortClick(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- private
- procedure HandleQueryNotificationMsg(var AMessage : TMessage); message WM_MYSQL_THREAD_NOTIFY;
- public
-
- end;
-
-var
- frmQueryProgress: TfrmQueryProgress;
-
-implementation
-
-uses
- helpers,
- main;
-
-{$R *.dfm}
-
-procedure TfrmQueryProgress.btnAbortClick(Sender: TObject);
-begin
- MainForm.CancelQuery;
-end;
-
-
-procedure TfrmQueryProgress.FormClose(Sender: TObject;
- var Action: TCloseAction);
-begin
- Action := caFree;
-end;
-
-procedure TfrmQueryProgress.FormCreate(Sender: TObject);
-begin
- InheritFont(Font);
-end;
-
-{***
- Handles the TMysqlQueryThread notification messages.
-
- @param TMessage Message structure containing
- * LParam: Event type
- * WParam: MysqlQuery object containing status + resultset
-}
-
-procedure TfrmQueryProgress.HandleQueryNotificationMsg(var AMessage: TMessage);
-begin
- debug(Format('qry: Progress form received WM_MYSQL_THREAD_NOTIFY message with status %d', [AMessage.LParam]));
- case AMessage.LParam of
- MQE_INITED:
- begin
- debug('qry: Setting running flag to ''true''.');
- end;
- MQE_FINISHED:
- begin
- debug('qry: Setting running flag to ''false'' and closing dialog.');
- Close();
- end;
- end;
-end;
-
-
-
-end.
diff --git a/source/routine_editor.pas b/source/routine_editor.pas
index da71a013..6f6201ce 100644
--- a/source/routine_editor.pas
+++ b/source/routine_editor.pas
@@ -5,7 +5,7 @@ interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, SynEdit, SynMemo, StdCtrls, TntStdCtrls, ComCtrls, ToolWin,
- VirtualTrees, WideStrings, db, SynRegExpr, WideStrUtils;
+ VirtualTrees, WideStrings, mysql_connection, SynRegExpr, WideStrUtils;
type
TfrmRoutineEditor = class(TFrame)
@@ -116,7 +116,7 @@ end;
procedure TfrmRoutineEditor.Init(AlterRoutineName: WideString=''; AlterRoutineType: String='');
var
- ds: TDataSet;
+ Results: TMySQLQuery;
Create, Params: WideString;
ParenthesesCount: Integer;
Context: String;
@@ -138,22 +138,21 @@ begin
if FAlterRoutineName <> '' then begin
// Editing existing routine
Mainform.SetEditorTabCaption(Self, FAlterRoutineName);
- ds := Mainform.GetResults('SELECT * FROM '+DBNAME_INFORMATION_SCHEMA+'.ROUTINES'+
+ Results := Mainform.Connection.GetResults('SELECT * FROM '+DBNAME_INFORMATION_SCHEMA+'.ROUTINES'+
' WHERE ROUTINE_SCHEMA='+esc(Mainform.ActiveDatabase)+
' AND ROUTINE_NAME='+esc(FAlterRoutineName)+
' AND ROUTINE_TYPE='+esc(FAlterRoutineType)
);
- if ds.RecordCount <> 1 then
+ if Results.RecordCount <> 1 then
Exception.Create('Cannot find properties of stored routine '+FAlterRoutineName);
- ds.First;
comboType.ItemIndex := ListIndexByRegExpr(comboType.Items, '^'+FAlterRoutineType+'\b');
- chkDeterministic.Checked := ds.FieldByName('IS_DETERMINISTIC').AsString = 'YES';
- comboReturns.Text := ds.FieldByName('DTD_IDENTIFIER').AsWideString;
- comboDataAccess.ItemIndex := comboDataAccess.Items.IndexOf(ds.FieldByName('SQL_DATA_ACCESS').AsString);
- comboSecurity.ItemIndex := comboSecurity.Items.IndexOf(ds.FieldByName('SECURITY_TYPE').AsString);
- editComment.Text := ds.FieldByName('ROUTINE_COMMENT').AsWideString;
- SynMemoBody.Text := ds.FieldByName('ROUTINE_DEFINITION').AsWideString;
- Create := Mainform.GetVar('SHOW CREATE '+FAlterRoutineType+' '+Mainform.mask(editName.Text), 2);
+ chkDeterministic.Checked := Results.Col('IS_DETERMINISTIC') = 'YES';
+ comboReturns.Text := Results.Col('DTD_IDENTIFIER');
+ comboDataAccess.ItemIndex := comboDataAccess.Items.IndexOf(Results.Col('SQL_DATA_ACCESS'));
+ comboSecurity.ItemIndex := comboSecurity.Items.IndexOf(Results.Col('SECURITY_TYPE'));
+ editComment.Text := Results.Col('ROUTINE_COMMENT');
+ SynMemoBody.Text := Results.Col('ROUTINE_DEFINITION');
+ Create := Mainform.Connection.GetVar('SHOW CREATE '+FAlterRoutineType+' '+Mainform.mask(editName.Text), 2);
rx := TRegExpr.Create;
rx.ModifierI := True;
rx.ModifierG := True;
@@ -181,7 +180,7 @@ begin
if not rx.ExecNext then
break;
end;
- FreeAndNil(ds);
+ FreeAndNil(Results);
end else
Mainform.SetEditorTabCaption(Self, '');
editNameChange(Self);
@@ -443,7 +442,7 @@ begin
if FAlterRoutineName <> '' then begin
// Create temp name
i := 0;
- allRoutineNames := Mainform.GetCol('SELECT ROUTINE_NAME FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.'+Mainform.mask('ROUTINES')+
+ allRoutineNames := Mainform.Connection.GetCol('SELECT ROUTINE_NAME FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.'+Mainform.mask('ROUTINES')+
' WHERE ROUTINE_SCHEMA = '+esc(Mainform.ActiveDatabase)+
' AND ROUTINE_TYPE = '+esc(ProcOrFunc)
);
@@ -462,18 +461,18 @@ begin
break;
end;
TempSQL := 'CREATE '+ProcOrFunc+' '+Mainform.mask(tempName)+'(' + BaseSQL;
- Mainform.ExecUpdateQuery(TempSQL, False, True);
+ Mainform.Connection.Query(TempSQL);
// Drop temporary routine, used for syntax checking
- Mainform.ExecUpdateQuery('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(TempName));
+ Mainform.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(TempName));
// Drop edited routine
- Mainform.ExecUpdateQuery('DROP '+FAlterRoutineType+' IF EXISTS '+Mainform.mask(FAlterRoutineName));
+ Mainform.Connection.Query('DROP '+FAlterRoutineType+' IF EXISTS '+Mainform.mask(FAlterRoutineName));
if TargetExists then begin
// Drop target routine - overwriting has been confirmed, see above
- Mainform.ExecUpdateQuery('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(editName.Text));
+ Mainform.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(editName.Text));
end;
end;
FinalSQL := 'CREATE '+ProcOrFunc+' '+Mainform.mask(editName.Text)+'(' + BaseSQL;
- Mainform.ExecUpdateQuery(FinalSQL, False, True);
+ Mainform.Connection.Query(FinalSQL);
// Set editing name if create/alter query was successful
FAlterRoutineName := editName.Text;
FAlterRoutineType := ProcOrFunc;
diff --git a/source/runsqlfile.pas b/source/runsqlfile.pas
index 540f9a6f..5f5d1dcf 100644
--- a/source/runsqlfile.pas
+++ b/source/runsqlfile.pas
@@ -143,7 +143,8 @@ begin
lblTimeValue.Caption := FormatTimeNumber( (GetTickCount - starttime) DIV 1000 );
// Execute single query and display affected rows
- rowsaffected := rowsaffected + Mainform.ExecUpdateQuery( SQL[i], True, False );
+ Mainform.Connection.Query(SQL[i]);
+ rowsaffected := rowsaffected + Mainform.Connection.RowsAffected;
lblAffectedRowsValue.Caption := FormatNumber( rowsaffected );
Repaint;
diff --git a/source/selectdbobject.pas b/source/selectdbobject.pas
index b43f64c0..37c8f571 100644
--- a/source/selectdbobject.pas
+++ b/source/selectdbobject.pas
@@ -4,7 +4,7 @@ interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls, VirtualTrees, DB, WideStrings,
+ Dialogs, StdCtrls, VirtualTrees, mysql_connection, WideStrings,
TntStdCtrls;
type
@@ -163,14 +163,14 @@ procedure TfrmSelectDBObject.TreeDBOGetImageIndex(Sender: TBaseVirtualTree;
Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex; var Ghosted:
Boolean; var ImageIndex: Integer);
var
- ds: TDataset;
+ Results: TMySQLQuery;
begin
case Sender.GetNodeLevel(Node) of
0: ImageIndex := ICONINDEX_DB;
1: begin
- ds := Mainform.FetchDbTableList(Mainform.Databases[Node.Parent.Index]);
- ds.RecNo := Node.Index+1;
- case GetDBObjectType(ds.Fields) of
+ Results := Mainform.FetchDbTableList(Mainform.Databases[Node.Parent.Index]);
+ Results.RecNo := Node.Index;
+ case GetDBObjectType(Results) of
lntCrashedTable: ImageIndex := ICONINDEX_CRASHED_TABLE;
lntTable: ImageIndex := ICONINDEX_TABLE;
lntView: ImageIndex := ICONINDEX_VIEW;
@@ -191,22 +191,22 @@ end;
procedure TfrmSelectDBObject.TreeDBOInitChildren(Sender: TBaseVirtualTree;
Node: PVirtualNode; var ChildCount: Cardinal);
var
- ds: TDataset;
+ Results: TMySQLQuery;
cols: TWideStringList;
begin
// Fetch sub nodes
case Sender.GetNodeLevel(Node) of
0: begin // DB expanding
- ds := Mainform.FetchDbTableList(Mainform.Databases[Node.Index]);
- ChildCount := ds.RecordCount;
- SetLength(FColumns[Node.Index], ds.RecordCount);
+ Results := Mainform.FetchDbTableList(Mainform.Databases[Node.Index]);
+ ChildCount := Results.RecordCount;
+ SetLength(FColumns[Node.Index], Results.RecordCount);
end;
1: begin // Table expanding
- ds := Mainform.FetchDbTableList(Mainform.Databases[Node.Parent.Index]);
- ds.RecNo := Node.Index+1;
- cols := Mainform.GetCol('SHOW COLUMNS FROM '
+ Results := Mainform.FetchDbTableList(Mainform.Databases[Node.Parent.Index]);
+ Results.RecNo := Node.Index;
+ cols := Mainform.Connection.GetCol('SHOW COLUMNS FROM '
+ Mainform.mask(Mainform.Databases[Node.Parent.Index])+'.'
- + Mainform.Mask(ds.FieldByName(DBO_NAME).AsWideString));
+ + Mainform.Mask(Results.Col(DBO_NAME)));
FColumns[Node.Parent.Index][Node.Index] := cols;
ChildCount := cols.Count;
end;
@@ -219,14 +219,14 @@ procedure TfrmSelectDBObject.TreeDBOGetText(Sender: TBaseVirtualTree; Node:
PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText:
WideString);
var
- ds: TDataset;
+ Results: TMySQLQuery;
begin
case Sender.GetNodeLevel(Node) of
0: CellText := Mainform.Databases[Node.Index];
1: begin
- ds := Mainform.FetchDbTableList(Mainform.Databases[Node.Parent.Index]);
- ds.RecNo := Node.Index+1;
- CellText := ds.FieldByName(DBO_NAME).AsWideString;
+ Results := Mainform.FetchDbTableList(Mainform.Databases[Node.Parent.Index]);
+ Results.RecNo := Node.Index;
+ CellText := Results.Col(DBO_NAME);
end;
2: CellText := FColumns[Node.Parent.Parent.Index][Node.Parent.Index][Node.Index];
end;
diff --git a/source/sqlhelp.pas b/source/sqlhelp.pas
index f1ce7ff8..88ba7520 100644
--- a/source/sqlhelp.pas
+++ b/source/sqlhelp.pas
@@ -6,7 +6,7 @@ uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ExtCtrls, ShellApi, Buttons,
PngSpeedButton, SynMemo, SynEditHighlighter, SynHighlighterURI,
- SynURIOpener, SynEdit;
+ SynURIOpener, SynEdit, mysql_connection;
type
TfrmSQLhelp = class(TForm)
@@ -57,7 +57,7 @@ type
implementation
-uses ZDataset, helpers, main, db;
+uses helpers, main, db;
{$I const.inc}
@@ -107,46 +107,36 @@ end;
}
procedure TfrmSQLhelp.fillTreeLevel( ParentNode: TTreeNode );
var
- tnode : TTreeNode;
- i : integer;
- ds : TDataSet;
- topic : String;
+ tnode: TTreeNode;
+ Results: TMySQLQuery;
+ topic: String;
begin
- if ParentNode = nil then
- begin
+ if ParentNode = nil then begin
treeTopics.Items.Clear;
topic := 'CONTENTS';
- end
- else
- begin
+ end else begin
ParentNode.DeleteChildren;
topic := ParentNode.Text;
end;
- ds := nil;
try
Screen.Cursor := crHourglass;
- ds := Mainform.GetResults( 'HELP "'+topic+'"' );
- for i:=1 to ds.RecordCount do
- begin
- tnode := treeTopics.Items.AddChild( ParentNode, ds.FieldByName('name').AsString );
- if (ds.FindField('is_it_category') <> nil) and (ds.FieldByName('is_it_category').AsString = 'Y') then
- begin
+ Results := Mainform.Connection.GetResults( 'HELP "'+topic+'"' );
+ while not Results.Eof do begin
+ tnode := treeTopics.Items.AddChild( ParentNode, Results.Col('name'));
+ if Results.ColExists('is_it_category') and (Results.Col('is_it_category') = 'Y') then begin
tnode.ImageIndex := ICONINDEX_CATEGORY_CLOSED;
tnode.SelectedIndex := ICONINDEX_CATEGORY_OPENED;
// Add a dummy item to show the plus-button so the user sees that there this
// is a category. When the plus-button is clicked, fetch the content of the category
treeTopics.Items.AddChild( tnode, DUMMY_NODE_TEXT );
- end
- else
- begin
+ end else begin
tnode.ImageIndex := ICONINDEX_HELPITEM;
tnode.SelectedIndex := tnode.ImageIndex;
end;
- ds.Next;
+ Results.Next;
end;
finally
- if ds <> nil then ds.Close;
- FreeAndNil( ds );
+ FreeAndNil(Results);
Screen.Cursor := crDefault;
end;
end;
@@ -245,7 +235,7 @@ end;
}
function TfrmSQLhelp.ShowHelpItem: Boolean;
var
- ds : TDataSet;
+ Results: TMySQLQuery;
begin
lblKeyword.Caption := Copy(Keyword, 0, 100);
MemoDescription.Lines.Clear;
@@ -253,26 +243,23 @@ begin
Caption := DEFAULT_WINDOW_CAPTION;
result := false; // Keyword not found yet
- ds := nil;
if Keyword <> '' then
try
Screen.Cursor := crHourglass;
- ds := Mainform.GetResults( 'HELP "'+lblKeyword.Caption+'"' );
- if ds.RecordCount = 1 then
- begin
+ Results := Mainform.Connection.GetResults('HELP "'+lblKeyword.Caption+'"');
+ if Results.RecordCount = 1 then begin
// We found exactly one matching help item
- lblKeyword.Caption := ds.FieldByName('name').AsString;
+ lblKeyword.Caption := Results.Col('name');
Keyword := lblKeyword.Caption;
if lblKeyword.Caption = '&' then
lblKeyword.Caption := '&&'; // Avoid displaying "_" as alt-hotkey
Caption := Caption + ' - ' + Keyword;
- MemoDescription.Text := fixNewlines(ds.FieldByName('description').AsString);
- MemoExample.Text := fixNewlines(ds.FieldByName('example').AsString);
+ MemoDescription.Text := fixNewlines(Results.Col('description'));
+ MemoExample.Text := fixNewlines(Results.Col('example'));
result := true;
end;
finally
- if ds <> nil then ds.Close;
- FreeAndNil( ds );
+ FreeAndNil(Results);
Screen.Cursor := crDefault;
end;
@@ -317,7 +304,7 @@ end;
}
procedure TfrmSQLhelp.ButtonOnlinehelpClick(Sender: TObject);
begin
- ShellExec( APPDOMAIN + 'sqlhelp.php?mysqlversion='+inttostr(Mainform.mysql_version)+
+ ShellExec( APPDOMAIN + 'sqlhelp.php?mysqlversion='+inttostr(Mainform.Connection.ServerVersionInt)+
'&keyword='+urlencode(keyword) );
end;
diff --git a/source/synchronization.pas b/source/synchronization.pas
deleted file mode 100644
index d1cea10a..00000000
--- a/source/synchronization.pas
+++ /dev/null
@@ -1,470 +0,0 @@
-unit synchronization;
-
-(*
- Inter-Process Synchronization.
-
- Current limitations:
- * Hard limit on number of windows.
- * Reuses various Delphi exceptions instead of defining own.
- (Both could be fixed if necessary.)
-*)
-
-
-
-interface
-
-const
- appName = 'HeidiSQL';
- (*
- If you alter the structure of the shared data (TWindowData)
- or the window limit (maxWindows), you must alter the string
- below so the two incompatible versions of your app can coxist
- peacefully.
- *)
- compatibilityLevel = 'v3';
- maxWindows = 99;
-
-type
- TWindowData = packed record
- appHandle: THandle;
- (*connectionUid: integer;*)
- name: ShortString;
- namePostFix: integer;
- (*ready: boolean;*)
- connected: boolean;
- end;
- TWindowDataArray = packed array of TWindowData;
-
-(*
- Run this procedure at application startup.
- catch any exceptions and abort after showing
- an error message if one occurred.
-*)
-procedure InitializeSync(myWindow: THandle);
-
-(*
- Run this procedure at application shutdown.
- Catch any exceptions and show an error message if one occurred.
-*)
-procedure DeInitializeSync;
-
-(*
- Run this procedure when (dis-)connecting.
- Set uid to a connection profile's uid,
- or 0 if it's a custom connection or disconnection.
-
- Commented out:
- We currently do not have any uniqueness handling nor versioning of connection profiles.
-*)
-(*procedure SetConnectionUid(uid: integer);*)
-
-(*
- Run this procedure when starting and ending database queries.
-
- Commented out:
- I'm not sure we want 1 connection per window.
- Perhaps we want multiple tabs, each with their own connection,
- in which case a per-window flag is useless.
-*)
-(*procedure SetWindowReady(ready: boolean);*)
-
-(*
- Run this procedure when opening/closing connection to a host.
-*)
-procedure SetWindowConnected(connected: boolean);
-
-(*
- Run this procedure when opening/closing connection.
-*)
-function SetWindowName(name: string): integer;
-
-(*
- Run this procedure to get a list of application windows.
- If you run this function from a timer, consider:
- 1) Disable the timer at once when it's fired, reenable when event handler is all done.
- 2) Before reenabling the timer, adjust it's interval value by adding 100msec * nr. of windows.
-*)
-function GetWindowList: TWindowDataArray;
-
-(*
- Run this procedure to find and remove disappeared application instances' data.
- If you run this function from a timer, consider:
- 1) Disable the timer at once when it's fired, reenable when event handler is all done.
- 2) Before reenabling the timer, adjust it's interval value by adding 100msec * nr. of windows.
-*)
-procedure CheckForCrashedWindows;
-
-
-
-implementation
-
-uses
- Windows,
- SysUtils;
-
-const
- FILE_BACKING_PAGEFILE = $ffffffff;
-
-type
- PSharedData = ^TSharedData;
- TSharedData = record
- windows: array[0..maxWindows] of TWindowData;
- end;
-
-var
- sharedData: PSharedData = nil;
- mySlot: integer = -1;
- myDataArea: THandle = 0;
- myInternalLock: TRTLCriticalSection;
- mutexName: PAnsiChar;
- dataAreaName: PAnsiChar;
-
-procedure InitializeSync(myWindow: THandle);
-var
- mutex: THandle;
- errorCode: integer;
- i: integer;
-begin
- EnterCriticalSection(myInternalLock);
- try
- // Take ownership of a mutually exclusive lock shared
- // between multiple instances of this application.
- // Create the lock if it doesn't exist.
- mutex := CreateMutex(nil, true, mutexName);
- if GetLastError = ERROR_ALREADY_EXISTS then begin
- mutex := OpenMutex(MUTEX_ALL_ACCESS, false, mutexName);
- end;
-
- // Die on failure to open or create lock.
- if mutex = 0 then begin
- raise EAssertionFailed.CreateFmt('Failed to create or open mutex ''%s'': Win32 error %d.', [mutexName, GetLastError]);
- end;
-
- // Create or open shared data area.
- myDataArea := CreateFileMapping(FILE_BACKING_PAGEFILE, nil, PAGE_READWRITE, 0, SizeOf(TSharedData), dataAreaName);
- errorCode := GetLastError;
-
- // Die on failure to open or create shared data area.
- if myDataArea = 0 then begin
- raise EAssertionFailed.CreateFmt('Failed to create or open file mapping ''%s'': Win32 error %d.', [dataAreaName, errorCode]);
- end;
-
- // Map shared data area into our process memory.
- sharedData := MapViewOfFile(myDataArea, FILE_MAP_ALL_ACCESS, 0, 0, 0);
-
- // Die on failure to map data area.
- if sharedData = nil then begin
- raise EAssertionFailed.CreateFmt('Failed to map data area into memory: Win32 error %d.', [GetLastError]);
- end;
-
- // If we've just created the data area, initialize it.
- // (Not particularly needed on Windows, since it clears
- // memory in a background thread before giving it to apps.
- // But that's a security feature so who knows if it will
- // be around as a feature later / on different platforms.)
- if errorCode <> ERROR_ALREADY_EXISTS then begin
- FillChar(sharedData^, SizeOf(TSharedData), 0);
- end;
-
- // Find an empty slot and grab it.
- for i := 0 to maxWindows do begin
- if sharedData^.windows[i].appHandle = 0 then begin
- sharedData^.windows[i].appHandle := myWindow;
- (*sharedData^.windows[i].connectionUid := 0;*)
- (*sharedData^.windows[i].ready := true;*)
- sharedData^.windows[i].name := '';
- sharedData^.windows[i].namePostFix := 0;
- sharedData^.windows[i].connected := false;
- mySlot := i;
- break;
- end;
- end;
-
- // Die if no empty slot was found.
- if mySlot = -1 then begin
- raise EAssertionFailed.CreateFmt('Failed to allocate window slot. No more than %d instances is allowed.', [maxWindows + 1]);
- end;
-
- // Disown lock.
- ReleaseMutex(mutex);
-
- finally
- LeaveCriticalSection(myInternalLock);
- end;
-end;
-
-
-// Internal helper procedure to grab the mutex and abort on error.
-procedure GrabLock(var mutex: THandle);
-begin
- mutex := OpenMutex(MUTEX_ALL_ACCESS, false, mutexName);
-
- // Die on failure to open lock.
- if mutex = 0 then begin
- raise EAssertionFailed.CreateFmt('Failed to open mutex ''%s'': Win32 error %d.', [mutexName, GetLastError]);
- end;
-end;
-
-
-function FindWindowsWithName(searchName: string; excludeSlot: integer; addPostFix: boolean; clearPostFix: boolean): integer;
-var
- max: integer;
- i: integer;
-begin
- // Find out if other windows has the same name.
- max := 0;
- for i := 0 to maxWindows do begin
- if i <> excludeSlot then with sharedData^.windows[i] do begin
- if appHandle <> 0 then begin
- if name = searchName then begin
- if addPostFix or clearPostFix then begin
- if addPostFix and (namePostFix = 0) then namePostFix := 1;
- if clearPostFix then namePostFix := 0;
- end else if max = 0 then max := max + 1;
- if namePostFix > max then max := namePostFix;
- end;
- end;
- end;
- end;
- result := max;
-end;
-
-
-procedure DeInitializeSync;
-var
- mutex: THandle;
-begin
- EnterCriticalSection(myInternalLock);
- try
- // Take ownership of lock.
- GrabLock(mutex);
-
- // Clear uniqueness postfix if only one window with this name is left.
- if FindWindowsWithName(sharedData^.windows[mySlot].name, mySlot, false, false) = 1 then begin
- FindWindowsWithName(sharedData^.windows[mySlot].name, -1, false, true);
- end;
-
- // Remove ourselves from our slot.
- if mySlot > -1 then begin
- sharedData^.windows[mySlot].appHandle := 0;
- mySlot := -1;
- end;
-
- // Unmap shared data from memory.
- if sharedData <> nil then begin
- UnmapViewOfFile(sharedData);
- sharedData := nil;
- end;
- if myDataArea <> 0 then begin
- CloseHandle(myDataArea);
- myDataArea := 0;
- end;
-
- // We could potentially clean up the mutex if we're
- // the last instance, but we really need not bother
- // since Windows does it for us when we terminate.
-
- // Release lock.
- ReleaseMutex(mutex);
-
- finally
- LeaveCriticalSection(myInternalLock);
- end;
-end;
-
-
-(*
-procedure SetConnectionUid(uid: integer);
-var
- mutex: THandle;
-begin
- EnterCriticalSection(myInternalLock);
- try
- // Take ownership of lock.
- GrabLock(mutex);
-
- // Set UID value.
- sharedData^.windows[mySlot].connectionUid := uid;
-
- // Release lock.
- ReleaseMutex(mutex);
-
- finally
- LeaveCriticalSection(myInternalLock);
- end;
-end;
-*)
-
-
-(*
-procedure SetWindowReady(ready: boolean);
-var
- mutex: THandle;
-begin
- EnterCriticalSection(myInternalLock);
- try
- // Take ownership of lock.
- GrabLock(mutex);
-
- // Set UID value.
- sharedData^.windows[mySlot].ready := ready;
-
- // Release lock.
- ReleaseMutex(mutex);
-
- finally
- LeaveCriticalSection(myInternalLock);
- end;
-end;
-*)
-
-
-procedure SetWindowConnected(connected: boolean);
-var
- mutex: THandle;
-begin
- EnterCriticalSection(myInternalLock);
- try
- // Take ownership of lock.
- GrabLock(mutex);
-
- // Set UID value.
- sharedData^.windows[mySlot].connected := connected;
-
- // Release lock.
- ReleaseMutex(mutex);
-
- finally
- LeaveCriticalSection(myInternalLock);
- end;
-end;
-
-
-function SetWindowName(name: string): integer;
-var
- mutex: THandle;
- count: integer;
-begin
- EnterCriticalSection(myInternalLock);
- try
- // Take ownership of lock.
- GrabLock(mutex);
-
- // Find out if other windows has the same name, in which case set namePostFix > 0.
- count := FindWindowsWithName(name, mySlot, true, false);
- if count > 0 then count := count + 1;
- sharedData^.windows[mySlot].namePostFix := count;
- result := count;
-
- // Set name by copying string value into array.
- sharedData^.windows[mySlot].name := name;
-
- // Release lock.
- ReleaseMutex(mutex);
-
- finally
- LeaveCriticalSection(myInternalLock);
- end;
-end;
-
-
-function GetWindowList: TWindowDataArray;
-var
- mutex: THandle;
- i: integer;
- count: integer;
-begin
- EnterCriticalSection(myInternalLock);
- try
- // Take ownership of lock.
- GrabLock(mutex);
-
- // Find how many slots are used.
- count := 0;
- if sharedData <> nil then begin
- for i := 0 to maxWindows do begin
- if sharedData^.windows[i].appHandle <> 0 then begin
- count := count + 1;
- end;
- end;
- end;
-
- // Create an array with a clone of the slot data.
- SetLength(result, count);
- if sharedData <> nil then begin
- count := 0;
- for i := 0 to maxWindows do begin
- if sharedData^.windows[i].appHandle <> 0 then begin
- result[count] := sharedData^.windows[i];
- count := count + 1;
- if count = High(result) + 1 then break;
- end;
- end;
- end;
-
- // Release lock.
- ReleaseMutex(mutex);
-
- // Hint the programmer that he might or might not have an issue.
- // This exception can be safely ignored, it's ok to hit it on purpose.
- if count = 0 then begin
- raise ERangeError.Create('GetWindowList() called, but there is 0 instances left.');
- end;
-
- finally
- LeaveCriticalSection(myInternalLock);
- end;
-end;
-
-
-procedure CheckForCrashedWindows;
-var
- mutex: THandle;
- count: integer;
- i: integer;
-begin
- EnterCriticalSection(myInternalLock);
- try
- // Take ownership of lock.
- GrabLock(mutex);
-
- // Remove application instance shared data if they've disappeared.
- count := 0;
- if sharedData <> nil then begin
- for i := 0 to maxWindows do with sharedData^.windows[i] do begin
- if appHandle <> 0 then begin
- count := count + 1;
- if not IsWindow(appHandle) then begin
- // Clear uniqueness postfix if only one window with this name is left.
- if FindWindowsWithName(name, i, false, false) = 0 then FindWindowsWithName(name, -1, false, true);
- appHandle := 0;
- end;
- end;
- end;
- end;
-
- // Release lock.
- ReleaseMutex(mutex);
-
- // Hint the programmer that he might or might not have an issue.
- // This exception can be safely ignored, it's ok to hit it on purpose.
- if count = 0 then begin
- raise ERangeError.Create('CheckForCrashedWindows() called, but there is 0 instances left.');
- end;
-
- finally
- LeaveCriticalSection(myInternalLock);
- end;
-end;
-
-
-initialization
- // The critical section is technically not absolutely necessary,
- // but it makes this unit thread-safe, thereby making it easier
- // to use the functions herein.
- InitializeCriticalSection(myInternalLock);
- mutexName := appName + '_mutex_' + compatibilityLevel;
- dataAreaName := appName + '_data_' + compatibilityLevel;
-
-end.
-
diff --git a/source/table_editor.pas b/source/table_editor.pas
index 06bc577f..4aac2bb2 100644
--- a/source/table_editor.pas
+++ b/source/table_editor.pas
@@ -5,8 +5,8 @@ interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, TntStdCtrls, ComCtrls, ToolWin, VirtualTrees, WideStrings,
- SynRegExpr, ActiveX, DB, ExtCtrls, ImgList, SynEdit, SynMemo, Menus, WideStrUtils,
- Contnrs, grideditlinks, mysql_structures, helpers;
+ SynRegExpr, ActiveX, ExtCtrls, ImgList, SynEdit, SynMemo, Menus, WideStrUtils,
+ Contnrs, grideditlinks, mysql_structures, mysql_connection, helpers;
type
TfrmTableEditor = class(TFrame)
@@ -286,7 +286,7 @@ end;
procedure TfrmTableEditor.Init(AlterTableName: WideString='');
var
- ds: TDataset;
+ Results: TMySQLQuery;
Props: TWideStringlist;
Col: TColumn;
IndexType: String;
@@ -323,7 +323,7 @@ begin
editMaxRows.Text := '';
chkChecksum.Checked := False;
comboRowFormat.ItemIndex := 0;
- comboCollation.ItemIndex := comboCollation.Items.IndexOf(Mainform.GetVar('SHOW VARIABLES LIKE ''collation_database''', 1));
+ comboCollation.ItemIndex := comboCollation.Items.IndexOf(Mainform.Connection.GetVar('SHOW VARIABLES LIKE ''collation_database''', 1));
memoUnionTables.Clear;
comboInsertMethod.ItemIndex := -1;
@@ -333,21 +333,21 @@ begin
// Editing existing table
editName.Text := FAlterTableName;
Mainform.SetEditorTabCaption(Self, FAlterTableName);
- ds := Mainform.GetResults('SHOW TABLE STATUS LIKE '+esc(FAlterTableName));
- memoComment.Text := ds.FieldByName(DBO_COMMENT).AsWideString;
- if ds.FindField(DBO_ENGINE) <> nil then
- engine := ds.FieldByName(DBO_ENGINE).AsString
+ Results := Mainform.Connection.GetResults('SHOW TABLE STATUS LIKE '+esc(FAlterTableName));
+ memoComment.Text := Results.Col(DBO_COMMENT);
+ if Results.ColExists(DBO_ENGINE) then
+ engine := Results.Col(DBO_ENGINE)
else
- engine := ds.FieldByName(DBO_TYPE).AsString;
+ engine := Results.Col(DBO_TYPE);
comboEngine.ItemIndex := comboEngine.Items.IndexOf(engine);
- if ds.FindField(DBO_COLLATION) <> nil then
- comboCollation.ItemIndex := comboCollation.Items.IndexOf(ds.FieldByName(DBO_COLLATION).AsWideString);
- editAutoInc.Text := ds.FieldByName(DBO_AUTOINC).AsString;
- editAvgRowLen.Text := ds.FieldByName(DBO_AVGROWLEN).AsString;
- chkChecksum.Checked := Pos('checksum=1', LowerCase(ds.FieldByName(DBO_CROPTIONS).AsString)) > 0;
- comboRowFormat.ItemIndex := comboRowFormat.Items.IndexOf(ds.FieldByName(DBO_ROWFORMAT).AsString);
- FreeAndNil(ds);
- CreateTable := Mainform.GetVar('SHOW CREATE TABLE '+Mainform.mask(FAlterTableName), 1);
+ if Results.ColExists(DBO_COLLATION) then
+ comboCollation.ItemIndex := comboCollation.Items.IndexOf(Results.Col(DBO_COLLATION));
+ editAutoInc.Text := Results.Col(DBO_AUTOINC);
+ editAvgRowLen.Text := Results.Col(DBO_AVGROWLEN);
+ chkChecksum.Checked := Pos('checksum=1', LowerCase(Results.Col(DBO_CROPTIONS))) > 0;
+ comboRowFormat.ItemIndex := comboRowFormat.Items.IndexOf(Results.Col(DBO_ROWFORMAT));
+ FreeAndNil(Results);
+ CreateTable := Mainform.Connection.GetVar('SHOW CREATE TABLE '+Mainform.mask(FAlterTableName), 1);
rx := TRegExpr.Create;
rx.ModifierI := True;
rx.Expression := '\bUNION=\((.+)\)';
@@ -496,30 +496,30 @@ begin
end;
FreeAndNil(rx);
- ds := Mainform.GetResults('SHOW KEYS FROM '+Mainform.mask(FAlterTableName));
+ Results := Mainform.Connection.GetResults('SHOW KEYS FROM '+Mainform.mask(FAlterTableName));
LastKeyName := '';
Props := nil;
- while not ds.Eof do begin
- if LastKeyName <> ds.FieldByName('Key_name').AsWideString then begin
+ while not Results.Eof do begin
+ if LastKeyName <> Results.Col('Key_name') then begin
Props := TWideStringlist.Create;
Props.OnChange := IndexesChange;
- IndexType := ds.FieldByName('Key_name').AsString;
- if (ds.FindField('Index_type') <> nil) and (
- (ds.FieldByName('Index_type').AsString = FKEY) or (ds.FieldByName('Index_type').AsString = SKEY)) then
- IndexType := ds.FieldByName('Index_type').AsString
- else if (IndexType <> PKEY) and (ds.FieldByName('Non_unique').AsInteger = 0) then
+ IndexType := Results.Col('Key_name');
+ if Results.ColExists('Index_type') and (
+ (Results.Col('Index_type') = FKEY) or (Results.Col('Index_type') = SKEY)) then
+ IndexType := Results.Col('Index_type')
+ else if (IndexType <> PKEY) and (Results.Col('Non_unique') = '0') then
IndexType := UKEY
- else if ds.FieldByName('Non_unique').AsInteger = 1 then
+ else if Results.Col('Non_unique') = '1' then
IndexType := KEY;
- Indexes.AddObject(ds.FieldByName('Key_name').AsWideString+REGDELIM+IndexType, Props);
+ Indexes.AddObject(Results.Col('Key_name')+REGDELIM+IndexType, Props);
end;
- Props.Add(ds.FieldByName('Column_name').AsWideString);
- if ds.FieldByName('Sub_part').AsString <> '' then
- Props[Props.Count-1] := Props[Props.Count-1] + '('+ds.FieldByName('Sub_part').AsString+')';
- LastKeyName := ds.FieldByName('Key_name').AsWideString;
- ds.Next;
+ Props.Add(Results.Col('Column_name'));
+ if Results.Col('Sub_part') <> '' then
+ Props[Props.Count-1] := Props[Props.Count-1] + '('+Results.Col('Sub_part')+')';
+ LastKeyName := Results.Col('Key_name');
+ Results.Next;
end;
- FreeAndNil(ds);
+ FreeAndNil(Results);
end;
listColumns.RootNodeCount := FColumns.Count;
@@ -571,9 +571,9 @@ begin
Specs.Add('DROP FOREIGN KEY '+Mainform.mask(Key.KeyName));
end;
if Specs.Count > 0 then
- Mainform.ExecUpdateQuery('ALTER TABLE '+Mainform.mask(FAlterTableName)+' '+ImplodeStr(', ', Specs));
+ Mainform.Connection.Query('ALTER TABLE '+Mainform.mask(FAlterTableName)+' '+ImplodeStr(', ', Specs));
end;
- Mainform.ExecUpdateQuery(sql);
+ Mainform.Connection.Query(sql);
// Set table name for altering if Apply was clicked
FAlterTableName := editName.Text;
tabALTERcode.TabVisible := FAlterTableName <> '';
@@ -645,7 +645,7 @@ var
ColSpec, OldColName, IndexSQL: WideString;
i: Integer;
DropIt: Boolean;
- ds: TDataset;
+ Results: TMySQLQuery;
Key: TForeignKey;
Col, PreviousCol: PColumn;
ColObj: TColumn;
@@ -678,13 +678,13 @@ begin
if comboInsertMethod.Enabled and (comboInsertMethod.Tag = ModifiedFlag) and (comboInsertMethod.Text <> '') then
Specs.Add('INSERT_METHOD='+comboInsertMethod.Text);
if chkCharsetConvert.Checked then begin
- ds := Mainform.GetCollations;
- while not ds.Eof do begin
- if ds.FieldByName('Collation').AsWideString = comboCollation.Text then begin
- Specs.Add('CONVERT TO CHARSET '+ds.FieldByName('Charset').AsWideString);
+ Results := Mainform.GetCollations;
+ while not Results.Eof do begin
+ if Results.Col('Collation') = comboCollation.Text then begin
+ Specs.Add('CONVERT TO CHARSET '+Results.Col('Charset'));
break;
end;
- ds.Next;
+ Results.Next;
end;
end;
@@ -719,7 +719,7 @@ begin
ColSpec := ColSpec + Col.Collation;
end;
// Server version requirement, see http://dev.mysql.com/doc/refman/4.1/en/alter-table.html
- if Mainform.mysql_version >= 40001 then begin
+ if Mainform.Connection.ServerVersionInt >= 40001 then begin
if PreviousCol = nil then
ColSpec := ColSpec + ' FIRST'
else
@@ -2110,7 +2110,7 @@ begin
MessageDlg('Please select a reference table before selecting foreign columns.', mtError, [mbOk], 0)
else begin
try
- Mainform.GetVar('SELECT 1 FROM '+Mainform.MaskMulti(Key.ReferenceTable));
+ Mainform.Connection.GetVar('SELECT 1 FROM '+Mainform.MaskMulti(Key.ReferenceTable));
Allowed := True;
except
// Leave Allowed = False
@@ -2129,7 +2129,7 @@ var
VT: TVirtualStringTree;
EnumEditor: TEnumEditorLink;
SetEditor: TSetEditorLink;
- ds: TDataset;
+ Results: TMySQLQuery;
Key: TForeignKey;
ColNode: PVirtualNode;
Col: PColumn;
@@ -2151,17 +2151,17 @@ begin
2: begin
EnumEditor := TEnumEditorLink.Create(VT);
EnumEditor.AllowCustomText := True;
- ds := Mainform.FetchActiveDbTableList;
- while not ds.Eof do begin
- EnumEditor.ValueList.Add(ds.FieldByName(DBO_NAME).AsWideString);
- ds.Next;
+ Results := Mainform.FetchActiveDbTableList;
+ while not Results.Eof do begin
+ EnumEditor.ValueList.Add(Results.Col(DBO_NAME));
+ Results.Next;
end;
EditLink := EnumEditor;
end;
3: begin
Key := ForeignKeys[Node.Index] as TForeignKey;
SetEditor := TSetEditorLink.Create(VT);
- SetEditor.ValueList := Mainform.GetCol('SHOW COLUMNS FROM '+Mainform.MaskMulti(Key.ReferenceTable));
+ SetEditor.ValueList := Mainform.Connection.GetCol('SHOW COLUMNS FROM '+Mainform.MaskMulti(Key.ReferenceTable));
EditLink := SetEditor;
end;
4, 5: begin
diff --git a/source/tabletools.pas b/source/tabletools.pas
index 6b4bf50f..32dec7e9 100644
--- a/source/tabletools.pas
+++ b/source/tabletools.pas
@@ -9,8 +9,8 @@ unit tabletools;
interface
uses
- Windows, SysUtils, Classes, Controls, Forms, StdCtrls, ComCtrls, Buttons,
- WideStrings, WideStrUtils, VirtualTrees, ExtCtrls, Db, Contnrs, Graphics, TntStdCtrls;
+ Windows, SysUtils, Classes, Controls, Forms, StdCtrls, ComCtrls, Buttons, Dialogs,
+ WideStrings, WideStrUtils, VirtualTrees, ExtCtrls, mysql_connection, Contnrs, Graphics, TntStdCtrls;
type
TfrmTableTools = class(TForm)
@@ -137,7 +137,7 @@ begin
TreeObjects.Clear;
TreeObjects.RootNodeCount := Mainform.DBtree.RootNodeCount;
// CHECKSUM available since MySQL 4.1.1
- if Mainform.mysql_version < 40101 then
+ if Mainform.Connection.ServerVersionInt < 40101 then
comboOperation.Items[comboOperation.Items.IndexOf('Checksum')] := 'Checksum ('+STR_NOTSUPPORTED+')';
comboOperation.OnChange(Sender);
end;
@@ -204,7 +204,7 @@ end;
procedure TfrmTableTools.TreeObjectsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
var
- ds: TDataset;
+ Results: TMySQLQuery;
begin
// Attach a checkbox to all nodes
Mainform.DBtreeInitNode(Sender, ParentNode, Node, InitialStates);
@@ -224,10 +224,10 @@ begin
end;
end;
2: begin
- ds := Mainform.FetchDbTableList(Mainform.Databases[ParentNode.Index]);
- ds.RecNo := Node.Index+1;
+ Results := Mainform.FetchDbTableList(Mainform.Databases[ParentNode.Index]);
+ Results.RecNo := Node.Index;
// No checkbox for stored routines
- if not (GetDBObjectType(ds.Fields) in [lntTable, lntCrashedTable, lntView]) then
+ if not (GetDBObjectType(Results) in [lntTable, lntCrashedTable, lntView]) then
Node.CheckType := ctNone
else begin
if Node.Parent.CheckState in [csCheckedNormal, csCheckedPressed] then begin
@@ -236,7 +236,7 @@ begin
end else if (Mainform.Databases[Node.Parent.Index] = Mainform.ActiveDatabase)
// ... or table name is in SelectedTables
and (SelectedTables.Count > 0)
- and (SelectedTables.IndexOf(ds.FieldByName(DBO_NAME).AsWideString) > -1) then begin
+ and (SelectedTables.IndexOf(Results.Col(DBO_NAME)) > -1) then begin
Node.CheckState := csCheckedNormal;
Node.Parent.CheckState := csMixedNormal;
end;
@@ -281,7 +281,7 @@ procedure TfrmTableTools.ProcessTableNode(Sender: TObject; Node: PVirtualNode);
var
SQL, db, table, QuotedTable: WideString;
TableSize, RowsInTable: Int64;
- ds: TDataset;
+ Results: TMySQLQuery;
i: Integer;
HasSelectedDatatype: Boolean;
begin
@@ -293,18 +293,18 @@ begin
// Find table in cashed dataset and check its size - perhaps it has to be skipped
TableSize := 0;
RowsInTable := 0;
- ds := Mainform.FetchDbTableList(db);
- while not ds.Eof do begin
- if (ds.FieldByName(DBO_NAME).AsWideString = table)
- and (GetDBObjectType(ds.Fields) in [lntTable, lntCrashedTable]) then begin
- TableSize := GetTableSize(ds);
- RowsInTable := MakeInt(ds.FieldByName(DBO_ROWS).AsString);
+ Results := Mainform.FetchDbTableList(db);
+ while not Results.Eof do begin
+ if (Results.Col(DBO_NAME) = table)
+ and (GetDBObjectType(Results) in [lntTable, lntCrashedTable]) then begin
+ TableSize := GetTableSize(Results);
+ RowsInTable := MakeInt(Results.Col(DBO_ROWS));
// Avoid division by zero in below SQL
if RowsInTable = 0 then
RowsInTable := 1;
break;
end;
- ds.Next;
+ Results.Next;
end;
if (udSkipLargeTables.Position = 0) or ((TableSize div SIZE_MB) < udSkipLargeTables.Position) then try
if Sender = btnExecuteMaintenance then begin
@@ -316,19 +316,19 @@ begin
if chkChanged.Enabled and chkChanged.Checked then SQL := SQL + ' CHANGED';
if chkUseFrm.Enabled and chkUseFrm.Checked then SQL := SQL + ' USE_FRM';
end else if Sender = btnFindText then begin
- ds := Mainform.GetResults('SHOW COLUMNS FROM '+QuotedTable);
+ Results := Mainform.Connection.GetResults('SHOW COLUMNS FROM '+QuotedTable);
SQL := '';
- while not ds.Eof do begin
+ while not Results.Eof do begin
HasSelectedDatatype := comboDatatypes.ItemIndex = 0;
if not HasSelectedDatatype then for i:=Low(Datatypes) to High(Datatypes) do begin
- HasSelectedDatatype := (LowerCase(getFirstWord(ds.FieldByName('Type').AsString)) = LowerCase(Datatypes[i].Name))
+ HasSelectedDatatype := (LowerCase(getFirstWord(Results.Col('Type'))) = LowerCase(Datatypes[i].Name))
and (Integer(Datatypes[i].Category)+1 = comboDatatypes.ItemIndex);
if HasSelectedDatatype then
break;
end;
if HasSelectedDatatype then
- SQL := SQL + Mainform.mask(ds.FieldByName('Field').AsWideString) + ' LIKE ' + esc('%'+memoFindText.Text+'%') + ' OR ';
- ds.Next;
+ SQL := SQL + Mainform.mask(Results.Col('Field')) + ' LIKE ' + esc('%'+memoFindText.Text+'%') + ' OR ';
+ Results.Next;
end;
if SQL <> '' then begin
Delete(SQL, Length(SQL)-3, 3);
@@ -358,39 +358,40 @@ var
i: Integer;
Col: TVirtualTreeColumn;
Row: TWideStringlist;
- ds: TDataset;
+ Results: TMySQLQuery;
begin
// Execute query and append results into grid
- ds := Mainform.GetResults(SQL);
- if ds = nil then
+ Results := Mainform.Connection.GetResults(SQL);
+ if Results = nil then
Exit;
// Add missing columns
- for i:=ResultGrid.Header.Columns.Count to ds.FieldCount-1 do begin
+ for i:=ResultGrid.Header.Columns.Count to Results.ColumnCount-1 do begin
Col := ResultGrid.Header.Columns.Add;
Col.Width := 130;
end;
// Remove superfluous columns
- for i:=ResultGrid.Header.Columns.Count-1 downto ds.FieldCount do
+ for i:=ResultGrid.Header.Columns.Count-1 downto Results.ColumnCount do
ResultGrid.Header.Columns[i].Free;
// Set column header names
- for i:=0 to ds.FieldCount-1 do begin
+ for i:=0 to Results.ColumnCount-1 do begin
Col := ResultGrid.Header.Columns[i];
- Col.Text := ds.Fields[i].FieldName;
- if ds.Fields[i].DataType in [ftSmallint, ftInteger, ftWord, ftLargeint, ftFloat] then
+ Col.Text := Results.ColumnNames[i];
+ if Results.DataType(i).Category in [dtcInteger, dtcIntegerNamed, dtcReal] then
Col.Alignment := taRightJustify
else
Col.Alignment := taLeftJustify;
end;
- ds.First;
- while not ds.Eof do begin
+ Results.First;
+ while not Results.Eof do begin
Row := TWideStringlist.Create;
- for i:=0 to ds.FieldCount-1 do begin
- Row.Add(ds.Fields[i].AsString);
+ for i:=0 to Results.ColumnCount-1 do begin
+ Row.Add(Results.Col(i));
end;
FResults.Add(Row);
- ds.Next;
+ Results.Next;
end;
+ Results.Free;
Inc(FRealResultCounter);
lblResults.Caption := IntToStr(FRealResultCounter)+' results:';
diff --git a/source/usermanager.pas b/source/usermanager.pas
index ae27b489..a0f3d8e3 100644
--- a/source/usermanager.pas
+++ b/source/usermanager.pas
@@ -5,7 +5,7 @@ interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
- ComCtrls, StdCtrls, CheckLst, ExtCtrls, Buttons, DB,
+ ComCtrls, StdCtrls, CheckLst, ExtCtrls, Buttons, mysql_connection,
ToolWin, TntCheckLst, WideStrings, WideStrUtils, helpers;
{$I const.inc}
@@ -26,8 +26,8 @@ type
DBONames: TWideStringList;
PrivNames: TWideStringList;
SelectedPrivNames: TWideStringList;
- constructor Create(Fields: TFields; FieldDefs: TDataset = nil; AvoidFieldDefs: TDataSet = nil; CropFieldDefs: TDataSet = nil; SimulateDbField: Boolean = False);
- procedure Merge(Fields: TFields);
+ constructor Create(Fields: TMySQLQuery; FieldDefs: TMySQLQuery=nil; AvoidFieldDefs: TMySQLQuery=nil; CropFieldDefs: TMySQLQuery=nil; SimulateDbField: Boolean = False);
+ procedure Merge(Fields: TMySQLQuery);
property DBOType: TListNodeType read FDBOType;
property DBOKey: String read GetDBOKey;
property DBOPrettyKey: String read GetDBOPrettyKey;
@@ -47,11 +47,11 @@ type
function GetCount: Integer;
public
constructor Create(AOwner: TUser);
- function AddPrivilege(Fields: TFields; FieldDefs: TDataset = nil; AvoidFieldDefs: TDataSet = nil; CropFieldDefs: TDataSet = nil; SimulateDbField: Boolean = False): TPrivilege;
+ function AddPrivilege(Fields: TMySQLQuery; FieldDefs: TMySQLQuery=nil; AvoidFieldDefs: TMySQLQuery=nil; CropFieldDefs: TMySQLQuery=nil; SimulateDbField: Boolean = False): TPrivilege;
property Items[Index: Integer]: TPrivilege read GetPrivilege; default;
property Count: Integer read GetCount;
procedure DeletePrivilege(Index: Integer);
- function FindPrivilege(Fields: TFields; SimulateDbField: Boolean): TPrivilege;
+ function FindPrivilege(Fields: TMySQLQuery; SimulateDbField: Boolean): TPrivilege;
end;
TUser = class(TObject)
@@ -85,7 +85,7 @@ type
procedure SetHost(str: String);
procedure SetPassword(str: String);
public
- constructor Create(Fields: TFields = nil); overload;
+ constructor Create(Fields: TMySQLQuery=nil); overload;
constructor Create(Name: String; Host: String); overload;
property Name: String read GetName write SetName;
property Host: String read GetHost write SetHost;
@@ -202,7 +202,7 @@ type
{ Public declarations }
end;
-procedure GetPrivilegeRowKey(Fields: TFields; SimulateDbField: Boolean; out DBOType: TListNodeType; out DBONames: TWideStringList);
+procedure GetPrivilegeRowKey(Fields: TMySQLQuery; SimulateDbField: Boolean; out DBOType: TListNodeType; out DBONames: TWideStringList);
implementation
@@ -216,7 +216,7 @@ var
// Results from SELECT * FROM user/db/...
dsUser, dsDb, dsTables, dsColumns,
// Results from SHOW FIELDS FROM user/db/...
- dsTablesFields, dsColumnsFields : TDataset;
+ dsTablesFields, dsColumnsFields : TMySQLQuery;
{$R *.DFM}
@@ -266,14 +266,14 @@ begin
// Test if we can access the privileges database and tables by
// A. Using the mysql-DB
try
- Mainform.ExecUseQuery(DBNAME_MYSQL);
+ Mainform.Connection.Database := DBNAME_MYSQL;
except
MessageDlg('You have no access to the privileges database.', mtError, [mbOK], 0);
Result := false;
Exit;
end;
// B. retrieving a count of all users.
- test_result := Mainform.GetVar( 'SELECT COUNT(*) FROM '+db+'.'+Mainform.Mask(PRIVTABLE_USERS), 0, true, false );
+ test_result := Mainform.Connection.GetVar('SELECT COUNT(*) FROM '+db+'.'+Mainform.Mask(PRIVTABLE_USERS));
if test_result = '' then begin
MessageDlg('You have no access to the privileges tables.', mtError, [mbOK], 0);
Result := false;
@@ -291,26 +291,26 @@ var
snr: String;
begin
// Set hints text
- snr := Mainform.GetVar('SHOW VARIABLES LIKE ' + esc('skip_name_resolve'), 0, True, False);
+ snr := Mainform.Connection.GetVar('SHOW VARIABLES LIKE ' + esc('skip_name_resolve'));
if snr = '' then snr := 'Unknown';
lblHostHints.Caption := StringReplace(lblHostHints.Caption, '$SNR', snr, []);
// Load users into memory
Users := TUsers.Create;
// Enable limitations editors only if relevant columns exist
- lblMaxQuestions.Enabled := dsUser.FindField('max_questions') <> nil;
+ lblMaxQuestions.Enabled := dsUser.ColExists('max_questions');
editMaxQuestions.Enabled := lblMaxQuestions.Enabled;
udMaxQuestions.Enabled := lblMaxQuestions.Enabled;
- lblMaxUpdates.Enabled := dsUser.FindField('max_updates') <> nil;
+ lblMaxUpdates.Enabled := dsUser.ColExists('max_updates');
editMaxQuestions.Enabled := lblMaxUpdates.Enabled;
udMaxUpdates.Enabled := lblMaxUpdates.Enabled;
- lblMaxConnections.Enabled := dsUser.FindField('max_connections') <> nil;
+ lblMaxConnections.Enabled := dsUser.ColExists('max_connections');
editMaxConnections.Enabled := lblMaxConnections.Enabled;
udMaxConnections.Enabled := lblMaxConnections.Enabled;
- lblMaxUserConnections.Enabled := dsUser.FindField('max_user_connections') <> nil;
+ lblMaxUserConnections.Enabled := dsUser.ColExists('max_user_connections');
editMaxUserConnections.Enabled := lblMaxUserConnections.Enabled;
udMaxUserConnections.Enabled := lblMaxUserConnections.Enabled;
@@ -600,7 +600,7 @@ end;
procedure TUserManagerForm.btnAddObjectClick(Sender: TObject);
var
NewObj: TWideStringList;
- ds, FieldDefs: TDataset;
+ ds, FieldDefs: TMySQLQuery;
NewPriv: TPrivilege;
u: TUser;
i: Integer;
@@ -626,7 +626,7 @@ begin
else
Exception.Create('Added privilege object has an invalid number of segments ('+IntToStr(NewObj.Count)+')');
end;
- NewPriv := u.Privileges.AddPrivilege(ds.Fields, FieldDefs);
+ NewPriv := u.Privileges.AddPrivilege(ds, FieldDefs);
NewPriv.Added := True;
NewPriv.DBONames := NewObj;
u.Modified := True;
@@ -878,7 +878,7 @@ var
u: TUser;
p: TPrivilege;
sql, TableName, SetFieldName: String;
- TableSet: TDataSet;
+ TableSet: TMySQLQuery;
AcctWhere, AcctValues, PrivWhere: String;
AcctUpdates, PrivValues, PrivUpdates: TWideStringList;
procedure LogSQL(sql: String);
@@ -888,7 +888,7 @@ var
procedure Exec(sql: String);
begin
//LogSQL(sql); Exit;
- Mainform.ExecuteNonQuery(sql);
+ Mainform.Connection.Query(sql);
end;
function Mask(sql: String): String;
begin
@@ -981,16 +981,16 @@ begin
end else if u.PasswordModified then
AcctUpdates.Add(mask('Password') + '= PASSWORD(' + esc(u.Password) + ')');
// Apply limitation updates.
- if dsUser.FindField('max_questions') <> nil then
+ if dsUser.ColExists('max_questions') then
if u.FOldMaxQuestions <> u.MaxQuestions then
AcctUpdates.Add(mask('max_questions') + '=' + IntToStr(u.MaxQuestions));
- if dsUser.FindField('max_updates') <> nil then
+ if dsUser.ColExists('max_updates') then
if u.FOldMaxUpdates <> u.MaxUpdates then
AcctUpdates.Add(mask('max_updates') + '=' + IntToStr(u.MaxUpdates));
- if dsUser.FindField('max_connections') <> nil then
+ if dsUser.ColExists('max_connections') then
if u.FOldMaxConnections <> u.MaxConnections then
AcctUpdates.Add(mask('max_connections') + '=' + IntToStr(u.MaxConnections));
- if dsUser.FindField('max_user_connections') <> nil then
+ if dsUser.ColExists('max_user_connections') then
if u.FOldMaxUserConnections <> u.MaxUserConnections then
AcctUpdates.Add(mask('max_user_connections') + '=' + IntToStr(u.MaxUserConnections));
// Skip accounts with fx only username / host changes, they've already been processed.
@@ -1020,20 +1020,20 @@ begin
else
AcctUpdates.Add(mask('Password') + '=PASSWORD(' + esc(u.Password) + ')');
// Apply limits.
- if dsUser.FindField('max_questions') <> nil then
+ if dsUser.ColExists('max_questions') then
AcctUpdates.Add(mask('max_questions') + '=' + IntToStr(u.MaxQuestions));
- if dsUser.FindField('max_updates') <> nil then
+ if dsUser.ColExists('max_updates') then
AcctUpdates.Add(mask('max_updates') + '=' + IntToStr(u.MaxUpdates));
- if dsUser.FindField('max_connections') <> nil then
+ if dsUser.ColExists('max_connections') then
AcctUpdates.Add(mask('max_connections') + '=' + IntToStr(u.MaxConnections));
- if dsUser.FindField('max_user_connections') <> nil then
+ if dsUser.ColExists('max_user_connections') then
AcctUpdates.Add(mask('max_user_connections') + '=' + IntToStr(u.MaxUserConnections));
// Special case: work around missing default values (bug) in MySQL.
- if dsUser.FindField('ssl_cipher') <> nil then
+ if dsUser.ColExists('ssl_cipher') then
AcctUpdates.Add(mask('ssl_cipher') + '=' + esc(''));
- if dsUser.FindField('x509_issuer') <> nil then
+ if dsUser.ColExists('x509_issuer') then
AcctUpdates.Add(mask('x509_issuer') + '=' + esc(''));
- if dsUser.FindField('x509_subject') <> nil then
+ if dsUser.ColExists('x509_subject') then
AcctUpdates.Add(mask('x509_subject') + '=' + esc(''));
sql := 'INSERT INTO ' + db + '.' + mask(PRIVTABLE_USERS);
sql := sql + ' SET ' + Delim(AcctUpdates);
@@ -1095,7 +1095,7 @@ begin
if (p.DBOType = lntDb) and (p.DBOKey = '%') then begin
PrivUpdates.Clear;
for k := 0 to p.PrivNames.Count - 1 do begin
- if dsUser.FindField(p.PrivNames[k] + '_priv') <> nil then
+ if dsUser.ColExists(p.PrivNames[k] + '_priv') then
PrivUpdates.Add(mask(p.PrivNames[k] + '_priv') + '=' + esc('N'));
end;
sql := 'UPDATE ' + db + '.' + mask(PRIVTABLE_USERS);
@@ -1113,7 +1113,7 @@ begin
// instead, we have to set them manually to 'N'.
PrivUpdates.Clear;
for k := 0 to p.PrivNames.Count - 1 do
- if TableSet.FindField(p.PrivNames[k] + '_priv') <> nil then
+ if TableSet.ColExists(p.PrivNames[k] + '_priv') then
PrivUpdates.Add(mask(p.PrivNames[k] + '_priv') + '=' + esc('N'));
sql := 'UPDATE ' + db + '.' + TableName;
sql := sql + ' SET ' + Delim(PrivUpdates);
@@ -1137,7 +1137,7 @@ begin
// Assemble values of new privilege definition.
for k := 0 to p.PrivNames.Count - 1 do begin
if p.SelectedPrivNames.IndexOf(p.PrivNames[k]) > -1 then c := 'Y' else c := 'N';
- if TableSet.FindField(p.PrivNames[k] + '_priv') <> nil then begin
+ if TableSet.ColExists(p.PrivNames[k] + '_priv') then begin
// There's an ENUM field matching the privilege name.
PrivUpdates.Add(mask(p.PrivNames[k] + '_priv') + '=' + esc(c));
end else
@@ -1153,11 +1153,11 @@ begin
if (p.DBOType = lntNone) then begin
// Server barfs if we do not set missing defaults, sigh.
PrivValues.Clear;
- if dsUser.FindField('ssl_cipher') <> nil then
+ if dsUser.ColExists('ssl_cipher') then
PrivValues.Add(mask('ssl_cipher') + '=' + esc(''));
- if dsUser.FindField('x509_issuer') <> nil then
+ if dsUser.ColExists('x509_issuer') then
PrivValues.Add(mask('x509_issuer') + '=' + esc(''));
- if dsUser.FindField('x509_subject') <> nil then
+ if dsUser.ColExists('x509_subject') then
PrivValues.Add(mask('x509_subject') + '=' + esc(''));
if PrivValues.Count > 0 then
sql := sql + ', ' + Delim(PrivValues);
@@ -1166,7 +1166,7 @@ begin
end;
Exec(sql);
// Special case: update redundant column privileges in mysql.tables_priv.
- if (p.DBOType = lntColumn) and (dsTables.FindField('column_priv') <> nil) then begin
+ if (p.DBOType = lntColumn) and dsTables.ColExists('column_priv') then begin
// We need to deduce a completely new key because column_priv in mysql.tables_priv does not have a column field next to it, sigh.
PrivUpdates.Clear;
PrivUpdates.Add(mask('Host') + '=' + esc(u.Host));
@@ -1200,55 +1200,55 @@ var
i: Integer;
user, host: WideString;
begin
- dsUser := Mainform.GetResults('SELECT * FROM '+db+'.'+Mainform.Mask(PRIVTABLE_USERS) + ' ORDER BY '
+ dsUser := Mainform.Connection.GetResults('SELECT * FROM '+db+'.'+Mainform.Mask(PRIVTABLE_USERS) + ' ORDER BY '
+ Mainform.Mask('User')+', '
+ Mainform.Mask('Host'));
- dsDb := Mainform.GetResults('SELECT * FROM '+db+'.'+Mainform.Mask(PRIVTABLE_DB)
+ dsDb := Mainform.Connection.GetResults('SELECT * FROM '+db+'.'+Mainform.Mask(PRIVTABLE_DB)
// Ignore db entries that contain magic pointers to the mysql.host table.
+ ' WHERE Db <> '#39#39
+ ' ORDER BY '
+ Mainform.Mask('User')+', '
+ Mainform.Mask('Host')+', '
+ Mainform.Mask('Db'));
- dsTables := Mainform.GetResults('SELECT * FROM '+db+'.'+Mainform.Mask(PRIVTABLE_TABLES) + ' ORDER BY '
+ dsTables := Mainform.Connection.GetResults('SELECT * FROM '+db+'.'+Mainform.Mask(PRIVTABLE_TABLES) + ' ORDER BY '
+ Mainform.Mask('User')+', '
+ Mainform.Mask('Host')+', '
+ Mainform.Mask('Db')+', '
+ Mainform.Mask('Table_name'));
- dsColumns := Mainform.GetResults('SELECT * FROM '+db+'.'+Mainform.Mask(PRIVTABLE_COLUMNS) + ' ORDER BY '
+ dsColumns := Mainform.Connection.GetResults('SELECT * FROM '+db+'.'+Mainform.Mask(PRIVTABLE_COLUMNS) + ' ORDER BY '
+ Mainform.Mask('User')+', '
+ Mainform.Mask('Host')+', '
+ Mainform.Mask('Db')+', '
+ Mainform.Mask('Table_name')+', '
+ Mainform.Mask('Column_name'));
- dsTablesFields := Mainform.GetResults('SHOW FIELDS FROM '+db+'.tables_priv LIKE ''%\_priv''');
- dsColumnsFields := Mainform.GetResults('SHOW FIELDS FROM '+db+'.columns_priv LIKE ''%\_priv''');
- for i := 1 to dsUser.RecordCount do begin
+ dsTablesFields := Mainform.Connection.GetResults('SHOW FIELDS FROM '+db+'.tables_priv LIKE ''%\_priv''');
+ dsColumnsFields := Mainform.Connection.GetResults('SHOW FIELDS FROM '+db+'.columns_priv LIKE ''%\_priv''');
+ for i:=0 to dsUser.RecordCount-1 do begin
// Avoid using dsUser.Next and dsUser.Eof here because TUser.Create
// also iterates through the global dsUser result and moves the cursor
dsUser.RecNo := i;
- u := TUser.Create(dsUser.Fields);
+ u := TUser.Create(dsUser);
AddUser(u);
end;
// Find orphaned privileges in mysql.db.
- for i := 1 to dsDb.RecordCount do begin
+ for i:=0 to dsDb.RecordCount-1 do begin
dsDb.RecNo := i;
- user := dsDb.Fields.FieldByName('User').AsWideString;
- host := dsDb.Fields.FieldByName('Host').AsWideString;
+ user := dsDb.Col('User');
+ host := dsDb.Col('Host');
if FindUser(user, host) = nil then AddUser(TUser.Create(user, host));
end;
// Find orphaned privileges in mysql.tables_priv.
- for i := 1 to dsTables.RecordCount do begin
+ for i:=0 to dsTables.RecordCount-1 do begin
dsTables.RecNo := i;
- user := dsTables.Fields.FieldByName('User').AsWideString;
- host := dsTables.Fields.FieldByName('Host').AsWideString;
+ user := dsTables.Col('User');
+ host := dsTables.Col('Host');
if FindUser(user, host) = nil then AddUser(TUser.Create(user, host));
end;
// Find orphaned privileges in mysql.columns_priv.
- for i := 1 to dsColumns.RecordCount do begin
+ for i:=0 to dsColumns.RecordCount-1 do begin
dsColumns.RecNo := i;
- user := dsColumns.Fields.FieldByName('User').AsWideString;
- host := dsColumns.Fields.FieldByName('Host').AsWideString;
+ user := dsColumns.Col('User');
+ host := dsColumns.Col('Host');
if FindUser(user, host) = nil then AddUser(TUser.Create(user, host));
end;
end;
@@ -1322,7 +1322,7 @@ begin
FPrivileges := TPrivileges.Create(Self);
end;
-constructor TUser.Create(Fields: TFields);
+constructor TUser.Create(Fields: TMySQLQuery);
begin
// Loading an existing user
FAdded := False;
@@ -1331,8 +1331,8 @@ begin
FPasswordModified := False;
FDisabled := False;
FNameChanged := False;
- FOldName := Fields.FieldByName('User').AsWideString;
- FOldHost := Fields.FieldByName('Host').AsWideString;
+ FOldName := Fields.Col('User', True);
+ FOldHost := Fields.Col('Host', True);
if FOldHost = '' then begin
// Get rid of duplicate entries.
// Todo: handle collisions.
@@ -1340,22 +1340,22 @@ begin
FOtherModified := True;
end;
FPassword := '';
- FOldPasswordHashed := Fields.FieldByName('Password').AsString;
+ FOldPasswordHashed := Fields.Col('Password', True);
FOldMaxQuestions := 0;
- if Fields.FindField('max_questions') <> nil then
- FOldMaxQuestions := MakeInt(Fields.FieldByName('max_questions').AsString);
+ if Fields.ColExists('max_questions') then
+ FOldMaxQuestions := MakeInt(Fields.Col('max_questions'));
FMaxQuestions := FOldMaxQuestions;
FOldMaxUpdates := 0;
- if Fields.FindField('max_updates') <> nil then
- FOldMaxUpdates := MakeInt(Fields.FieldByName('max_updates').AsString);
+ if Fields.ColExists('max_updates') then
+ FOldMaxUpdates := MakeInt(Fields.Col('max_updates'));
FMaxUpdates := FOldMaxUpdates;
FOldMaxConnections := 0;
- if Fields.FindField('max_connections') <> nil then
- FOldMaxConnections := MakeInt(Fields.FieldByName('max_connections').AsString);
+ if Fields.ColExists('max_connections') then
+ FOldMaxConnections := MakeInt(Fields.Col('max_connections'));
FMaxConnections := FOldMaxConnections;
FOldMaxUserConnections := 0;
- if Fields.FindField('max_user_connections') <> nil then
- FOldMaxUserConnections := MakeInt(Fields.FieldByName('max_user_connections').AsString);
+ if Fields.ColExists('max_user_connections') then
+ FOldMaxUserConnections := MakeInt(Fields.Col('max_user_connections'));
FMaxUserConnections := FOldMaxUserConnections;
FPrivileges := TPrivileges.Create(Self);
@@ -1413,30 +1413,30 @@ var
p: TPrivilege;
host, user: String;
// Extract privilege objects from results of user, db, tables_priv + columns_priv
- procedure LoadPrivs(ds: TDataset; FieldDefs: TDataset = nil; AvoidFieldDefs: TDataset = nil; CropDbFieldDefs: TDataset = nil);
+ procedure LoadPrivs(ds: TMySQLQuery; FieldDefs: TMySQLQuery=nil; AvoidFieldDefs: TMySQLQuery=nil; CropDbFieldDefs: TMySQLQuery=nil);
var
hasUserField : Boolean;
simulateDb : Boolean;
begin
ds.First;
// The priv table 'host' does not have a user field, use '%'.
- hasUserField := ds.FieldDefs.IndexOf('User') > -1;
+ hasUserField := ds.ColExists('User');
user := '%';
// When cropping the priv table 'user' to load only db privileges, use '%' for db.
simulateDb := cropDbFieldDefs <> nil;
while not ds.Eof do begin
- if hasUserField then user := ds.FieldByName('User').AsWideString;
- host := ds.FieldByName('Host').AsWideString;
+ if hasUserField then user := ds.Col('User');
+ host := ds.Col('Host');
// Canonicalize: Host='' and Host='%' means the same.
if host = '' then host := '%';
if (host = FOwner.FOldHost) and (user = FOwner.FOldName) then begin
// Find existing privilege, or create + add new one.
- p := FindPrivilege(ds.Fields, simulateDb);
+ p := FindPrivilege(ds, simulateDb);
if (p = nil) then begin
- p := AddPrivilege(ds.Fields, FieldDefs, AvoidFieldDefs, CropDbFieldDefs, simulateDb);
+ p := AddPrivilege(ds, FieldDefs, AvoidFieldDefs, CropDbFieldDefs, simulateDb);
end;
// Merge grants from row into the privilege object.
- p.Merge(ds.Fields)
+ p.Merge(ds)
end;
ds.Next;
end;
@@ -1445,8 +1445,8 @@ begin
FOwner := AOwner;
if AOwner.Added then begin
// Create blanket "server privileges" and "all objects" items.
- AddPrivilege(dsUser.Fields, nil, dsDb);
- AddPrivilege(dsUser.Fields, nil, nil, dsDb, True);
+ AddPrivilege(dsUser, nil, dsDb);
+ AddPrivilege(dsUser, nil, nil, dsDb, True);
end;
// Load server privileges from 'user' rows, avoiding db privileges.
LoadPrivs(dsUser, nil, dsDb);
@@ -1468,7 +1468,7 @@ begin
Result := Length(FPrivilegeItems);
end;
-function TPrivileges.FindPrivilege(Fields: TFields; SimulateDbField: Boolean): TPrivilege;
+function TPrivileges.FindPrivilege(Fields: TMySQLQuery; SimulateDbField: Boolean): TPrivilege;
var
i : Integer;
DBOType: TListNodeType;
@@ -1487,7 +1487,7 @@ begin
end;
end;
-function TPrivileges.AddPrivilege(Fields: TFields; FieldDefs: TDataset = nil; AvoidFieldDefs: TDataSet = nil; CropFieldDefs: TDataSet = nil; SimulateDbField: Boolean = False): TPrivilege;
+function TPrivileges.AddPrivilege(Fields: TMySQLQuery; FieldDefs: TMySQLQuery=nil; AvoidFieldDefs: TMySQLQuery=nil; CropFieldDefs: TMySQLQuery=nil; SimulateDbField: Boolean = False): TPrivilege;
begin
Result := TPrivilege.Create(Fields, FieldDefs, AvoidFieldDefs, CropFieldDefs, SimulateDbField);
SetLength(FPrivilegeItems, Length(FPrivilegeItems)+1);
@@ -1518,20 +1518,19 @@ end;
{ *** TPrivilege *** }
-constructor TPrivilege.Create(Fields: TFields; FieldDefs: TDataset = nil; AvoidFieldDefs: TDataSet = nil; CropFieldDefs: TDataSet = nil; SimulateDbField: Boolean = False);
+constructor TPrivilege.Create(Fields: TMySQLQuery; FieldDefs: TMySQLQuery=nil; AvoidFieldDefs: TMySQLQuery=nil; CropFieldDefs: TMySQLQuery=nil; SimulateDbField: Boolean = False);
var
i: Integer;
tables_col_ignore: Boolean;
- cropNames: TWideStringList;
// Find possible values for the given SET column
function GetSETValues(FieldName: String): TWideStringList;
begin
FieldDefs.First;
Result := TWideStringList.Create;
while not FieldDefs.Eof do begin
- if FieldDefs.FieldByName('Field').AsWideString = FieldName + '_priv' then begin
+ if FieldDefs.Col('Field') = FieldName + '_priv' then begin
Result.QuoteChar := '''';
- Result.DelimitedText := getEnumValues( FieldDefs.FieldByName('Type').AsWideString );
+ Result.DelimitedText := getEnumValues(FieldDefs.Col('Type'));
end;
FieldDefs.Next;
end;
@@ -1545,22 +1544,20 @@ begin
PrivNames := TWideStringList.Create;
SelectedPrivNames := TWideStringList.Create;
// Find out what xxxx_priv privilege columns this server/version has.
- Fields.GetFieldNames(PrivNames);
+ PrivNames.Text := Fields.ColumnNames.Text;
for i := PrivNames.Count - 1 downto 0 do begin
if Length(PrivNames[i]) > 5 then begin
if Copy(PrivNames[i], Length(PrivNames[i]) - 4, 5) = '_priv' then begin
// Avoid duplicated db privileges in user table.
if AvoidFieldDefs = nil then Continue;
- if AvoidFieldDefs.FieldDefs.IndexOf(PrivNames[i]) = -1 then Continue;
+ if AvoidFieldDefs.ColumnNames.IndexOf(PrivNames[i]) = -1 then Continue;
end;
end;
- PrivNames.Delete(i)
+ PrivNames.Delete(i);
end;
if CropFieldDefs <> nil then begin
- cropNames := TWideStringList.Create;
- CropFieldDefs.Fields.GetFieldNames(cropNames);
for i := PrivNames.Count - 1 downto 0 do begin
- if cropNames.IndexOf(PrivNames[i]) = -1 then PrivNames.Delete(i);
+ if CropFieldDefs.ColumnNames.IndexOf(PrivNames[i]) = -1 then PrivNames.Delete(i);
end;
end;
// Find out what SET columns in tables_priv this server/version has.
@@ -1590,34 +1587,29 @@ begin
GetPrivilegeRowKey(Fields, SimulateDbField, FDBOType, DBONames);
end;
-procedure TPrivilege.Merge(Fields: TFields);
+procedure TPrivilege.Merge(Fields: TMySQLQuery);
var
i: Integer;
tmp: TStringList;
- fieldNames: TStringList;
begin
- fieldNames := TStringList.Create;
- Fields.GetFieldNames(fieldNames);
// Apply ENUM privileges, skipping any SET privileges.
for i := PrivNames.Count - 1 downto 0 do begin
- if fieldNames.IndexOf(PrivNames[i] + '_priv') > -1 then begin
- if UpperCase(Fields.FieldByName(PrivNames[i] + '_priv').AsString) = 'Y' then begin
+ if Fields.ColumnNames.IndexOf(PrivNames[i] + '_priv') > -1 then begin
+ if UpperCase(Fields.Col(PrivNames[i] + '_priv')) = 'Y' then begin
SelectedPrivNames.Add(PrivNames[i]);
end;
end;
end;
// Parse SET field in column "tables_priv"
- i := fieldNames.IndexOf('Table_priv');
- if i > -1 then begin
+ if Fields.ColExists('Table_priv') then begin
tmp := TStringList.Create;
- tmp.CommaText := Fields.FieldByName('Table_priv').AsString;
+ tmp.CommaText := Fields.Col('Table_priv');
SelectedPrivNames.AddStrings(tmp);
end else begin
// Parse SET field in column "columns_priv"
- i := fieldNames.IndexOf('Column_priv');
- if i > -1 then begin
+ if Fields.ColExists('Column_priv') then begin
tmp := TStringList.Create;
- tmp.CommaText := Fields.FieldByName('Column_priv').AsString;
+ tmp.CommaText := Fields.Col('Column_priv');
SelectedPrivNames.AddStrings(tmp);
end;
end;
@@ -1663,7 +1655,7 @@ begin
end;
-procedure GetPrivilegeRowKey(Fields: TFields; SimulateDbField: Boolean; out DBOType: TListNodeType; out DBONames: TWideStringList);
+procedure GetPrivilegeRowKey(Fields: TMySQLQuery; SimulateDbField: Boolean; out DBOType: TListNodeType; out DBONames: TWideStringList);
begin
DBOType := lntNone;
DBONames := TWideStringList.Create;
@@ -1672,17 +1664,17 @@ begin
DBOType := lntDb;
DBONames.Add('%');
end;
- if Fields.FindField('Db') <> nil then begin
+ if Fields.ColExists('Db') then begin
DBOType := lntDb;
- DBONames.Add(Fields.FieldByName('Db').AsString);
+ DBONames.Add(Fields.Col('Db'));
end;
- if Fields.FindField('Table_name') <> nil then begin
+ if Fields.ColExists('Table_name') then begin
DBOType := lntTable;
- DBONames.Add(Fields.FieldByName('Table_name').AsString);
+ DBONames.Add(Fields.Col('Table_name'));
end;
- if Fields.FindField('Column_name') <> nil then begin
+ if Fields.ColExists('Column_name') then begin
DBOType := lntColumn;
- DBONames.Add(Fields.FieldByName('Column_name').AsString);
+ DBONames.Add(Fields.Col('Column_name'));
end;
end;
diff --git a/source/view.pas b/source/view.pas
index 6ac194f8..7cddbe72 100644
--- a/source/view.pas
+++ b/source/view.pas
@@ -4,7 +4,7 @@ interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, StdCtrls, ComCtrls, SynEdit, SynMemo, ExtCtrls, DB, SynRegExpr;
+ Dialogs, StdCtrls, ComCtrls, SynEdit, SynMemo, ExtCtrls, mysql_connection, SynRegExpr;
type
TfrmView = class(TFrame)
@@ -55,8 +55,8 @@ end;
}
procedure TfrmView.Init(EditViewName: WideString='');
var
- ds: TDataset;
- db: String;
+ Results: TMySQLQuery;
+ db: WideString;
rx: TRegExpr;
begin
FEditViewName := EditViewName;
@@ -65,21 +65,21 @@ begin
editName.Text := FEditViewName;
Mainform.SetEditorTabCaption(Self, FEditViewName);
db := Mainform.ActiveDatabase;
- ds := Mainform.GetResults('SELECT * FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.VIEWS ' +
+ Results := Mainform.Connection.GetResults('SELECT * FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.VIEWS ' +
'WHERE TABLE_SCHEMA = '+esc(db)+' AND TABLE_NAME = '+esc(FEditViewName));
- if ds.RecordCount = 0 then
+ if Results.RecordCount = 0 then
raise Exception.Create('Can''t find view definition for "'+FEditViewName+'" in '+DBNAME_INFORMATION_SCHEMA);
// Algorithm is not changeable as we cannot look up its current state!
rgAlgorithm.Enabled := False;
rgAlgorithm.ItemIndex := 0;
- rgCheck.ItemIndex := rgCheck.Items.IndexOf(ds.FieldByName('CHECK_OPTION').AsString);
- rgCheck.Enabled := ds.FieldByName('IS_UPDATABLE').AsString = 'YES';
+ rgCheck.ItemIndex := rgCheck.Items.IndexOf(Results.Col('CHECK_OPTION'));
+ rgCheck.Enabled := Results.Col('IS_UPDATABLE') = 'YES';
rx := TRegExpr.Create;
rx.ModifierG := True;
rx.ModifierI := True;
rx.Expression := '\s+WITH\s+\w+\s+CHECK\s+OPTION$';
- SynMemoSelect.Text := rx.Replace(ds.FieldByName('VIEW_DEFINITION').AsString, '');
+ SynMemoSelect.Text := rx.Replace(Results.Col('VIEW_DEFINITION'), '');
rx.Free;
end else begin
// Create mode
@@ -160,11 +160,11 @@ begin
sql := sql + 'WITH '+Uppercase(rgCheck.Items[rgCheck.ItemIndex])+' CHECK OPTION';
// Execute query and keep form open in any error case
- Mainform.ExecUpdateQuery(sql);
+ Mainform.Connection.Query(sql);
// Probably rename view
if (FEditViewName <> '') and (FEditViewName <> editName.Text) then begin
renamed := Mainform.mask(editName.Text);
- Mainform.ExecUpdateQuery('RENAME TABLE '+viewname + ' TO '+renamed);
+ Mainform.Connection.Query('RENAME TABLE '+viewname + ' TO '+renamed);
end;
Mainform.RefreshTreeDB(Mainform.ActiveDatabase);
end;