消息6522,级别16但没有从sys.all_columns中选择错误消息

时间:2017-08-18 13:40:30

标签: .net sql-server user-defined-functions sqlclr

我正在使用SqlConnection("context connection=true")运行SQLCLR功能。

在某些情况下,我得到例外

  

System.Data.SqlClient.SqlException(0x80131904)
  在System.Data.SqlClient.SqlConnection.OnError(SqlException异常,布尔breakConnection,Action`1 wrapCloseInAction)
  在System.Data.SqlClient.SqlInternalConnectionSmi.EventSink.DispatchMessages(Boolean ignoreNonFatalMessages)
  在System.Data.SqlClient.SqlDataReaderSmi.InternalRead(Boolean ignoreNonFatalErrors)
  at ObjDb.Functions.ObjDb(String db,String schema,String obj,String col,String val)

     

ClientConnectionId:00000000-0000-0000-0000-000000000000
  错误号码:200,州:4,班级:25

每次在同一记录号下使用相同的查询时都会发生这种情况。

连接

SqlConnection(@"Server=" + @"localhost\sqldeveloper16" + ";Database=" + db + ";Integrated Security=true;connect Timeout = 50")

我从来没有得到这个错误,一切都很好。

我不明白为什么。

然后我在SQL Server 2008上尝试了相同的CLR,没有问题......我该怎么检查?!?!

这可能是SQL Server 2016的错误吗?!

这是我的班级

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Xml;
using Newtonsoft.Json;
using System.Xml.Linq;
using System.IO;
using System.Linq;
using System.Text;

namespace ObjDb
{
    public partial class Functions
    {
        [SqlFunction
        (
            //DataAccess = DataAccessKind.Read,//serve x accedere alle tabelle del db, altrimenti accede solo a qlle di sistema...
            SystemDataAccess = SystemDataAccessKind.Read,
            FillRowMethodName = "columns_ok",
            TableDefinition = "c1 nvarchar(max), node nvarchar(max)"
        )
        ]

        public static IEnumerable ObjDb(String db, String schema, String obj, String col, String val)
        {
            List<String> rows = new List<String>();//List<Object[]> rows = new List<Object[]>();
            //List<tuple.t2<String, String>> rows = new List<tuple.t2<String, String>>();

            SqlCommand command = null;// = new SqlCommand(query, conn);
            SqlConnection conn = null;// new SqlConnection("context connection=true");

            try
            {
                conn = new SqlConnection("context connection=true");//new SqlConnection(@"Server=" + @"localhost\sqldeveloper16" + ";Database=" + db + ";Integrated Security=true;connect Timeout = 50"); //new SqlConnection("context connection=true");//
                conn.Open();

                String query;
                StringBuilder sb = new StringBuilder();
                sb.Append("where 0=0");

                if ((col != null && !col.Equals("")) && (val != null && !val.Equals("")))
                {
                    String[] cols = col.Split(',');
                    String[] vals = val.Split(',');

                    for (int i = 0; i < Math.Min(cols.Length, vals.Length); i++)
                    {
                        sb.Append(" and [").Append(cols[i]).Append("]='").Append(vals[i].Replace("'", "''")).Append("'");
                    }
                    //filter = "where 0=0 " + sb.ToString();
                    //filter = "where [" + col + "]='" + val + "'";
                }
                //estrazione inline dell xml (un xml x ogni riga)
                //"BINARY BASE64" -> https://stackoverflow.com/questions/8801697/xml-export-via-bcp-bulk-export - bug 2008R2, converte il varbinary in ascii
                query =
                "select (select t.* for xml raw('root'),BINARY BASE64) " +
                "from [" + db + "].[" + schema + "].[" + obj + "] t " +
                sb.ToString(); ;//filter;

                command = new SqlCommand(query, conn);
                //command.CommandTimeout = 0;
                SqlDataReader dr = command.ExecuteReader();

                while (dr.Read())
                {
                    //rows.Add(new tuple.t2<String, String>("", (String)dr[0]));
                    rows.Add((String)dr[0]);
                }
                return rows;
            }
            catch (Exception e)
            {
                rows.Add(e.ToString().Substring(0, Math.Min(4000, e.ToString().Length)));
                return  rows;
            }
            finally
            {
                if (command != null)
                    command.Dispose();
                if (conn != null)
                    conn.Close();
            }
        }
        private static void columns_ok(object resultObj, out SqlString node)
        {
            //String res = (String)resultObj;

            node = (String)resultObj;
        }
    }
}

然后从Sql

select *
from dbo.objdb('test','sys','all_columns',null,null)

结果是(5248条记录,最后一条包含异常,我只发布了最后3条):

<root object_id="-103402673" name="similarity_index_page_count" column_id="4" system_type_id="127" user_type_id="127" max_length="8" precision="19" scale="0" is_nullable="1" is_ansi_padded="0" is_rowguidcol="0" is_identity="0" is_computed="0" is_filestream="0" is_replicated="0" is_non_sql_subscribed="0" is_merge_published="0" is_dts_replicated="0" is_x005F_xml_document="0" xml_collection_id="0" default_object_id="0" rule_object_id="0" is_sparse="0" is_column_set="0" generated_always_type="0" generated_always_type_desc="NOT_APPLICABLE" is_hidden="0" is_masked="0"/>
<root object_id="-103085222" name="database_id" column_id="1" system_type_id="56" user_type_id="56" max_length="4" precision="10" scale="0" is_nullable="0" is_ansi_padded="0" is_rowguidcol="0" is_identity="0" is_computed="0" is_filestream="0" is_replicated="0" is_non_sql_subscribed="0" is_merge_published="0" is_dts_replicated="0" is_x005F_xml_document="0" xml_collection_id="0" default_object_id="0" rule_object_id="0" is_sparse="0" is_column_set="0" generated_always_type="0" generated_always_type_desc="NOT_APPLICABLE" is_hidden="0" is_masked="0"/>
System.Data.SqlClient.SqlException (0x80131904)     at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)     at System.Data.SqlClient.SqlInternalConnectionSmi.EventSink.DispatchMessages(Boolean ignoreNonFatalMessages)     at System.Data.SqlClient.SqlDataReaderSmi.InternalRead(Boolean ignoreNonFatalErrors)     at ObjDb.Functions.ObjDb(String db, String schema, String obj, String col, String val)  ClientConnectionId:00000000-0000-0000-0000-000000000000  Error Number:200,State:4,Class:25

提前谢谢!!

更新: 我不知道为什么,但问题是专栏&#34; collation_name&#34;仅限SQL 2016。

我试图将其从查询中删除,没有例外......

2 个答案:

答案 0 :(得分:2)

错误来自sys.system_columns中的一个特定行,这是sys.all_columns系统目录视图中查询的两个内部表之一。

只有在collation_namesys.system_columns选择的查询中使用sys.all_columns字段时,才会出现此错误。

测试行的子集,我能够确定错误只发生在一行上。那个目标是:

sys.pdw_nodes_pdw_physical_databases

此行存在于SQL Server 2012中(除了2012 SP3和2016 SP1之外,我没有测试任何内容),并且根本没有任何错误。

O.P.提到只有在选择collation_name字段时才会出现此错误。查看该特定行的该字段,它是NULL。当然NULL没有任何问题,因为NULL显示了collation_name这么多其他行。这一行的不同之处在于数据类型为sysname,它是NVARCHAR(128)的别名,它是一种字符串类型,因此应始终具有非NULL排序规则。我不确定此列physical_name是否具有NULL排序规则,但它是SQL Server 2016中唯一具有NULL排序规则的字符串列,并且在SQL Server 2012中没有。

为什么会出错?嗯,真正的错误是:

  

Ms 6522,Level 16,State 1,Line 406
  在执行用户定义的例程或聚合“ObjDb”期间发生A.NET Framework错误:
  System.Data.SqlClient.SqlException:
  System.Data.SqlClient.SqlException:
  在System.Data.SqlClient.SqlConnection.OnError(SqlException异常,布尔breakConnection,Action`1 wrapCloseInAction)
  在System.Data.SqlClient.SqlInternalConnectionSmi.EventSink.DispatchMessages(Boolean ignoreNonFatalMessages)
  在System.Data.SqlClient.SqlDataReaderSmi.InternalRead(Boolean ignoreNonFatalErrors)
  在System.Data.SqlClient.SqlDataReaderSmi.Read()
  at ObjDb.Functions.ObjDb(String db,String schema,String obj,String col,String val)

注意没有实际的错误消息!奇怪的。不确定是怎么发生的,但collation_name字段实际上是以下表达式:

convert(sysname, ColumnPropertyEx(object_id, name, 'collation')) AS collation_name

ColumnPropertyEx函数没有记录,因此没有太多内容可以继续。

我怀疑这是一个错误,其中ColumnPropertyEx引发了一个低级错误,低到足以在SSMS中不显示为错误。但是,进程间连接(即Context Connection = true)似乎非常敏感,实际上可以捕获ColumnPropertyEx发生的任何事情。

现在,如果模式名称为WHERE,那么,避免使用 应该<{em> 将一个简单的问题添加到sys子句中object_name为all_columnssystem_columns

NOT (user_type_id IN (231, 256) AND collation_name IS NULL)

但是,由于这些是视图,因此在应用这些过滤器之前似乎会处理所有行。

所以,我发现的一种方法是使用以下内容过滤id字段:

NOT (t.[object_id] = -103085222 AND t.[column_id] = 2)

现在唯一真正的问题是我不知道所有版本的SQL Server 2016中的object_id是否相同,也不知道SQL Server 2017中是否相同(我还没有检查过)。

什么/真正的错误在哪里?

虽然似乎ColumnPropertyEx函数可能不应该按原样运行,但我认为主要问题是pdw_nodes_pdw_physical_databases的3列应该从sys.all_columns返回第一名。在Azure SQL数据仓库和并行数据仓库之外,甚至无法使用pdw_nodes_pdw_physical_databases。实际上,pdw_nodes_pdw_physical_databases函数返回了对象名OBJECT_NAME,但却没有显示在sys.all_objects; - )中,这很奇怪。

答案 1 :(得分:0)

我不知道这个问题,所以我的工作是添加一个新参数来定义要提取的列。

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Xml;
using Newtonsoft.Json;
using System.Xml.Linq;
using System.IO;
using System.Linq;
using System.Text;

namespace ObjDb
{
    public partial class Functions
    {
        [SqlFunction
        (
            //DataAccess = DataAccessKind.Read,//serve x accedere alle tabelle del db, altrimenti accede solo a qlle di sistema...
            SystemDataAccess = SystemDataAccessKind.Read,
            FillRowMethodName = "columns_ok",
            TableDefinition = "c1 nvarchar(max), node nvarchar(max)"
        )
        ]

        public static IEnumerable ObjDb(String db, String schema, String obj, String col, String col, String val)
        {
            List<String> rows = new List<String>();//List<Object[]> rows = new List<Object[]>();
            //List<tuple.t2<String, String>> rows = new List<tuple.t2<String, String>>();

            SqlCommand command = null;// = new SqlCommand(query, conn);
            SqlConnection conn = null;// new SqlConnection("context connection=true");

            try
            {
                conn = new SqlConnection("context connection=true");//new SqlConnection(@"Server=" + @"localhost\sqldeveloper16" + ";Database=" + db + ";Integrated Security=true;connect Timeout = 50"); //new SqlConnection("context connection=true");//
                conn.Open();

                String query;
                StringBuilder sb = new StringBuilder();
                sb.Append("where 0=0");

                if ((col != null && !col.Equals("")) && (val != null && !val.Equals("")))
                {
                    String[] cols = col.Split(',');
                    String[] vals = val.Split(',');

                    for (int i = 0; i < Math.Min(cols.Length, vals.Length); i++)
                    {
                        sb.Append(" and [").Append(cols[i]).Append("]='").Append(vals[i].Replace("'", "''")).Append("'");
                    }
                    //filter = "where 0=0 " + sb.ToString();
                    //filter = "where [" + col + "]='" + val + "'";
                }

            String headers;

            if (col != null && !col.Equals(""))
            {
                headers = col;
            }
            else
            {
                headers = "t.*";
            }
                //estrazione inline dell xml (un xml x ogni riga)
                //"BINARY BASE64" -> https://stackoverflow.com/questions/8801697/xml-export-via-bcp-bulk-export - bug 2008R2, converte il varbinary in ascii
                query =
                "select (select " + headers + " for xml raw('root'),BINARY BASE64) " +
                "from [" + db + "].[" + schema + "].[" + obj + "] t " +
                sb.ToString(); ;//filter;

                command = new SqlCommand(query, conn);
                //command.CommandTimeout = 0;
                SqlDataReader dr = command.ExecuteReader();

                while (dr.Read())
                {
                    //rows.Add(new tuple.t2<String, String>("", (String)dr[0]));
                    rows.Add((String)dr[0]);
                }
                return rows;
            }
            catch (Exception e)
            {
                rows.Add(e.ToString().Substring(0, Math.Min(4000, e.ToString().Length)));
                return  rows;
            }
            finally
            {
                if (command != null)
                    command.Dispose();
                if (conn != null)
                    conn.Close();
            }
        }
        private static void columns_ok(object resultObj, out SqlString node)
        {
            //String res = (String)resultObj;

            node = (String)resultObj;
        }
    }
}
我尝试了什么:

select *
from dbo.objdb('test','sys','all_columns',null,null,null)

错误

select *
from dbo.objdb('test','sys','all_columns','collation_name',null,null)

错误

select *
from dbo.objdb('test','sys','all_columns','object_id,name,column_id,system_type_id,user_type_id,max_length,precision,scale,is_nullable,is_ansi_padded,is_rowguidcol,is_identity,is_computed,is_filestream,is_replicated,is_non_sql_subscribed,is_merge_published,is_dts_replicated,is_xml_document,xml_collection_id,default_object_id,rule_object_id,is_sparse,is_column_set,generated_always_type,generated_always_type_desc,encryption_type,encryption_type_desc,encryption_algorithm_name,column_encryption_key_id,column_encryption_key_database_name,is_hidden,is_masked',null,null)

(所有列都没有“collat​​ion_name”) FINE!

 select *
 from dbo.objdb('test','sys','columns','collation_name',null,null)

FINE O.o