Skip to content
Permalink
Browse files

Use TDBObject.TableColumns for views as well, handle these like table…

…s. Fixes crash when editing view data, when trying to create a table copy of a view, and some more.
  • Loading branch information
ansgarbecker committed Feb 2, 2020
1 parent 858e8a3 commit 4a440229a412da11119034f8258d0e7535008989
Showing with 22 additions and 112 deletions.
  1. +1 −6 source/copytable.pas
  2. +9 −78 source/dbconnection.pas
  3. +1 −3 source/loaddata.pas
  4. +7 −19 source/main.pas
  5. +3 −5 source/tabletools.pas
  6. +1 −1 source/view.pas
@@ -100,7 +100,6 @@ procedure TCopyTableForm.FormResize(Sender: TObject);
procedure TCopyTableForm.FormShow(Sender: TObject);
var
Filter: String;
Dummy: String;
Obj: PDBObject;
i: Integer;
Item: TMenuItem;
@@ -127,15 +126,11 @@ procedure TCopyTableForm.FormShow(Sender: TObject);

// Fetch columns and key structures from table or view
case FDBObj.NodeType of
lntTable: begin
lntTable, lntView: begin
FColumns := FDBObj.TableColumns;
FKeys := FDBObj.TableKeys;
FForeignKeys := FDBObj.TableForeignKeys;
end;
lntView: begin
FColumns := TTableColumnList.Create;
FConnection.ParseViewStructure(FDBObj.CreateCode, FDBObj, FColumns, Dummy, Dummy, Dummy, Dummy, Dummy);
end
else raise Exception.CreateFmt(_('Neither table nor view: %s'), [FDBObj.Name]);
end;

@@ -445,7 +445,7 @@ TDBConnection = class(TComponent)
function GetDateTimeValue(Input: String; Datatype: TDBDatatypeIndex): String;
procedure ClearDbObjects(db: String);
procedure ClearAllDbObjects;
procedure ParseViewStructure(CreateCode: String; DBObj: TDBObject; Columns: TTableColumnList;
procedure ParseViewStructure(CreateCode: String; DBObj: TDBObject;
var Algorithm, Definer, SQLSecurity, CheckOption, SelectCode: String);
procedure ParseRoutineStructure(Obj: TDBObject; Parameters: TRoutineParamList);
procedure PurgePrefetchResults;
@@ -3223,8 +3223,7 @@ function TMySQLConnection.GetCreateViewCode(Database, Name: String): String;
if rx.Exec(AlternativeSelectCode) then begin
// Put pieces of CREATE VIEW together
Obj := FindObject(Database, Name);
ParseViewStructure(Result, Obj, nil,
Algorithm, Definer, SQLSecurity, CheckOption, SelectCode);
ParseViewStructure(Result, Obj, Algorithm, Definer, SQLSecurity, CheckOption, SelectCode);
AlternativeSelectCode := UnescapeString(rx.Match[1]);
Result := 'CREATE ';
if Algorithm <> '' then
@@ -6002,13 +6001,11 @@ function TPgConnection.ConnectionInfo: TStringList;
end;


procedure TDBConnection.ParseViewStructure(CreateCode: String; DBObj: TDBObject; Columns: TTableColumnList;
procedure TDBConnection.ParseViewStructure(CreateCode: String; DBObj: TDBObject;
var Algorithm, Definer, SQLSecurity, CheckOption, SelectCode: String);
var
rx: TRegExpr;
Col: TTableColumn;
Results: TDBQuery;
SchemaClause, DataType, EscQuote: String;
EscQuote: String;
begin
if CreateCode <> '' then begin
// CREATE
@@ -6043,64 +6040,6 @@ procedure TDBConnection.ParseViewStructure(CreateCode: String; DBObj: TDBObject;
rx.Free;
end;

if Assigned(Columns) then begin
Columns.Clear;
rx := TRegExpr.Create;
rx.Expression := '(\((.+)\))(\s+unsigned)?(\s+zerofill)?';
if DBObj.Schema <> '' then
SchemaClause := 'AND TABLE_SCHEMA='+EscapeString(DBObj.Schema)
else
SchemaClause := 'AND '+GetSQLSpecifity(spISTableSchemaCol)+'='+EscapeString(DBObj.Database);
Results := GetResults('SELECT * '+
'FROM '+InfSch+'.COLUMNS '+
'WHERE '+
' TABLE_NAME='+EscapeString(DBObj.Name)+' '+
SchemaClause+
' ORDER BY ORDINAL_POSITION'
);
while not Results.Eof do begin
Col := TTableColumn.Create(Self);
Columns.Add(Col);
Col.Name := Results.Col('COLUMN_NAME');
Col.AllowNull := UpperCase(Results.Col('IS_NULLABLE')) = 'YES';
DataType := Results.Col('DATA_TYPE');
Col.DataType := GetDatatypeByName(DataType, False, Col.Name);
if Results.ColExists('COLUMN_TYPE') then begin
// Use MySQL's proprietary column_type - the only way to get SET and ENUM values
if rx.Exec(Results.Col('COLUMN_TYPE')) then begin
Col.LengthSet := rx.Match[2];
if Col.DataType.Category in [dtcInteger, dtcReal] then begin
Col.Unsigned := rx.Match[3] <> '';
Col.ZeroFill := rx.Match[4] <> '';
end;
end;
end else begin
if not Results.IsNull('CHARACTER_MAXIMUM_LENGTH') then begin
Col.LengthSet := Results.Col('CHARACTER_MAXIMUM_LENGTH');
end else if not Results.IsNull('NUMERIC_PRECISION') then begin
Col.LengthSet := Results.Col('NUMERIC_PRECISION');
if not Results.IsNull('NUMERIC_SCALE') then
Col.LengthSet := Col.LengthSet + ',' + Results.Col('NUMERIC_SCALE');
end;
if Col.LengthSet = '-1' then
Col.LengthSet := 'max';
end;
Col.Collation := Results.Col('COLLATION_NAME');
Col.Comment := Results.Col('COLUMN_COMMENT', True);
Col.DefaultText := Results.Col('COLUMN_DEFAULT');
if Results.IsNull('COLUMN_DEFAULT') then begin
if Col.AllowNull then
Col.DefaultType := cdtNull
else
Col.DefaultType := cdtNothing;
end else if Col.DataType.Category = dtcText then
Col.DefaultType := cdtText
else
Col.DefaultType := cdtExpression;
Results.Next;
end;
rx.Free;
end;
end;


@@ -7481,7 +7420,7 @@ function TSQLiteQuery.HasResult: Boolean;

procedure TDBQuery.PrepareColumnAttributes;
var
CreateCode, Dummy, DB: String;
DB: String;
DBObjects: TDBObjectList;
LObj, Obj: TDBObject;
begin
@@ -7504,18 +7443,10 @@ procedure TDBQuery.PrepareColumnAttributes;
if Obj = nil then
raise EDbError.Create(f_('Could not find table or view %s.%s. Please refresh database tree.', [DB, TableName]));
end;
case Obj.NodeType of
lntTable: begin
FColumns := Obj.TableColumns;
FKeys := Obj.TableKeys;
FForeignKeys := Obj.TableForeignKeys;
end;
lntView: begin
CreateCode := Connection.GetCreateCode(Obj);
FColumns := TTableColumnList.Create;
Connection.ParseViewStructure(CreateCode, Obj, FColumns, Dummy, Dummy, Dummy, Dummy, Dummy);
end;
end;
// Obj.NodeType must be lntTable or lntView here, otherwise we get no columns or keys
FColumns := Obj.TableColumns;
FKeys := Obj.TableKeys;
FForeignKeys := Obj.TableForeignKeys;
end;


@@ -249,7 +249,6 @@ procedure Tloaddataform.comboDatabaseChange(Sender: TObject);

procedure Tloaddataform.comboTableChange(Sender: TObject);
var
DummyStr: String;
Col: TTableColumn;
DBObjects: TDBObjectList;
Obj: TDBObject;
@@ -263,8 +262,7 @@ procedure Tloaddataform.comboTableChange(Sender: TObject);
for Obj in DBObjects do begin
if (Obj.Database=comboDatabase.Text) and (Obj.Name=comboTable.Text) then begin
case Obj.NodeType of
lntTable: Columns := Obj.TableColumns;
lntView: Obj.Connection.ParseViewStructure(Obj.CreateCode, Obj, Columns, DummyStr, DummyStr, DummyStr, DummyStr, DummyStr);
lntTable, lntView: Columns := Obj.TableColumns;
end;
end;
end;
@@ -5987,7 +5987,7 @@ procedure TMainForm.SynCompletionProposalExecute(Kind: SynCompletionType;

procedure AddColumns(const LeftToken: String);
var
dbname, tblname, Dummy: String;
dbname, tblname: String;
Columns: TTableColumnList;
Col: TTableColumn;
Obj: TDBObject;
@@ -6006,15 +6006,7 @@ procedure TMainForm.SynCompletionProposalExecute(Kind: SynCompletionType;
DBObjects := Conn.GetDBObjects(dbname);
for Obj in DBObjects do begin
if (Obj.Name = tblname) and (Obj.NodeType in [lntTable, lntView]) then begin
Columns := TTableColumnList.Create(True);
case Obj.NodeType of
lntTable: begin
Columns := Obj.TableColumns;
end;
lntView: begin
Conn.ParseViewStructure(Obj.CreateCode, Obj, Columns, Dummy, Dummy, Dummy, Dummy, Dummy);
end;
end;
Columns := Obj.TableColumns;
for Col in Columns do begin
Proposal.InsertList.Add(Col.Name);
Proposal.ItemList.Add(Format(SYNCOMPLETION_PATTERN, [ICONINDEX_FIELD, LowerCase(Col.DataType.Name), Col.Name, '']) );
@@ -8555,7 +8547,7 @@ procedure TMainForm.DBtreeFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualN
var
DBObj, PrevDBObj, ParentDBObj: PDBObject;
MainTabToActivate: TTabSheet;
DummyStr, TabHostName: String;
TabHostName: String;
begin
// Set wanted main tab and call SetMainTab later, when all lists have been invalidated
MainTabToActivate := nil;
@@ -8614,14 +8606,10 @@ procedure TMainForm.DBtreeFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualN
SelectedTableTimestampColumns.Text := AppSettings.ReadString(asTimestampColumns);
InvalidateVT(DataGrid, VTREE_NOTLOADED_PURGECACHE, False);
try
case FActiveDbObj.NodeType of
lntTable: begin
SelectedTableColumns := FActiveDbObj.TableColumns;
SelectedTableKeys := FActiveDbObj.TableKeys;
SelectedTableForeignKeys := FActiveDbObj.TableForeignKeys;
end;
lntView:
FActiveDbObj.Connection.ParseViewStructure(FActiveDbObj.CreateCode, FActiveDbObj, SelectedTableColumns, DummyStr, DummyStr, DummyStr, DummyStr, DummyStr);
if FActiveDbObj.NodeType in [lntTable, lntView] then begin
SelectedTableColumns := FActiveDbObj.TableColumns;
SelectedTableKeys := FActiveDbObj.TableKeys;
SelectedTableForeignKeys := FActiveDbObj.TableForeignKeys;
end;
except on E:EDbError do
ErrorDialog(E.Message);
@@ -849,7 +849,7 @@ procedure TfrmTableTools.DoFind(DBObj: TDBObject);
var
Columns: TTableColumnList;
Col: TTableColumn;
SQL, Dummy, Column, RoutineDefinitionColumn, RoutineSchemaColumn, FindText, FindTextJokers: String;
SQL, Column, RoutineDefinitionColumn, RoutineSchemaColumn, FindText, FindTextJokers: String;
IsRegExp: Boolean;
begin
FFindSeeResultSQL.Add('');
@@ -882,8 +882,7 @@ procedure TfrmTableTools.DoFind(DBObj: TDBObject);

Columns := TTableColumnList.Create(True);
case DBObj.NodeType of
lntTable: Columns := DBObj.TableColumns;
lntView: DBObj.Connection.ParseViewStructure(DBObj.CreateCode, DBObj, Columns, Dummy, Dummy, Dummy, Dummy, Dummy);
lntTable, lntView: Columns := DBObj.TableColumns;
lntProcedure, lntFunction: ;
// TODO: Triggers + Events
else AddNotes(DBObj, STRSKIPPED+'a '+LowerCase(DBObj.ObjType)+' does not contain rows.', '');
@@ -1584,8 +1583,7 @@ procedure TfrmTableTools.DoExport(DBObj: TDBObject);
lntView: begin
if not FSecondExportPass then begin
// Create temporary VIEW replacement
ColumnList := TTableColumnList.Create(True);
DBObj.Connection.ParseViewStructure(DBObj.CreateCode, DBObj, ColumnList, Dummy, Dummy, Dummy, Dummy, Dummy);
ColumnList := DBObj.TableColumns;
Struc := '';
if menuExportAddComments.Checked then
Struc := Struc + '-- '+_('Creating temporary table to overcome VIEW dependency errors')+CRLF;
@@ -76,7 +76,7 @@ procedure TfrmView.Init(Obj: TDBObject);
if Obj.Name <> '' then begin
// Edit mode
editName.Text := Obj.Name;
Obj.Connection.ParseViewStructure(Obj.CreateCode, Obj, nil, Algorithm, Definer, SQLSecurity, CheckOption, SelectCode);
Obj.Connection.ParseViewStructure(Obj.CreateCode, Obj, Algorithm, Definer, SQLSecurity, CheckOption, SelectCode);
comboDefiner.Text := Definer;
rgAlgorithm.ItemIndex := rgAlgorithm.Items.IndexOf(Algorithm);
rgCheck.ItemIndex := rgCheck.Items.IndexOf(CheckOption);

0 comments on commit 4a44022

Please sign in to comment.
You can’t perform that action at this time.