Текущий архив: 2008.04.13;
Скачать: CL | DM;
Вниз
SQL выражение в ADO вызывает исключение в msvcrt.dll Найти похожие ветки
← →
ЮЮ © (2007-11-19 12:24) [40]> Нет именно.
>
> a.ParamCheck:=false;
> a.CommandText:=a.Parameters.ParseSQL(текст_запроса,true)
>
> a.Parameters.ParseSQL(текст_запроса,true);
Тогда третья строка, пожалуй, лишняя - ведь всё это уже выполнено во аторой.
← →
ЮЮ © (2007-11-19 12:25) [41]> Тогда третья строка, пожалуй, лишняя - ведь всё это уже
> выполнено во аторой.
Мда, поспешил.a.CommandText:=
очистит a.Parameters
← →
oxffff © (2007-11-19 12:26) [42]
> ЮЮ © (19.11.07 12:24) [40]
После второй строки a.Parameters.Count=0.
← →
Anatoly Podgoretsky © (2007-11-19 12:27) [43]> oxffff (19.11.2007 12:20:39) [39]
Это странное слово - собака друг человека.
В данной строке должен быть запрос, а вот следующая строка как раз и занимается парсингом и созданием параметров, и то иногда не сможет исправиться. Кроме этого можно параметр создать и в ДизайнТайм, для фиксированых запросов.
← →
oxffff © (2007-11-19 12:36) [44]
> Anatoly Podgoretsky © (19.11.07 12:27) [43]
Если сделать, на чем настаиваете вы, а именно
a.CommandText:=текст_запроса
a.Parameters.ParseSQL(текст_запроса,true);
..
a.open;
тогда ошибка следующая
Incorrect systax near :
при Adodataset.open
← →
oxffff © (2007-11-19 12:40) [45]
> Кроме этого можно параметр создать и в ДизайнТайм, для фиксированых
> запросов.
В том то и дело, что запросы у меня формируются на лету.
И количество параметров меняется в зависимости от условий.
Генератор запроса сам ищет нужный параметр в классе формы и заполняет его на лету.
Таким образом я здесь вообще не принимаю участия, за исключением написания этой логики.
← →
Сусл © (2007-11-19 12:54) [46]
> [37] Anatoly Podgoretsky © (19.11.07 11:33)
> > Сусл (19.11.2007 11:26:35) [35]
>
> И выяснеешь у сервера, а в каком виде он например принимает
> даты.
> Про оптимизацию я вообще молчу, про нее можешь забыть.
грусновато, Анатолий, от тебя это слышать.
1. конкретный сервер всегда имеет универсальный формат даты, которые понимается всегда. есть он и у mssql.
2. ты смотрел профайлером как вызывается например AdoCommand? Это приводит к вызову sp_executesql. никто мне не запрещает пользоваться его параметрами самому. оптимизация (я так понимаю повторное использование плана запроса) в этом случае будет работать прекрасно.
а для оптимизации существенно важднее при использовании sp_executesql не забывать давать fully qualified всем таблицами и запросам (документированная, кстати, фича).
← →
Anatoly Podgoretsky © (2007-11-19 13:13) [47]Вот пример из одного очень древнего проекта
CommonCommand.CommandText := "DELETE FROM AuditDocuments WHERE OperationTime<:D";
CommonCommand.Parameters.ParseSQL(CommonCommand.CommandText, True);
CommonCommand.Parameters.ParamByName("D").Value := Now - 30;
CommonCommand.Execute;
ParamCheck = False
← →
oxffff © (2007-11-19 13:29) [48]
> Anatoly Podgoretsky © (19.11.07 13:13) [47]
А у меня пример из сегодняшнего проекта. :)
Только у меня TadoDataset у которого нет Execute.
+запрос для возврат набора данных.
← →
Anatoly Podgoretsky © (2007-11-19 13:30) [49]
> грусновато, Анатолий, от тебя это слышать.
Почему же грустно, это же обусловлено принципом работы сервера
НапримерWHERE DT="20071119"
иWHERE DT="20071120"
Будет проводится полный комплекс от разбора до компиляции запроса, аWHERE DT=:DT
при любых DT как минимум компилирование будет только один раз, но также сработает и статистика, в результате если 19 числа запрос выполнялся за 30 секунд, то 20 возможно уже за 10 секунд.
← →
Anatoly Podgoretsky © (2007-11-19 13:34) [50]> oxffff (19.11.2007 13:29:48) [48]
Не обращай ты внимание на Execute, это первый попавшийся пример. Для dataset тоже самое, только Open
Правда я эту технику использовал только на БДЕ, там эта проблема с параметрами наблюдалась, а на АДО я ни разу не наткнулся. Но я помню эту технологию на случай возникновение проблем.
← →
oxffff © (2007-11-19 14:05) [51]
> Anatoly Podgoretsky © (19.11.07 13:34) [50]
Да я еще на одни такие грабли наткнулся. Но уже в Delphi реализации.
Грабли следующие
Запустите следующий код
var a:TADODataSet;
b:string;
begin
inherited;
a:=TADODataSet.Create(nil);
b:=b+"select * from abc where a=:param1";
a.Parameters.ParseSQL(b,true);
showmessage(b);
и посмотрите чему равно b
← →
Anatoly Podgoretsky © (2007-11-19 14:09) [52]> oxffff (19.11.2007 14:05:51) [51]
Зачем в угадайку играть?
Но меня здесь смучает b+, зачем?
← →
oxffff © (2007-11-19 14:13) [53]
> Anatoly Podgoretsky © (19.11.07 14:09) [52]
> > oxffff (19.11.2007 14:05:51) [51]
>
> Зачем в угадайку играть?
> Но меня здесь смучает b+, зачем?
А затем чтобы счетчик был не FFFFFFFF.
← →
oxffff © (2007-11-19 14:16) [54]b:="select * from abc where a=:param1";
a.Parameters.ParseSQL(b,true);
showmessage(b);
на экране select * from abc where a=:param1
А если
b:=b+"select * from abc where a=:param1";
a.Parameters.ParseSQL(b,true);
showmessage(b);
на экране select * from abc where a=?
← →
Сусл © (2007-11-19 14:20) [55]
> [49] Anatoly Podgoretsky © (19.11.07 13:30)
>
> WHERE DT=:DT
> при любых DT как минимум компилирование будет только один
> раз, но также сработает и статистика, в результате если
> 19 числа запрос выполнялся за 30 секунд, то 20 возможно
> уже за 10 секунд.
ты эта, невнимательно мой пост прочел.
← →
Anatoly Podgoretsky © (2007-11-19 14:23) [56]Что то с оптимизацией и со ссылками в строках. Второй вариант работает не правильно. Что именно не пойму, но это последствие b+ и то что функция ParseSQLиспользуется как процедура.
Во втором варианте есть побочное использование b, результат почему то помещенно в нее.
Сейчас проверю на своем компиляторе.
← →
Anatoly Podgoretsky © (2007-11-19 14:25) [57]
> ты эта, невнимательно мой пост прочел.
Разве нет, если не понял, то доведи свою мысль. Мой ответ касается MS SQL и как подготавливаются запросы, если в запросе будет изменен хотя бы один символ, то он будет перекомпилирован, со статистикой 0 и неизвестным планом.
← →
oxffff © (2007-11-19 14:26) [58]
> Anatoly Podgoretsky © (19.11.07 14:23) [56]
А вы посмотрите реализацию ParseSQL.
И все станет ясно.
Я на эти грабли 2 часа убил.
← →
sniknik © (2007-11-19 14:27) [59]> А если
а если сделать правильно?
...
b:= a.Parameters.ParseSQL(b,true);
...
(параметр b, не var чтобы расчитывать на возврат)
← →
oxffff © (2007-11-19 14:30) [60]
> sniknik © (19.11.07 14:27) [59]
Вы что-то не поняли.
b:=b+"select * from abc where a=:param1";
a.Parameters.ParseSQL(b,true);
showmessage(b);
на экране будет select * from abc where a=?
А не "select * from abc where a=:param1
← →
Anatoly Podgoretsky © (2007-11-19 14:33) [61]Проверил.
В Д7 ошибка есть, и не зависит присваивается ли результат функции переменной.
В Д10 ошибка устранена.
← →
Anatoly Podgoretsky © (2007-11-19 14:35) [62]
> sniknik © (19.11.07 14:27) [59]
Строки это очень хитрая вещь, могут быть любые сюрпризы, тем более когда в таком странном виде.
← →
oxffff © (2007-11-19 14:37) [63]
> Anatoly Podgoretsky © (19.11.07 14:33) [61]
Во во, И я о том же. Сидел и думал почему, когда я делаю так
Dataset.ParamCheck:=false;
Dataset.CommandText:=Dataset.Parameters.ParseSQL(SQL,true);
Dataset.Parameters.ParseSQL(SQL,true);
showmessage(Dataset.Parameters.ParseSQL(SQL,true)) дает 0. :)
Пришлось поправить на
Dataset.ParamCheck:=false;
Dataset.CommandText:=Dataset.Parameters.ParseSQL(DupeString(SQL,1),true);
Dataset.Parameters.ParseSQL(SQL,true);
← →
oxffff © (2007-11-19 14:38) [64]
> showmessage(Dataset.Parameters.ParseSQL(SQL,true)) дает
> 0. :)
showmessage(inttostr(Dataset.Parameters.count));
← →
oxffff © (2007-11-19 14:42) [65]
> sniknik © (19.11.07 14:27) [59]
> > А если
> а если сделать правильно?
> ...
> b:= a.Parameters.ParseSQL(b,true);
> ...
> (параметр b, не var чтобы расчитывать на возврат)
Запустите
a:=TADODataSet.Create(nil);
a.Connection:=ADOConnection;
b:=b+"select * from abc where a=:param1";
c:=a.Parameters.ParseSQL(b,true);
if pointer(b)=pointer(c) then showmessage("Idential Ref");
← →
sniknik © (2007-11-19 14:58) [66]> Запустите
я понял что ты хочеш сказать с первого раза...
но учитывая
Anatoly Podgoretsky © (19.11.07 14:35) [62]
> Строки это очень хитрая вещь
+ отсутствие var для параметра, + что строка это всетаки указатель и работа в процедуре идет с ней по адресу (value:= PChar(...)) + непонятное(бессмысленное) компилятору действие
=
> а если сделать правильно?
и получать выражение (если оно нужно) оттуда где оно гарантируется.
← →
oxffff © (2007-11-19 15:12) [67]
> sniknik © (19.11.07 14:58) [66]
Строки не хитрее нас с вами.
Что значит гарантируется?
Если передается параметр по значению.
То его значение не должно меняться.
Это правило.
>и получать выражение (если оно нужно) оттуда где оно гарантируется.
мне нужен результат и неизмененоое значение входного параметра.
А то что эта функция производят прямое взаимодействие со строкой и нарушает семантику типа. То это БАГ.
← →
Anatoly Podgoretsky © (2007-11-19 15:26) [68]> oxffff (19.11.2007 15:12:07) [67]
Это баг, но привел к нему ты, кострукцией B := B + Text
Баг устранен в следующей версии Дельфи.
← →
oxffff © (2007-11-19 15:34) [69]
> Anatoly Podgoretsky © (19.11.07 15:26) [68]
Что значит я привел?
То есть вы хотите сказать, что это нормально?
А правильно вас понял?
← →
Сусл © (2007-11-19 15:34) [70]
> [57] Anatoly Podgoretsky © (19.11.07 14:25)
>
> > ты эта, невнимательно мой пост прочел.
>
> Разве нет, если не понял, то доведи свою мысль. Мой ответ
> касается MS SQL и как подготавливаются запросы, если в запросе
> будет изменен хотя бы один символ, то он будет перекомпилирован,
> со статистикой 0 и неизвестным планом.
запрос все равно в большинстве случаев выливается в вызов sp_executesql
так тебе никто не мешает самому пользоваться ентой штукой.
вот о чем речь.
← →
oxffff © (2007-11-19 15:36) [71]
> Это баг, но привел к нему ты, кострукцией B := B + Text
Да какая конструкция. Эта конструкция нужна для того, чтобы выявить бажную ситуацию. И сделано для того, чтобы строка была в куче, а сегменте данных. Я же вам написал
oxffff © (19.11.07 14:13) [53]
oxffff © (19.11.07 14:30) [60]
← →
oxffff © (2007-11-19 15:39) [72]oxffff © (19.11.07 15:36) [71]
Точнее
oxffff © (19.11.07 14:16) [53]
oxffff © (19.11.07 14:16) [54]
← →
Anatoly Podgoretsky © (2007-11-19 15:39) [73]> oxffff (19.11.2007 15:34:09) [69]
Нет, я так не говорил, это не нормально, как ошибка, так и код.
Твое объяснение насчет ссылок меня не убедило.
← →
Anatoly Podgoretsky © (2007-11-19 15:40) [74]> oxffff (19.11.2007 15:36:11) [71]
Я возможно не понимаю истинной цели данной операции.
← →
Anatoly Podgoretsky © (2007-11-19 15:43) [75]> Сусл (19.11.2007 15:34:10) [70]
Можно много чего, но я предпочту стандартный механизм. Но если ты обеспечишь изменение запроса, что бы получилось where a=? и сумеешь передать параметры, тогда да, но тогда это ничем не будет отличаться от стандартного пути + некоторый геморой.
А как выполняются запросы в MS SQL неплохо описано в BOL, я попытался рассказать на рабоче-крестьянском. Ведь если я даже и стремлюсь переубедить тебя, то не очень настойчиво.
← →
oxffff © (2007-11-19 16:09) [76]
> Anatoly Podgoretsky © (19.11.07 15:40) [74]
> > oxffff (19.11.2007 15:36:11) [71]
>
> Я возможно не понимаю истинной цели данной операции.
> Anatoly Podgoretsky © (19.11.07 15:40) [74]
Потому что для строкового литерала(который размещен в сегменте данных будет создана копия при Result := SQL (первая строка ParseSQL)
А для не строкового литерала будет просто увеличен счетчик.
См. реализацию LStrLAsg
← →
oxffff © (2007-11-19 16:11) [77]
> oxffff © (19.11.07 16:09) [76]
А далее идет прямое обращение со строкой приводя ее к pchar, тем самым нарушая семантику типа.
Отсюда грабли.
Теперь понятно??
← →
Anatoly Podgoretsky © (2007-11-19 16:15) [78]> oxffff (19.11.2007 16:09:16) [76]
Это то понятно, а вот цель нет.
← →
sniknik © (2007-11-19 16:21) [79]> Теперь понятно??
а вот теперь мне не понятно, получается ты специально "сбил настройки", в полном уме и трезвой памяти, а после удивляешься "ой, а тут получается разный результат", получая этот результат оттуда откуда не должен...
зачем?
← →
oxffff © (2007-11-19 16:30) [80]Anatoly Podgoretsky © (19.11.07 16:15) [78]
sniknik © (19.11.07 16:21) [79]
Начнем по порядку.
1. Баг1 не некорректная обработка параметров провайдером.
--> Решение
Dataset.ParamCheck:=false;
Dataset.CommandText:=Dataset.Parameters.ParseSQL(SQL,true);
Dataset.Parameters.ParseSQL(SQL,true);
Но поскольку у меня вместо SQL был вызов процедуры которая возвращает WideString. А поскольку в двух вызовах создается две копии string. Поэтому одна на другую не влияет.
Далее.
Я делаю так
SQL:= <- здесь это уже string
Dataset.ParamCheck:=false;
Dataset.CommandText:=Dataset.Parameters.ParseSQL(SQL,true);
Dataset.Parameters.ParseSQL(SQL,true);
и нарываюсь на другие грабли уже в delphi.
По скольку если строка в куче, то параметров после вызова
Dataset.CommandText:=Dataset.Parameters.ParseSQL(SQL,true);
уже нет.
По скольку они заменены на ? напрямую во входном параметре.
А после вызов Dataset.Parameters.ParseSQL(SQL,true);
не создает параметров. По скольку в строке уже их нет.
Чего не понятно то?
Страницы: 1 2 3 4 вся ветка
Текущий архив: 2008.04.13;
Скачать: CL | DM;
Память: 0.64 MB
Время: 0.011 c