![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
ADOQuery + ClientDataSet. Ошибка при пустом параметре [D7, MSSQL]
Vlad © (2005-11-15 17:54:00)БД - MS-SQL
В ADOQuery пишу простейший запрос:
select * from MyTable where MyStringField = :param
Параметру задаю тип String, нужную длину и т.п.
в коде программы:
AdoQuery.Parameters[0].Value := ''; // задаю пустую строку
AdoQuery.Open;
Все работает как надо.
Теперь беру ClientDataSet и через провайдера подключаю его к моему ADOQuery. У ClientDataSet так же прописываю параметр и задаю ему тип String и нужную длину.
в коде программы пишу:
ClientDataSet.Params[0].Value := '';
ClientDataSet.Open;
Так вот, если параметру присвоить пустое значение, то на Open вываливается exception: "The text, ntext ot image data can not be compared or sorted, except wher using IS NULL or LIKE operator".
Если непустое - то все ОК.
Смотрю профайлером, какой запрос посылается на сервер.
Профайлер говорит что тип моего параметра почему-то "text", значение - ''
а в случае непустого параметра - тип varchar, как и должно быть.
Так же, если использовать ADOQuery, без всяких ClientDataSet-ов, то пустой параметр тоже проходит нормально, и подставляется как varchar
Вобщем, понятно что кто-то (толи ClientDataSet, толи DataSetProvider) неправильно интерпретирует тип параметра, в случае, если ему присвоить ''. Но непонятно как это побороть.
Приходила в голову идея в sql запросе явно преобразовывать параметр к varchar, но это если не докопаюсь до истины...
Поделитесь, если у кого нибудь возникнут какие-то мысли по поводу данной проблемы.
Спасибо.
Vlad (2005-11-16 16:37:00) [1]
> ClientDataSet.Params[0].Value := #0;
Так сработало :-)
Но так придется каждый раз в программе производить подмену пустой строки на #0., ну впринципе тоже выход :-)
Johnmen (2005-11-16 15:52:00) [2]>Vlad © (16.11.05 15:04) [27]
...
Ещё есть смутные идеи... Но озвучивать не буду :)
PS
попробуй
ClientDataSet.Params[0].Value := #0;
Vlad (2005-11-16 15:04:00) [3]
> Johnmen © (16.11.05 13:49) [26]
Прошелся ради интереса. Тип нигде не переопределяется.
DataSetProvider считывает параметры у ClientDataSet и подставляет их в ADOQuery (подставляет правильно, я проверил). Больше никаких манипуляций с параметрами не проводилось.
Затем провайдер открывает ADOQuery, и там, вглубине метода Open возникает исключение в строчке Recordset.Open (вызов метода COM-объекта).
При всем при этом никаких изменений в параметрах не происходило вплоть до возникновения exception-a. Тип и значения были верными.
Johnmen (2005-11-16 13:49:00) [4]>Vlad © (16.11.05 13:35) [25]
Я бы вывел в Watches тип интересующего параметра и пошёл бы дебаггером, чтобы найти то место, где тип переопределяется...
Vlad (2005-11-16 13:35:00) [5]
> Johnmen © (16.11.05 13:22) [24]
> ParamLen := Length(S) + 1;
ну здесь то все понятно: устанавливают длину параметра равной длине переменной + 1 (видимо для завершающего #0)
> ParamType := ParamType shl dsSizeBitsLen or ParamLen;
Вот тут не очень понятно... С какой-то целью меняется тип параметра в завис. от его размера
но фишка в другом: TCustomClientDataSet.SetOptionalParam не выполняется вообще (дебаггером проверял).
А вот то место где считываются параметры (которые TParams, а не опциональные) и где они подставляются в запрос - я так и не нашел :-(
Johnmen (2005-11-16 13:22:00) [6]Что-то ДельфиМастера подглюкивают...:)
Писал пост, он ушёл в аут. Повторяться лень.
>Vlad © (16.11.05 12:45) [23]
Я имел в в виду строки
ParamLen := Length(S) + 1;
и
ParamType := ParamType shl dsSizeBitsLen or ParamLen;
Опциональные параметры м.б. и непричём. Важно, что какие-то манипуляции с типом происходят на основании данных параметра.
Vlad (2005-11-16 12:45:00) [7]
> Johnmen © (16.11.05 11:52) [21]
Я кажется понял, что ты имел ввиду...
ParamType := ParamTypeMap[VarType(Value) and varTypeMask];
для того чтобы получилось dsfldZSTRING нужно чтобы параметр был типа OleStr
кстати, если VarType(Value) вернет varString получится полная фигня :-)
Но опять же встает вопрос - как опциональные параметры применить к моей ситуации? :-)
Vlad (2005-11-16 12:12:00) [8]
> Johnmen © (16.11.05 11:52) [21]
Ты про OleStr, там где происходит попытка преобразования к TSQLTimeStamp?
И, кстати, а причем тут опциональные параметры, я ж их не задаю...
Johnmen (2005-11-16 11:52:00) [9]Я, кажить, понял в чём дело...
Глянь в DBClient.pas реализацию TCustomClientDataSet.SetOptionalParam
Очень интересно со строковым типом...:)
Vlad (2005-11-16 10:30:00) [10]
> Params[x].Text в рантайме
пустая строка
> Params -> Value -> Type в дизайне
string
Johnmen (2005-11-16 10:13:00) [11]Посмотри ещё
Params[x].Textв рантайме
и
Params -> Value -> Typeв дизайне
Vlad (2005-11-16 09:57:00) [12]
> Кстати, а какой тип в дизайне у параметра CDS?
ftString
а вот что выдает профайлер, если присвоить пустое значение параметру:
exec sp_executesql N'select * from personalaccount where personalaccount_id = @P1', N'@P1 text', ''
(Возникает вышеуказанная ошибка)
и вот что при непустом:
exec sp_executesql N'select * from personalaccount where personalaccount_id = @P1', N'@P1 varchar(4)', 'AFKN'
(Ошибки нет)
в обоих случаях в CDS тип параметра ftString. Менял только строчку кода
в первом случае писал
ClientDataSet.Params[0].AsString := '';
во втором
ClientDataSet.Params[0].AsString := 'AFKN';
Johnmen (2005-11-16 09:44:00) [13]
> Vlad © (16.11.05 09:36) [16]
> Непонятно почему без этого не работает :-)
Ну это то понятно
>"The text, ntext ot image data can not be compared or sorted, except wher
>using IS NULL or LIKE operator".
Непонятно, почему это...
:)
Кстати, а какой тип в дизайне у параметра CDS?
Vlad (2005-11-16 09:36:00) [14]
> Johnmen © (16.11.05 09:32) [15]
Угу. Это первое, что пришло мне в голову. Так работает.
Непонятно почему без этого не работает :-)
Johnmen (2005-11-16 09:32:00) [15]
> Vlad © (15.11.05 17:54)
> БД - MS-SQL
> В ADOQuery пишу простейший запрос:
> select * from MyTable where MyStringField = :param
А если так
select * from MyTable where MyStringField =CAST(:param AS VARCHAR(X))
Vlad (2005-11-16 09:05:00) [16]
> sniknik © (16.11.05 08:58) [12]
> > С пробелом-то все работает. Но это не пустая строка :-
> )
> а ты всетаки попробуй.
Пробовал. Запрос формируется нормально, параметр имеет тип varchar как нужно. Ошибок нет. Но и данных нет :-)
Vlad (2005-11-16 09:04:00) [17]Я кстати пытался посмотреть как все-таки провайдер формирует sql запрос, но исходников нету. Видимо все это зашито в midaslib, а pas-файла нету, только dcu
sniknik (2005-11-16 08:58:00) [18]> С пробелом-то все работает. Но это не пустая строка :-)
а ты всетаки попробуй.
Vlad (2005-11-16 08:29:00) [19]
> Desdechado © (15.11.05 22:49) [8]
> может, стоит присваивать не Value, а AsString ?
Нет, не в этом дело. И Value и AsString дают одинаковый результат (ошибку), если присваивать параметру пустую строку.
Причем, если работать напрямую с ADOQuery, то с его параметром проходит нормально хоть пустой хоть непустой параметр.
А вот ClientDataSet-овскому параметру присвоить пустое значение, то получается такая вот фигня... Провайдер почему-то решил, что пустая строка имеет тип text, а не varchar, и в запрос подставляет ее как тип text, из-за чего видимо и вылазит ошибка.
> sniknik © (15.11.05 23:56) [10]
С пробелом-то все работает. Но это не пустая строка :-)
sniknik (2005-11-15 23:56:00) [20]> Это же пробел...:)
а то я не знаю. просто напиши здесь пробел в скобочках ' ' практически не отличается от '', а так видиш заметно.