Implement fetching multiple results from one query, e.g. from a procedure call. Fixes remaining stuff in issue #1135.

This commit is contained in:
Ansgar Becker
2010-08-28 15:17:10 +00:00
parent 68eea80072
commit b87745d0d3
2 changed files with 49 additions and 23 deletions

View File

@ -2175,24 +2175,19 @@ begin
ShowStatusMsg('Executing query #'+FormatNumber(i+1)+' of '+FormatNumber(SQLBatch.Count)+' ...'); ShowStatusMsg('Executing query #'+FormatNumber(i+1)+' of '+FormatNumber(SQLBatch.Count)+' ...');
ProgressBarStatus.StepIt; ProgressBarStatus.StepIt;
ProgressBarStatus.Repaint; ProgressBarStatus.Repaint;
Results := TMySQLQuery.Create(Self);
Results.Connection := Connection;
Results.LogCategory := lcUserFiredSQL;
Results.SQL := SQLBatch[i].SQL;
Results.StoreResult := QueryTab.ResultTabs.Count < prefMaxQueryResults;
try try
Results.Execute; Connection.Query(SQLBatch[i].SQL, QueryTab.ResultTabs.Count < prefMaxQueryResults, lcUserFiredSQL);
Inc(QueryCount); Inc(QueryCount);
Inc(SQLtime, Connection.LastQueryDuration); Inc(SQLtime, Connection.LastQueryDuration);
Inc(SQLNetTime, Connection.LastQueryNetworkDuration); Inc(SQLNetTime, Connection.LastQueryNetworkDuration);
Inc(RowsAffected, Connection.RowsAffected); Inc(RowsAffected, Connection.RowsAffected);
Inc(RowsFound, Connection.RowsFound); Inc(RowsFound, Connection.RowsFound);
if Results.StoreResult and Results.HasResult then begin if (Connection.ResultCount > 0) then for Results in Connection.GetLastResults do begin
NewTab := TResultTab.Create; NewTab := TResultTab.Create;
QueryTab.ResultTabs.Add(NewTab); QueryTab.ResultTabs.Add(NewTab);
NewTab.Results := Results; NewTab.Results := Results;
try try
TabCaption := Results.TableName; TabCaption := NewTab.Results.TableName;
except on E:EDatabaseError do except on E:EDatabaseError do
TabCaption := 'Result #'+IntToStr(QueryTab.ResultTabs.Count); TabCaption := 'Result #'+IntToStr(QueryTab.ResultTabs.Count);
end; end;
@ -2220,8 +2215,7 @@ begin
NewTab.Grid.EndUpdate; NewTab.Grid.EndUpdate;
for j:=0 to NewTab.Grid.Header.Columns.Count-1 do for j:=0 to NewTab.Grid.Header.Columns.Count-1 do
AutoCalcColWidth(NewTab.Grid, j); AutoCalcColWidth(NewTab.Grid, j);
end else end;
FreeAndNil(Results);
except except
on E:EDatabaseError do begin on E:EDatabaseError do begin
if actQueryStopOnErrors.Checked or (i = SQLBatch.Count - 1) then begin if actQueryStopOnErrors.Checked or (i = SQLBatch.Count - 1) then begin

View File

@ -185,6 +185,7 @@ type
TMySQLDatabaseEvent = procedure(Database: String) of object; TMySQLDatabaseEvent = procedure(Database: String) of object;
TMySQLQuery = class; TMySQLQuery = class;
TMySQLQueryList = TObjectList<TMySQLQuery>;
TMySQLConnection = class(TComponent) TMySQLConnection = class(TComponent)
private private
FHandle: PMYSQL; FHandle: PMYSQL;
@ -204,6 +205,7 @@ type
FServerVersionUntouched: String; FServerVersionUntouched: String;
FRealHostname: String; FRealHostname: String;
FLastQueryDuration, FLastQueryNetworkDuration: Cardinal; FLastQueryDuration, FLastQueryNetworkDuration: Cardinal;
FLastQuerySQL: String;
FIsUnicode: Boolean; FIsUnicode: Boolean;
FTableEngines: TStringList; FTableEngines: TStringList;
FTableEngineDefault: String; FTableEngineDefault: String;
@ -213,6 +215,8 @@ type
FDatabases: TDatabaseList; FDatabases: TDatabaseList;
FObjectNamesInSelectedDB: TStrings; FObjectNamesInSelectedDB: TStrings;
FPlinkProcInfo: TProcessInformation; FPlinkProcInfo: TProcessInformation;
FLastResults: Array of PMYSQL_RES;
FResultCount: Integer;
procedure SetActive(Value: Boolean); procedure SetActive(Value: Boolean);
procedure ClosePlink; procedure ClosePlink;
procedure SetDatabase(Value: String); procedure SetDatabase(Value: String);
@ -255,6 +259,7 @@ type
function ParseDateTime(Str: String): TDateTime; function ParseDateTime(Str: String): TDateTime;
function GetKeyColumns(Columns: TTableColumnList; Keys: TTableKeyList): TStringList; function GetKeyColumns(Columns: TTableColumnList; Keys: TTableKeyList): TStringList;
function ConnectionInfo: TStringList; function ConnectionInfo: TStringList;
function GetLastResults: TMySQLQueryList;
procedure ClearDbObjects(db: String); procedure ClearDbObjects(db: String);
procedure ClearAllDbObjects; procedure ClearAllDbObjects;
property Parameters: TConnectionParameters read FParameters write FParameters; property Parameters: TConnectionParameters read FParameters write FParameters;
@ -281,6 +286,7 @@ type
property CharsetList: TStringList read GetCharsetList; property CharsetList: TStringList read GetCharsetList;
property InformationSchemaObjects: TStringList read GetInformationSchemaObjects; property InformationSchemaObjects: TStringList read GetInformationSchemaObjects;
property ObjectNamesInSelectedDB: TStrings read FObjectNamesInSelectedDB write FObjectNamesInSelectedDB; property ObjectNamesInSelectedDB: TStrings read FObjectNamesInSelectedDB write FObjectNamesInSelectedDB;
property ResultCount: Integer read FResultCount;
published published
property Active: Boolean read FActive write SetActive default False; property Active: Boolean read FActive write SetActive default False;
property Database: String read FDatabase write SetDatabase; property Database: String read FDatabase write SetDatabase;
@ -310,7 +316,6 @@ type
FCurrentRow: PMYSQL_ROW; FCurrentRow: PMYSQL_ROW;
FCurrentUpdateRow: TRowData; FCurrentUpdateRow: TRowData;
FEof: Boolean; FEof: Boolean;
FLogCategory: TMySQLLogCategory;
FStoreResult: Boolean; FStoreResult: Boolean;
FColumns: TTableColumnList; FColumns: TTableColumnList;
FKeys: TTableKeyList; FKeys: TTableKeyList;
@ -327,7 +332,7 @@ type
public public
constructor Create(AOwner: TComponent); override; constructor Create(AOwner: TComponent); override;
destructor Destroy; override; destructor Destroy; override;
procedure Execute(AddResult: Boolean=False); procedure Execute(AddResult: Boolean=False; Res: PMYSQL_RES=nil);
procedure First; procedure First;
procedure Next; procedure Next;
function ColumnCount: Integer; function ColumnCount: Integer;
@ -363,7 +368,6 @@ type
property Eof: Boolean read FEof; property Eof: Boolean read FEof;
property RecordCount: Int64 read FRecordCount; property RecordCount: Int64 read FRecordCount;
property ColumnNames: TStringList read FColumnNames; property ColumnNames: TStringList read FColumnNames;
property LogCategory: TMySQLLogCategory read FLogCategory write FLogCategory;
property StoreResult: Boolean read FStoreResult write FStoreResult; property StoreResult: Boolean read FStoreResult write FStoreResult;
property ColumnOrgNames: TStringList read FColumnOrgNames write SetColumnOrgNames; property ColumnOrgNames: TStringList read FColumnOrgNames write SetColumnOrgNames;
published published
@ -631,7 +635,7 @@ end;
} }
function TMySQLConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TMySQLLogCategory=lcSQL): PMYSQL_RES; function TMySQLConnection.Query(SQL: String; DoStoreResult: Boolean=False; LogCategory: TMySQLLogCategory=lcSQL): PMYSQL_RES;
var var
querystatus, i: Integer; querystatus: Integer;
NativeSQL: AnsiString; NativeSQL: AnsiString;
TimerStart: Cardinal; TimerStart: Cardinal;
NextResult: PMYSQL_RES; NextResult: PMYSQL_RES;
@ -639,11 +643,14 @@ begin
if not Ping then if not Ping then
Active := True; Active := True;
Log(LogCategory, SQL); Log(LogCategory, SQL);
FLastQuerySQL := SQL;
if IsUnicode then if IsUnicode then
NativeSQL := UTF8Encode(SQL) NativeSQL := UTF8Encode(SQL)
else else
NativeSQL := AnsiString(SQL); NativeSQL := AnsiString(SQL);
TimerStart := GetTickCount; TimerStart := GetTickCount;
SetLength(FLastResults, 0);
FResultCount := 0;
querystatus := mysql_real_query(FHandle, PAnsiChar(NativeSQL), Length(NativeSQL)); querystatus := mysql_real_query(FHandle, PAnsiChar(NativeSQL), Length(NativeSQL));
FLastQueryDuration := GetTickCount - TimerStart; FLastQueryDuration := GetTickCount - TimerStart;
FLastQueryNetworkDuration := 0; FLastQueryNetworkDuration := 0;
@ -668,20 +675,27 @@ begin
FRowsFound := mysql_num_rows(Result); FRowsFound := mysql_num_rows(Result);
FRowsAffected := 0; FRowsAffected := 0;
Log(lcDebug, IntToStr(RowsFound)+' rows found.'); Log(lcDebug, IntToStr(RowsFound)+' rows found.');
if not DoStoreResult then begin
if DoStoreResult then begin
SetLength(FLastResults, 1);
FLastResults[0] := Result;
end else begin
mysql_free_result(Result); mysql_free_result(Result);
Result := nil; Result := nil;
end; end;
// No support for real multi results yet, throw them away, so mysql_ping() does not crash on the *next* query. // No support for real multi results yet, throw them away, so mysql_ping() does not crash on the *next* query.
i := 1;
while mysql_next_result(FHandle) = 0 do begin while mysql_next_result(FHandle) = 0 do begin
Inc(i);
Log(lcDebug, 'Storing and freeing result #'+IntToStr(i)+' from multiple result set ...');
NextResult := mysql_store_result(FHandle); NextResult := mysql_store_result(FHandle);
if NextResult <> nil then if NextResult <> nil then begin
if DoStoreResult then begin
SetLength(FLastResults, Length(FLastResults)+1);
FLastResults[Length(FLastResults)-1] := NextResult;
end else
mysql_free_result(NextResult); mysql_free_result(NextResult);
end; end;
end;
FResultCount := Length(FLastResults);
end else begin end else begin
// Query did not return a result // Query did not return a result
@ -699,6 +713,22 @@ begin
end; end;
function TMySQLConnection.GetLastResults: TMySQLQueryList;
var
r: TMySQLQuery;
i: Integer;
begin
Result := TMySQLQueryList.Create(False);
for i:=Low(FLastResults) to High(FLastResults) do begin
r := TMySQLQuery.Create(nil);
r.Connection := Self;
r.SQL := FLastQuerySQL;
r.Execute(True, FLastResults[i]);
Result.Add(r);
end;
end;
{** {**
Set "Database" property and select that db if connected Set "Database" property and select that db if connected
} }
@ -1604,7 +1634,6 @@ begin
FColumnOrgNames := TStringList.Create; FColumnOrgNames := TStringList.Create;
FColumnOrgNames.CaseSensitive := True; FColumnOrgNames.CaseSensitive := True;
FStoreResult := True; FStoreResult := True;
FLogCategory := lcSQL;
end; end;
@ -1635,7 +1664,7 @@ begin
end; end;
procedure TMySQLQuery.Execute(AddResult: Boolean=False); procedure TMySQLQuery.Execute(AddResult: Boolean=False; Res: PMYSQL_RES=nil);
var var
i, j, NumFields: Integer; i, j, NumFields: Integer;
NumResults: Int64; NumResults: Int64;
@ -1643,7 +1672,10 @@ var
IsBinary: Boolean; IsBinary: Boolean;
FLastResult: PMYSQL_RES; FLastResult: PMYSQL_RES;
begin begin
FLastResult := Connection.Query(FSQL, FStoreResult, FLogCategory); if Res <> nil then
FLastResult := Res
else
FLastResult := Connection.Query(FSQL, FStoreResult);
if AddResult and (Length(FResultList) = 0) then if AddResult and (Length(FResultList) = 0) then
AddResult := False; AddResult := False;
if AddResult then if AddResult then