为什么 CURSOR_STATUS 在创建它的存储过程中的输出游标返回意外结果?

Joe*_*ish 4 sql-server cursors

我有一个具有该CURSOR VARYING类型的输出参数的存储过程。我想验证调用存储过程的代码是否可以使用输出游标。这似乎CURSOR_STATUS是正确使用的函数,但将其应用到输出光标时,我得到了意想不到的结果。该函数在创建它的存储过程内返回值 -3,但在存储过程外按预期工作。请参阅下面的代码:

CREATE OR ALTER PROCEDURE dbo.OutputCursorTest  
(@Cursor_OUT CURSOR VARYING OUTPUT)
AS  
BEGIN
    SET NOCOUNT ON;

    SET @Cursor_OUT = CURSOR FORWARD_ONLY STATIC FOR
    SELECT [high]
    from master..spt_values

    OPEN @Cursor_OUT;

    SELECT CURSOR_STATUS('variable', '@Cursor_OUT'); -- this seems to always return -3

    -- possible workaround
    /*
    DECLARE @Cur_Copy CURSOR;
    SET @Cur_Copy =  @Cursor_OUT;
    SELECT CURSOR_STATUS('variable', '@Cur_Copy');
    DEALLOCATE @Cur_Copy;
    */

    RETURN;
END;

GO     

DECLARE @Cur CURSOR;
EXEC dbo.OutputCursorTest @Cursor_OUT = @Cur OUTPUT;
SELECT CURSOR_STATUS('variable', '@Cur'); -- this returns 1 as expected
Run Code Online (Sandbox Code Playgroud)

如果重要的话,我正在使用 SQL Server 2019 CU14。为什么CURSOR_STATUS在存储过程中返回值 -3(“具有指定名称的游标不存在。”)?

Pau*_*ite 10

@Cursor_OUT直到过程结束时复制出来时,光标才会分配给“变量” 。

在此之前,它不是“游标变量”,因此CURSOR_STATUS对于sp_describe_cursor.

也就是说,游标的名称@Cursor_OUT是,并且可以通过sys.dm_exec_cursors看到。

您还可以使用非变量语法创建游标:

CREATE OR ALTER PROCEDURE dbo.OutputCursorTest  
    @Cursor_OUT CURSOR VARYING OUTPUT
AS  
BEGIN
    SET NOCOUNT ON;

    DECLARE c CURSOR LOCAL 
        FORWARD_ONLY STATIC READ_ONLY
    FOR
    SELECT [high]
    FROM master..spt_values;

    OPEN c;

    -- SELECT EC.* FROM sys.dm_exec_cursors(@@SPID) AS EC;

    SELECT CURSOR_STATUS('local', N'c');

    -- Assign output
    SET @Cursor_OUT = c;

    RETURN;
END;
Run Code Online (Sandbox Code Playgroud)

您还可以分配@Cursor_OUT较早的值并在OPEN通话中使用它。它只是一个指向“真实”光标的指针。

使用上述语法的优点之一是它允许您指定LOCALor GLOBAL。这对于变量形式来说是不可用的;您获得的游标类型由数据库选项决定CURSOR_DEFAULT。通常情况下,明确可以防止出现意外。