2012-06-15 3 views
1

я использую что-то вроде этого, чтобы определить команду SQL вставки:Почему конкатенация строковых функций ставит результаты в неправильном порядке?

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

после присваивания, переменная SQL содержит форматированные значения а, б, в в другом порядке, в результате чего-то например:

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 ', значения команды вставки находятся в другом порядке, чем указано во входной строке.

+1

@tetri: Мейсон прав. У вас есть ошибка в другом месте вашего кода. –

+0

Я уверен, что, как и многие офисы по всему миру, мы используем эту точную конкатенацию строк в наших SQL-запросах и никогда не сталкивались с подобной проблемой. Мой опыт ограничен 2010 годом и XE2, но, глядя на ваш пример кода, я не вижу причины, по которой вы получите такое поведение. Более подробный код будет полезен. – JamesW

+0

, если эта строка кода, которую вы отправили, является точно такой же строкой из вашего кода, установите точку останова и допросите значения до их отправки через функцию формата ... Я согласен с остальными комментариями, скорее всего, ваша ошибка находится в другом месте. – GDF

ответ

9

Ваш код зависит от порядка оценки операндов в выражении. Этот порядок оценки не определен.

Глядя на более простом случае, рассмотрим следующий код:

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

Там нет никакой гарантии, в течение которого заказ функция вызывает f1() и f2() будет выполняться. Предположительно, вы ожидаете, что f1() будет исполнен до f2(), но компилятор не гарантирует этого, и на практике я считаю, что эти операнды обычно оцениваются справа налево.

В вашем коде операнды в выражении включают вызов функции ExtractValue(), который имеет побочный эффект, который изменяет его аргумент. Поскольку операнды в вашем выражении не оцениваются слева направо, вызовы ExtractValue() не встречаются в том же порядке, что и в выражении. А так как ExtractValue() имеет побочный эффект, который влияет на остальную часть выражения, результаты зависят от порядка оценки.

Вам необходимо будет переработать этот код, чтобы вызовы ExtractValue() происходили в отдельных операциях.

+0

Функция ExtractValue «потребляет» строку v - это точно ожидаемый результат ... – tetri

+0

Да, я это понимаю. Проблема в том, что вызовы 'ExtractValue()' не встречаются в том же порядке, в котором они записаны в выражении, как я пытался объяснить выше. –

+0

нет директивы компилятора для обеспечения исполнения заказа? – tetri

Смежные вопросы