Browse Source

Additional fixes for Apply, Commit button. Issue #20 should be fixed now

Reinier Olislagers 11 years ago
parent
commit
0dad5bfbf1
1 changed files with 76 additions and 70 deletions
  1. 76 70
      querywindow.pas

+ 76 - 70
querywindow.pas

@@ -9,7 +9,7 @@ uses
   Controls, Graphics, Dialogs, ExtCtrls, PairSplitter, StdCtrls, Buttons,
   Controls, Graphics, Dialogs, ExtCtrls, PairSplitter, StdCtrls, Buttons,
   DBGrids, Menus, ComCtrls, SynEdit, SynHighlighterSQL, Reg,
   DBGrids, Menus, ComCtrls, SynEdit, SynHighlighterSQL, Reg,
   SynEditTypes, SynCompletion, Clipbrd, grids, DbCtrls, types, LCLType,
   SynEditTypes, SynCompletion, Clipbrd, grids, DbCtrls, types, LCLType,
-  modsqlscript, dbugintf, turbocommon;
+  modsqlscript, dbugintf, turbocommon, variants;
 
 
 type
 type
 
 
@@ -184,12 +184,13 @@ type
     FCounter: Integer;
     FCounter: Integer;
     FModifiedRecords: array of array of Integer;
     FModifiedRecords: array of array of Integer;
 
 
+    // Makes commit button in current tabsheet visible
     procedure EnableCommitButton;
     procedure EnableCommitButton;
     procedure ExecuteQuery;
     procedure ExecuteQuery;
     function GetNewTabNum: string;
     function GetNewTabNum: string;
     procedure FinishCellEditing(DataSet: TDataSet);
     procedure FinishCellEditing(DataSet: TDataSet);
-    // Gets sql query on current result tabsheet
-    function GetRecordSet: TSQLQuery;
+    // Gets TSQLQuery of current result tabsheet - only if it is a select query
+    function GetCurrentSelectQuery: TSQLQuery;
     // Gets both querytype and whether SQL is DML or DDL
     // Gets both querytype and whether SQL is DML or DDL
     // Investigates QueryList[LookAtIndex] to find out
     // Investigates QueryList[LookAtIndex] to find out
     function GetQuerySQLType(QueryList: TStringList; var LookAtIndex: Integer;
     function GetQuerySQLType(QueryList: TStringList; var LookAtIndex: Integer;
@@ -204,7 +205,6 @@ type
     procedure ApplyClick(Sender: TObject);
     procedure ApplyClick(Sender: TObject);
     procedure EnableApplyButton;
     procedure EnableApplyButton;
     function GetTableName(SQLText: string): string;
     function GetTableName(SQLText: string): string;
-    function GetCurrentSQLText: string;
     procedure CommitResultClick(Sender: TObject);
     procedure CommitResultClick(Sender: TObject);
   protected
   protected
     // This procedure will receive the events that are logged by the connection:
     // This procedure will receive the events that are logged by the connection:
@@ -401,27 +401,25 @@ end;
 { ApplyClick: Save Updates for the query }
 { ApplyClick: Save Updates for the query }
 
 
 procedure TfmQueryWindow.ApplyClick(Sender: TObject);
 procedure TfmQueryWindow.ApplyClick(Sender: TObject);
+//todo: review this and perhaps use regular FPC databound controls? autogenerated updatesql etc
 var
 var
   i, x: Integer;
   i, x: Integer;
-  aTableName: string;
+  TableName: string;
   UpdateQuery: TSQLQuery;
   UpdateQuery: TSQLQuery;
   PKIndexName: string;
   PKIndexName: string;
   ConstraintName: string;
   ConstraintName: string;
   KeyList, FieldsList: TStringList;
   KeyList, FieldsList: TStringList;
   WhereClause: string;
   WhereClause: string;
-  RecordSet: TSQLQuery;
+  UserData: TSQLQuery;
   TabIndex: Integer;
   TabIndex: Integer;
-  //todo: review this and perhaps use regular FPC databound controls? autogenerated updatesql etc
   FieldsSQL: string;
   FieldsSQL: string;
 begin
 begin
   try
   try
     TabIndex:= pgOutputPageCtl.TabIndex;
     TabIndex:= pgOutputPageCtl.TabIndex;
-    RecordSet:= nil;
-    RecordSet:= GetRecordSet;
-    aTableName:= GetTableName(RecordSet.SQL.Text);
-
+    UserData:= nil;
+    UserData:= GetCurrentSelectQuery;
     // Better safe than sorry
     // Better safe than sorry
-    if not(Assigned(RecordSet)) then
+    if not(Assigned(UserData)) then
     begin
     begin
       ShowMessage('Error getting query from tabsheet.');
       ShowMessage('Error getting query from tabsheet.');
       {$IFDEF DEBUG}
       {$IFDEF DEBUG}
@@ -429,9 +427,10 @@ begin
       {$ENDIF}
       {$ENDIF}
       exit;
       exit;
     end;
     end;
+    TableName:= GetTableName(UserData.SQL.Text);
 
 
     // Get primary key name
     // Get primary key name
-    PKIndexName:= fmMain.GetPrimaryKeyIndexName(FDBIndex, ATableName, ConstraintName);
+    PKIndexName:= fmMain.GetPrimaryKeyIndexName(FDBIndex, TableName, ConstraintName);
     if PKIndexName <> '' then
     if PKIndexName <> '' then
     begin
     begin
       KeyList:= TStringList.Create;
       KeyList:= TStringList.Create;
@@ -442,43 +441,45 @@ begin
         UpdateQuery.Transaction:= FSQLTrans;
         UpdateQuery.Transaction:= FSQLTrans;
 
 
         // Get primary key fields
         // Get primary key fields
-        fmMain.GetIndexFields(ATableName, PKIndexName, UpdateQuery, KeyList);
-        fmMain.GetFields(FDBIndex, ATableName, FieldsList);
+        fmMain.GetIndexFields(TableName, PKIndexName, UpdateQuery, KeyList);
+        fmMain.GetFields(FDBIndex, TableName, FieldsList);
         WhereClause:= 'where ';
         WhereClause:= 'where ';
 
 
-        RecordSet.DisableControls;
-        // Check modified fields
+        UserData.DisableControls;
+        // Check modified records
         for i:= Low(FModifiedRecords[TabIndex]) to High(FModifiedRecords[TabIndex]) do
         for i:= Low(FModifiedRecords[TabIndex]) to High(FModifiedRecords[TabIndex]) do
         begin
         begin
           FieldsSQL:= '';
           FieldsSQL:= '';
-          RecordSet.RecNo:= FModifiedRecords[TabIndex][i];
-          for x:= 0 to RecordSet.FieldCount - 1 do
+          UserData.RecNo:= FModifiedRecords[TabIndex][i];
+          // For each record, check modified fields:
+          for x:= 0 to UserData.FieldCount - 1 do
           begin
           begin
-            if (FieldsList.IndexOf(RecordSet.Fields[x].FieldName) <> -1) and  // Field exist in origional table
-              (RecordSet.Fields[x].NewValue <> RecordSet.Fields[x].OldValue) then // field data has been modified
+            if (FieldsList.IndexOf(UserData.Fields[x].FieldName) <> -1) and  // Field exists in origional table
+              (UserData.Fields[x].NewValue <> UserData.Fields[x].OldValue) then // field data has been modified
             begin
             begin
               if FieldsSQL <> '' then
               if FieldsSQL <> '' then
                 FieldsSQL += ',';
                 FieldsSQL += ',';
-              FieldsSQL += RecordSet.Fields[x].FieldName + '=';
+              FieldsSQL += UserData.Fields[x].FieldName + '=';
 
 
               // Typecast field values according to their main type
               // Typecast field values according to their main type
-              case RecordSet.Fields[x].DataType of
-                ftInteger, ftSmallint: FieldsSQL += IntToStr(RecordSet.Fields[x].NewValue);
-                ftFloat: FieldsSQL += FloatToStr(RecordSet.Fields[x].NewValue);
-                ftTimeStamp, ftDateTime: FieldsSQL += '''' + DateTimeToStr(RecordSet.Fields[x].NewValue) + '''';
-                ftTime: FieldsSQL += '''' + TimeToStr(RecordSet.Fields[x].NewValue) + '''';
-                ftDate: FieldsSQL += '''' + DateToStr(RecordSet.Fields[x].NewValue) + '''';
+              case UserData.Fields[x].DataType of
+                ftInteger, ftSmallint: FieldsSQL += IntToStr(UserData.Fields[x].NewValue);
+                ftFloat: FieldsSQL += FloatToStr(UserData.Fields[x].NewValue);
+                ftTimeStamp, ftDateTime: FieldsSQL += QuotedStr(DateTimeToStr(UserData.Fields[x].NewValue));
+                ftTime: FieldsSQL += QuotedStr(TimeToStr(UserData.Fields[x].NewValue));
+                ftDate: FieldsSQL += QuotedStr(DateToStr(UserData.Fields[x].NewValue));
               else // Other types like string
               else // Other types like string
-                FieldsSQL += '''' + RecordSet.Fields[x].NewValue + '''';
+                FieldsSQL += QuotedStr(UserData.Fields[x].NewValue);
               end;
               end;
             end;
             end;
           end;
           end;
 
 
           // Update current record
           // Update current record
+          // todo: high priority: add facility for inserting records
           if FieldsSQL <> '' then
           if FieldsSQL <> '' then
           begin
           begin
             UpdateQuery.Close;
             UpdateQuery.Close;
-            UpdateQuery.SQL.Text:= 'update ' + aTableName + ' set ' + FieldsSQL;
+            UpdateQuery.SQL.Text:= 'update ' + TableName + ' set ' + FieldsSQL;
 
 
             WhereClause:= 'where ';
             WhereClause:= 'where ';
             // where clause
             // where clause
@@ -486,20 +487,37 @@ begin
             begin
             begin
               if Trim(KeyList[x]) <> '' then
               if Trim(KeyList[x]) <> '' then
               begin
               begin
-                WhereClause += KeyList[x] + ' = ';
-
-                // Typecast index values
-                case RecordSet.Fields[x].DataType of
-                  ftInteger, ftSmallint: WhereClause += IntToStr(RecordSet.Fields[x].OldValue);
-                  ftFloat: WhereClause += FloatToStr(RecordSet.Fields[x].OldValue);
-                else
-                  WhereClause += '''' + RecordSet.Fields[x].OldValue + '''';
+                { Typecast key values
+                If the old value was null the, typecast will fail so try to
+                deal with that }
+                try
+                  case UserData.Fields[x].DataType of
+                    ftInteger, ftSmallint:
+                      WhereClause += KeyList[x] + ' = ' + IntToStr(UserData.Fields[x].OldValue);
+                    ftFloat:
+                      WhereClause += KeyList[x] + ' = ' + FloatToStr(UserData.Fields[x].OldValue);
+                  else
+                    WhereClause += KeyList[x] + ' = ' + QuotedStr(UserData.Fields[x].OldValue);
+                  end;
+                except
+                  on E: EVariantTypeCastError do
+                  begin
+                    // Only ignore typecast errors;
+                    // let higher level handle the rest
+                    // Assume field was NULL
+                    WhereClause += KeyList[x] + ' IS NULL';
+                  end;
                 end;
                 end;
+
                 if x < KeyList.Count - 1 then
                 if x < KeyList.Count - 1 then
                   WhereClause += ' and ';
                   WhereClause += ' and ';
               end;
               end;
             end;
             end;
             UpdateQuery.SQL.Add(WhereClause);
             UpdateQuery.SQL.Add(WhereClause);
+            {$IFDEF DEBUG}
+            //todo: debug
+            SendDebug('going to run update query: '+Updatequery.sql.text);
+            {$ENDIF DEBUG}
             UpdateQuery.ExecSQL;
             UpdateQuery.ExecSQL;
             (Sender as TBitBtn).Visible:= False;
             (Sender as TBitBtn).Visible:= False;
 
 
@@ -513,7 +531,7 @@ begin
 
 
         // Reset FModifiedRecords pointer
         // Reset FModifiedRecords pointer
         FModifiedRecords[TabIndex]:= nil;
         FModifiedRecords[TabIndex]:= nil;
-        RecordSet.EnableControls;
+        UserData.EnableControls;
       finally
       finally
         FieldsList.Free;
         FieldsList.Free;
         KeyList.Free;
         KeyList.Free;
@@ -521,7 +539,7 @@ begin
       end;
       end;
     end
     end
     else
     else
-      ShowMessage('There is no primary key on the table: ' + aTableName);
+      ShowMessage('There is no primary key on the table: ' + TableName);
   except
   except
     on e: exception do
     on e: exception do
     begin
     begin
@@ -627,26 +645,6 @@ begin
 end;
 end;
 
 
 
 
-{ GetCurrentSQLText: return current SQL query text }
-
-function TfmQueryWindow.GetCurrentSQLText: string;
-var
-  i: Integer;
-  Ctl: TControl;
-begin
-  // Tabsheet has grid as well as panel
-  for i:= 0 to pgOutputPageCtl.ActivePage.ControlCount-1 do
-  begin
-    Ctl:=pgOutputPageCtl.ActivePage.Controls[i];
-    if (Ctl is TDBGrid) then
-    begin
-      Result:= (TDBGrid(Ctl).DataSource.DataSet as TSQLQuery).SQL.Text;
-      Break;
-    end;
-  end;
-end;
-
-
 { CommitResultClick: commit current transaction }
 { CommitResultClick: commit current transaction }
 
 
 procedure TfmQueryWindow.CommitResultClick(Sender: TObject);
 procedure TfmQueryWindow.CommitResultClick(Sender: TObject);
@@ -674,22 +672,20 @@ begin
 end;
 end;
 
 
 
 
-{ GetRecordSet: return result recordset of a page tab }
+{ GetCurrentSelectQuery: return result recordset of a page tab }
 
 
-function TfmQueryWindow.GetRecordSet: TSQLQuery;
+function TfmQueryWindow.GetCurrentSelectQuery: TSQLQuery;
 var
 var
   i: Integer;
   i: Integer;
   Ctl: TControl;
   Ctl: TControl;
 begin
 begin
-  // Tabsheet has grid as well as panel - let's use that to get the dataset
-  //todo: high priority perhaps better go directly to Tsqlquery object?
-  for i:= 0 to pgOutputPageCtl.ActivePage.ControlCount-1 do
+  // Tabsheet's tag property should point to any select query
+  Result:= nil;
+  if (pgOutputPageCtl.PageCount > 0) then
   begin
   begin
-    Ctl:=pgOutputPageCtl.ActivePage.Controls[i];
-    if (Ctl is TDBGrid) then
+    if (pgOutputPageCtl.ActivePage.Tag<>0) then
     begin
     begin
-      Result:= (TDBGrid(Ctl).DataSource.DataSet as TSQLQuery);
-      Break;
+      Result:= TSQLQuery(pgOutputPageCtl.ActivePage.Tag);
     end;
     end;
   end;
   end;
 end;
 end;
@@ -1168,12 +1164,18 @@ begin
   if QueryType = qtSelectable then // Select, need record set result
   if QueryType = qtSelectable then // Select, need record set result
   begin
   begin
     // Query
     // Query
+    // Clean up any existing object to avoid memory leak
+    if assigned(aSQLQuery) then
+      aSQLQuery.Free;
     aSqlQuery:= TSQLQuery.Create(self);
     aSqlQuery:= TSQLQuery.Create(self);
     aSqlQuery.DataBase:= FIBConnection;
     aSqlQuery.DataBase:= FIBConnection;
     aSqlQuery.Transaction:= FSQLTrans;
     aSqlQuery.Transaction:= FSQLTrans;
     aSqlQuery.AfterScroll:= @QueryAfterScroll;
     aSqlQuery.AfterScroll:= @QueryAfterScroll;
     aSqlQuery.AfterPost:= @FinishCellEditing;
     aSqlQuery.AfterPost:= @FinishCellEditing;
-    aSqlQuery.Tag:= ATab.TabIndex;
+    aSqlQuery.Tag:= ATab.TabIndex; //Query points to tabsheet number
+    {Tab points to query object so we can look it up more easily via the
+    tab sheet if we need to enable Apply/Commit buttons etc}
+    ATab.Tag:= PtrInt(aSQLQuery);
 
 
     // Status Bar
     // Status Bar
     StatusBar:= TStatusBar.Create(self);
     StatusBar:= TStatusBar.Create(self);
@@ -1234,6 +1236,9 @@ begin
       end;
       end;
       qtScript: // Script
       qtScript: // Script
       begin
       begin
+        // Clean up to avoid memory leak
+        if assigned(aSQLScript) then
+          aSQLScript.Free;
         aSQLScript:= TModSQLScript.Create(self);
         aSQLScript:= TModSQLScript.Create(self);
         aSQLScript.DataBase:= FIBConnection;
         aSQLScript.DataBase:= FIBConnection;
         aSQLScript.Transaction:= FSQLTrans;
         aSQLScript.Transaction:= FSQLTrans;
@@ -1583,6 +1588,7 @@ begin
     begin
     begin
       for i:= 0 to ControlCount - 1 do
       for i:= 0 to ControlCount - 1 do
       begin
       begin
+        //todo: directly go to sqlquery?
         if Controls[i] is TDBGrid then
         if Controls[i] is TDBGrid then
         begin
         begin
           Result:= TSqlQuery((Controls[i] as TDBGrid).DataSource.DataSet);
           Result:= TSqlQuery((Controls[i] as TDBGrid).DataSource.DataSet);