Browse Source

* Allow parameter-names between double-quotes
* Place parameter-names between double-quotes in TBufDataset.ApplyUpdates +tests (bug 12275)

git-svn-id: trunk@12284 -

joost 16 years ago
parent
commit
a7086e7164

+ 47 - 29
packages/fcl-db/src/base/dsparams.inc

@@ -1,4 +1,27 @@
 
+procedure SkipQuotesString(var p : pchar; QuoteChar : char; EscapeSlash, EscapeRepeat : Boolean);
+var notRepeatEscaped : boolean;
+begin
+  Inc(p);
+  repeat
+    notRepeatEscaped := True;
+    while not (p^ in [#0, QuoteChar]) do
+    begin
+      if EscapeSlash and (p^='\') and (p[1] <> #0) then Inc(p,2) // make sure we handle \' and \\ correct
+      else Inc(p);
+    end;
+    if p^=QuoteChar then
+    begin
+      Inc(p); // skip final '
+      if (p^=QuoteChar) and EscapeRepeat then // Handle escaping by ''
+      begin
+      notRepeatEscaped := False;
+      inc(p);
+      end
+    end;
+  until notRepeatEscaped;
+end;
+
 { TParams }
 
 Function TParams.GetItem(Index: Integer): TParam;
@@ -177,36 +200,20 @@ begin
 end;
 
 function SkipComments(var p: PChar; EscapeSlash, EscapeRepeat : Boolean) : Boolean;
-var notRepeatEscaped : boolean;
 
-  procedure SkipQuotesString(QuoteChar : char);
-  begin
-    Inc(p);
-    Result := True;
-    repeat
-      notRepeatEscaped := True;
-      while not (p^ in [#0, QuoteChar]) do
+begin
+  result := false;
+  case p^ of
+    '''':
       begin
-        if EscapeSlash and (p^='\') and (p[1] <> #0) then Inc(p,2) // make sure we handle \' and \\ correct
-        else Inc(p);
+        SkipQuotesString(p,'''',EscapeSlash,EscapeRepeat); // single quote delimited string
+        Result := True;
       end;
-      if p^=QuoteChar then
+    '"':
       begin
-        Inc(p); // skip final '
-        if (p^=QuoteChar) and EscapeRepeat then // Handle escaping by ''
-        begin
-        notRepeatEscaped := False;
-        inc(p);
-        end
+        SkipQuotesString(p,'"',EscapeSlash,EscapeRepeat);  // double quote delimited string
+        Result := True;
       end;
-    until notRepeatEscaped;
-  end;
-
-begin
-  result := false;
-  case p^ of
-    '''': SkipQuotesString('''');       // single quote delimited string
-    '"':  SkipQuotesString('"');        // double quote delimited string
     '-': // possible start of -- comment
       begin
         Inc(p);
@@ -295,10 +302,21 @@ begin
             end
             else
             begin
-              ParamNameStart:=p;
-              while not (p^ in (SQLDelimiterCharacters+[#0,'=','+','-','*','\','/','[',']','|'])) do
-                Inc(p);
-              ParamName:=Copy(ParamNameStart,1,p-ParamNameStart);
+              if p^='"' then // Check if the parameter-name is between quotes
+                begin
+                ParamNameStart:=p;
+                SkipQuotesString(p,'"',EscapeSlash,EscapeRepeat);
+                // Do not include the quotes in ParamName, but they must be included
+                // when the parameter is replaced by some place-holder.
+                ParamName:=Copy(ParamNameStart+1,1,p-ParamNameStart-2);
+                end
+              else
+                begin
+                ParamNameStart:=p;
+                while not (p^ in (SQLDelimiterCharacters+[#0,'=','+','-','*','\','/','[',']','|'])) do
+                  Inc(p);
+                ParamName:=Copy(ParamNameStart,1,p-ParamNameStart);
+                end;
             end;
           end
           else

+ 3 - 3
packages/fcl-db/src/sqldb/sqldb.pp

@@ -1366,7 +1366,7 @@ var FieldNamesQuoteChar : char;
     if (pfInKey in Fields[x].ProviderFlags) or
        ((FUpdateMode = upWhereAll) and (pfInWhere in Fields[x].ProviderFlags)) or
        ((FUpdateMode = UpWhereChanged) and (pfInWhere in Fields[x].ProviderFlags) and (fields[x].value <> fields[x].oldvalue)) then
-      sql_where := sql_where + '(' + FieldNamesQuoteChar + fields[x].FieldName + FieldNamesQuoteChar + '= :OLD_' + fields[x].FieldName + ') and ';
+      sql_where := sql_where + '(' + FieldNamesQuoteChar + fields[x].FieldName + FieldNamesQuoteChar + '= :' + FieldNamesQuoteChar + 'OLD_' + fields[x].FieldName + FieldNamesQuoteChar +') and ';
   end;
 
   function ModifyRecQuery : string;
@@ -1383,7 +1383,7 @@ var FieldNamesQuoteChar : char;
       UpdateWherePart(sql_where,x);
 
       if (pfInUpdate in Fields[x].ProviderFlags) then
-        sql_set := sql_set +FieldNamesQuoteChar + fields[x].FieldName + FieldNamesQuoteChar +'=:' + fields[x].FieldName + ',';
+        sql_set := sql_set +FieldNamesQuoteChar + fields[x].FieldName + FieldNamesQuoteChar +'=:' + FieldNamesQuoteChar + fields[x].FieldName + FieldNamesQuoteChar + ',';
       end;
 
     if length(sql_set) = 0 then DatabaseErrorFmt(sNoUpdateFields,['update'],self);
@@ -1408,7 +1408,7 @@ var FieldNamesQuoteChar : char;
       if (not fields[x].IsNull) and (pfInUpdate in Fields[x].ProviderFlags) then
         begin
         sql_fields := sql_fields + FieldNamesQuoteChar + fields[x].FieldName + FieldNamesQuoteChar + ',';
-        sql_values := sql_values + ':' + fields[x].FieldName + ',';
+        sql_values := sql_values + ':' + FieldNamesQuoteChar + fields[x].FieldName + FieldNamesQuoteChar +',';
         end;
       end;
     if length(sql_fields) = 0 then DatabaseErrorFmt(sNoUpdateFields,['insert'],self);

+ 9 - 0
packages/fcl-db/tests/testbasics.pas

@@ -37,6 +37,7 @@ var Params  : TParams;
     pb      : TParamBinding;
 begin
   Params := TParams.Create;
+
   AssertEquals(     'select * from table where id = $1',
     params.ParseSQL('select * from table where id = :id',true,True,True,psPostgreSQL));
 
@@ -95,6 +96,14 @@ begin
   AssertEquals(     'select * from table where "id  = :id\',
     params.ParseSQL('select * from table where "id  = :id\',true,True,True,psInterbase));
 
+// Test strange-field names
+  AssertEquals(     'select * from table where "field-name" = ?',
+    params.ParseSQL('select * from table where "field-name" = :"field-name"',true,True,True,psInterbase));
+  AssertEquals('field-name',Params.Items[0].Name);
+
+  AssertEquals(     'select * from table where "field-name" = ?',
+    params.ParseSQL('select * from table where "field-name" = :"field-name',true,True,True,psInterbase));
+
   Params.Free;
 end;
 

+ 30 - 0
packages/fcl-db/tests/testfieldtypes.pas

@@ -34,6 +34,7 @@ type
     procedure TestParseUnion; // bug 8442
     procedure TestInsertLargeStrFields; // bug 9600
     procedure TestNumericNames; // Bug9661
+    procedure TestApplyUpdFieldnames; // Bug 12275;
     procedure Test11Params;
     procedure TestRowsAffected; // bug 9758
     procedure TestStringsReplace;
@@ -1132,6 +1133,35 @@ begin
     end;
 end;
 
+procedure TTestFieldTypes.TestApplyUpdFieldnames;
+begin
+  with TSQLDBConnector(DBConnector) do
+    begin
+    AssertEquals(-1,query.RowsAffected);
+    Connection.ExecuteDirect('create table FPDEV2 (         ' +
+                              '  ID INT NOT NULL            , ' +
+                              '  "NAME-TEST" VARCHAR(250),  ' +
+                              '  PRIMARY KEY (ID)           ' +
+                              ')                            ');
+// Firebird/Interbase need a commit after a DDL statement. Not necessary for the other connections
+    TSQLDBConnector(DBConnector).Transaction.CommitRetaining;
+    Connection.ExecuteDirect('insert into FPDEV2(ID,"NAME-TEST") values (1,''test1'')');
+    Query.SQL.Text := 'select * from fpdev2';
+    Query.Open;
+    AssertEquals(1,Query.FieldByName('ID').AsInteger);
+    AssertEquals('test1',Query.FieldByName('NAME-TEST').AsString);
+    Query.Edit;
+    Query.FieldByName('NAME-TEST').AsString:='Edited';
+    Query.Post;
+    Query.ApplyUpdates;
+    Query.Close;
+    Query.Open;
+    AssertEquals(1,Query.FieldByName('ID').AsInteger);
+    AssertEquals('Edited',Query.FieldByName('NAME-TEST').AsString);
+    Query.Close;
+    end;
+end;
+
 procedure TTestFieldTypes.TestRowsAffected;
 begin
   with TSQLDBConnector(DBConnector) do