Refactor exclusion of virtual columns in various places:

* introduce TDBQuery.ColIsVirtal() returning a boolean for a column index, and use that instead of examining a columns virtuality everywhere
* exclude virtual column when exporting SQL code in the grid export dialog - see #53
* sql export dialog must not activate edit mode on a result, as this introduces endless loops
* instead, move some code out of PrepareEditing into PrepareColumnAttributes, which we can now call separately without activating edit mode
This commit is contained in:
Ansgar Becker
2017-12-22 10:07:17 +01:00
parent c5f655753e
commit 19a1c3fbb4
4 changed files with 36 additions and 17 deletions

View File

@ -595,6 +595,7 @@ type
function ColIsPrimaryKeyPart(Column: Integer): Boolean; virtual; abstract;
function ColIsUniqueKeyPart(Column: Integer): Boolean; virtual; abstract;
function ColIsKeyPart(Column: Integer): Boolean; virtual; abstract;
function ColIsVirtual(Column: Integer): Boolean;
function ColAttributes(Column: Integer): TTableColumn;
function IsNull(Column: Integer): Boolean; overload; virtual; abstract;
function IsNull(Column: String): Boolean; overload;
@ -615,6 +616,7 @@ type
function TableName: String; virtual; abstract;
function QuotedDbAndTableName: String;
procedure DiscardModifications;
procedure PrepareColumnAttributes;
procedure PrepareEditing;
property RecNo: Int64 read FRecNo write SetRecNo;
property Eof: Boolean read FEof;
@ -6109,7 +6111,7 @@ begin
Result := nil;
if (Column < 0) or (Column >= FColumnOrgNames.Count) then
raise EDatabaseError.CreateFmt(_('Column #%s not available.'), [IntToStr(Column)]);
if FEditingPrepared then begin
if FColumns <> nil then begin
for i:=0 to FColumns.Count-1 do begin
if FColumns[i].Name = FColumnOrgNames[Column] then begin
Result := FColumns[i];
@ -6181,6 +6183,18 @@ begin
end;
function TDBQuery.ColIsVirtual(Column: Integer): Boolean;
var
Col: TTableColumn;
begin
Result := False;
Col := ColAttributes(Column);
if Col <> nil then begin
Result := not Col.Virtuality.IsEmpty;
end;
end;
function TMySQLQuery.IsNull(Column: Integer): Boolean;
begin
if FEditingPrepared and Assigned(FCurrentUpdateRow) then
@ -6256,17 +6270,14 @@ begin
end;
procedure TDBQuery.PrepareEditing;
procedure TDBQuery.PrepareColumnAttributes;
var
CreateCode, Dummy, DB: String;
DBObjects: TDBObjectList;
LObj, Obj: TDBObject;
begin
// Try to fetch column names and keys
if FEditingPrepared then
Exit;
// This is probably a VIEW, so column names need to be fetched differently
Obj := nil;
if FDBObject <> nil then
Obj := FDBObject
@ -6294,6 +6305,15 @@ begin
lntView:
Connection.ParseViewStructure(CreateCode, Obj, FColumns, Dummy, Dummy, Dummy, Dummy, Dummy);
end;
end;
procedure TDBQuery.PrepareEditing;
begin
// Try to fetch column names and keys and init update data
if FEditingPrepared then
Exit;
PrepareColumnAttributes;
FreeAndNil(FUpdateData);
FUpdateData := TUpdateData.Create(True);
FEditingPrepared := True;

View File

@ -759,7 +759,7 @@ begin
tmp := tmp + ' (';
Col := Grid.Header.Columns.GetFirstVisibleColumn;
while Col > NoColumn do begin
if Col <> ExcludeCol then
if (Col <> ExcludeCol) and (not GridData.ColIsVirtual(Col)) then
tmp := tmp + GridData.Connection.QuoteIdent(Grid.Header.Columns[Col].Text)+', ';
Col := Grid.Header.Columns.GetNextVisibleColumn(Col);
end;
@ -829,7 +829,9 @@ begin
end;
efSQLInsert, efSQLReplace, efSQLDeleteInsert: begin
if GridData.IsNull(Col) then
if GridData.ColIsVirtual(Col) then
Data := ''
else if GridData.IsNull(Col) then
Data := 'NULL'
else if (GridData.DataType(Col).Index = dtBit) and GridData.Connection.Parameters.IsMySQL then
Data := 'b' + esc(Data)
@ -839,6 +841,7 @@ begin
Data := esc(Data)
else if Data = '' then
Data := esc(Data);
if not Data.IsEmpty then
tmp := tmp + Data + ', ';
end;

View File

@ -4533,7 +4533,6 @@ var
i: Integer;
Value: String;
IsNull, AllowNewNode: Boolean;
TableCol: TTableColumn;
begin
Grid := ActiveGrid;
Results := GridResult(Grid);
@ -4559,8 +4558,7 @@ begin
continue; // Ignore invisible key column
if Results.ColIsPrimaryKeyPart(i) then
continue; // Empty value for primary key column
TableCol := Results.ColAttributes(i);
if (TableCol <> nil) and (not TableCol.Virtuality.IsEmpty) then
if Results.ColIsVirtual(i) then
continue; // Don't copy virtual column value
Results.RecNo := DupeNum^;
Value := Results.Col(i);

View File

@ -1602,9 +1602,6 @@ begin
TargetDbAndObject := Quoter.QuoteIdent(DBObj.Name);
if ToDb then
TargetDbAndObject := Quoter.QuoteIdent(FinalDbName) + '.' + TargetDbAndObject;
// Parse columns, so we can check for special things like virtual columns
ColumnList := TTableColumnList.Create(True);
DBObj.Connection.ParseTableStructure(DBObj.CreateCode, ColumnList, nil, nil);
Offset := 0;
RowCount := 0;
// Calculate limit so we select ~100MB per loop
@ -1623,6 +1620,7 @@ begin
Inc(Offset, Limit);
if Data.RecordCount = 0 then
break;
Data.PrepareColumnAttributes;
BaseInsert := 'INSERT INTO ';
if comboExportData.Text = DATA_INSERTNEW then
BaseInsert := 'INSERT IGNORE INTO '
@ -1630,7 +1628,7 @@ begin
BaseInsert := 'REPLACE INTO ';
BaseInsert := BaseInsert + TargetDbAndObject + ' (';
for i:=0 to Data.ColumnCount-1 do begin
if ColumnList[i].Virtuality.IsEmpty then
if not Data.ColIsVirtual(i) then
BaseInsert := BaseInsert + Quoter.QuoteIdent(Data.ColumnNames[i]) + ', ';
end;
Delete(BaseInsert, Length(BaseInsert)-1, 2);
@ -1644,7 +1642,7 @@ begin
if not IsFirstRowInChunk then
Row := Row + ','+CRLF+#9+'(';
for i:=0 to Data.ColumnCount-1 do begin
if not ColumnList[i].Virtuality.IsEmpty then
if Data.ColIsVirtual(i) then
Continue;
if Data.IsNull(i) then
Row := Row + 'NULL'