AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 47091
Accepted
GSerg
GSerg
Asked: 2013-07-27 09:26:04 +0800 CST2013-07-27 09:26:04 +0800 CST 2013-07-27 09:26:04 +0800 CST

将 NULL xml 值传递给某个 CLR 存储函数会在以某种方式调用时崩溃

  • 772

考虑一个接受 XML 参数并在同一架构中调用另一个存储过程的 CLR 存储过程:

[SqlFunction(DataAccess = DataAccessKind.Read,
     IsDeterministic = false, IsPrecise = true,
     SystemDataAccess = SystemDataAccessKind.Read)]
public static SqlBoolean TestTest(SqlXml Data)
{
    using (var c = new SqlConnection("context connection=true"))
    {
        c.Open();

        using (var cmd = new SqlCommand(@"select case when exists(select 0 from [testing].WillBeCalledByCLR(@d)) then 1 else 0 end;", c))
        {
            var p = cmd.Parameters.Add("@d", SqlDbType.Xml);

            p.Direction = ParameterDirection.Input;
            if (Data.IsNull)
                { p.Value = DBNull.Value; }
            else
                { p.Value = Data; }  // Or Data.Value

            return (bool)cmd.ExecuteScalar();
        }
    }
}

此 CLR 函数在 SQL 中显示为:

create function [testing].[TestTest] ( @data xml )
returns bit
WITH CALLED ON NULL INPUT
AS
EXTERNAL NAME [Test].[Test.Test].[TestTest]

它调用的存储函数是这样的:

create function testing.WillBeCalledByCLR (@x xml = null)
returns table
as
return (
  select 1 as one, 2 as two, 'three' as three
);

在此设置中,如果我这样调用 CLR 函数:

if testing.TestTest(null) = 1
begin
  select 'Meaningful actions';
end;

或像这样:

declare @res bit = testing.TestTest(null);

或像这样:

declare @res bit;
set @res = testing.TestTest(null);

或像这样:

declare @res bit;
select @res = testing.TestTest(null);

然后我得到:

消息 2905,25 级,状态 1,第 6 行

Msg 0, Level 20, State 0, Line 0 当前命令发生严重错误。结果,如果有的话,应该丢弃。

但如果我这样称呼它:

select testing.TestTest(null);

或像这样:

declare @res bit;
set @res = (select testing.TestTest(null));

我得到了一个适当的值(例如1)。

如果null我传递了一个空字符串'',而不是 ,则在所有情况下都成功调用了该函数。

为什么?我在 CLR 函数中做错了吗?

Microsoft SQL Server 2008 (SP2) - 10.0.4000.0 (X64)
2010 年 9 月 16 日 19:43:16
版权所有 (c) 1988-2008 Microsoft Corporation
Standard Edition (64-bit) o​​n Windows NT 6.0 (Build 6002: Service Pack 2) (虚拟机)

sql-server-2008 xml
  • 1 1 个回答
  • 1698 Views

1 个回答

  • Voted
  1. Best Answer
    Solomon Rutzky
    2016-10-08T13:39:24+08:002016-10-08T13:39:24+08:00

    总的来说,不,您的 .NET 代码没有做错任何事情。有一个小技术问题,但我们稍后会解决。

    我能够在 SQL Server 2008 R2 RTM 中重现这个(错误和非错误场景)。起初,在“非错误”场景中,我遇到了另一个错误:

    指定的演员表无效

    此错误是由于查询传回 anINT并且 C# 代码尝试将其转换为bool. 我将查询更改为:

    ... then CONVERT(BIT, 1) else CONVERT(BIT, 0) end ...
    

    这迫使要返回的值的数据类型是可以转换为bool. 这是我所指的“小错误”,我认为它是“小错误”,并不是真正的错误,因为我怀疑您的代码最初试图转换int并返回 a ,SqlInt32因为您声称传入一个空字符串允许它成功返回。如果您的代码试图强制转换为并返回,即使使用空字符串而不是NULL输入值,这也不会成功返回。是的,我本可以将演员表更改为 be并将返回类型更改为 be ,但这不是结构上的更改。boolSqlBoolean(int)SqlInt32

    我测试了几种类型的更改:删除执行,删除@d参数并将其硬编码null到查询中但仍然具有SqlParameter定义,删除@d参数和SqlParameter等。最终归结为:仅存在一个SqlParameterLOB 类型(即XML, VARCHAR(MAX), )的 LOB 类型NVARCHAR(MAX),VARBINARY(MAX)即使在查询中未使用,也会在传入NULL. 但是,如果将这些MAX类型中的任何一个更改为它们的最大非 MAX 长度(即分别为 8000、4000 和 8000),则在传递 a 时不会出错NULL。因此,以下简化的代码应该足以在传入时重现错误NULL到 SQLCLR 标量函数:

    using (var cmd = new SqlCommand(@"SELECT 1;", c))
    {
        var p = cmd.Parameters.Add("@d", SqlDbType.NVarChar, (int)SqlMetaData.Max);
    
        cmd.ExecuteScalar();
    }
    

    现在,我无法使用 SQL Server 2012 SP3 或 SQL Server 2014 SP1 中的原始代码重现错误:-)。因此,我怀疑这是 CLR 2.0 和/或与 CLR 2.0 关联的 .NET Framework 版本(即“2.0”、“3.0”和“3.5”)的问题。或者,要考虑的另一个方面是,它与这个失败 ( declare @res bit; set @res = testing.TestTest(null);) 而这个工作 ( declare @res bit; set @res = (select testing.TestTest(null));) 可能指向查询优化器的问题,而不是 CLR 版本的问题。或者也许是两者的结合。又或许是笛卡尔的讨厌鬼。无论哪种方式。(**请看文末评论)

    如果您能够升级到 SQL Server 2012 或更高版本,那么问题应该“神奇地”消失。但是,如果卡在 SQL Server 2008 / 2008 R2 上,如果输入为 ,我可以通过将参数声明为非 MAX 类型来解决该问题NULL,这应该没问题,因为不会有截断的风险当通过一个NULL. 而且,在 T-SQL 对象的输入参数数据类型被调用的情况下XML,它仍然可以在 .NET 代码中定义参数数据类型,NVARCHAR(4000)因为它会在调用时将其隐式转换为XML。在传递 a 时,以下代码在 SQL Server 2008 R2 中对我有用NULL:

    SqlParameter _XmlData;
    
    if (Data.IsNull)
    {
        // Parameter can't be a LOB type if input is NULL
        _XmlData = new SqlParameter("@d", SqlDbType.NVarChar, 4000);
        _XmlData.Value = DBNull.Value;
    }
    else
    {
        _XmlData = new SqlParameter("@d", SqlDbType.Xml);
        _XmlData.Value = Data.Value;
    }
    
    cmd.Parameters.Add(_XmlData);
    

    ** @MartinSmith留下了这条富有启发性的评论:

    具体来说,错误似乎是“访问冲突读取位置 0x0000000000000000”内部sqlservr.exe!CClrXvarProxy::EnsureBufferInit,所以看起来像一个空指针错误,但谷歌搜索这些方法名称不会返回任何 KB 文章。

    • 3

相关问题

  • 连接不同地理区域的数据库的最佳实践

  • 死锁的主要原因是什么,可以预防吗?

  • 我在索引上放了多少“填充”?

  • 是否有开发人员遵循数据库更改的“最佳实践”类型流程?

  • 从 SQL Server 2008 降级到 2005

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    授予用户对所有表的访问权限

    • 5 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve