Форум: "Базы";
Текущий архив: 2007.02.04;
Скачать: [xml.tar.bz2];
ВнизПочему не возникает ошибка? Найти похожие ветки
← →
Bless © (2006-11-14 11:22) [0]ситуация :
есть
cmd: TADOCommand;
cmd.CommandText = "exec sp_executesql N"DELETE FROM t1 WHERE 1=0 INSERT INTO t2 (kod) values (1)""
Причем в свойствах ADOConnection стоит пользователь, имеющий все права на таблицу t1 и не имеющий никаких прав (ни SELECT, ни INSERT, ни DELETE) на таблицу t2.
по клику на кнопку выполняется
cmd.execute.
Вопрос: почему не выскакивает ошибка "нет права на INSERT"?
Примечание (нужно оно, не нужно, не знаю, на всякий случай напишу):
Если заменить:
-DELETE FROM t1..., INSERT INTO t2...
на
"SELECT... FROM t1..., SELECT... FROM t2..."
-TADOCommand
наTADODataset
-cmd.execute
наcmd.open; cmd.nextRecordset;
то на строчкеcmd.nextRecordset;
словим желаемую ошибку.
← →
ANB © (2006-11-14 11:29) [1]Вот такая у MS SQL дебильная логика. Нету у них исключений. Есть только ошибки, которые складываются в некий буфер. Буфер можешь посмотреть после выполнения. А у ADO есть некоторые проблемы при работе с такой извращенной логикой.
← →
ANB © (2006-11-14 11:30) [2]Кистате, я на такую граблю наступал. Если бы ошибок было много ты бы еще увидел, что часть из них пропадает (сравнивать с результатом выполнения в QA)
← →
Bless © (2006-11-14 11:34) [3]
> ANB © (14.11.06 11:29) [1]
>
> Вот такая у MS SQL дебильная логика. Нету у них исключений.
> Есть только ошибки, которые складываются в некий буфер.
> Буфер можешь посмотреть после выполнения.
Если видоизменить запрос на
exec sp_executesql N"INSERT INTO t2 (kod) values (1)",
то отсутсвие исключений (в MSSQL) не помешают мне поймать исключение (в Delphi). Так что камень в сторону дебильной логики MS SQL, как мне кажется, брошен зря.
← →
ЮЮ © (2006-11-14 11:36) [4]а если добавить SET NOCOUNT ON дабы не было кучи лишних recordSet-ов ?
← →
Bless © (2006-11-14 11:40) [5]ЮЮ © (14.11.06 11:36) [4]>
Тады исключение выскакивает :)
А почему она не выскакивает в первом случае, не объяснишь?
← →
Anatoly Podgoretsky © (2006-11-14 11:41) [6]> Bless (14.11.2006 11:22:00) [0]
До ошибок дело не дойдет, поскольку не откомпилируется
← →
ЮЮ © (2006-11-14 11:41) [7]Кстати, почему
cmd.CommandText = "exec sp_executesql N"DELETE FROM t1 WHERE 1=0 INSERT INTO t2 (kod) values (1)""
а не просто
cmd.CommandText = "DELETE FROM t1 WHERE 1=0 INSERT INTO t2 (kod) values (1)"
← →
ЮЮ © (2006-11-14 11:45) [8]Потому что первое предложение выполнилось без ошибок. И "ххх row affected" попало в тот самый первый recordset, а ошибка - во второй.
← →
Bless © (2006-11-14 11:48) [9]
> Anatoly Podgoretsky © (14.11.06 11:41) [6]
>
> > Bless (14.11.2006 11:22:00) [0]
>
> До ошибок дело не дойдет, поскольку не откомпилируется
Если Вы на кавычки намекаете, то это ведь не помешало понять мысль, которую я хотел донести?
> ЮЮ © (14.11.06 11:41) [7]
>
> Кстати, почему
Не до конца упростил пример :)
← →
ЮЮ © (2006-11-14 11:59) [10]
> Не до конца упростил пример :)
Всё равно, не понимаю, как на клиентской стороне вообще могло возникнуть exec sp_executesql :) Тем более до упрощения.
← →
Bless © (2006-11-14 12:06) [11]
> ЮЮ © (14.11.06 11:45) [8]
>
> Потому что первое предложение выполнилось без ошибок. И
> "ххх row affected" попало в тот самый первый recordset,
> а ошибка - во второй.
Гм... Как-то я сомневаюсь, что "ххх row affected" попадает в recordset, потому что
ADODataset1.Recordset := cmd.Execute;
даст исключение "Recordset is not open"
← →
Bless © (2006-11-14 12:11) [12]
> ЮЮ © (14.11.06 11:59) [10]
> Всё равно, не понимаю, как на клиентской стороне вообще
> могло возникнуть exec sp_executesql :) Тем более до упрощения.
>
На клиентской стороне динамически формировался длинный запрос с параметрами и был он естественно без exec sp_executesql. Я просто взял его в том виде, в каком он попал в профайлер (с exec sp_excutesql) и вставил в тестовом проекте в CommandText, вместо того чтоб копировать кусок кода, формирующий запрос и заполняющий параметры .
← →
sniknik © (2006-11-14 12:13) [13]> сравнивать с результатом выполнения в QA
врядли сравнение будет корректным, QA сам разбивает блоки команд по своей логике, и выполняет частями, для явного разделения введена команда GO... (ИМХО естественно т.к. это нигде не задокументировано а основано на наблюдениях за поведением и догадках)
ошибка там всетаки есть, ты до не просто не "доходишь", в варианте с SET NOCOUNT ON пропускаются отработанные "пустые" и сразу первым встает ошибочный...
один из вариантов как до нее всетаки можно добратьсяvar
i: integer;
Recordset: _Recordset;
V: OleVariant;
begin
Info:= false;
ADOConnection1.Close;
ADOConnection1.CursorLocation:= clUseServer;
ADOConnection1.ConnectionString:= {строка коннекта с твоим ограниченным юзером};
Recordset:= ADOConnection1.Execute("exec sp_executesql N""DELETE FROM t1 WHERE 1=0 INSERT INTO t2 (kod) values (1)""");
while not (stOpen in ADOConnection1.State) do;
while true do begin
for i:= 0 to ADOConnection1.Errors.Count-1 do
if ADOConnection1.Errors[i].NativeError = 0 then
Memo1.Lines.Add(IntToStr(ADOConnection1.Errors[i].NativeError)+ ADOConnection1.Errors[i].Description);
try
if Recordset = nil then Exit
else Recordset:= Recordset.NextRecordset(V);
except
for i:= 0 to ADOConnection1.Errors.Count-1 do
Memo1.Lines.Add(IntToStr(ADOConnection1.Errors[i].NativeError)+" : "+ADOConnection1.Errors[i].Description);
Exit;
end;
end;
end;
← →
ЮЮ © (2006-11-14 12:24) [14]>Гм... Как-то я сомневаюсь, что "ххх row affected" попадает в recordset, потому что...
Я имел в виду Recordset в контексте
cmd.nextRecordset;
т.е. _Recordset а не ADODataset1.Recordset
← →
Anatoly Podgoretsky © (2006-11-14 12:39) [15]> Bless (14.11.2006 11:48:09) [9]
Мысль будем пытаться понимать, после того как она изложена в четкой форме.
← →
Anatoly Podgoretsky © (2006-11-14 12:39) [16]> ЮЮ (14.11.2006 11:59:10) [10]
> Тем более до упрощения.
И после тоже
← →
Bless © (2006-11-15 11:07) [17]Я все-таки не понимаю.
1)
При SET NOCOUNT OFF на клиента посылаются сообщения "... rows affected". Как на клиенте эти сообжения посмотреть?
2)
В MSDN по поводу NextRecordset написано:...Use the NextRecordset method to return the results of the next command in a compound command statement...
f a non–row-returning command executes successfully, the returned Recordset object will be closed...
запрос"SET NOCOUNT ON INSERT INTO t1(kod) VALUES 9 DELETE FROM t1 WHERE kod=9 "
compound? Да. Insert и Delete executes successfully? Да.
Значит, по идееRecordset:= ADOConnection1.Execute("SET NOCOUNT ON INSERT INTO t1(kod) VALUES 9 DELETE FROM t1 WHERE kod=9 ");
Recordset:= Recordset.NextRecordset(V);
и после первой и после второй строчек recordset должен бы быть не равным nil. Хотя это не так (из-за SET NOCOUNT ON).
>
> ошибка там всетаки есть, ты до не просто не "доходишь",
> в варианте с SET NOCOUNT ON пропускаются отработанные "пустые"
> и сразу первым встает ошибочный...
Что имеется в виду под "пустые"?
> if ADOConnection1.Errors[i].NativeError = 0 then
А чем так примечательны error-ы с NativeError = 0?
← →
sniknik © (2006-11-15 12:01) [18]> Значит, по идее
> ...
у Execute есть еще параметры, и SET NOCOUNT ON убрал в твоем варианте результат первого запроса, остался один, т.е. при присвоение следующего будет ошибка т.к. в next null.
> Что имеется в виду под "пустые"?
не возвращающие данных, рекордсет который возвращается только ради сообщения по отработанной команде, количества обработанных записей (может еще чего служебного) на каждую команду, получается связанный список от всех комманд в пакете. SET NOCOUNT ON такие "пустышки" и убирает, оставляет только с данными либо с критической ошибкой... на клиента получаешь усеченный список, где либо в первом сразу данные либо ошибка.
вот попробуй первой командой поставить SELECT, он нокаунтом не уберется, и ошибка опять в твоем варианте "пропадет", т.к. делфевый компонент увидит первым нормально отработавшую команду.
кстати посмотри отработку выполнения команд как это делается в TADODataSet, он тоже чистит список, до первого с данными... т.е. тут не только ADO, но нужно еще и понимание работы делфевых оберток. (понять что это не одно и тоже ;)
> А чем так примечательны error-ы с NativeError = 0?
не помню, давно это писалось, и в общем то не для твоего вопроса, а для получения сообщений от PRINT. может это и есть это самое сообщение.
← →
Bless © (2006-11-15 12:39) [19]
> sniknik © (15.11.06 12:01) [18]
>
> у Execute есть еще параметры
>
Что-то не пойму, это к чему? Если намек на то, что через параметр ExecuteOptions передался eoExecuteNoRecords, то ведь это не так в данном случае. Или просто совет ознакомиться?
> и SET NOCOUNT ON убрал в твоем варианте результат первого
> запроса, остался один, т.е. при присвоение следующего будет
> ошибка т.к. в next null.
Почему тогда NOCOUNT не убрал оба? Ведь оба запроса - "пустые". Ну вернул бы recordset=nil, делов-то.
← →
sniknik © (2006-11-15 12:53) [20]> Что-то не пойму, это к чему?
> При SET NOCOUNT OFF на клиента посылаются сообщения "... rows affected". Как на клиенте эти сообжения посмотреть?
> Почему тогда NOCOUNT не убрал оба?
а как тогда сигнализировать что чтото вообще выполнилось? чтото должно вернутся, если нет/не осталось вообще ни одного, то будет послан "анонимный" ник чему и ни о чем, с affectreords = -1, и пустым списком ошибок. (ну, насколько помню ;)
но в твоем случае второй с ошибкой, он останется в любом случае.
← →
Bless © (2006-11-15 15:39) [21]
> sniknik © (15.11.06 12:53) [20]
>
> а как тогда сигнализировать что чтото вообще выполнилось?
Ну мало ли способов... А зачем для этого сигнал? Вот если не выполнилось, то и возвращали бы Recordset с непустым errors. А nil -значит выполнилось.
Возвращать цельный объект recordset, не несущий смысловой нагрузки, только чтоб сигнализировать о том, что что-то там выполнилось как-то некрасиво, имхо.
Впрочем ладно, может быть, со временем, перечитывая ветку, я проникнусь логичностью такого выбора :)
Спасибо.
← →
sniknik © (2006-11-15 15:57) [22]> Ну мало ли способов... А зачем для этого сигнал?
как сделано так сделано. и что значит зачем? не нужен, включи асинхронное выполнение и не жди ответов... а в этом случае токов режим/протокол работы.
> Возвращать цельный объект recordset
не уверен что возвращается именно рекордсет, даже когда он возвращается... скорее какаято структура, типа record/интерфейс у которой одно поле указатель на непосредственно рекордсет (данные)... пустышка его не содержит, только заголовок/header .
просто принято так, во всех хелпах/руководствах пишется/называется что возвращается рекордсет... но как оно внутри организовано это к мелкософтским разработчикам или собственные хакерские изыскания/догадки...
p.s. назови это не рекордсетоми, а пакетами ответов, в которых есть или нету данных... и не отвлекайся больше на ерунду.
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2007.02.04;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.042 c