我无法通过 pyodbc 成功执行 SQL Server 存储过程
sp_setapprole
SQL Server 2019
Client OS: Windows 10
Python: v3.8
PyODBC: v4.0.34
SQLAlchemy: v1.4.39
最终用户安全最初是通过主动安全组进行管理的Active Directory 组有一个 SQL Server 登录名,该组是 SQL Server 公共角色的成员,并且具有 SQL Server 的“连接 SQL”权限
此外,SQL Server 登录会映射到目标数据库中的用户帐户。该用户帐户是数据库“公共”角色的成员,并且仅被显式授予对数据库的“CONNECT”权限。
我已经在 SQL Server Management Studio (SSMS) 中测试了 SQL 代码,它可以正常工作,没有任何问题。
当我使用 Python/pyodbc 运行相同的代码时,它会生成我无法解决的错误。
注 1:错误消息因我使用的 ODBC 驱动程序而异。 (见下文)
SQL Server(SQLSRV32.DLL)
ERROR: An exception/error has occurred.
Traceback (most recent call last):
File "C:\Users\...\testcode.py", line ..., in ...
cursor_obj.execute(sql, sp_val)
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC SQL Server Driver][SQL Server]Application roles can only be activated at the ad hoc level. (15422) (SQLExecDirectW)")
SQL Server 本机客户端 11.0 (SQLNCLI11.DLL)
ERROR: An exception/error has occurred.
Traceback (most recent call last):
File "C:\Users\...\testcode.py", line ..., in ...
cursor_obj.execute(sql, sp_val)
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][SQL Server Native Client 11.0][SQL Server]The procedure 'sys.sp_setapprole' cannot be executed within a transaction. (15002) (SQLExecDirectW)")
适用于 SQL Server 的 ODBC 驱动程序 17 (MSODBCSQL17.DLL)
ERROR: An exception/error has occurred.
Traceback (most recent call last):
File "C:\Users\...\testcode.py", line ..., in ...
cursor_obj.execute(sql, sp_val)
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]The procedure 'sys.sp_setapprole' cannot be executed within a transaction. (15002) (SQLExecDirectW)")
注 2:应用程序中的所有其他代码均有效。尽管与数据库的大部分交互是通过 SQL Alchemy 进行的,但使用 pyodbc 的其他例程可以正常工作。注意 3:我不想多次运行“sp_setapprole”。在我对数据库执行任何其他操作之前,第一次尝试运行存储过程时会出现此问题。
注 4:db_engine 是从数据库连接字符串创建的 SQLAlchemy 引擎对象。生成上述第一条错误消息时,正在使用以下连接字符串:
connection_string = "DRIVER={SQL Server};SERVER=SQLserverName;DATABASE=MyDatabase;TRUSTED_CONNECTION=YES"
以下代码片段包含与 sp_setapprole
问题相关的代码:
app_role_info = {'@rolename' : 'MyAppRole',
'@password' : 'AppRolePassword',
'@fCreateCookie' : 1} # MSSQL True = 1
connection = db_engine.raw_connection()
try:
cursor_obj = connection.cursor()
first_key = True
sp_var=' '
sp_var_list=[]
for k,v in app_role_info.items():
if not first_key:
sp_var = sp_var + ', '
sp_var = sp_var + k + ' = ?'
sp_val_list.append(v)
first_key = False
sp_val = tuple(sp_val_list)
sql = f"""
SET NOCOUNT ON;
DECLARE @ret_value VARBINARY(8000);
EXEC sp_setapprole {sp_var}, @cookie=@ret_value OUTPUT;
SELECT @ret_value AS AppRoleCookie;
"""
cursor_obj.execute(sql, sp_val)
任何帮助/指导/智慧之言将不胜感激。
connection_string = "DRIVER={ODBC Driver 17 for SQL Server};SERVER=SQLserverName;DATABASE=MyDatabase;TRUSTED_CONNECTION=YES"
app_role_info = {'@rolename' : 'MyAppRole',
'@password' : 'AppRolePassword',
'@fCreateCookie' : 1} # MSSQL True = 1
connection = pyodbc.connect(connection_string, autocommit=True)
try:
cursor_obj = connection.cursor()
first_key = True
sp_var=' '
sp_var_list=[]
for k,v in app_role_info.items():
if not first_key:
sp_var = sp_var + ', '
sp_var = sp_var + k + ' = ?'
sp_val_list.append(v)
first_key = False
sp_val = tuple(sp_val_list)
sql = f"""
SET NOCOUNT ON;
DECLARE @ret_value VARBINARY(8000);
EXEC sp_setapprole {sp_var}, @cookie=@ret_value OUTPUT;
SELECT @ret_value AS AppRoleCookie;
"""
cursor_obj.execute(sql, sp_val)
运行更新后的代码(上面)现在会导致以下异常/错误:
ERROR: An exception/error has occurred.
Traceback (most recent call last):
File "C:\Users\...\testcode.py", line ..., in ...
cursor_obj.execute(sql, sp_val)
pyodbc.ProgrammingError: ('42000', "[42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Application roles can only be activated at the ad hoc level. (15422) (SQLExecDirectW)")
该错误与本文前面的 ODBC Driver 17 for SQL Server 错误消息不同。我相信@siggemannen 评论是正确的,并将自动提交设置为 True 纠正了事务/嵌套问题。我仍然不知道如何纠正“...临时级别”。错误。
.callproc
,如文档中所述,因此它可能无法按照您的方式工作。看来
sp_setapprole
根本无法从参数化批次中调用。唯一可行的是使用 ODBC 调用转义语法:
tuple = (role_name, pass, "none", "odbc", true, null,)
cursor_obj.execute("{call sp_setapprole(?, ?, ?, ?, ?, ?)}", tuple)
然后这些元组值中的最后一个应该成为输出参数