Недостаточно памяти при открытии TClientDataSet с REPLACE в базовом запросе - PullRequest
0 голосов
/ 28 мая 2018

Мой код Delphi открывает TFDQuery (FireDAC), затем открывает TClientDataSet, подключенный к нему через TDataSetProvider:

ClientDataSetData.Close;
with QueryData do
begin
  Close;
  SQL.Clear;
  SQL.Add(ASelectSQL);
  Open;
end;    
ClientDataSetData.Open;

ASelectSQL содержит этот SQL:

SELECT TT_NIV_ID,
TT_NIV,
REPLACE(TT_NIV_NAME, '|', '!') as TT_NIV_NAME2
FROM TT_SYS_PRJ_NIV

ClientDataSetData.Open выдает недостаточную ошибку памяти в наборе данных с записями 42200.

Если я проверяю данные результата (в коде Delphi), я вижу, что TT_NIV_NAME2 - это строка длины8000!Из документации REPLACE () :

Если string_expression не относится к типу varchar (max) или nvarchar (max), REPLACE усекает возвращаемое значение до 8000 байт

... так что, похоже, это происходит;не только усечение, но и установка типа результата.

TT_NIV_NAME - это VARCHAR(50), поэтому быстрое решение состоит в том, чтобы изменить SQL на

SELECT TT_NIV_ID,
TT_NIV,
CAST(REPLACE(TT_NIV_NAME, '|', '!') as VARCHAR(50))  as TT_NIV_NAME2
FROM TT_SYS_PRJ_NIV

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

Могу ли я что-нибудь сделать с кодом Delphi (Настройки TClientDataset или TFDQuery или TFDConnection?), Которые предотвращают такое высокое использование памяти?

И, честно говоря, почему бы REPLACE пришел к выводу, что "string_expression не относится к типу varchar (max) ", когда TT_NIV_NAME является VARCHAR(50)?

Примечания:

  • Протестировано с несколькими драйверами сервера SQL - это не проблема драйвера.
  • TFDConnection имеет FetchOptions.Mode := fmAll и FetchOptions.Items := FetchOptions.Items - [fiMeta];fmAll должно остаться *, и не вычитать fiMeta не имеет значения.
  • Связано [1] , но здесь string_expression длиннее 8000, или [2] , где string_expression не относится к типу varchar(max), но оба не применимы к моим данным SQL.
  • Delphi Tokyo 10.2.3 с использованием FireDAC против SQL Server 2012, приложение Win32запуск под Win7 или Win10

* .. для предотвращения известной ошибки hstmt в среде, где установлены только самые базовые драйверы SQL Server;и в любом случае в моем тестовом приложении это не имеет значения.

1 Ответ

0 голосов
/ 29 мая 2018

Мы «решили» это, применив правило отображения специально для этой строки ANSI-строки из 8000 символов.Я знаю, что это грязно, но для унаследованного приложения это работает (тем более, что мы использовали SQLDirect до перехода на FireDAC, и там varchars> 256 байтов уже были переведены в памятку).

with FDConnection.FormatOptions.MapRules.Add do
begin
  SourceDataType := dtAnsiString;
  SizeMin := 8000;
  SizeMax := 8000;
  TargetDataType := dtMemo;
end;

Это отображение специфично для SQL Server, поскольку функция REPLACE в двух других поддерживаемых нами типах баз данных (Oracle, FireBird) не имеет поведения SQL Server.

...