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 に答える