Переглянути джерело

Comparison: add support for scripting missing indices. Should fix issue #28

Reinier Olislagers 11 роки тому
батько
коміт
f7259f9753
3 змінених файлів з 115 додано та 22 видалено
  1. 99 21
      comparison.pas
  2. 4 0
      scriptdb.pas
  3. 12 1
      turbocommon.pas

+ 99 - 21
comparison.pas

@@ -101,6 +101,9 @@ type
     procedure InitializeQueryWindow;
 
     procedure ScriptMissingFields;
+    // Script missing indexes as CREATE INDEX (no primary key or other constraints)
+    // Requires missing objects to be set up first
+    procedure ScriptMissingIndexes;
 
     procedure ScriptModifiedFields;
     procedure ScriptModifiedIndices;
@@ -139,7 +142,7 @@ begin
   ComparedDBIndex:= cbComparedDatabase.ItemIndex;
   if ComparedDBIndex = FDBIndex then
   begin
-    ShowMessage('Could not compare database with it self');
+    ShowMessage('Cannot compare database with itself');
     cbComparedDatabase.ItemIndex:= -1;
   end
   else
@@ -614,8 +617,15 @@ begin
     ScriptList.Free;
     FieldsList.Free;
   end;
-  FQueryWindow.Show;
 
+  // Missing indices may have dependencies on tables created in block above,
+  // so wait until now to create them
+  if cxTables.Checked then
+  begin
+    ScriptMissingIndexes;
+  end;
+
+  FQueryWindow.Show;
 end;
 
 procedure TfmComparison.DisplayStatus(AStatus: string);
@@ -1354,6 +1364,72 @@ begin
   end;
 end;
 
+procedure TfmComparison.ScriptMissingIndexes;
+//todo: move create index script to generic function e.g. in SysTables or turbocommon
+var
+  i: integer;
+  FldCount: integer;
+  TableName, IndexName: string;
+  Line: string;
+  FieldsList: TStringList;
+  ConstraintName: string;
+  Unique, Ascending, IsPrimary: boolean;
+begin
+  // Missing indexes are stored in
+  // FDBObjectsList[ord(otIndexes)] as Table,IndexName
+  if FDBObjectsList[ord(otIndexes)].Count > 0 then
+  begin
+    FQueryWindow.meQuery.Lines.Add('');
+    FQueryWindow.meQuery.Lines.Add('-- Missing indices');
+  end;
+
+  FieldsList:= TStringList.Create;
+  try
+    for i:= 0 to FDBObjectsList[ord(otIndexes)].Count - 1 do
+    begin
+      Line:= FDBObjectsList[ord(otIndexes)][i];
+      TableName:= copy(Line, 1, Pos(',', Line) - 1);
+      System.Delete(Line, 1, Pos(',', Line));
+      IndexName:= Line;
+
+      // Try to avoid auto-generated primary key indexes. When creating a unique
+      // primary key, the index will be autogenerated once the create table script
+      // is run. Todo: verify this
+      if IsPrimaryIndexSystemGenerated(IndexName) then
+      begin
+        Line:= '-- Not scripting auto-generated primary key index ' +
+           IndexName + ' (on table ' + TableName + ')';
+      end
+      else
+      begin
+        FieldsList.Clear;
+        dmSysTables.GetIndexInfo(FDBIndex, TableName, IndexName,
+          FieldsList, ConstraintName, Unique, Ascending, IsPrimary);
+
+        // Script new index
+        Line:= 'CREATE ';
+        if Unique then
+          Line:= Line + 'UNIQUE ';
+        if not(Ascending) then
+          Line:= Line + 'DESCENDING ';
+        Line:= Line + 'INDEX ' + IndexName + ' ON ' + TableName + ' (';
+        // Add all fields in list
+        for FldCount:= 0 to FieldsList.Count-1 do
+        begin
+          if FldCount = FieldsList.Count-1 then
+            Line:= Line + FieldsList[i]
+          else
+            Line:= Line + FieldsList[i] + ', ';
+        end;
+        Line:= Line + '); ';
+      end;
+      FQueryWindow.meQuery.Lines.Add(Line);
+    end;
+  finally
+    FieldsList.Free;
+  end;
+end;
+
 procedure TfmComparison.ScriptModifiedFields;
 var
   i: Integer;
@@ -1476,7 +1552,7 @@ begin
       begin
         if IsPrimary then
         begin
-          FQueryWindow.meQuery.Lines.Add('alter table AAAA DROP constraint ' + ConstraintName + ';');
+          FQueryWindow.meQuery.Lines.Add('alter table ' + ATableName + ' DROP constraint ' + ConstraintName + ';');
 
           Line:= 'alter table ' + ATableName + LineEnding +
           'add constraint ' + AIndexName + LineEnding +
@@ -1963,11 +2039,11 @@ end;
 procedure TfmComparison.CheckMissingIndices;
 var
   i, j: Integer;
-  List, ComparedList: TStringList;
+  IndexList, ComparedList: TStringList;
   TablesList: TStringList;
   Count: Integer;
 begin
-  List:= TStringList.Create;
+  IndexList:= TStringList.Create;
   ComparedList:= TStringList.Create;
   TablesList:= TStringList.Create;
   try
@@ -1978,46 +2054,48 @@ begin
     FDBObjectsList[ord(otIndexes)].Clear;
     FExistIndicesList.Clear;
     try
+      // Go through each table and compare indexes:
       for i:= 0 to TablesList.Count - 1 do
       begin
-
         // Check for cancel button press
         Application.ProcessMessages;
         if FCanceled then
           Exit;
 
-        List.Clear;
-        dmSysTables.GetIndices(FDBIndex, TablesList[i], '', List);
+        IndexList.Clear;
+        dmSysTables.GetIndices(FDBIndex, TablesList[i], '', IndexList);
         ComparedList.Clear;
         if dmSysTables.GetIndices(cbComparedDatabase.ItemIndex, TablesList[i], '', ComparedList) then
         begin
-          for j:= 0 to List.Count - 1 do
-            if ComparedList.IndexOf(List[j]) = -1 then // Add to missing indices
+          for j:= 0 to IndexList.Count - 1 do
+            if ComparedList.IndexOf(IndexList[j]) = -1 then // Add to missing indices
             begin
-              meLog.Lines.Add(' ' + List[j]);
-              FDBObjectsList[ord(otIndexes)].Add(TablesList[i] + ',' + List[j]);
+              meLog.Lines.Add(' ' + IndexList[j]);
+              FDBObjectsList[ord(otIndexes)].Add(TablesList[i] + ',' + IndexList[j]);
               Inc(FDiffCount);
             end
             else
-              FExistIndicesList.Add(TablesList[i] + ',' + List[j]); // Add to existing indices list
+            begin
+              FExistIndicesList.Add(TablesList[i] + ',' + IndexList[j]); // Add to existing indices IndexList
+            end;
         end
-        else // Table does not exist, all indices are missing
-        if List.Count > 0 then
-        for j:= 0 to List.Count - 1 do
+        else // Table does not exist so all indices are missing
+        if IndexList.Count > 0 then
+        for j:= 0 to IndexList.Count - 1 do
         begin
-          FDBObjectsList[ord(otIndexes)].Add(TablesList[i] + ',' + List[j]);
-          meLog.Lines.Add(' ' + List[j]);
+          FDBObjectsList[ord(otIndexes)].Add(TablesList[i] + ',' + IndexList[j]);
+          meLog.Lines.Add(' ' + IndexList[j]);
           Inc(FDiffCount);
         end;
       end;
     except
-      on e: exception do
+      on E: Exception do
       begin
-        meLog.Lines.Add('---- Error while comparing indices: ' + e.Message);
+        meLog.Lines.Add('-- Error while comparing indices: ' + E.Message);
       end;
     end;
   finally
-    List.Free;
+    IndexList.Free;
     ComparedList.Free;
     TablesList.Free;
   end;

+ 4 - 0
scriptdb.pas

@@ -94,12 +94,16 @@ var
 begin
   R:= Pos('returns', LowerCase(AParams));
   if R > 0 then
+  begin
     for i:= R downto 0 do
+    begin
       if AParams[i] = ')' then
       begin
         Delete(AParams, i, 1);
         Break;
       end;
+    end;
+  end;
 end;
 
 function ScriptAllFunctions(dbIndex: Integer; var List: TStringList): Boolean;

+ 12 - 1
turbocommon.pas

@@ -275,6 +275,9 @@ function GetFBTypeName(Index: Integer;
 // Tries to guess if an RDB$RELATION_FIELDS.RDB$FIELD_SOURCE domain name for a column is system-generated.
 function IsFieldDomainSystemGenerated(FieldSource: string): boolean;
 
+// Tries to guess if an index name is a system generated primary key index
+function IsPrimaryIndexSystemGenerated(IndexName: string): boolean;
+
 // Given TIBConnection parameters, sets transaction isolation level
 procedure SetTransactionIsolation(Params: TStringList);
 
@@ -405,7 +408,15 @@ function IsFieldDomainSystemGenerated(FieldSource: string): boolean;
 begin
   // Unfortunately there does not seem to be a way to search the system tables to find out
   // if the constraint name is system-generated
-  result:=(pos('RDB$',uppercase(Trim(FieldSource)))=1);
+  result:= (pos('RDB$',uppercase(Trim(FieldSource)))=1);
+end;
+
+function IsPrimaryIndexSystemGenerated(IndexName: string): boolean;
+begin
+  // todo: investigate if there is a system-generated flag or something to find
+  // out instead of using heuristics on the index name. I donot think so but it
+  // could be possible
+  result:= (pos('RDB$PRIMARY',uppercase(Trim(IndexName)))=1);
 end;