浏览代码

Querywindow: replace manually generated/executed update sql statements with sqldb-provided insertsql/updatesql/deletesql as well as a workaround for SELECT FIRST x.

Reinier Olislagers 11 年之前
父节点
当前提交
6514ac17f3
共有 1 个文件被更改,包括 47 次插入156 次删除
  1. 47 156
      querywindow.pas

+ 47 - 156
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, variants;
+  modsqlscript, dbugintf, turbocommon, variants, strutils;
 
 
 type
 type
 
 
@@ -182,13 +182,11 @@ type
     FAText: string;
     FAText: string;
     FModifyCount: Integer;
     FModifyCount: Integer;
     FCounter: Integer;
     FCounter: Integer;
-    FModifiedRecords: array of array of Integer;
 
 
     // Makes commit button in current tabsheet visible
     // 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);
     // Gets TSQLQuery of current result tabsheet - only if it is a select query
     // Gets TSQLQuery of current result tabsheet - only if it is a select query
     function GetCurrentSelectQuery: TSQLQuery;
     function GetCurrentSelectQuery: TSQLQuery;
     // Gets both querytype and whether SQL is DML or DDL
     // Gets both querytype and whether SQL is DML or DDL
@@ -201,7 +199,6 @@ type
     procedure RemoveAllSingleLineComments(QueryList: TStringList);
     procedure RemoveAllSingleLineComments(QueryList: TStringList);
     procedure RemoveEmptyLines(QueryList: TStringList;
     procedure RemoveEmptyLines(QueryList: TStringList;
       var SecondRealStart: Integer; const RealStartLine: Integer);
       var SecondRealStart: Integer; const RealStartLine: Integer);
-    procedure InsertModifiedRecord(RecordNo, TabIndex: Integer);
     procedure ApplyClick(Sender: TObject);
     procedure ApplyClick(Sender: TObject);
     procedure EnableApplyButton;
     procedure EnableApplyButton;
     function GetTableName(SQLText: string): string;
     function GetTableName(SQLText: string): string;
@@ -228,6 +225,7 @@ type
     function GetSQLSegment(QueryList: TStringList; StartLine: Integer;
     function GetSQLSegment(QueryList: TStringList; StartLine: Integer;
       var QueryType: TQueryTypes; var EndLine: Integer;
       var QueryType: TQueryTypes; var EndLine: Integer;
       var SQLSegment: string; var IsDDL: Boolean): Boolean;
       var SQLSegment: string; var IsDDL: Boolean): Boolean;
+    procedure QueryAfterPost(DataSet: TDataSet);
     procedure QueryAfterScroll(DataSet: TDataSet);
     procedure QueryAfterScroll(DataSet: TDataSet);
     // Run query; use aQueryType to force running as e.g. script or open query
     // Run query; use aQueryType to force running as e.g. script or open query
     procedure CallExecuteQuery(aQueryType: TQueryTypes);
     procedure CallExecuteQuery(aQueryType: TQueryTypes);
@@ -351,50 +349,6 @@ end;
 { TQueryThread }
 { TQueryThread }
 
 
 
 
-{ FinishCellEditing: Insert current just edited record in ModifiedRecords array }
-
-procedure TfmQueryWindow.FinishCellEditing(DataSet: TDataSet);
-begin
-  InsertModifiedRecord(Dataset.RecNo, pgOutputPageCtl.TabIndex);
-end;
-
-
-
-{ InsertModifiedRecord: insert modified query record in ModifiedRecords array }
-
-procedure TfmQueryWindow.InsertModifiedRecord(RecordNo, TabIndex: Integer);
-var
-  i: Integer;
-  Exists: Boolean;
-begin
-  Exists:= False;
-  if TabIndex > High(FModifiedRecords) then // Insert new tab
-  begin
-    SetLength(FModifiedRecords, TabIndex + 1);
-  end;
-
-  // Check if record already inserted
-  for i:= 0 to High(FModifiedRecords[TabIndex]) do
-  begin
-    if FModifiedRecords[TabIndex][i] = RecordNo then
-    begin
-      Exists:= True;
-      Break;
-    end;
-  end;
-
-  if not Exists then  // Insert record pointer
-  begin
-    setLength(FModifiedRecords[TabIndex], Length(FModifiedRecords[TabIndex]) + 1);
-    FModifiedRecords[TabIndex][High(FModifiedRecords[TabIndex])]:= RecordNo;
-  end;
-
-  // Enable apply/save button
-  if Length(FModifiedRecords[TabIndex]) = 1 then
-  begin
-    EnableApplyButton;
-  end;
-end;
 
 
 
 
 { ApplyClick: Save Updates for the query }
 { ApplyClick: Save Updates for the query }
@@ -426,115 +380,17 @@ begin
       {$ENDIF}
       {$ENDIF}
       exit;
       exit;
     end;
     end;
-    TableName:= GetTableName(UserData.SQL.Text);
-
-    // Get primary key name
-    PKIndexName:= fmMain.GetPrimaryKeyIndexName(FDBIndex, TableName, ConstraintName);
-    if PKIndexName <> '' then
-    begin
-      KeyList:= TStringList.Create;
-      Fieldslist:= TStringList.Create;
-      UpdateQuery:= TSQLQuery.Create(nil);
-      try
-        UpdateQuery.DataBase:= FIBConnection;
-        UpdateQuery.Transaction:= FSQLTrans;
-
-        // Get primary key fields
-        fmMain.GetIndexFields(TableName, PKIndexName, UpdateQuery, KeyList);
-        fmMain.GetFields(FDBIndex, TableName, FieldsList);
-        WhereClause:= ' where ';
-
-        UserData.DisableControls;
-        // Check modified records
-        for i:= Low(FModifiedRecords[TabIndex]) to High(FModifiedRecords[TabIndex]) do
-        begin
-          FieldsSQL:= '';
-          UserData.RecNo:= FModifiedRecords[TabIndex][i];
-          // For each record, check modified fields:
-          for x:= 0 to UserData.FieldCount - 1 do
-          begin
-            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
-              if FieldsSQL <> '' then
-                FieldsSQL += ',';
-              FieldsSQL += UserData.Fields[x].FieldName + '=';
-
-              // Typecast field values according to their main type
-              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
-                FieldsSQL += QuotedStr(UserData.Fields[x].NewValue);
-              end;
-            end;
-          end;
+    UserData.ApplyUpdates; // lets query run InsertSQL, UpdateSQL, DeleteSQL
 
 
-          // Update current record
-          // todo: (high priority) add facility for inserting records.
-          if FieldsSQL <> '' then
-          begin
-            UpdateQuery.Close;
-            UpdateQuery.SQL.Text:= 'update ' + TableName + ' set ' + FieldsSQL;
+    (Sender as TBitBtn).Visible:= False;
 
 
-            WhereClause:= ' where ';
-            // where clause
-            for x:= 0 to KeyList.Count - 1 do
-            begin
-              if Trim(KeyList[x]) <> '' then
-              begin
-                { 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;
-
-                if x < KeyList.Count - 1 then
-                  WhereClause += ' and ';
-              end;
-            end;
-            UpdateQuery.SQL.Add(WhereClause);
-            UpdateQuery.ExecSQL;
-            (Sender as TBitBtn).Visible:= False;
-
-            // Auto commit
-            if cxAutoCommit.Checked then
-              FSQLTrans.CommitRetaining
-            else
-              EnableCommitButton;
-          end;
-        end;
-
-        // Reset FModifiedRecords pointer
-        FModifiedRecords[TabIndex]:= nil;
-        UserData.EnableControls;
-      finally
-        FieldsList.Free;
-        KeyList.Free;
-        UpdateQuery.Free;
-      end;
-    end
+    // Auto commit
+    if cxAutoCommit.Checked then
+      FSQLTrans.CommitRetaining
     else
     else
-      ShowMessage('There is no primary key on the table: ' + TableName);
+      EnableCommitButton;
+
+    UserData.EnableControls;
   except
   except
     on e: exception do
     on e: exception do
     begin
     begin
@@ -1120,7 +976,7 @@ end;
 
 
 { GetQuery: get query text from editor }
 { GetQuery: get query text from editor }
 
 
-function TfmQueryWindow.GetQuery(QueryContents: TStrings): boolean;
+function TfmQueryWindow.GetQuery(QueryContents: tstrings): boolean;
 var
 var
   Seltext: string;
   Seltext: string;
 begin
 begin
@@ -1164,8 +1020,8 @@ begin
     aSqlQuery:= TSQLQuery.Create(self);
     aSqlQuery:= TSQLQuery.Create(self);
     aSqlQuery.DataBase:= FIBConnection;
     aSqlQuery.DataBase:= FIBConnection;
     aSqlQuery.Transaction:= FSQLTrans;
     aSqlQuery.Transaction:= FSQLTrans;
+    aSqlQuery.AfterPost:= @QueryAfterPost; //detect user-edited grid
     aSqlQuery.AfterScroll:= @QueryAfterScroll;
     aSqlQuery.AfterScroll:= @QueryAfterScroll;
-    aSqlQuery.AfterPost:= @FinishCellEditing;
     aSqlQuery.Tag:= ATab.TabIndex; //Query points to tabsheet number
     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 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}
     tab sheet if we need to enable Apply/Commit buttons etc}
@@ -1254,6 +1110,9 @@ var
   IsDDL: Boolean;
   IsDDL: Boolean;
   Affected: Integer;
   Affected: Integer;
   fQueryType: TQueryTypes;
   fQueryType: TQueryTypes;
+  TempQuery: TSQLQuery;
+  SanitizedSQL: string;
+  i: integer;
 begin
 begin
   try
   try
     // Script
     // Script
@@ -1291,6 +1150,32 @@ begin
           FTab.ShowHint:= True;
           FTab.ShowHint:= True;
           FSQLQuery.SQL.Text:= FQueryPart;
           FSQLQuery.SQL.Text:= FQueryPart;
 
 
+          // Work around sqldb not detecting insert/updatesql for FIRST x queries
+          // Massage the SQL, assign it to a temp query and use the insertquery
+          // etc generated by sqldb.
+          // Support for ROWS x TO y at the end of the statement could be
+          // added perhaps
+
+          if (pos('select first ',lowercase(FQueryPart))=1) then
+          begin
+            // Get rid of the select first x part by copying everything after
+            // the third word
+            SanitizedSQL:= ExtractWordPos(3, FQueryPart, StdWordDelims,i);
+            if i>0 then
+            begin
+              SanitizedSQL:= 'select ' + trim(copy(FQueryPart, i+length(SanitizedSQL), maxint));
+              TempQuery:= TSQLQuery.Create(nil);
+              try
+                TempQuery.ParseSQL:= true;
+                FSQLQuery.InsertSQL:= TempQuery.InsertSQL;
+                FSQLQuery.UpdateSQL:= TempQuery.UpdateSQL;
+                FSQLQuery.DeleteSQL:= TempQuery.DeleteSQL;
+              finally
+                TempQuery.Free;
+              end;
+            end;
+          end;
+
           // Create thread to open dataset
           // Create thread to open dataset
           FQT:= TQueryThread.Create(qaOpen);
           FQT:= TQueryThread.Create(qaOpen);
           FQT.Query:= FSQLQuery;
           FQT.Query:= FSQLQuery;
@@ -1662,6 +1547,12 @@ begin
   end;
   end;
 end;
 end;
 
 
+procedure TfmQueryWindow.QueryAfterPost(DataSet: TDataSet);
+begin
+  // User has edited cells, so let him save
+  EnableApplyButton;
+end;
+
 
 
 
 
 { Run query, 0 for auto-detect query type }
 { Run query, 0 for auto-detect query type }