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

View File

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

View File

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

View File

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