* Allow parameter-names between double-quotes

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

git-svn-id: trunk@12284 -
This commit is contained in:
joost 2008-12-01 13:13:48 +00:00
parent e9976b6ced
commit a7086e7164
4 changed files with 90 additions and 33 deletions

View File

@ -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
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;
begin
result := false;
case p^ of
'''': SkipQuotesString(''''); // single quote delimited string
'"': SkipQuotesString('"'); // double quote delimited string
'''':
begin
SkipQuotesString(p,'''',EscapeSlash,EscapeRepeat); // single quote delimited string
Result := True;
end;
'"':
begin
SkipQuotesString(p,'"',EscapeSlash,EscapeRepeat); // double quote delimited string
Result := True;
end;
'-': // 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

View File

@ -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);

View File

@ -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;

View File

@ -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