SQL Server describing first result set fails when temp table is used (sp_describe_first_result_set)

对着背影说爱祢 提交于 2019-12-10 17:14:39

问题


Long story short, I have a third-party application which behaves differently when it cannot retrieve the metadata of the query/stored procedure.

It is known, that sys.sp_describe_first_result_set fails to retrieve the metadata for a stored procedure when a temp table is used in it.

For the sake of simplicity, here is a simple example.

CREATE PROCEDURE dbo.Test
    @Seed INT = 0
AS
BEGIN
    CREATE TABLE #MyTemp (
        ID INT NOT NULL
    );

    INSERT INTO #MyTemp (ID)
    VALUES
          (@Seed + 1)
        , (@Seed + 2)
        , (@Seed + 3)
    ;

    SELECT
        ID
    FROM
        #MyTemp
END

Execution this SP will return one result set, in which we have one column (ID) and three records.

EXEC dbo.Test
    @Seed = 1;

Result is:

ID
-----------
2
3
4

However, trying to get the metadata will fail:

EXEC sys.sp_describe_first_result_set @tsql = N'EXEC dbo.Test @Seed = 1;';

Result is:

Msg 11526, Level 16, State 1, Procedure sp_describe_first_result_set, Line 1 [Batch Start Line 24]
The metadata could not be determined because statement 'INSERT INTO #MyTemp (ID)
    VALUES
          (@Seed + 1)
        , (@Seed + 2)
        , (@Seed + 3)' in procedure 'Test' uses a temp table.

(Which is expected, since this is a known limitation of sp_describe_first_result_set)

The problem is, when our third-party app encounters this error, it executes the SP twice (first to analyze the result set and create a temp table, then to do an INSERT .. EXEC to load the data into the temp table it created).

When the metadata is available, it will get the metadata using sys.sp_describe_first_result_set and use that info to create it's temp table.

Since we don't have any SQL Servers below version 2012, I could use the WITH RESULT SETS clause, however it is not possible in the said app to configure it, or to manually provide metadata info.

How to make the metadata available for applications using this SP?

I am providing two solutions in my answer, but I am curious if there is one what I don't know about.


回答1:


My current solution is to create a wrapper stored procedure, which executes the existing one, passing through all the parameters, but defining the metadata of the result sets.

To continue the example in the question:

EXEC sp_rename 'dbo.Test', 'Test_Logic', 'OBJECT';
GO

CREATE PROCEDURE dbo.Test
    @Seed INT = 0
AS
BEGIN
    EXEC dbo.Test_Logic
        @Seed = @Seed
    WITH RESULT SETS (
        (
            ID INT
        )
    )
    ;
END

Now, if I try to get the metadata, I can get it:

EXEC sys.sp_describe_first_result_set @tsql = N'EXEC dbo.Test @Seed = 1;';

And the result is:

is_hidden column_ordinal name                                                                                                                             is_nullable system_type_id system_type_name                                                                                                                 max_length precision scale collation_name                                                                                                                   user_type_id user_type_database                                                                                                               user_type_schema                                                                                                                 user_type_name                                                                                                                   assembly_qualified_type_name                                                                                                                                                                                                                                     xml_collection_id xml_collection_database                                                                                                          xml_collection_schema                                                                                                            xml_collection_name                                                                                                              is_xml_document is_case_sensitive is_fixed_length_clr_type source_server                                                                                                                    source_database                                                                                                                  source_schema                                                                                                                    source_table                                                                                                                     source_column                                                                                                                    is_identity_column is_part_of_unique_key is_updateable is_computed_column is_sparse_column_set ordinal_in_order_by_list order_by_is_descending order_by_list_length tds_type_id tds_length  tds_collation_id tds_collation_sort_id
--------- -------------- -------------------------------------------------------------------------------------------------------------------------------- ----------- -------------- -------------------------------------------------------------------------------------------------------------------------------- ---------- --------- ----- -------------------------------------------------------------------------------------------------------------------------------- ------------ -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- --------------- ----------------- ------------------------ -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------- ------------------ --------------------- ------------- ------------------ -------------------- ------------------------ ---------------------- -------------------- ----------- ----------- ---------------- ---------------------
0         1              ID                                                                                                                               1           56             int                                                                                                                              4          10        0     NULL                                                                                                                             NULL         NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                                                                                                                                                             NULL              NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             0               0                 0                        NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             NULL                                                                                                                             NULL               NULL                  NULL          NULL               NULL                 NULL                     NULL                   NULL                 38          4           NULL             NULL

(Which looks awful here, but it works)

The downside is that now I have to maintain two SPs and there is a subsequent SP execution.

Alternative solution

An alternative solution is to use dynamic sql and sys.sp_executesql to run it with the WITH RESULT SETS clause.

The main downside of this is, that SQL Server and VisualStudio (database projects) cannot track dependencies in dynamic SQLs.

This would look like something like this:

ALTER PROCEDURE dbo.Test
    @Seed INT = 0
AS
BEGIN
    CREATE TABLE #MyTemp (
        ID INT NOT NULL
    );

    INSERT INTO #MyTemp (ID)
    VALUES
          (@Seed + 1)
        , (@Seed + 2)
        , (@Seed + 3)
    ;


    DECLARE @STMT NVARCHAR(MAX) = N'
SELECT
    ID
FROM
    #MyTemp
;';

    EXEC sys.sp_executesql
        @stmt = @STMT
    WITH RESULT SETS (
        (
            ID INT
        )
    )
END

Of course, the more complex the SP, the harder to maintain the dynamic SQL in my opinion, so I prefer the first solution.



来源:https://stackoverflow.com/questions/47926745/sql-server-describing-first-result-set-fails-when-temp-table-is-used-sp-describ

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!