В Delphi Rio (10.3.3) fdQuery неправильно переводит условную функцию 'iif', когда макрос равен NULL - PullRequest
1 голос
/ 05 августа 2020

У меня есть следующая команда SQL для запуска запроса с TFDQuery с использованием PostgreSQL в качестве базы данных:

fdqr.SQL.Text: = 
  'select * from (values (current_date-1), (current_date), (current_date + 1)) as t (datetest) ' +
  '{iif (! Datevalue, where datetest =! Datevalue)}';

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

fdqr.MacroByName('datevalue').Clear;
fdqr.Open;

Итоговый журнал базы данных:

select * from (values(current_date-1), (current_date), (current_date+1)) as t(datetest) 
where datetest = NULL

Однако, если вы включите присвоение через AsRaw, оно работает должным образом, даже если предыдущее значение было '' (пустая строка), а IsNull - True.

fdqr.MacroByName('datevalue').Clear;
{ at this point IsNull = True and AsRaw is '' }
fdqr.MacroByName('datevalue').AsRaw := '';
fdqr.Open;

Журнал результирующей базы данных:

select * from (values(current_date-1), (current_date), (current_date+1)) as t(datetest) 

Это ошибка FireDA C или особенность , которую я неправильно понимаю?

1 Ответ

6 голосов
/ 05 августа 2020

Чтобы применить замену {IIF(…)} или {IF}…{FI} на основе макропеременной, значение переменной не должно быть пустым. Это то, что говорится в документации для условной замены . Это буквально означает, что подстановка применяется, если макропеременная расширяется до непустой строки. Этот факт можно проверить, просмотрев исходный код FireDA C, в частности метод TFDPhysConnectionMetadata.TranslateEscapeSequence в модуле FireDAC.Phys.Meta. В случае eskIF вы можете найти:

s := Trim(ASeq.FArgs[0]);
…
else if s <> '' then
  Result := 'True';

Давайте посмотрим, что произойдет, когда вы Clear макрос-переменную. Его Value установлен на Null, а его DataType установлен на mdUnknown. В этом случае переменная расширяется препроцессором до NULL литерала, который не является пустой строкой. Значение AsRaw не имеет значения, потому что препроцессор использует свойство SQL для подстановки.

Кажется, нет другого способа расширить макропеременную до пустой строки, кроме установки AsRaw := ''. В этом случае его DataType установлено на mdRaw, а свойство value SQL равно AsRaw.

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

Помимо вышеизложенного, вы можете избежать макросов, используя простые параметры:

select * from (values(current_date-1), (current_date), (current_date+1)) as t(datetest) 
where :Datevalue is null or datetest = :Datevalue

Таким образом вы можете очистить или установить значение параметра Datevalue, как и следовало ожидать:

{ to bind null value }
fdqr.ParamByName('Datevalue').Clear;
{ to bind some value }
fdqr.ParamByName('Datevalue').AsDate := Today;
...