У меня есть хранимая процедура SQL Server, вызываемая удаленно из стороннего приложения. Хранимая процедура выполняется правильно при локальном вызове, но не выполняется при удаленном вызове. Под локальным я подразумеваю, если я щелкну правой кнопкой мыши и выберу «Выполнить»; или если я ввожу exec sp_EBRRecipeMove
из окна запроса. Несмотря на то, что он не выполняется при удаленном вызове, никаких ошибок не возвращается.
Предыстория: эта хранимая процедура является частью последовательности хранимых процедур, которые вызываются из клиентского API. API вызывает sp_1
. sp_1
вызывает sp_2
, sp3
и sp_4
. Если ошибок нет, sp_1
вызывает sp_EBRRecipeMove
. Все это делается для проверки ошибок и переноса заданных значений из одной базы данных в другую.
Я рассыпал RAISERROR
по всему сценарию, чтобы понять, как далеко он заходит в сценарии. Журнал SQL показывает, что сценарий выполняется, но значения никогда не обновляются, а значения из исходных таблиц никогда не переносятся в целевые таблицы.
До сих пор приложение конечного пользователя (я полагаю, PHP) вызывает такое поведение, и простое приложение Java для вызова хранимой процедуры также вызывает его. Я могу выполнить это вручную/локально без проблем. У меня не будет доступа к PHP-коду.
Приложение конечного пользователя успешно вызывает другие хранимые процедуры из той же базы данных.
Чтобы уменьшить вероятность проблемы с правами доступа к БД, я предоставил пользователю, который используется для удаленного подключения, доступ системного администратора.
Я проверил, что все экземпляры столбца RecipeID
в базе данных и связанные с ними переменные имеют значение INT
. В целевой таблице этот столбец имеет значение Int NOT NULL
, но в других таблицах (EBR) я разрешаю значения Null, поскольку значение может быть не заполнено.
ОБНОВЛЕНИЕ: с тех пор я убедился, что стороннее приложение не вызывает хранимую процедуру через транзакцию. Из базы данных Oracle, которую они используют, это простой вызов.
Используя уже опубликованные подсказки, я значительно устранил неполадки, поскольку смог успешно выполнить хранимую процедуру, вызвав ее из стороннего Java-приложения. Однако при внесении изменений в настройку клиента команды не выполняются. Я прокомментировал код и попытался выполнить по одной команде за раз с помощью Try... Catch вокруг каждого. Попробуйте... Catch не возвращает никаких ошибок, но команды не выполняются. Есть ли в таблицах специальное разрешение или настройка, которые разрешают удаленное выполнение команд «Вставить», «Удалить» и «Обновить»? Любая помощь или подсказки очень ценятся!
ОБНОВЛЕНИЕ 2: из другого сообщения stackoverflow, связанного с Deletes от @Remus Rusanu, я могу предоставить следующую информацию о случаях, когда Deletes или другие команды могут не выполняться, и, надеюсь, завтра опубликую свой исправленный код:
• DELETE не выполняется (проблема управления логическим потоком, она использует другую ветвь IF...) [Это не так, у меня есть RAISERROR непосредственно перед и сразу после команды, которая записывает разумную информацию с учетом входных данных (за исключением того, что Удаление не произошло)]
• DELETE выполняется, но не влияет на какие-либо строки (предложение WHERE или проблема JOIN) [Это не так, или, по крайней мере, кажется, поскольку я могу взять Delete...Where и поместить его в запрос и выполнить. Я не использую соединения.]
• DELETE выполняется и ошибки, и ошибка молча подавляется (проблема обработки ошибок) [Это не должно быть проблемой, поскольку я закомментировал весь код, кроме 1 оператора Delete...Where и поместил Try...Catch непосредственно вокруг него ]
• DELETE выполняется, но эффект откатывается (проблема управления транзакциями) [Это не тот случай, потому что я не использую транзакции, и вызывающий клиент не использует транзакцию.]
• DELETE выполняется, но эффект компенсируется приложением (проблема с логикой приложения). Кроме того, клиент использует простую команду CALL от Oracle.]
• DELETE не выполняется, потому что предыдущая ошибка останавливает запрос (опять проблема с обработкой ошибок) [Этого не должно быть, потому что я вижу, что RAISERROR регистрирует разумную информацию непосредственно перед и сразу после оператора Delete.]
• DELETE выполняется, но ваша проверка неверна (PBCAK) [Это не так, поскольку строка не удаляется. Оператор Select таблицы указывает, что после выполнения хранимой процедуры строка не повреждена.]
ALTER PROCEDURE [dbo].[sp_EBRRecipeMove]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare @Version smallint;
Declare @CheckedOutID tinyint;
Declare @AbleToSave bit;
Declare @EquipName varchar(80);
Declare @RcpName varchar(80);
Declare @EquipID tinyint;
Declare @status int;
Declare @prRcpName varchar(80);
Declare @prVersion smallint;
Declare @tmprows int;
Declare @recipeid int;
Declare @tmpid int
Declare @groupid tinyint;
Declare @rcpcomment varchar(200);
Declare @prrcpcomment varchar(200);
Declare @savedatim datetime;
Declare @saveuser varchar(80);
Declare @approvaldatim datetime;
Declare @approvaluser varchar(80);
Declare @deactdatim datetime;
Declare @deactuser varchar(80);
Declare @existingRecID int;
DECLARE @ErrorSave int
SET @ErrorSave = 0
-- Select recipe info from EBRRecipeHeader table
SELECT @RcpName=recipename
FROM EBRRecipeHeader
-- Select recipe info from prRecipeHeader table
SELECT @prRcpName=RecipeName
FROM prRecipeHeader
WHERE RecipeName = @RcpName
set @Version = 1;
set @status = 3;
set @groupid = 1;
set @savedatim = CURRENT_TIMESTAMP;
set @saveuser = 'EBR'
set @approvaldatim = CURRENT_TIMESTAMP;
set @approvaluser = 'EBR'
set @CheckedOutID = 0;
if @@ROWCOUNT = 0
begin
INSERT INTO dbo.prRecipeHeader(
GroupID,
Status,
RecipeName,
Version,
RecipeComment,
SaveDateTime,
SaveUser,
ApprovalDateTime,
ApprovalUser,
DeactivateDateTime,
DeactivateUser,
CheckedOutID
) VALUES (
@groupid,
@status,
@RcpName,
@Version,
@rcpcomment,
@savedatim,
@saveuser,
@approvaldatim,
@approvaluser,
@deactdatim,
@deactuser,
@CheckedOutID
)
end
ELSE
begin
DELETE FROM prRecipeHeader
WHERE RecipeName = @RcpName
INSERT INTO dbo.prRecipeHeader(
GroupID,
Status,
RecipeName,
Version,
RecipeComment,
SaveDateTime,
SaveUser,
ApprovalDateTime,
ApprovalUser,
DeactivateDateTime,
DeactivateUser,
CheckedOutID
) VALUES (
@groupid,
@status,
@RcpName,
@Version,
@rcpcomment,
@savedatim,
@saveuser,
@approvaldatim,
@approvaluser,
@deactdatim,
@deactuser,
@CheckedOutID
)
end --if <>0
select @recipeid = RecipeID from prRecipeHeader where prRecipeHeader.RecipeName = @RcpName;
declare @recipeidText as varchar(8)
set @recipeidText = convert(varchar(8), @recipeid)
RAISERROR (@recipeidtext,10,1) WITH LOG
RAISERROR ('RecipeID before Globals',10,1) WITH LOG
UPDATE EBRRecipeGlobals SET EBRRecipeGlobals.recipeid = @recipeid;
set @recipeidText = convert(varchar(8), @recipeid)
RAISERROR (@recipeidtext,10,1) WITH LOG
RAISERROR ('RecipeID before global insert',10,1) WITH LOG
INSERT INTO prRecipeGlobals SELECT * FROM EBRRecipeGlobals where EBRRecipeGlobals.recipeid = @recipeid;
DELETE From EBRRecipeGlobals Where EBRRecipeGlobals.recipeid = @recipeid;
set @recipeidText = convert(varchar(8), @recipeid)
RAISERROR (@recipeidtext,10,1) WITH LOG
RAISERROR ('RecipeID after globals insert, before steps',10,1) WITH LOG
UPDATE EBRRecipeSteps SET EBRRecipeSteps.RecipeID = @recipeid;
set @recipeidText = convert(varchar(8), @recipeid)
RAISERROR (@recipeidtext,10,1) WITH LOG
RAISERROR ('RecipeID before steps insert',10,1) WITH LOG
INSERT INTO prRecipeSteps SELECT * FROM EBRRecipeSteps where EBRRecipeSteps.RecipeID = @recipeid;
DELETE From EBRRecipeSteps Where EBRRecipeSteps.RecipeID = @recipeid;
DELETE FROM EBRRecipeHeader
end