Browse Source

* sqlDB update SQLParser to parse DML statements WITH common table expressions
Patch by Lacak2, Mantis #21851

git-svn-id: trunk@21010 -

marco 13 years ago
parent
commit
abaf2eaf12
1 changed files with 33 additions and 15 deletions
  1. 33 15
      packages/fcl-db/src/sqldb/sqldb.pp

+ 33 - 15
packages/fcl-db/src/sqldb/sqldb.pp

@@ -36,7 +36,7 @@ type
   TSQLScript = class;
   TSQLScript = class;
 
 
 
 
-  TStatementType = (stNone, stSelect, stInsert, stUpdate, stDelete,
+  TStatementType = (stUnknown, stSelect, stInsert, stUpdate, stDelete,
     stDDL, stGetSegment, stPutSegment, stExecProcedure,
     stDDL, stGetSegment, stPutSegment, stExecProcedure,
     stStartTrans, stCommit, stRollback, stSelectForUpd);
     stStartTrans, stCommit, stRollback, stSelectForUpd);
 
 
@@ -63,7 +63,7 @@ const
   SingleQuotes : TQuoteChars = ('''','''');
   SingleQuotes : TQuoteChars = ('''','''');
   DoubleQuotes : TQuoteChars = ('"','"');
   DoubleQuotes : TQuoteChars = ('"','"');
   LogAllEvents = [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack];
   LogAllEvents = [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack];
-  StatementTokens : Array[TStatementType] of string = ('(none)', 'select',
+  StatementTokens : Array[TStatementType] of string = ('(unknown)', 'select',
                   'insert', 'update', 'delete',
                   'insert', 'update', 'delete',
                   'create', 'get', 'put', 'execute',
                   'create', 'get', 'put', 'execute',
                   'start','commit','rollback', '?'
                   'start','commit','rollback', '?'
@@ -542,9 +542,10 @@ var T : TStatementType;
 
 
 begin
 begin
   S:=Lowercase(s);
   S:=Lowercase(s);
-  For t:=stselect to strollback do
-    if (S=StatementTokens[t]) then
-      Exit(t);
+  for T:=stSelect to stRollback do
+    if (S=StatementTokens[T]) then
+      Exit(T);
+  Result:=stUnknown;
 end;
 end;
 
 
 procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
 procedure TSQLConnection.SetTransaction(Value : TSQLTransaction);
@@ -621,7 +622,7 @@ begin
       DatabaseError(SErrNoStatement);
       DatabaseError(SErrNoStatement);
 
 
     Cursor := AllocateCursorHandle;
     Cursor := AllocateCursorHandle;
-    Cursor.FStatementType := stNone;
+    Cursor.FStatementType := stUnknown;
     PrepareStatement(cursor,ATransaction,SQL,Nil);
     PrepareStatement(cursor,ATransaction,SQL,Nil);
     execute(cursor,ATransaction, Nil);
     execute(cursor,ATransaction, Nil);
     UnPrepareStatement(Cursor);
     UnPrepareStatement(Cursor);
@@ -1218,7 +1219,7 @@ end;
 
 
 function TCustomSQLQuery.SQLParser(const ASQL : string) : TStatementType;
 function TCustomSQLQuery.SQLParser(const ASQL : string) : TStatementType;
 
 
-type TParsePart = (ppStart,ppSelect,ppWhere,ppFrom,ppOrder,ppComment,ppGroup,ppBogus);
+type TParsePart = (ppStart,ppWith,ppSelect,ppFrom,ppWhere,ppGroup,ppOrder,ppComment,ppBogus);
 
 
 Var
 Var
   PSQL,CurrentP,
   PSQL,CurrentP,
@@ -1248,13 +1249,13 @@ begin
     begin
     begin
     inc(CurrentP);
     inc(CurrentP);
 
 
-    EndOfComment := SkipComments(CurrentP,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions);
-    if EndOfcomment then dec(currentp);
+    EndOfComment := SkipComments(CurrentP, sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions);
+    if EndOfcomment then dec(CurrentP);
     if EndOfComment and (ParsePart = ppStart) then PhraseP := CurrentP;
     if EndOfComment and (ParsePart = ppStart) then PhraseP := CurrentP;
 
 
     // skip everything between bracket, since it could be a sub-select, and
     // skip everything between bracket, since it could be a sub-select, and
     // further nothing between brackets could be interesting for the parser.
     // further nothing between brackets could be interesting for the parser.
-    if currentp^='(' then
+    if CurrentP^='(' then
       begin
       begin
       inc(currentp);
       inc(currentp);
       BracketCount := 0;
       BracketCount := 0;
@@ -1279,10 +1280,25 @@ begin
         case ParsePart of
         case ParsePart of
           ppStart  : begin
           ppStart  : begin
                      Result := TSQLConnection(Database).StrToStatementType(s);
                      Result := TSQLConnection(Database).StrToStatementType(s);
-                     if s = 'SELECT' then ParsePart := ppSelect else break;
+                     case s of
+                       'WITH'  : ParsePart := ppWith;
+                       'SELECT': ParsePart := ppSelect;
+                       else      break;
+                     end;
                      if not FParseSQL then break;
                      if not FParseSQL then break;
                      PStatementPart := CurrentP;
                      PStatementPart := CurrentP;
                      end;
                      end;
+          ppWith   : begin
+                     // WITH [RECURSIVE] CTE_name [ ( column_names ) ] AS ( CTE_query_definition ) [, ...]
+                     //  { SELECT | INSERT | UPDATE | DELETE } ...
+                     case s of
+                       'SELECT': Result := stSelect;
+                       'INSERT': Result := stInsert;
+                       'UPDATE': Result := stUpdate;
+                       'DELETE': Result := stDelete;
+                     end;
+                     if Result <> stUnknown then break;
+                     end;
           ppSelect : begin
           ppSelect : begin
                      if s = 'FROM' then
                      if s = 'FROM' then
                        begin
                        begin
@@ -1323,7 +1339,7 @@ begin
                          begin
                          begin
                          Setlength(FFromPart,StrLength);
                          Setlength(FFromPart,StrLength);
                          Move(PStatementPart^,FFromPart[1],(StrLength));
                          Move(PStatementPart^,FFromPart[1],(StrLength));
-                         FFrompart := trim(FFrompart);
+                         FFromPart := trim(FFromPart);
 
 
                          // Meta-data requests and are never updateable select-statements
                          // Meta-data requests and are never updateable select-statements
                          // from more then one table are not updateable
                          // from more then one table are not updateable
@@ -1749,8 +1765,10 @@ end;
 function TCustomSQLQuery.GetStatementType : TStatementType;
 function TCustomSQLQuery.GetStatementType : TStatementType;
 
 
 begin
 begin
-  if assigned(FCursor) then Result := FCursor.FStatementType
-    else Result := stNone;
+  if assigned(FCursor) then
+    Result := FCursor.FStatementType
+  else
+    Result := stUnknown;
 end;
 end;
 
 
 procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringlist);
 procedure TCustomSQLQuery.SetDeleteSQL(const AValue: TStringlist);
@@ -1996,7 +2014,7 @@ begin
   inherited DoInternalConnect;
   inherited DoInternalConnect;
   CreateProxy;
   CreateProxy;
   FProxy.CharSet:=Self.CharSet;
   FProxy.CharSet:=Self.CharSet;
-  FProxy.Role:=self.Role;
+  FProxy.Role:=Self.Role;
   FProxy.DatabaseName:=Self.DatabaseName;
   FProxy.DatabaseName:=Self.DatabaseName;
   FProxy.HostName:=Self.HostName;
   FProxy.HostName:=Self.HostName;
   FProxy.UserName:=Self.UserName;
   FProxy.UserName:=Self.UserName;