AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 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

Passar o valor NULL xml para uma determinada função armazenada CLR trava-o quando chamado de uma determinada maneira

  • 772

Considere um procedimento armazenado CLR que aceita um parâmetro XML e chama outro procedimento armazenado no mesmo esquema:

[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();
        }
    }
}

Esta função CLR é visível no SQL como:

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

A função armazenada que ele chama é esta:

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

Nesta configuração, se eu chamar a função CLR assim:

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

ou assim:

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

ou assim:

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

ou assim:

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

então eu recebo:

Msg 2905, Nível 25, Estado 1, Linha 6

Msg 0, Level 20, State 0, Line 0 Ocorreu um erro grave no comando atual. Os resultados, se existirem, deveriam ser descartados.

Mas se eu chamar assim:

select testing.TestTest(null);

ou assim:

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

Recebo um valor adequado de volta (por exemplo 1).

Se, ao invés de null, eu passar uma string vazia '', a função é chamada com sucesso em todos os casos.

Por quê? Fiz algo errado na minha função CLR?

Microsoft SQL Server 2008 (SP2) - 10.0.4000.0 (X64)
16 de setembro de 2010 19:43:16
Copyright (c) 1988-2008 Microsoft Corporation
Standard Edition (64 bits) no Windows NT 6.0 (Build 6002: Service Pack 2) (MV)

sql-server-2008 xml
  • 1 1 respostas
  • 1698 Views

1 respostas

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

    No geral, não, você não fez nada de errado com seu código .NET. Há um pequeno problema técnico, mas chegaremos a isso em um momento.

    Consegui reproduzir isso (ambos os cenários de erro e não erro) no SQL Server 2008 R2 RTM. A princípio, no cenário "sem erro", recebi outro erro para:

    elenco especificado é inválido

    Esse erro foi resultado da consulta passando de volta um INTe o código C# tentando convertê-lo em um arquivo bool. Alterei a consulta para:

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

    Isso força o tipo de dados do valor a ser retornado para ser algo que pode ser convertido em bool. Este foi o "erro menor" ao qual eu estava me referindo, e eu o considero "menor" e não realmente um erro, porque suspeito que seu código originalmente tentou converter inte retornou um SqlInt32, já que você afirma que passar uma string vazia permitiu retornar com sucesso. Não há como isso retornar com sucesso, mesmo com uma string vazia em vez do NULLvalor de entrada, se o seu código estiver tentando converter boole retornar SqlBoolean. E sim, eu poderia ter mudado o cast para be (int)e o tipo de retorno para be SqlInt32, mas isso foi menos uma mudança estrutural.

    Testei vários tipos de alterações: remover a execução, remover o parâmetro@d e codificar o nullna consulta, mas ainda com o SqlParameterdefinido, remover o @dparâmetro e o SqlParameteretc. de um tipo LOB (ou seja , , , , ), mesmo não utilizado na consulta, causava o "erro grave" ao passar um . No entanto, se qualquer um desses tipos for alterado para ter o comprimento máximo não MAX (ou seja, 8.000, 4.000 e 8.000, respectivamente), não haverá erro ao passar em um arquivo . Portanto, o seguinte código reduzido deve ser suficiente para reproduzir o erro ao passar em umSqlParameterXMLVARCHAR(MAX)NVARCHAR(MAX)VARBINARY(MAX)NULLMAXNULLNULLpara a função escalar SQLCLR:

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

    Agora, não consegui reproduzir o erro com o código original no SQL Server 2012 SP3 ou SQL Server 2014 SP1 :-). Portanto, suspeito que esse seja um problema com o CLR 2.0 e/ou as versões do .NET Framework associadas ao CLR 2.0 (ou seja, "2.0", "3.0" e "3.5"). OU, outro aspecto a considerar é que com esta falha ( declare @res bit; set @res = testing.TestTest(null);) enquanto isso funciona ( declare @res bit; set @res = (select testing.TestTest(null));) isso pode apontar para um problema com o Query Optimizer e não com a versão CLR. Ou talvez seja uma combinação dos dois. Ou talvez seja o incômodo Demônio Maligno de Descartes . De qualquer jeito. ( ** por favor, veja o comentário no final )

    Se você conseguir mudar para o SQL Server 2012 ou mais recente, o problema deve desaparecer "magicamente". MAS, se travado no SQL Server 2008/2008 R2, consegui contornar o problema declarando o parâmetro como um tipo não MAX se a entrada for NULL, o que deve ser bom, pois não haverá risco de truncamento ao passar por um NULL. E, no caso do tipo de dados do parâmetro de entrada do objeto T-SQL sendo chamado sendo XML, ele ainda funciona para definir o tipo de dados do parâmetro no código .NET, NVARCHAR(4000)pois ele o converterá implicitamente XMLquando chamado. O código a seguir funcionou para mim no SQL Server 2008 R2 ao passar em um 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 deixou este comentário esclarecedor:

    Especificamente, o erro parece ser "Violação de acesso lendo o local 0x0000000000000000" interno sqlservr.exe!CClrXvarProxy::EnsureBufferInit, então parece um bug de ponteiro nulo, mas pesquisar no Google esses nomes de método não retorna nenhum artigo da KB.

    • 3

relate perguntas

  • Melhores práticas para conectar bancos de dados que estão em diferentes regiões geográficas

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Quanto "Padding" coloco em meus índices?

  • Existe um processo do tipo "práticas recomendadas" para os desenvolvedores seguirem para alterações no banco de dados?

  • Downgrade do SQL Server 2008 para 2005

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Conceder acesso a todas as tabelas para um usuário

    • 5 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

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

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve