Оператор TSQL в OSQL не выполняется при вызове из пакетного файла, вызываемого из пакетного файла
Я автоматизирую различные EXE-файлы с помощью пакетного файла, включая вызов существующего пакетного файла, который, в свою очередь, выполняет различные операторы TSQL через OSQL.exe.
Существующий пакетный файл работает нормально. Однако при вызове из моего пакетного файла происходит сбой вызова osql.exe, что приводит к выходу самого пакетного файла.
:check_user_privs
%OSQLPATH% %CONNECTSTRING% -S "%SERVER_INSTANCE%" -d "%DBNAME%" -Q "DECLARE @userName varchar(100) ; set @userName = user_name() ; IF IS_SRVROLEMEMBER ('sysadmin') != 1 RAISERROR ('This user ''%s'' is not a member of the ''sysadmin'' group.' , 16 , 127 , @userName )" > /nul
if errorlevel 1 (
echo ** ERROR - The user is NOT a sysadmin member on "%SERVER_INSTANCE%" - Exiting ** 1
echo.
pause
exit
)
Достаточно сказать, что ошибка происходит. С ECHO ON эта первая строка становится:
"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\OSQL.EXE" -U"ADMIN" -P"PASSWORD" -S "SQL_SRVR10" -d "DB01" -Q "DECLARE @userName varchar(100) ; set @userName = user_name() ; IF IS_SRVROLEMEMBER ('sysadmin') != 1 RAISERROR ('This user ''ADMIN'' is not a member of the ''sysadmin'' group.' , 16 , 127 , @userName )" > /nul
Эта строка идентична, когда я вызываю скрипт непосредственно из командной строки или из моего собственного командного файла.
Я вручную захватил переменные среды, которые устанавливаются, когда этот пакетный файл вызывается из моего пакетного файла. Затем я устанавливаю их вручную в командной строке, а затем запускаю командный файл вручную. Нет репро
Я изменил оператор TSQL, чтобы просто вывести возвращаемое значение функции IS_SRVROLEMEMBER(). И из вызова из моего скрипта и из командной строки, вывод идентичен - "1":
"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\OSQL.EXE" -U"ADMIN" -P"PASSWORD" -S "SQL_SRVR10" -d "DB01" -Q "SELECT IS_SRVROLEMEMBER ('sysadmin')"
3 ответа
Что ж, я потратил на это больше времени и заметил, что ошибка не возникает, если я использовал CMD.EXE /C или START /B /WAIT для вызова другого скрипта. Так что это было определенно что-то о состоянии процесса CMD.EXE, который вызывал проблему.
Кроме того, я решил ECHO каждой строки в текстовом файле. И я заметил, что была небольшая разница
ECHO "C:\Program Files\Microsoft SQL Server\100\Tools\Binn\OSQL.EXE" -U"ADMIN" -P"PASSWORD" -S "SQL_SRVR10" -d "DB01" -Q "DECLARE @userName varchar(100) ; set @userName = user_name() ; IF IS_SRVROLEMEMBER ('sysadmin') != 1 RAISERROR ('This user ''ADMIN'' is not a member of the ''sysadmin'' group.' , 16 , 127 , @userName )" > out.txt
Когда вы смотрите на out.txt, он содержит:
"C:\Program Files\Microsoft SQL Server\100\Tools\Binn\OSQL.EXE" -U"ADMIN" -P"PASSWORD" -S "SQL_SRVR10" -d "DB01" -Q "DECLARE @userName varchar(100) ; set @userName = user_name() ; IF IS_SRVROLEMEMBER ('sysadmin') = 1 RAISERROR ('This user ''ADMIN'' is not a member of the ''sysadmin'' group.' , 16 , 127 , @userName )"
Разница в том, что восклицательный знак (!) Исчез. Это объясняет, почему сравнение всегда оценивается как ложное, потому что сравнение является полной противоположностью ожидаемого.
В конце концов я выяснил, что происходит то, что CMD.EXE, который вызывает этот скрипт, в настоящее время находится в режиме расширения переменной среды с задержкой из-за предыдущего выполнения SETLOCAL ENABLEDELAYEDEXPANSION. Когда CMD.EXE обрабатывает строку,! символ отмечает начало раскрытия, поэтому он автоматически удаляет его. Однако следующий символ - это символ равенства (=), который недопустим в переменных среды, поэтому обработка немедленно отменяет расширение переменной и вместо этого обрабатывает этот символ. Поэтому в качестве аргумента для OSQL.EXE устанавливается только символ =.
Правильное решение состоит в том, чтобы непосредственно перед вызовом скрипта выполнить SETLOCAL DISABLEDELAYEDEXPANSION, а затем выполнить ENDLOCAL.
Кроме того, у вас могут возникнуть проблемы с синтаксисом, использующим "LIKE '%mytext%'" в пакете, выполняющем osql/sqlcmd, потому что вам нужно удвоить эти противные знаки процента!! Но, конечно, он работает FINE, когда вы тестируете его в командной строке. Я потратил около часа, пытаясь отладить это ранее сегодня. Почему я не сразу увидел и понял проблему? К сожалению, моя память с каждым днем становится все более похожей на мою маму... слабоумие в семье;-(
Я бы поменял EXIT
для EXIT /B
EXIT
завершает CMD
сессия.
exit /b optionalerrorlevelnumber
завершает текущий пакет, при необходимости возвращая уровень ошибки.