1

我正在使用类似的东西来定义一个 SQL 插入命令:

sql := 'insert into table(a, b, c) values (' + formatfunction(a) + ', ' + 
                                               formatfunction(b) + ', ' +
                                               formatfunction(c) + ');';

赋值后,变量sql包含a、b、c的不同顺序的格式化值,结果是这样的:

insert into (a, b, c) values ​​('value in c', 'value in a', 'value in b');

编译器优化可能有问题?

抱歉,示例代码不佳,完整的可执行代码如下:

procedure Execute(var v : String);
  function ExtractValue(var Content: String; Separator: Char = '|'): String;
  var
    vpHead,
    vpTail,
    vpContent: PChar;
    vsValor: String;
  begin
    vpContent := PChar(Content);
    Result := '';
    if (vpContent = nil) or
       (vpContent^=#0) then
      Exit;
    vpTail := vpContent;
    vpHead := vpTail;

    while not (CharInSet(vpTail^, [Separator]) or (vpTail^=#0)) do
      vpTail := StrNextChar(vpTail);

    if (vpHead^ <> #0) then
    begin
      if (vpHead <> vpTail) then
      begin
        SetString(vsValor, vpHead, vpTail - vpHead);
        Result := vsValor;
      end
      else
        Result := '';
    end;

    Content := Copy(Content, Length(vsValor) + 2, (Length(Content) - Length(vsValor)) + 1);
  end;

  function FormatAsDate(const s: String): TDate;
  begin
    Result := 0;

    if Trim(s) <> '' then
      Result := StrToDateDef(Copy(s, 1, 2) + '/' + Copy(s, 3, 2) + '/' + Copy(s, 5, 4), 0);
  end;

  function AsCurrency(const s: string): Double;
  begin
    Result := StrToFloatDef(s, 0);
  end;

  function AsDate(const s: string): string;
  var
    d: TDate;
  begin
    d := FormatAsDate(s);

    if d = 0 then
      Result := QuotedStr('null')
    else
      Result := QuotedStr(FormatDateTime('yyyy/mm/dd', d));
  end;

  function AsText(const s: string): string;
  begin
    Result := QuotedStr(s);
  end;
begin
  v :=
    'INSERT INTO TABLE (A, B, C, D, E, F, G, H, I, J, K, L, M) VALUES (' +
     AsText(ExtractValue(v)) + ', ' +
     AsText(ExtractValue(v)) + ', ' +
     AsText(ExtractValue(v)) + ', ' +
     AsText(ExtractValue(v)) + ', ' +
     AsText(ExtractValue(v)) + ', ' +
     AsText(ExtractValue(v)) + ', ' +
     AsDate(ExtractValue(v)) + ', ' +
     AsDate(ExtractValue(v)) + ', ' +
     StringReplace(FloatToStr(AsCurrency(ExtractValue(v))), ',', '.', []) + ', ' +
     StringReplace(FloatToStr(AsCurrency(ExtractValue(v))), ',', '.', []) + ', ' +
     AsText(ExtractValue(v)) + ', ' +
     StringReplace(FloatToStr(AsCurrency(ExtractValue(v))), ',', '.', []) + ', ' +
     StringReplace(FloatToStr(AsCurrency(ExtractValue(v))), ',', '.', []) + ');';
end;

使用输入字符串'04368898000106|06|00|||3413572|26102011|31102011|1656,81|334,57||0,00|0,00',插入命令的值顺序不同比输入字符串中显示的要多。

4

1 回答 1

9

您的代码取决于表达式中操作数的计算顺序。该评估顺序未定义。

看一个更简单的例子,考虑这个代码:

x := f1(a) + f2(b);

f1()无法保证函数调用和f2()执行的顺序。您大概希望f1()在之前执行,f2()但编译器不保证这一点,实际上我相信这些操作数通常会从右到左进行评估。

在您的代码中,表达式中的操作数涉及一个函数调用,ExtractValue()它具有修改其参数的副作用。由于表达式中的操作数不是从左到右计算的,因此调用ExtractValue()的顺序与它们在表达式中出现的顺序不同。并且由于ExtractValue()具有影响表达式其余部分的副作用,因此结果取决于评估顺序。

您将需要重新处理此代码,以便ExtractValue()在单独的语句中进行调用。

于 2012-06-15T20:02:13.000 回答