2013-06-26 2 views
0

Я автоматизирую различные EXE-файлы через командный файл, включая вызов существующего командного файла, который, в свою очередь, выполняет различные инструкции TSQL через OSQL.exe.Оператор TSQL в OSQL терпит неудачу при вызове из командного файла, вызванного из командного файла

Существующий пакетный файл работает нормально. Однако при вызове моего командного файла вызывается вызов 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')" 

ответ

1

Ну, я потратил еще немного времени на это, и я заметил, что ошибка не возникла, если я использовал 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)" 

Разница заключается в том, что восклицательный символ исчез (!). Это объясняет, почему сравнение всегда оценивается как false, потому что сравнение является полной противоположностью тому, который вы ожидаете.

В конечном итоге я понял, что происходит то, что CMD.EXE, который вызывает этот скрипт, в настоящее время находится в режиме расширения переменной среды с задержкой из-за предыдущего выполнения SETLOCAL ENABLEDELAYEDEXPANSION. Когда CMD.EXE обрабатывает строку, значение! символ знаменует начало расширения, поэтому он автоматически вытесняет его. Однако следующий символ является символом равенства (=), который не допускается в переменных среды, поэтому обработка немедленно отменяет расширение переменной и вместо этого обрабатывает этот символ. Поэтому в качестве аргумента OSQL.EXE устанавливается только символ =.

Правильное решение должно быть выполнено непосредственно перед вызовом сценария, выполнить SETLOCAL DISABLEDELAYEDEXPANSION, а затем выполнить ENDLOCAL.

+0

Я думаю, что вы правы с «задержкой расширения». Это всегда хорошая идея работать без него из-за побочных эффектов, я делаю это. – Endoro

+0

Но это * так * полезно! :-) –

0

Я изменил бы EXIT к EXIT /B

EXIT завершает сеанс CMD.

exit /b optionalerrorlevelnumber завершает текущий пакет, при необходимости возвращая уровень ошибок.

+0

Питер - вы правы. Когда происходит ошибка, это сбивает весь процесс. сценарий у меня нет прямого контроля. –

1

Кроме того, у вас могут возникнуть проблемы с синтаксисом, используя «LIKE»% mytext% »в пакетном запуске osql/sqlcmd, потому что вам нужно удвоить эти досадные процентные знаки! Но, конечно, он работает FINE, когда вы проверяете его в командной строке. Я потратил около часа, пытаясь отладить , что ранее сегодня. Почему я не сразу понял и не понял эту проблему? К сожалению, моя память больше похожа на мою маму каждый день ... деменция работает в семье ;-(