mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
* Bugfix: after an edit, a new row which did not match the filter was included in the grid.
* Bugfix: the entire width of all fields of edited columns were loaded, instead of a limited view. * Bugfix: (follow-up to above) one too many rows were included in RootNodeCount after less rows were matched than expected from the data source. * Bugfix: some memory was not released as early as it could've been when less rows were matched than expected from the data source. Hopefully fixes issue #730.
This commit is contained in:
@ -297,8 +297,9 @@ type
|
|||||||
procedure ShowTableProperties;
|
procedure ShowTableProperties;
|
||||||
procedure ShowTableData(table: WideString);
|
procedure ShowTableData(table: WideString);
|
||||||
procedure EnsureFullWidth(Grid: TBaseVirtualTree; Column: TColumnIndex; Node: PVirtualNode);
|
procedure EnsureFullWidth(Grid: TBaseVirtualTree; Column: TColumnIndex; Node: PVirtualNode);
|
||||||
procedure EnsureDataLoaded(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
procedure EnsureNodeLoaded(Sender: TBaseVirtualTree; Node: PVirtualNode; WhereClause: String);
|
||||||
procedure DiscardData(Sender: TVirtualStringTree; Node: PVirtualNode);
|
procedure EnsureChunkLoaded(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
||||||
|
procedure DiscardNodeData(Sender: TVirtualStringTree; Node: PVirtualNode);
|
||||||
procedure viewdata(Sender: TObject);
|
procedure viewdata(Sender: TObject);
|
||||||
procedure RefreshFieldListClick(Sender: TObject);
|
procedure RefreshFieldListClick(Sender: TObject);
|
||||||
procedure MenuRefreshClick(Sender: TObject);
|
procedure MenuRefreshClick(Sender: TObject);
|
||||||
@ -538,7 +539,9 @@ type
|
|||||||
TablePropertiesForm : Ttbl_properties_form;
|
TablePropertiesForm : Ttbl_properties_form;
|
||||||
FDataGridResult,
|
FDataGridResult,
|
||||||
FQueryGridResult : TGridResult;
|
FQueryGridResult : TGridResult;
|
||||||
DataGridCurrentQuery : WideString;
|
DataGridCurrentSelect : WideString;
|
||||||
|
DataGridCurrentFilter : WideString;
|
||||||
|
DataGridCurrentSort : WideString;
|
||||||
|
|
||||||
|
|
||||||
procedure Init(AConn : POpenConnProf; AMysqlConn : TMysqlConn);
|
procedure Init(AConn : POpenConnProf; AMysqlConn : TMysqlConn);
|
||||||
@ -1419,14 +1422,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
MainForm.ShowStatus( STATUS_MSG_READY );
|
MainForm.ShowStatus( STATUS_MSG_READY );
|
||||||
|
|
||||||
sl_query.Clear;
|
DataGridCurrentSelect := select_base + select_from;
|
||||||
sl_query.Add( select_base );
|
DataGridCurrentFilter := Filter;
|
||||||
sl_query.Add(select_from);
|
DataGridCurrentSort := sorting;
|
||||||
// Apply custom WHERE filter
|
|
||||||
if Filter <> '' then sl_query.Add('WHERE ' + Filter);
|
|
||||||
// Apply custom ORDER BY if detected in registry
|
|
||||||
if sorting <> '' then sl_query.Add( sorting );
|
|
||||||
DataGridCurrentQuery := sl_query.Text;
|
|
||||||
|
|
||||||
SetLength(FDataGridResult.Rows, DataGrid.RootNodeCount);
|
SetLength(FDataGridResult.Rows, DataGrid.RootNodeCount);
|
||||||
for i:=0 to DataGrid.RootNodeCount-1 do begin
|
for i:=0 to DataGrid.RootNodeCount-1 do begin
|
||||||
@ -3622,12 +3620,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
// Create instance of the progress form (but don't show it yet)
|
// Create instance of the progress form (but don't show it yet)
|
||||||
// Todo: This apparently causes an exception if invoked via an event handler?
|
|
||||||
// Classes.TStream.ReadComponent(???)
|
|
||||||
// Classes.InternalReadComponentRes(???,???,???)
|
|
||||||
// Classes.InitComponent(TfrmQueryProgress)
|
|
||||||
// Classes.InitInheritedComponent($17E0710,TForm)
|
|
||||||
// Forms.TCustomForm.Create(???)
|
|
||||||
FProgressForm := TFrmQueryProgress.Create(Self);
|
FProgressForm := TFrmQueryProgress.Create(Self);
|
||||||
|
|
||||||
{ Launch a thread of execution that passes the query to the server
|
{ Launch a thread of execution that passes the query to the server
|
||||||
@ -5511,7 +5503,56 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TMDIChild.EnsureDataLoaded(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
procedure TMDIChild.EnsureNodeLoaded(Sender: TBaseVirtualTree; Node: PVirtualNode; WhereClause: String);
|
||||||
|
var
|
||||||
|
res: PGridResult;
|
||||||
|
query: WideString;
|
||||||
|
ds: TDataSet;
|
||||||
|
i, j: LongInt;
|
||||||
|
begin
|
||||||
|
if Sender = DataGrid then res := @FDataGridResult
|
||||||
|
else res := @FQueryGridResult;
|
||||||
|
if (not res.Rows[Node.Index].Loaded) and (res.Rows[Node.Index].State <> grsInserted) then begin
|
||||||
|
query := DataGridCurrentSelect;
|
||||||
|
if DataGridCurrentFilter = '' then begin
|
||||||
|
query := query + ' WHERE ' + WhereClause;
|
||||||
|
end else begin
|
||||||
|
query := query + ' WHERE (' + DataGridCurrentFilter + ') AND (' + WhereClause + ')';
|
||||||
|
end;
|
||||||
|
|
||||||
|
// start query
|
||||||
|
MainForm.ShowStatus('Retrieving data...');
|
||||||
|
ds := GetResults(query);
|
||||||
|
// If new data does not match current filter, remove from tree.
|
||||||
|
if Cardinal(ds.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];
|
||||||
|
end;
|
||||||
|
SetLength(res.Rows, Length(res.Rows) - 1);
|
||||||
|
// Remove entry from node list.
|
||||||
|
Sender.DeleteNode(Node);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// fill in data
|
||||||
|
MainForm.ShowStatus('Filling grid with record-data...');
|
||||||
|
SetLength(res.Rows[Node.Index].Cells, ds.Fields.Count);
|
||||||
|
i := Node.Index;
|
||||||
|
for j := 0 to ds.Fields.Count - 1 do begin
|
||||||
|
if res.Columns[j].IsBinary then
|
||||||
|
res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(ds.Fields[j].AsString)
|
||||||
|
else
|
||||||
|
res.Rows[i].Cells[j].Text := ds.Fields[j].AsWideString;
|
||||||
|
res.Rows[i].Cells[j].IsNull := ds.Fields[j].IsNull;
|
||||||
|
end;
|
||||||
|
res.Rows[Node.Index].Loaded := True;
|
||||||
|
|
||||||
|
MainForm.ShowStatus( STATUS_MSG_READY );
|
||||||
|
FreeAndNil(ds);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMDIChild.EnsureChunkLoaded(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
||||||
var
|
var
|
||||||
res: PGridResult;
|
res: PGridResult;
|
||||||
start, limit: Cardinal;
|
start, limit: Cardinal;
|
||||||
@ -5523,40 +5564,42 @@ begin
|
|||||||
else res := @FQueryGridResult;
|
else res := @FQueryGridResult;
|
||||||
if (not res.Rows[Node.Index].Loaded) and (res.Rows[Node.Index].State <> grsInserted) then begin
|
if (not res.Rows[Node.Index].Loaded) and (res.Rows[Node.Index].State <> grsInserted) then begin
|
||||||
start := Node.Index - (Node.Index mod GridMaxRows);
|
start := Node.Index - (Node.Index mod GridMaxRows);
|
||||||
limit := DataGrid.RootNodeCount - start;
|
limit := TVirtualStringTree(Sender).RootNodeCount - start;
|
||||||
if limit > GridMaxRows then limit := GridMaxRows;
|
if limit > GridMaxRows then limit := GridMaxRows;
|
||||||
query := DataGridCurrentQuery + WideFormat(' LIMIT %d, %d', [start, limit]);
|
query := DataGridCurrentSelect;
|
||||||
|
if DataGridCurrentFilter <> '' then query := query + ' WHERE ' + DataGridCurrentFilter;
|
||||||
|
query := query + DataGridCurrentSort + WideFormat(' LIMIT %d, %d', [start, limit]);
|
||||||
|
|
||||||
// start query
|
// start query
|
||||||
MainForm.ShowStatus('Retrieving data...');
|
MainForm.ShowStatus('Retrieving data...');
|
||||||
ds := GetResults(query);
|
ds := GetResults(query);
|
||||||
if Cardinal(ds.RecordCount) < limit then begin
|
if Cardinal(ds.RecordCount) < limit then begin
|
||||||
limit := ds.RecordCount;
|
limit := ds.RecordCount;
|
||||||
DataGrid.RootNodeCount := start + limit + 1;
|
TVirtualStringTree(Sender).RootNodeCount := start + limit;
|
||||||
|
SetLength(res.Rows, start + limit);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// fill in data
|
// fill in data
|
||||||
MainForm.ShowStatus('Filling grid with record-data...');
|
MainForm.ShowStatus('Filling grid with record-data...');
|
||||||
for i := start to start + limit - 1 do begin
|
for i := start to start + limit - 1 do begin
|
||||||
SetLength(FDataGridResult.Rows[i].Cells, ds.Fields.Count);
|
SetLength(res.Rows[i].Cells, ds.Fields.Count);
|
||||||
for j := 0 to ds.Fields.Count - 1 do begin
|
for j := 0 to ds.Fields.Count - 1 do begin
|
||||||
if FDataGridResult.Columns[j].IsBinary then
|
if res.Columns[j].IsBinary then
|
||||||
FDataGridResult.Rows[i].Cells[j].Text := '0x' + BinToWideHex(ds.Fields[j].AsString)
|
res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(ds.Fields[j].AsString)
|
||||||
else
|
else
|
||||||
FDataGridResult.Rows[i].Cells[j].Text := ds.Fields[j].AsWideString;
|
res.Rows[i].Cells[j].Text := ds.Fields[j].AsWideString;
|
||||||
FDataGridResult.Rows[i].Cells[j].IsNull := ds.Fields[j].IsNull;
|
res.Rows[i].Cells[j].IsNull := ds.Fields[j].IsNull;
|
||||||
end;
|
end;
|
||||||
FDataGridResult.Rows[i].Loaded := True;
|
res.Rows[i].Loaded := True;
|
||||||
ds.Next;
|
ds.Next;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
MainForm.ShowStatus( STATUS_MSG_READY );
|
MainForm.ShowStatus( STATUS_MSG_READY );
|
||||||
// Todo: Seen an AV next line when this method was invoked via an event handler.
|
|
||||||
FreeAndNil(ds);
|
FreeAndNil(ds);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMDIChild.DiscardData(Sender: TVirtualStringTree; Node: PVirtualNode);
|
procedure TMDIChild.DiscardNodeData(Sender: TVirtualStringTree; Node: PVirtualNode);
|
||||||
var
|
var
|
||||||
Data: PGridResult;
|
Data: PGridResult;
|
||||||
begin
|
begin
|
||||||
@ -5585,9 +5628,9 @@ begin
|
|||||||
Exit;
|
Exit;
|
||||||
if Sender = DataGrid then gr := @FDataGridResult
|
if Sender = DataGrid then gr := @FDataGridResult
|
||||||
else gr := @FQueryGridResult;
|
else gr := @FQueryGridResult;
|
||||||
if Node.Index >= Cardinal(Length(gr.Rows)) then
|
if Node.Index >= Cardinal(Length(gr.Rows)) then Exit;
|
||||||
Exit;
|
EnsureChunkLoaded(Sender, Node);
|
||||||
EnsureDataLoaded(Sender, Node);
|
if Node.Index >= Cardinal(Length(gr.Rows)) then Exit;
|
||||||
c := @gr.Rows[Node.Index].Cells[Column];
|
c := @gr.Rows[Node.Index].Cells[Column];
|
||||||
EditingCell := Sender.IsEditing and (Node = Sender.FocusedNode) and (Column = Sender.FocusedColumn);
|
EditingCell := Sender.IsEditing and (Node = Sender.FocusedNode) and (Column = Sender.FocusedColumn);
|
||||||
if c.Modified then begin
|
if c.Modified then begin
|
||||||
@ -5675,8 +5718,8 @@ procedure TMDIChild.DataGridAfterCellPaint(Sender: TBaseVirtualTree;
|
|||||||
CellRect: TRect);
|
CellRect: TRect);
|
||||||
begin
|
begin
|
||||||
// Don't waist time
|
// Don't waist time
|
||||||
if Column = -1 then
|
if Column = -1 then Exit;
|
||||||
Exit;
|
if Node.Index >= Cardinal(Length(FDataGridResult.Rows)) then Exit;
|
||||||
// Paint a red triangle at the top left corner of the cell
|
// Paint a red triangle at the top left corner of the cell
|
||||||
if FDataGridResult.Rows[Node.Index].Cells[Column].Modified then
|
if FDataGridResult.Rows[Node.Index].Cells[Column].Modified then
|
||||||
Mainform.PngImageListMain.Draw(TargetCanvas, CellRect.Left, CellRect.Top, 111);
|
Mainform.PngImageListMain.Draw(TargetCanvas, CellRect.Left, CellRect.Top, 111);
|
||||||
@ -5813,7 +5856,6 @@ var
|
|||||||
i: Integer;
|
i: Integer;
|
||||||
sql, Val: WideString;
|
sql, Val: WideString;
|
||||||
Row: PGridRow;
|
Row: PGridRow;
|
||||||
ds: TDataSet;
|
|
||||||
begin
|
begin
|
||||||
sql := 'UPDATE '+mask(SelectedTable)+' SET';
|
sql := 'UPDATE '+mask(SelectedTable)+' SET';
|
||||||
Row := @FDataGridResult.Rows[Sender.FocusedNode.Index];
|
Row := @FDataGridResult.Rows[Sender.FocusedNode.Index];
|
||||||
@ -5849,28 +5891,8 @@ begin
|
|||||||
Row.Cells[i].IsNull := Row.Cells[i].NewIsNull;
|
Row.Cells[i].IsNull := Row.Cells[i].NewIsNull;
|
||||||
end;
|
end;
|
||||||
GridFinalizeEditing(Sender);
|
GridFinalizeEditing(Sender);
|
||||||
sql := 'SELECT ';
|
Row.Loaded := false;
|
||||||
for i := 0 to Length(FDataGridResult.Columns) - 1 do
|
EnsureNodeLoaded(Sender, Sender.FocusedNode, GetWhereClause(Row, @FDataGridResult.Columns, FSelectedTableKeys));
|
||||||
sql := sql + mask(FDataGridResult.Columns[i].Name) + ', ';
|
|
||||||
// Cut trailing comma
|
|
||||||
sql := Copy(sql, 1, Length(sql)-2);
|
|
||||||
sql := sql + ' FROM ' + mask(SelectedTable)
|
|
||||||
+ ' WHERE ' + GetWhereClause(Row, @FDataGridResult.Columns, FSelectedTableKeys);
|
|
||||||
ds := ExecSelectQuery(sql);
|
|
||||||
if ds.RecordCount = 1 then begin
|
|
||||||
for i := 0 to ds.FieldCount - 1 do begin
|
|
||||||
if FDataGridResult.Columns[i].IsBinary then
|
|
||||||
Row.Cells[i].Text := '0x' + BinToWideHex(ds.Fields[i].AsString)
|
|
||||||
else
|
|
||||||
Row.Cells[i].Text := ds.Fields[i].AsWideString;
|
|
||||||
Row.Cells[i].IsNull := ds.Fields[i].IsNull;
|
|
||||||
end;
|
|
||||||
Sender.RepaintNode(Sender.FocusedNode);
|
|
||||||
end else begin
|
|
||||||
logsql('Unable to identify updated row, found '+FormatNumber(ds.RecordCount)+' identical row(s). Doing full reload.');
|
|
||||||
viewdata(Sender);
|
|
||||||
end;
|
|
||||||
ds.Free;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -6019,14 +6041,12 @@ begin
|
|||||||
Vals := Copy(Vals, 1, Length(Vals)-2);
|
Vals := Copy(Vals, 1, Length(Vals)-2);
|
||||||
Cols := Copy(Cols, 1, Length(Cols)-2);
|
Cols := Copy(Cols, 1, Length(Cols)-2);
|
||||||
sql := 'INSERT INTO '+mask(SelectedTable)+' ('+Cols+') VALUES ('+Vals+')';
|
sql := 'INSERT INTO '+mask(SelectedTable)+' ('+Cols+') VALUES ('+Vals+')';
|
||||||
try
|
// Send INSERT query
|
||||||
// Send INSERT query
|
ExecUpdateQuery(sql, False, True);
|
||||||
ExecUpdateQuery(sql, False, True);
|
Result := True;
|
||||||
Result := True;
|
Row.Loaded := false;
|
||||||
GridFinalizeEditing(Sender);
|
EnsureNodeLoaded(Sender, Node, GetWhereClause(Row, @FDataGridResult.Columns, FSelectedTableKeys));
|
||||||
except
|
GridFinalizeEditing(Sender);
|
||||||
Result := False;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
@ -837,7 +837,7 @@ begin
|
|||||||
if not (coVisible in Grid.Header.Columns[i].Options) then
|
if not (coVisible in Grid.Header.Columns[i].Options) then
|
||||||
Continue;
|
Continue;
|
||||||
// Ensure basic data is loaded and load remainder of large fields.
|
// Ensure basic data is loaded and load remainder of large fields.
|
||||||
Mainform.Childwin.EnsureDataLoaded(Grid, Node);
|
Mainform.Childwin.EnsureChunkLoaded(Grid, Node);
|
||||||
Mainform.Childwin.EnsureFullWidth(Grid, i, Node);
|
Mainform.Childwin.EnsureFullWidth(Grid, i, Node);
|
||||||
Data := Grid.Text[Node, i];
|
Data := Grid.Text[Node, i];
|
||||||
// Handle nulls.
|
// Handle nulls.
|
||||||
@ -849,7 +849,7 @@ begin
|
|||||||
tmp := tmp + ' </tr>' + CRLF;
|
tmp := tmp + ' </tr>' + CRLF;
|
||||||
StreamWrite(S, tmp);
|
StreamWrite(S, tmp);
|
||||||
// Release some memory.
|
// Release some memory.
|
||||||
Mainform.Childwin.DiscardData(Grid, Node);
|
Mainform.Childwin.DiscardNodeData(Grid, Node);
|
||||||
Node := Grid.GetNext(Node);
|
Node := Grid.GetNext(Node);
|
||||||
end;
|
end;
|
||||||
// footer:
|
// footer:
|
||||||
@ -915,7 +915,7 @@ begin
|
|||||||
if not (coVisible in Grid.Header.Columns[i].Options) then
|
if not (coVisible in Grid.Header.Columns[i].Options) then
|
||||||
Continue;
|
Continue;
|
||||||
// Ensure basic data is loaded and load remainder of large fields.
|
// Ensure basic data is loaded and load remainder of large fields.
|
||||||
Mainform.Childwin.EnsureDataLoaded(Grid, Node);
|
Mainform.Childwin.EnsureChunkLoaded(Grid, Node);
|
||||||
Mainform.Childwin.EnsureFullWidth(Grid, i, Node);
|
Mainform.Childwin.EnsureFullWidth(Grid, i, Node);
|
||||||
Data := Grid.Text[Node, i];
|
Data := Grid.Text[Node, i];
|
||||||
// Remove 0x.
|
// Remove 0x.
|
||||||
@ -934,7 +934,7 @@ begin
|
|||||||
tmp := tmp + Terminator;
|
tmp := tmp + Terminator;
|
||||||
StreamWrite(S, tmp);
|
StreamWrite(S, tmp);
|
||||||
// Release some memory.
|
// Release some memory.
|
||||||
Mainform.Childwin.DiscardData(Grid, Node);
|
Mainform.Childwin.DiscardNodeData(Grid, Node);
|
||||||
Node := Grid.GetNext(Node);
|
Node := Grid.GetNext(Node);
|
||||||
end;
|
end;
|
||||||
Grid.Visible := true;
|
Grid.Visible := true;
|
||||||
@ -973,7 +973,7 @@ begin
|
|||||||
// Print cell start tag.
|
// Print cell start tag.
|
||||||
tmp := tmp + #9#9'<' + Grid.Header.Columns[i].Text;
|
tmp := tmp + #9#9'<' + Grid.Header.Columns[i].Text;
|
||||||
// Ensure basic data is loaded.
|
// Ensure basic data is loaded.
|
||||||
Mainform.Childwin.EnsureDataLoaded(Grid, Node);
|
Mainform.Childwin.EnsureChunkLoaded(Grid, Node);
|
||||||
if GridData.Rows[Node.Index].Cells[i].IsNull then tmp := tmp + ' isnull="true" />' + CRLF
|
if GridData.Rows[Node.Index].Cells[i].IsNull then tmp := tmp + ' isnull="true" />' + CRLF
|
||||||
else begin
|
else begin
|
||||||
if GridData.Columns[i].IsBinary then tmp := tmp + ' format="hex"';
|
if GridData.Columns[i].IsBinary then tmp := tmp + ' format="hex"';
|
||||||
@ -994,7 +994,7 @@ begin
|
|||||||
tmp := tmp + #9'</row>' + CRLF;
|
tmp := tmp + #9'</row>' + CRLF;
|
||||||
StreamWrite(S, tmp);
|
StreamWrite(S, tmp);
|
||||||
// Release some memory.
|
// Release some memory.
|
||||||
Mainform.Childwin.DiscardData(Grid, Node);
|
Mainform.Childwin.DiscardNodeData(Grid, Node);
|
||||||
Node := Grid.GetNext(Node);
|
Node := Grid.GetNext(Node);
|
||||||
end;
|
end;
|
||||||
// footer:
|
// footer:
|
||||||
|
Reference in New Issue
Block a user