瀏覽代碼

Compare and script missing fields
modified: TurboBird.lpi
modified: TurboBird.lpr
modified: comparison.lfm
modified: comparison.pas
modified: systables.pas

motaz 13 年之前
父節點
當前提交
1a54a979c8
共有 5 個文件被更改,包括 394 次插入169 次删除
  1. 81 73
      TurboBird.lpi
  2. 1 1
      TurboBird.lpr
  3. 1 0
      comparison.lfm
  4. 246 87
      comparison.pas
  5. 65 8
      systables.pas

+ 81 - 73
TurboBird.lpi

@@ -60,10 +60,11 @@
         <Filename Value="TurboBird.lpr"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="TurboBird"/>
+        <IsVisibleTab Value="True"/>
         <EditorIndex Value="1"/>
         <WindowIndex Value="0"/>
         <TopLine Value="1"/>
-        <CursorPos X="33" Y="6"/>
+        <CursorPos X="26" Y="5"/>
         <UsageCount Value="200"/>
         <Loaded Value="True"/>
       </Unit0>
@@ -73,10 +74,11 @@
         <ComponentName Value="fmMain"/>
         <ResourceBaseClass Value="Form"/>
         <UnitName Value="main"/>
-        <EditorIndex Value="4"/>
+        <EditorIndex Value="5"/>
         <WindowIndex Value="0"/>
-        <TopLine Value="2527"/>
-        <CursorPos X="56" Y="2540"/>
+        <TopLine Value="469"/>
+        <CursorPos X="29" Y="496"/>
+        <FoldState Value=" T3irS0v/"/>
         <UsageCount Value="200"/>
         <Loaded Value="True"/>
         <LoadedDesigner Value="True"/>
@@ -449,8 +451,8 @@
         <UnitName Value="SysTables"/>
         <EditorIndex Value="2"/>
         <WindowIndex Value="0"/>
-        <TopLine Value="257"/>
-        <CursorPos X="33" Y="267"/>
+        <TopLine Value="571"/>
+        <CursorPos X="32" Y="573"/>
         <UsageCount Value="200"/>
         <Loaded Value="True"/>
         <LoadedDesigner Value="True"/>
@@ -489,10 +491,13 @@
         <ComponentName Value="fmNewEditField"/>
         <ResourceBaseClass Value="Form"/>
         <UnitName Value="NewEditField"/>
+        <EditorIndex Value="4"/>
         <WindowIndex Value="0"/>
-        <TopLine Value="165"/>
-        <CursorPos X="3" Y="169"/>
+        <TopLine Value="65"/>
+        <CursorPos X="1" Y="94"/>
         <UsageCount Value="202"/>
+        <Loaded Value="True"/>
+        <LoadedDesigner Value="True"/>
       </Unit46>
       <Unit47>
         <Filename Value="/usr/lib/lazarus/0.9.28.2/lcl/dbgrids.pas"/>
@@ -529,7 +534,7 @@
         <Filename Value="scriptdb.pas"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="Scriptdb"/>
-        <EditorIndex Value="5"/>
+        <EditorIndex Value="6"/>
         <WindowIndex Value="0"/>
         <TopLine Value="393"/>
         <CursorPos X="41" Y="399"/>
@@ -554,7 +559,7 @@
         <WindowIndex Value="0"/>
         <TopLine Value="6"/>
         <CursorPos X="8" Y="34"/>
-        <UsageCount Value="185"/>
+        <UsageCount Value="191"/>
       </Unit53>
       <Unit54>
         <Filename Value="/usr/lib/lazarus/0.9.29/ide/lazarus.pp"/>
@@ -573,7 +578,7 @@
         <WindowIndex Value="0"/>
         <TopLine Value="303"/>
         <CursorPos X="20" Y="311"/>
-        <UsageCount Value="168"/>
+        <UsageCount Value="174"/>
       </Unit55>
       <Unit56>
         <Filename Value="/usr/lib/lazarus/0.9.29/lcl/grids.pas"/>
@@ -616,7 +621,7 @@
         <WindowIndex Value="0"/>
         <TopLine Value="13"/>
         <CursorPos X="22" Y="54"/>
-        <UsageCount Value="154"/>
+        <UsageCount Value="160"/>
       </Unit60>
       <Unit61>
         <Filename Value="unitfirebirdservices.pas"/>
@@ -682,7 +687,7 @@
         <WindowIndex Value="0"/>
         <TopLine Value="3"/>
         <CursorPos X="71" Y="7"/>
-        <UsageCount Value="124"/>
+        <UsageCount Value="130"/>
       </Unit68>
       <Unit69>
         <Filename Value="changepass.pas"/>
@@ -693,7 +698,7 @@
         <WindowIndex Value="0"/>
         <TopLine Value="3"/>
         <CursorPos X="88" Y="14"/>
-        <UsageCount Value="123"/>
+        <UsageCount Value="129"/>
       </Unit69>
       <Unit70>
         <Filename Value="permissionmanage.pas"/>
@@ -704,7 +709,7 @@
         <WindowIndex Value="0"/>
         <TopLine Value="61"/>
         <CursorPos X="44" Y="83"/>
-        <UsageCount Value="121"/>
+        <UsageCount Value="127"/>
       </Unit70>
       <Unit71>
         <Filename Value="sqlhistory.pas"/>
@@ -715,7 +720,7 @@
         <WindowIndex Value="0"/>
         <TopLine Value="1"/>
         <CursorPos X="18" Y="39"/>
-        <UsageCount Value="106"/>
+        <UsageCount Value="112"/>
       </Unit71>
       <Unit72>
         <Filename Value="../../lazarus/lazarus/lcl/include/menuitem.inc"/>
@@ -740,7 +745,7 @@
         <WindowIndex Value="0"/>
         <TopLine Value="18"/>
         <CursorPos X="1" Y="44"/>
-        <UsageCount Value="77"/>
+        <UsageCount Value="83"/>
       </Unit74>
       <Unit75>
         <Filename Value="/usr/lib/lazarus/0.9.30/lcl/comctrls.pp"/>
@@ -932,7 +937,7 @@
         <WindowIndex Value="0"/>
         <TopLine Value="20"/>
         <CursorPos X="22" Y="41"/>
-        <UsageCount Value="45"/>
+        <UsageCount Value="51"/>
       </Unit98>
       <Unit99>
         <Filename Value="../../FromInternet/fpc2.4/fpc-2.4.4/packages/ibase/src/ibase60dyn.pp"/>
@@ -963,133 +968,136 @@
         <ComponentName Value="fmComparison"/>
         <ResourceBaseClass Value="Form"/>
         <UnitName Value="Comparison"/>
-        <IsVisibleTab Value="True"/>
         <EditorIndex Value="3"/>
         <WindowIndex Value="0"/>
-        <TopLine Value="53"/>
-        <CursorPos X="1" Y="134"/>
-        <UsageCount Value="32"/>
+        <TopLine Value="392"/>
+        <CursorPos X="22" Y="397"/>
+        <UsageCount Value="38"/>
         <Loaded Value="True"/>
         <LoadedDesigner Value="True"/>
       </Unit102>
     </Units>
-    <JumpHistory Count="29" HistoryIndex="28">
+    <JumpHistory Count="30" HistoryIndex="29">
       <Position1>
-        <Filename Value="systables.pas"/>
-        <Caret Line="57" Column="14" TopLine="40"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="49" Column="34" TopLine="31"/>
       </Position1>
       <Position2>
-        <Filename Value="systables.pas"/>
-        <Caret Line="1" Column="1" TopLine="1"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="338" Column="22" TopLine="332"/>
       </Position2>
       <Position3>
         <Filename Value="systables.pas"/>
-        <Caret Line="29" Column="29" TopLine="1"/>
+        <Caret Line="256" Column="21" TopLine="251"/>
       </Position3>
       <Position4>
         <Filename Value="systables.pas"/>
-        <Caret Line="33" Column="23" TopLine="5"/>
+        <Caret Line="757" Column="3" TopLine="753"/>
       </Position4>
       <Position5>
-        <Filename Value="systables.pas"/>
-        <Caret Line="55" Column="85" TopLine="27"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="338" Column="37" TopLine="332"/>
       </Position5>
       <Position6>
-        <Filename Value="systables.pas"/>
-        <Caret Line="251" Column="44" TopLine="236"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="362" Column="35" TopLine="329"/>
       </Position6>
       <Position7>
-        <Filename Value="systables.pas"/>
-        <Caret Line="252" Column="4" TopLine="251"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="86" Column="19" TopLine="76"/>
       </Position7>
       <Position8>
-        <Filename Value="systables.pas"/>
-        <Caret Line="253" Column="52" TopLine="252"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="353" Column="25" TopLine="335"/>
       </Position8>
       <Position9>
-        <Filename Value="systables.pas"/>
-        <Caret Line="310" Column="8" TopLine="280"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="397" Column="37" TopLine="369"/>
       </Position9>
       <Position10>
-        <Filename Value="systables.pas"/>
-        <Caret Line="252" Column="43" TopLine="245"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="426" Column="31" TopLine="396"/>
       </Position10>
       <Position11>
-        <Filename Value="systables.pas"/>
-        <Caret Line="320" Column="37" TopLine="287"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="435" Column="27" TopLine="409"/>
       </Position11>
       <Position12>
-        <Filename Value="systables.pas"/>
-        <Caret Line="255" Column="1" TopLine="238"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="453" Column="37" TopLine="425"/>
       </Position12>
       <Position13>
-        <Filename Value="systables.pas"/>
-        <Caret Line="286" Column="40" TopLine="269"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="485" Column="30" TopLine="457"/>
       </Position13>
       <Position14>
-        <Filename Value="systables.pas"/>
-        <Caret Line="15" Column="18" TopLine="1"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="51" Column="37" TopLine="38"/>
       </Position14>
       <Position15>
-        <Filename Value="systables.pas"/>
-        <Caret Line="288" Column="1" TopLine="269"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="365" Column="3" TopLine="363"/>
       </Position15>
       <Position16>
-        <Filename Value="systables.pas"/>
-        <Caret Line="28" Column="1" TopLine="18"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="364" Column="1" TopLine="351"/>
       </Position16>
       <Position17>
-        <Filename Value="systables.pas"/>
-        <Caret Line="32" Column="14" TopLine="18"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="52" Column="35" TopLine="24"/>
       </Position17>
       <Position18>
-        <Filename Value="systables.pas"/>
-        <Caret Line="33" Column="113" TopLine="16"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="379" Column="16" TopLine="375"/>
       </Position18>
       <Position19>
-        <Filename Value="scriptdb.pas"/>
-        <Caret Line="419" Column="22" TopLine="397"/>
+        <Filename Value="neweditfield.pas"/>
+        <Caret Line="169" Column="3" TopLine="168"/>
       </Position19>
       <Position20>
-        <Filename Value="scriptdb.pas"/>
-        <Caret Line="410" Column="47" TopLine="393"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="408" Column="18" TopLine="379"/>
       </Position20>
       <Position21>
-        <Filename Value="systables.pas"/>
-        <Caret Line="29" Column="54" TopLine="12"/>
+        <Filename Value="main.pas"/>
+        <Caret Line="2366" Column="1" TopLine="2308"/>
       </Position21>
       <Position22>
-        <Filename Value="systables.pas"/>
-        <Caret Line="256" Column="67" TopLine="256"/>
+        <Filename Value="main.pas"/>
+        <Caret Line="1" Column="1" TopLine="1"/>
       </Position22>
       <Position23>
-        <Filename Value="systables.pas"/>
-        <Caret Line="257" Column="4" TopLine="256"/>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="416" Column="35" TopLine="383"/>
       </Position23>
       <Position24>
         <Filename Value="comparison.pas"/>
-        <Caret Line="317" Column="32" TopLine="303"/>
+        <Caret Line="230" Column="7" TopLine="230"/>
       </Position24>
       <Position25>
         <Filename Value="comparison.pas"/>
-        <Caret Line="246" Column="40" TopLine="221"/>
+        <Caret Line="275" Column="10" TopLine="257"/>
       </Position25>
       <Position26>
         <Filename Value="comparison.pas"/>
-        <Caret Line="97" Column="55" TopLine="67"/>
+        <Caret Line="285" Column="4" TopLine="268"/>
       </Position26>
       <Position27>
         <Filename Value="comparison.pas"/>
-        <Caret Line="255" Column="27" TopLine="231"/>
+        <Caret Line="398" Column="45" TopLine="381"/>
       </Position27>
       <Position28>
         <Filename Value="comparison.pas"/>
-        <Caret Line="248" Column="43" TopLine="235"/>
+        <Caret Line="410" Column="9" TopLine="402"/>
       </Position28>
       <Position29>
         <Filename Value="comparison.pas"/>
-        <Caret Line="217" Column="7" TopLine="176"/>
+        <Caret Line="130" Column="23" TopLine="116"/>
       </Position29>
+      <Position30>
+        <Filename Value="comparison.pas"/>
+        <Caret Line="114" Column="20" TopLine="107"/>
+      </Position30>
     </JumpHistory>
   </ProjectOptions>
   <CompilerOptions>

+ 1 - 1
TurboBird.lpr

@@ -2,7 +2,7 @@
 {  TurboBird: FireBird database administration and management tool          }
 {  Developed by: Motaz Abdel Azeem http://code.sd/                          }
 {  Start development :  5.Dec.2009                                          }
-{  Last updated      : 14.May.2012                                          }
+{  Last updated      : 15.May.2012                                          }
 {  License           : GPL for GUI, LGPL for Units                          }
 {***************************************************************************}
 

+ 1 - 0
comparison.lfm

@@ -70,6 +70,7 @@ object fmComparison: TfmComparison
     Top = 226
     Width = 603
     Anchors = [akTop, akLeft, akRight, akBottom]
+    Font.Name = 'Courier 10 Pitch'
     Font.Style = [fsUnderline]
     ParentFont = False
     ReadOnly = True

+ 246 - 87
comparison.pas

@@ -6,7 +6,7 @@ interface
 
 uses
   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
-  Buttons, IBConnection, sqldb;
+  Buttons, IBConnection, sqldb, QueryWindow;
 
 const
   dbObjects: array [1 .. 13] of string = ('Tables', 'Generators', 'Triggers', 'Views', 'Stored Procedures', 'UDFs',
@@ -42,7 +42,15 @@ type
   private
     fdbIndex: Integer;
     dbObjectsList: array [1 .. 13] of TStringList;
-    { private declarations }
+    dbExistingObjectsList: array [1 .. 13] of TStringList;
+    MissingFieldsList: TStringList;
+    fQueryWindow: TfmQueryWindow;
+    procedure CheckMissingIndices;
+    procedure CheckMissingConstraints;
+    procedure CheckMissingDBObjects;
+    procedure CheckMissingFields;
+    procedure InitializeQueryWindow;
+    procedure ScriptMissingFields;
   public
     procedure Init(dbIndex: Integer);
     { public declarations }
@@ -57,7 +65,7 @@ implementation
 
 { TfmComparison }
 
-uses Main, SysTables, Scriptdb, QueryWindow;
+uses Main, SysTables, Scriptdb;
 
 procedure TfmComparison.cbComparedDatabaseChange(Sender: TObject);
 begin
@@ -69,12 +77,31 @@ begin
   end;
 end;
 
+procedure TfmComparison.bbStartClick(Sender: TObject);
+begin
+  CheckMissingDBObjects;
+
+  if cxTables.Checked then
+    CheckMissingIndices;
+
+  if cxTables.Checked then
+    CheckMissingConstraints;
+
+  if cxTables.Checked then
+    CheckMissingFields;
+end;
+
 procedure TfmComparison.FormClose(Sender: TObject; var CloseAction: TCloseAction);
 var
   i: Integer;
 begin
   for i:= 1 to High(dbObjectsList) do
     dbObjectsList[i].Free;
+
+  for i:= 1 to High(dbExistingObjectsList) do
+    dbExistingObjectsList[i].Free;
+
+  MissingFieldsList.Free;
 end;
 
 procedure TfmComparison.laScriptClick(Sender: TObject);
@@ -82,7 +109,6 @@ var
   x: Integer;
   i: Integer;
   ScriptList: TStringList;
-  QueryWindow: TfmQueryWindow;
   ViewBody: string;
   Columns: string;
   SPOwner: string;
@@ -96,14 +122,18 @@ var
   KeyName, CurrentTableName, CurrentFieldName,
   OtherTableName, OtherFieldName, UpdateRule, DeleteRule: string;
 begin
+  InitializeQueryWindow;
   meLog.Clear;
   ScriptList:= TStringList.Create;
   FieldsList:= TStringList.Create;
 
-  QueryWindow:= fmMain.ShowQueryWindow(cbComparedDatabase.ItemIndex, 'Database Differences');
-  QueryWindow.meQuery.ClearAll;
+  ScriptMissingFields;
+
   dmSysTables.Init(fdbIndex);
 
+  fQueryWindow.meQuery.Lines.Add('');
+  fQueryWindow.meQuery.Lines.Add('-- Missing db Objects');
+
   for x:= 1 to 13 do
   begin
     if (x = 1) and cxTables.Checked then // Tables
@@ -112,8 +142,8 @@ begin
       ScriptList.Clear;
       Scriptdb.ScriptTableAsCreate(fdbIndex, dbObjectsList[x].Strings[i], ScriptList);
 
-      QueryWindow.meQuery.Lines.AddStrings(ScriptList);
-      QueryWindow.meQuery.Lines.Add('');
+      fQueryWindow.meQuery.Lines.AddStrings(ScriptList);
+      fQueryWindow.meQuery.Lines.Add('');
     end
     else
     if (x = 2) and cxGenerators.Checked then // Generators
@@ -121,8 +151,8 @@ begin
     begin
       ScriptList.Clear;
 
-      QueryWindow.meQuery.Lines.Add('create generator ' + dbObjectsList[x].Strings[i] + ';');
-      QueryWindow.meQuery.Lines.Add('');
+      fQueryWindow.meQuery.Lines.Add('create generator ' + dbObjectsList[x].Strings[i] + ';');
+      fQueryWindow.meQuery.Lines.Add('');
     end
     else
     if (x = 3) and cxTriggers.Checked then // Triggers
@@ -131,8 +161,8 @@ begin
       ScriptList.Clear;
       dmSysTables.ScriptTrigger(fdbIndex, dbObjectsList[x].Strings[i], ScriptList, True);
 
-      QueryWindow.meQuery.Lines.AddStrings(ScriptList);
-      QueryWindow.meQuery.Lines.Add('');
+      fQueryWindow.meQuery.Lines.AddStrings(ScriptList);
+      fQueryWindow.meQuery.Lines.Add('');
     end
     else
     if (x = 4) and cxViews.Checked then // Views
@@ -141,12 +171,12 @@ begin
       fmMain.GetViewInfo(fdbIndex, dbObjectsList[x].Strings[i], Columns, ViewBody);
       ScriptList.Text:= Trim(ViewBody);
 
-      QueryWindow.meQuery.Lines.Add('CREATE VIEW "' + dbObjectsList[x].Strings[i] + '" (' + Columns + ')');
-      QueryWindow.meQuery.Lines.Add('AS');
+      fQueryWindow.meQuery.Lines.Add('CREATE VIEW "' + dbObjectsList[x].Strings[i] + '" (' + Columns + ')');
+      fQueryWindow.meQuery.Lines.Add('AS');
       ScriptList.Text:= Trim(ViewBody);
-      QueryWindow.meQuery.Lines.AddStrings(ScriptList);
-      QueryWindow.meQuery.Lines.Add(' ;');
-      QueryWindow.meQuery.Lines.Add('');
+      fQueryWindow.meQuery.Lines.AddStrings(ScriptList);
+      fQueryWindow.meQuery.Lines.Add(' ;');
+      fQueryWindow.meQuery.Lines.Add('');
     end
     else
     if (x = 5) and cxStoredProcs.Checked then // Stored proc
@@ -159,8 +189,8 @@ begin
       ScriptList.Add('SET TERM ; ^');
       ScriptList.Add('');
 
-      QueryWindow.meQuery.Lines.AddStrings(ScriptList);
-      QueryWindow.meQuery.Lines.Add('');
+      fQueryWindow.meQuery.Lines.AddStrings(ScriptList);
+      fQueryWindow.meQuery.Lines.Add('');
     end
     else
     if (x = 6) and cxUDFs.Checked then // UDF
@@ -176,7 +206,7 @@ begin
         ScriptList.Add('MODULE_NAME ''' + ModuleName + ''';');
         ScriptList.Add('');
       end;
-      QueryWindow.meQuery.Lines.AddStrings(ScriptList);
+      fQueryWindow.meQuery.Lines.AddStrings(ScriptList);
     end
     else
     if (x = 8) and cxDomains.Checked then // Domains
@@ -189,16 +219,16 @@ begin
           Line:= Line + '(' + IntToStr(DomainSize) + ')';
         Line:= Line + ' ' + DefaultValue + ';';
 
-      QueryWindow.meQuery.Lines.Add(Line);
-      QueryWindow.meQuery.Lines.Add('');
+      fQueryWindow.meQuery.Lines.Add(Line);
+      fQueryWindow.meQuery.Lines.Add('');
     end
     else
     if (x = 9) and cxRoles.Checked then // Roles
     for i:= 0 to dbObjectsList[x].Count - 1 do
     begin
       ScriptList.Clear;
-      QueryWindow.meQuery.Lines.Add('create role ' + dbObjectsList[x].Strings[i] + ';');
-      QueryWindow.meQuery.Lines.Add('');
+      fQueryWindow.meQuery.Lines.Add('create role ' + dbObjectsList[x].Strings[i] + ';');
+      fQueryWindow.meQuery.Lines.Add('');
     end
     else
     if (x = 12) and cxTables.Checked then // Indices
@@ -221,8 +251,8 @@ begin
 
         Line:= Line + ' (' + FieldsList.CommaText + ') ;';
 
-        QueryWindow.meQuery.Lines.Add(Line);
-        QueryWindow.meQuery.Lines.Add('');
+        fQueryWindow.meQuery.Lines.Add(Line);
+        fQueryWindow.meQuery.Lines.Add('');
       end;
 
     end
@@ -246,8 +276,8 @@ begin
         if Trim(DeleteRule) <> 'RESTRICT' then
           Line:= Line + ' on delete ' + Trim(DeleteRule);
 
-        QueryWindow.meQuery.Lines.Add(Line);
-        QueryWindow.meQuery.Lines.Add('');
+        fQueryWindow.meQuery.Lines.Add(Line);
+        fQueryWindow.meQuery.Lines.Add('');
       end;
 
 
@@ -257,21 +287,18 @@ begin
   end;
 
 
-  QueryWindow.Show;
+  fQueryWindow.Show;
   ScriptList.Free;
   FieldsList.Free;
   Close;
 
 end;
 
-procedure TfmComparison.bbStartClick(Sender: TObject);
+procedure TfmComparison.CheckMissingDBObjects;
 var
   List, ComparedList: TStringList;
   Count: Integer;
   x, i, j: Integer;
-  TablesList: TStringList;
-  PrimaryIndexName: string;
-  ConstraintName: string;
 begin
   List:= TStringList.Create;
   ComparedList:= TStringList.Create;
@@ -289,30 +316,167 @@ begin
      ((x = 11) and cxUsers.Checked) then
   begin
     meLog.Lines.Add('');
-    meLog.Lines.Add(dbObjects[x] + ':');
+    meLog.Lines.Add('Missing ' + dbObjects[x] + ':');
 
     List.CommaText:= dmSysTables.GetDBObjectNames(fdbIndex, x, Count);
 
     ComparedList.CommaText:= dmSysTables.GetDBObjectNames(cbComparedDatabase.ItemIndex, x, Count);
     dbObjectsList[x].Clear;
+    dbExistingObjectsList[x].Clear;
     for i:= 0 to List.Count -1 do
-    if ComparedList.IndexOf(List[i]) = -1 then
+    if ComparedList.IndexOf(List[i]) = -1 then  // Not exist
     begin
-      meLog.Lines.Add('Missing : ' + List[i]);
+      meLog.Lines.Add(' ' + List[i]);
       dbObjectsList[x].Add(List[i]);
+    end
+    else                                        // Exist
+      dbExistingObjectsList[x].Add(List[i]);
+
+  end;
+
+
+  meLog.Visible:= True;
+  laScript.Enabled:= True;
+  ComparedList.Free;
+  List.Free;
+end;
+
+procedure TfmComparison.CheckMissingFields;
+var
+  i, j: Integer;
+  FieldsList: TStringList;
+  ComparedList: TStringList;
+begin
+  FieldsList:= TStringList.Create;
+  ComparedList:= TStringList.Create;
+  meLog.Lines.Add('');
+  meLog.Lines.Add('Missing fields');
+  MissingFieldsList.Clear;
+  for i:= 0 to dbExistingObjectsList[1].Count - 1 do
+  begin
+    dmSysTables.GetTableFields(fdbIndex, dbExistingObjectsList[1].Strings[i], FieldsList);
+    dmSysTables.GetTableFields(cbComparedDatabase.ItemIndex, dbExistingObjectsList[1].Strings[i], ComparedList);
+
+    // Get missing fields
+    for j:= 0 to FieldsList.Count - 1 do
+      if ComparedList.IndexOf(FieldsList[j]) = -1 then
+      begin
+        meLog.Lines.Add(' ' + dbExistingObjectsList[1].Strings[i] + ': ' + FieldsList[j]);
+        MissingFieldsList.Add(dbExistingObjectsList[1].Strings[i] + ',' + FieldsList[j]);
+      end;
+  end;
+
+  FieldsList.Free;
+  ComparedList.Free;
+
+end;
+
+procedure TfmComparison.InitializeQueryWindow;
+begin
+  fQueryWindow:= fmMain.ShowQueryWindow(cbComparedDatabase.ItemIndex, 'Database Differences');
+  fQueryWindow.meQuery.ClearAll;
+end;
+
+procedure TfmComparison.ScriptMissingFields;
+var
+  i: Integer;
+  ATableName, AFieldName: string;
+  Line: string;
+  FieldSize: Integer;
+  IsNull: Integer;
+  DefaultValue, Description: string;
+  FieldType: string;
+begin
+  fQueryWindow.meQuery.Lines.Add('');
+  fQueryWindow.meQuery.Lines.Add('-- Missing fields');
+  for i:= 0 to MissingFieldsList.Count - 1 do
+  begin
+    Line:= MissingFieldsList[i];
+    ATableName:= copy(Line, 1, Pos(',', Line) - 1);
+    System.Delete(Line, 1, Pos(',', Line));
+    AFieldName:= Line;
+    dmSysTables.GetFieldInfo(fdbIndex, ATableName, AFieldName, FieldType, FieldSize, IsNull, DefaultValue, Description);
+
+    // Script new field
+    Line:= FieldType;
+    if Pos('CHAR', Line) > 0 then
+      Line:= Line + '(' + IntToStr(FieldSize) + ')';
+
+    // Default value
+    if Trim(DefaultValue) <> '' then
+    begin
+      if (Pos('CHAR', FieldType) > 0) and (Pos('''', DefaultValue) = 0) then
+        Line:= Line + ' ''' + DefaultValue + ''''
+      else
+        Line:= Line + ' ' + DefaultValue;
     end;
 
+    // Null/Not null
+    if IsNull = 1 then
+      Line:= Line + ' not null';
+
+    fQueryWindow.meQuery.Lines.Add('ALTER TABLE ' + ATableName + ' ADD ' + AFieldName + ' ' + Line + ';');
+
   end;
 
-  if cxTables.Checked then
+end;
+
+procedure TfmComparison.Init(dbIndex: Integer);
+var
+  i: Integer;
+  Servername: string;
+begin
+  cxTables.Checked:= True;
+  cxGenerators.Checked:= True;
+  cxDomains.Checked:= True;
+  cxStoredProcs.Checked:= True;
+  cxViews.Checked:= True;
+  cxUDFs.Checked:= True;
+  cxTriggers.Checked:= True;
+  cxRoles.Checked:= True;
+  cxUsers.Checked:= False;
+
+  laScript.Enabled:= False;
+  laComparedDatabase.Caption:= '[]';
+  fdbIndex:= dbIndex;
+  bbStart.Enabled:= False;
+  with fmMain.RegisteredDatabases[dbIndex].RegRec do
+  laDatabase.Caption:= Title + ' (' + DatabaseName + ')';
+  cbComparedDatabase.Items.Clear;
+  for i:= 0 to High(fmMain.RegisteredDatabases) do
   begin
-    TablesList:= TStringList.Create;
-    TablesList.CommaText:= dmSysTables.GetDBObjectNames(fdbIndex, 1, Count);
+    Servername:= fmMain.GetServerName(fmMain.RegisteredDatabases[i].RegRec.DatabaseName);
+    cbComparedDatabase.Items.Add(ServerName + '-' + fmMain.RegisteredDatabases[i].RegRec.Title);
+  end;
 
-    // Indices
-    meLog.Lines.Add('');
-    meLog.Lines.Add('Indices:');
-    dbObjectsList[12].Clear;
+  for i:= 1 to High(dbObjectsList) do
+    dbObjectsList[i]:= TStringList.Create;
+
+  for i:= 1 to High(dbExistingObjectsList) do
+    dbExistingObjectsList[i]:= TStringList.Create;
+
+  MissingFieldsList:= TStringList.Create;
+
+end;
+
+procedure TfmComparison.CheckMissingIndices;
+var
+  i, j: Integer;
+  List, ComparedList: TStringList;
+  TablesList: TStringList;
+  PrimaryIndexName: string;
+  ConstraintName: string;
+  Count: Integer;
+begin
+  List:= TStringList.Create;
+  ComparedList:= TStringList.Create;
+  TablesList:= TStringList.Create;
+  TablesList.CommaText:= dmSysTables.GetDBObjectNames(fdbIndex, 1, Count);
+
+  meLog.Lines.Add('');
+  meLog.Lines.Add('Missing Indices:');
+  dbObjectsList[12].Clear;
+  try
     for i:= 0 to TablesList.Count - 1 do
     begin
       PrimaryIndexName:= dmSysTables.GetPrimaryKeyIndexName(fdbIndex, TablesList[i], ConstraintName);
@@ -324,7 +488,7 @@ begin
         for j:= 0 to List.Count - 1 do
           if ComparedList.IndexOf(List[j]) = -1 then
           begin
-            meLog.Lines.Add('Missing: ' + List[j]);
+            meLog.Lines.Add(' ' + List[j]);
             dbObjectsList[12].Add(TablesList[i] + ',' + List[j]);
           end
       end
@@ -333,18 +497,42 @@ begin
       for j:= 0 to List.Count - 1 do
       begin
         dbObjectsList[12].Add(TablesList[i] + ',' + List[j]);
-        meLog.Lines.Add('Missing: ' + List[j]);
+        meLog.Lines.Add(' ' + List[j]);
       end;
 
     end;
 
-    // Constraints
-    meLog.Lines.Add('');
-    meLog.Lines.Add('Constraints:');
+
+  except
+  on e: exception do
+  begin
+    meLog.Lines.Add('---- Error while comparing indices: ' + e.Message);
+  end;
+  end;
+  List.Free;
+  ComparedList.Free;
+  TablesList.Free;
+
+end;
+
+procedure TfmComparison.CheckMissingConstraints;
+var
+  i, j: Integer;
+  List, ComparedList: TStringList;
+  TablesList: TStringList;
+  Count: Integer;
+begin
+  List:= TStringList.Create;
+  ComparedList:= TStringList.Create;
+  TablesList:= TStringList.Create;
+  TablesList.CommaText:= dmSysTables.GetDBObjectNames(fdbIndex, 1, Count);
+
+  meLog.Lines.Add('');
+  meLog.Lines.Add('Missing Constraints:');
+  try
     dbObjectsList[13].Clear;
     for i:= 0 to TablesList.Count - 1 do
     begin
-      PrimaryIndexName:= dmSysTables.GetPrimaryKeyIndexName(fdbIndex, TablesList[i], ConstraintName);
       dmSysTables.Init(fdbIndex);
       List.Clear;
       dmSysTables.GetTableConstraints(TablesList[i], dmSysTables.sqQuery, List);
@@ -359,7 +547,7 @@ begin
         for j:= 0 to List.Count - 1 do
           if ComparedList.IndexOf(List[j]) = -1 then
           begin
-            meLog.Lines.Add('Missing: ' + List[j]);
+            meLog.Lines.Add(' ' + List[j]);
             dbObjectsList[13].Add(TablesList[i] + ',' + List[j]);
           end
       end
@@ -368,51 +556,22 @@ begin
       for j:= 0 to List.Count - 1 do
       begin
         dbObjectsList[13].Add(TablesList[i] + ',' + List[j]);
-        meLog.Lines.Add('Missing: ' + List[j]);
+        meLog.Lines.Add(' ' + List[j]);
       end;
 
     end;
 
 
-    TablesList.Free;
-  end;
-
-  meLog.Visible:= True;
-  laScript.Enabled:= True;
-  ComparedList.Free;
-  List.Free;
-end;
-
-procedure TfmComparison.Init(dbIndex: Integer);
-var
-  i: Integer;
-  Servername: string;
-begin
-  cxTables.Checked:= True;
-  cxGenerators.Checked:= True;
-  cxDomains.Checked:= True;
-  cxStoredProcs.Checked:= True;
-  cxViews.Checked:= True;
-  cxUDFs.Checked:= True;
-  cxTriggers.Checked:= True;
-  cxRoles.Checked:= True;
-  cxUsers.Checked:= False;
-
-  laScript.Enabled:= False;
-  laComparedDatabase.Caption:= '[]';
-  fdbIndex:= dbIndex;
-  bbStart.Enabled:= False;
-  with fmMain.RegisteredDatabases[dbIndex].RegRec do
-  laDatabase.Caption:= Title + ' (' + DatabaseName + ')';
-  cbComparedDatabase.Items.Clear;
-  for i:= 0 to High(fmMain.RegisteredDatabases) do
+  except
+  on e: exception do
   begin
-    Servername:= fmMain.GetServerName(fmMain.RegisteredDatabases[i].RegRec.DatabaseName);
-    cbComparedDatabase.Items.Add(ServerName + '-' + fmMain.RegisteredDatabases[i].RegRec.Title);
+    meLog.Lines.Add('---- Error while comparing constraints: ' + e.Message);
+  end;
   end;
 
-  for i:= 1 to High(dbObjectsList) do
-    dbObjectsList[i]:= TStringList.Create;
+  List.Free;
+  ComparedList.Free;
+  TablesList.Free;
 
 end;
 

+ 65 - 8
systables.pas

@@ -62,6 +62,9 @@ type
     function GetIndexInfo(dbIndex: Integer; ATableName, AIndexName: string;
       var FieldsList: TStringList; var Unique, Ascending: Boolean): Boolean;
 
+    procedure GetTableFields(dbIndex: Integer; ATableName: string; FieldsList: TStringList);
+
+
     { public declarations }
   end; 
 
@@ -720,14 +723,15 @@ begin
   Init(dbIndex);
   sqQuery.Close;
   sqQuery.SQL.Text:= 'SELECT RDB$Indices.*, RDB$INDEX_SEGMENTS.RDB$FIELD_NAME AS field_name, ' + #10 +
-     'RDB$INDICES.RDB$DESCRIPTION AS description, ' +#10 +
-     '(RDB$INDEX_SEGMENTS.RDB$FIELD_POSITION + 1) AS field_position ' +#10 +
-     'FROM RDB$INDEX_SEGMENTS ' +#10 +
-     'LEFT JOIN RDB$INDICES ON RDB$INDICES.RDB$INDEX_NAME = RDB$INDEX_SEGMENTS.RDB$INDEX_NAME ' +#10 +
-     'LEFT JOIN RDB$RELATION_CONSTRAINTS ON RDB$RELATION_CONSTRAINTS.RDB$INDEX_NAME = RDB$INDEX_SEGMENTS.RDB$INDEX_NAME ' +#10 +
-     ' WHERE UPPER(RDB$INDICES.RDB$RELATION_NAME)=''' + UpperCase(ATablename) + '''         -- table name ' +#10 +
-     '  AND UPPER(RDB$INDICES.RDB$INDEX_NAME)=''' + UpperCase(AIndexName) + ''' -- index name ' +#10 +
-     '--  AND RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_TYPE IS NULL ' +#10 +
+     'RDB$INDICES.RDB$DESCRIPTION AS description, ' + #10 +
+     '(RDB$INDEX_SEGMENTS.RDB$FIELD_POSITION + 1) AS field_position ' + #10 +
+     'FROM RDB$INDEX_SEGMENTS ' + #10 +
+     'LEFT JOIN RDB$INDICES ON RDB$INDICES.RDB$INDEX_NAME = RDB$INDEX_SEGMENTS.RDB$INDEX_NAME ' + #10 +
+     'LEFT JOIN RDB$RELATION_CONSTRAINTS ON RDB$RELATION_CONSTRAINTS.RDB$INDEX_NAME = RDB$INDEX_SEGMENTS.RDB$INDEX_NAME '
+     + #10 +
+     ' WHERE UPPER(RDB$INDICES.RDB$RELATION_NAME)=''' + UpperCase(ATablename) + '''         -- table name ' + #10 +
+     '  AND UPPER(RDB$INDICES.RDB$INDEX_NAME)=''' + UpperCase(AIndexName) + ''' -- index name ' + #10 +
+     '--  AND RDB$RELATION_CONSTRAINTS.RDB$CONSTRAINT_TYPE IS NULL ' + #10 +
      'ORDER BY RDB$INDEX_SEGMENTS.RDB$FIELD_POSITION;';
   sqQuery.Open;
   Result:= sqQuery.FieldCount > 0;
@@ -746,6 +750,59 @@ begin
   sqQuery.Close;
 end;
 
+procedure TdmSysTables.GetTableFields(dbIndex: Integer; ATableName: string; FieldsList: TStringList);
+var
+  FieldName: string;
+begin
+  Init(dbIndex);
+  sqQuery.SQL.Text:= 'SELECT r.RDB$FIELD_NAME AS field_name, ' +
+      '  r.RDB$DESCRIPTION AS field_description, ' +
+      '  r.RDB$DEFAULT_SOURCE AS field_default_value, ' +
+      '  r.RDB$NULL_FLAG AS field_not_null_constraint, ' +
+      '  f.RDB$FIELD_LENGTH AS field_length, ' +
+      '  f.RDB$FIELD_PRECISION AS field_precision, ' +
+      '  f.RDB$FIELD_SCALE AS field_scale, ' +
+      '  f.RDB$FIELD_TYPE as Field_Type_Int, ' +
+      '  CASE f.RDB$FIELD_TYPE ' +
+      '    WHEN 261 THEN ''BLOB'' ' +
+      '    WHEN 14 THEN ''CHAR'' ' +
+      '    WHEN 40 THEN ''CSTRING''  ' +
+      '    WHEN 11 THEN ''D_FLOAT'' ' +
+      '    WHEN 27 THEN ''DOUBLE Precision'' ' +
+      '    WHEN 10 THEN ''FLOAT'' ' +
+      '    WHEN 16 THEN ''BIGINT'' ' +
+      '    WHEN 8 THEN ''INTEGER'' ' +
+      '    WHEN 9 THEN ''QUAD'' ' +
+      '    WHEN 7 THEN ''SMALLINT'' ' +
+      '    WHEN 12 THEN ''DATE'' ' +
+      '    WHEN 13 THEN ''TIME'' ' +
+      '    WHEN 35 THEN ''TIMESTAMP'' ' +
+      '    WHEN 37 THEN ''VARCHAR'' ' +
+      '    ELSE ''UNKNOWN'' ' +
+      '  END AS field_type_Str, ' +
+      '  f.RDB$FIELD_SUB_TYPE AS field_subtype, ' +
+      '  coll.RDB$COLLATION_NAME AS field_collation, ' +
+      '  cset.RDB$CHARACTER_SET_NAME AS field_charset, ' +
+      ' f.RDB$COMPUTED_Source AS Computed_Source ' +
+      ' FROM RDB$RELATION_FIELDS r ' +
+      ' LEFT JOIN RDB$FIELDS f ON r.RDB$FIELD_SOURCE = f.RDB$FIELD_NAME ' +
+      ' LEFT JOIN RDB$COLLATIONS coll ON f.RDB$COLLATION_ID = coll.RDB$COLLATION_ID ' +
+      ' LEFT JOIN RDB$CHARACTER_SETS cset ON f.RDB$CHARACTER_SET_ID = cset.RDB$CHARACTER_SET_ID ' +
+      ' WHERE r.RDB$RELATION_NAME=''' + ATableName + '''  ' +
+      ' ORDER BY r.RDB$FIELD_POSITION;';
+
+    sqQuery.Open;
+    FieldsList.Clear;
+    while not sqQuery.EOF do
+    begin
+      FieldName:= Trim(sqQuery.FieldByName('field_name').AsString);
+      if FieldsList.IndexOf(FieldName) = -1 then
+        FieldsList.Add(FieldName);
+      sqQuery.Next;
+    end;
+    sqQuery.Close;
+end;
+
 initialization
   {$I systables.lrs}