소스 검색

Follow isql -x rather than FlameRobin when creating primary key and foreign key constraints: do not specify system-generated (INTEG_...) constraints.

Reinier Olislagers 11 년 전
부모
커밋
6ff7b0e992
4개의 변경된 파일55개의 추가작업 그리고 40개의 파일을 삭제
  1. 0 1
      comparison.pas
  2. 4 5
      main.pas
  3. 42 7
      scriptdb.pas
  4. 9 27
      systables.pas

+ 0 - 1
comparison.pas

@@ -482,7 +482,6 @@ begin
             Line:= Line + 'index ' + AIndexName + ' on ' + ATableName;
 
             Line:= Line + ' (' + FieldsList.CommaText + ') ;';
-
           end;
 
           fQueryWindow.meQuery.Lines.Add(Line);

+ 4 - 5
main.pas

@@ -239,6 +239,8 @@ type
     function GetFBTypeName(Index: Integer;
       SubType: integer=-1; FieldLength: integer=-1;
       Scale: integer=-1): string;
+    // Get name of index used for primary key
+    // Also returns name of constraint used
     function GetPrimaryKeyIndexName(DatabaseIndex: Integer; ATableName: string; var ConstraintName: string): string;
     function GetConstraintFields(ATableName, AIndexName: string; var List: TStringList): Boolean;
     // Get fields information for specified table
@@ -1032,7 +1034,6 @@ var
   EditForm: TfmEditDataFullRec;
   ATableName: string;
   i: Integer;
-  ConstraintsList: TStringList;
   PKFieldsList: TStringList;
   FieldLine: string;
   dbIndex: Integer;
@@ -1095,7 +1096,6 @@ var
   EditWindow: TfmEditTable;
   ATableName: string;
   i: Integer;
-  ConstraintsList: TStringList;
   PKFieldsList: TStringList;
   FieldLine: string;
   dbIndex: Integer;
@@ -1933,7 +1933,6 @@ var
   SelNode: TTreeNode;
   QWindow: TfmQueryWindow;
   ATableName: string;
-  ConstraintsList: TStringList;
   PKFieldsList: TStringList;
   FieldLine: string;
   FieldNames: string;
@@ -4200,8 +4199,8 @@ begin
   SQLQuery1.Open;
   if SQLQuery1.RecordCount > 0 then
   begin
-    Result:= Trim(SQLQuery1.Fields[0].AsString);
-    ConstraintName:= Trim(SQLQuery1.Fields[1].AsString);
+    Result:= Trim(SQLQuery1.FieldByName('RDB$Index_name').AsString);
+    ConstraintName:= Trim(SQLQuery1.FieldByName('RDB$Constraint_Name').AsString);
   end
   else
     Result:= '';

+ 42 - 7
scriptdb.pas

@@ -29,6 +29,7 @@ function ScriptAllTriggers(dbIndex: Integer; var List: TStringList): Boolean;
 // Scripts all non-primary key indexes for a database
 function ScriptAllSecIndices(dbIndex: Integer; var List: TStringList): Boolean;
 // Scripts all constraints (e.g. foreign key constraints) for tables in a database
+// For now, seems to only cover foreign keys. Todo: verify/confirm
 function ScriptAllConstraints(dbIndex: Integer; var List: TStringList): Boolean;
 function ScriptObjectPermission(dbIndex: Integer; ObjName, UserName: string; var ObjType: Integer;
    List: TStrings; NewUser: string = ''): Boolean;
@@ -45,6 +46,13 @@ implementation
 
 uses SysTables, Main;
 
+// Tries to guess if a constraint name is system-generated.
+// todo: find a way to search the system tables and make sure.
+function SystemGeneratedConstraint(ConstraintName: string): boolean;
+begin
+  result:=(pos('INTEG_',uppercase(Trim(ConstraintName)))=1);
+end;
+
 (********************  Script Roles  ***********************)
 
 function ScriptAllRoles(dbIndex: Integer; var List: TStringList): Boolean;
@@ -169,7 +177,7 @@ end;
 procedure ScriptTableAsCreate(dbIndex: Integer; ATableName: string; ScriptList: TStringList);
 var
   i: Integer;
-  PKeyName: string;
+  PKeyIndexName: string;
   PKFieldsList: TStringList;
   FieldLine: string;
   Skipped: Boolean;
@@ -251,11 +259,16 @@ begin
 
     // Primary Keys
     PKFieldsList:= TStringList.Create;
-    PKeyName:= fmMain.GetPrimaryKeyIndexName(dbIndex, ATableName, ConstraintName);
-    if PKeyName <> '' then
+    PKeyIndexName:= fmMain.GetPrimaryKeyIndexName(dbIndex, ATableName, ConstraintName);
+    if PKeyIndexName <> '' then
     begin
-      fmMain.GetConstraintFields(ATableName, PKeyName, PKFieldsList);
-      FieldLine:= 'constraint ' + PKeyName + ' primary key (';
+      fmMain.GetConstraintFields(ATableName, PKeyIndexName, PKFieldsList);
+      // Follow isql -x (not FlameRobin) by omitting system-generated
+      // constraint names and let the system generate its own names
+      if SystemGeneratedConstraint(ConstraintName) then
+        FieldLine:= ' primary key ('
+      else // User-specified, so explicilty mention constraint name
+        FieldLine:= 'constraint ' + ConstraintName + ' primary key (';
       for i:= 0 to PKFieldsList.Count - 1 do
         FieldLine:= FieldLine + PKFieldsList[i] + ', ';
       if PKFieldsList.Count > 0 then
@@ -469,16 +482,38 @@ var
     OtherFieldName, OtherTableName, DeleteRule, UpdateRule: string;
     var List: TStringList);
   const
+    { isql -x outputs DDL like this here:
+    ALTER TABLE DEPARTMENT ADD FOREIGN KEY (MNGR_NO) REFERENCES EMPLOYEE (EMP_NO);
+    i.e. does not mention constraint name.
+    This avoids name conflicts with autogenerated constraint names (which
+    FlameRobin also suffers from)
+    We're going to try follow this and find out what is a system-generated
+    constraint name and what is user-generated so we don't lose information
+    }
     Template= 'alter table %s' +
       ' add constraint %s' +
       ' foreign key (%s)'+
       ' references %s' +
       ' (%s)';
+    TemplateNoName= 'alter table %s' +
+      ' add foreign key (%s)'+
+      ' references %s' +
+      ' (%s)';
   var
     Line: string;
   begin
-    Line:= format(Template,[TableName,ConstraintName,CurrentFieldName,
-      OtherTableName, OtherFieldName]);
+    if SystemGeneratedConstraint(ConstraintName) then
+    begin
+      // If system-generated, don't specify constraint name
+      Line:= format(TemplateNoName,[TableName,CurrentFieldName,
+        OtherTableName, OtherFieldName]);
+    end
+    else
+    begin
+      // Do spell out constraint name
+      Line:= format(Template,[TableName,ConstraintName,CurrentFieldName,
+        OtherTableName, OtherFieldName]);
+    end;
     if UpdateRule <> 'RESTRICT' then
       Line:= Line + ' on update ' + UpdateRule;
     if DeleteRule <> 'RESTRICT' then

+ 9 - 27
systables.pas

@@ -345,32 +345,11 @@ end;
 
 function TdmSysTables.GetTableConstraints(ATableName: string; var SqlQuery: TSQLQuery;
    ConstraintsList: TStringList = nil): Boolean;
-begin
-  SqlQuery.Close;
-// Note that this query differs from the way constraints are
-// presented in GetConstraintsOfTable.
-// to do: find out what the differences are and indicate better in code/comments
-{ Query sample for employee database:
-select trim(rc.rdb$constraint_name) as ConstName,
-trim(rfc.rdb$const_name_uq) as KeyName,
-trim(rc2.rdb$relation_name) as OtherTableName,
-trim(flds_pk.rdb$field_name) as OtherFieldName,
-trim(rc.rdb$relation_name) as CurrentTableName,
-trim(flds_fk.rdb$field_name) as CurrentFieldName,
-trim(rfc.rdb$update_rule) as UpdateRule,
-trim(rfc.rdb$delete_rule) as DeleteRule
-from rdb$relation_constraints AS rc
-inner join rdb$ref_constraints as rfc on (rc.rdb$constraint_name =
-rfc.rdb$constraint_name) inner join rdb$index_segments as flds_fk on (flds_fk.rdb$index_name = rc.rdb$index_name)
-inner join rdb$relation_constraints as rc2 on (rc2.rdb$constraint_name = rfc.rdb$const_name_uq)
-inner join rdb$index_segments as flds_pk on
-((flds_pk.rdb$index_name = rc2.rdb$index_name) and (flds_fk.rdb$field_position = flds_pk.rdb$field_position))
-where rc.rdb$constraint_type = 'FOREIGN KEY' and
-rc.rdb$relation_name = 'EMPLOYEE'
-order by rc.rdb$constraint_name,
-flds_fk.rdb$field_position
-}
-  SQLQuery.SQL.Text:='select '+
+const
+  // Note that this query differs from the way constraints are
+  // presented in GetConstraintsOfTable.
+  // to do: find out what the differences are and indicate better in code/comments
+  Template='select '+
     'trim(rc.rdb$constraint_name) as ConstName, '+
     'trim(rfc.rdb$const_name_uq) as KeyName, '+
     'trim(rc2.rdb$relation_name) as OtherTableName, '+
@@ -386,8 +365,11 @@ flds_fk.rdb$field_position
     'inner join rdb$index_segments as flds_pk on ' +
     '((flds_pk.rdb$index_name = rc2.rdb$index_name) and (flds_fk.rdb$field_position = flds_pk.rdb$field_position)) ' +
     'where rc.rdb$constraint_type = ''FOREIGN KEY'' '+
-    'and rc.rdb$relation_name = ''' + UpperCase(ATableName) + ''' '+
+    'and rc.rdb$relation_name = ''%s'' '+
     'order by rc.rdb$constraint_name, flds_fk.rdb$field_position ';
+begin
+  SqlQuery.Close;
+  SQLQuery.SQL.Text:= format(Template, [UpperCase(ATableName)]);
   SqlQuery.Open;
   Result:= SqlQuery.RecordCount > 0;
   with SqlQuery do