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

Msg 6522, Level 16 but no error message selecting from sys.all_columns

我是 运行 SQLCLR 函数 SqlConnection("context connection=true")

在某些情况下,我得到异常

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

每次在相同记录编号的相同查询中都会发生这种情况。

有连接

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

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

我不明白为什么。

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

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

这是我的class

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" ->  - 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

提前致谢!!

更新: 我不知道为什么,但问题是列“collation_name”仅在 SQL 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 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" ->  - 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)

(没有 "collation_name" 的所有列) 很好!

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

很好O.o

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

此错误似乎也只发生在 collation_name 字段用于从 sys.system_columnssys.all_columns 中选择的查询中时。

测试行的子集,我能够确定错误只发生在一行中。该对象是:

sys.pdw_nodes_pdw_physical_databases

此行 出现在 SQL Server 2012 中(除了 2012 SP3 和 2016 SP1 之外,我没有测试过任何东西),那里根本没有错误.

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

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

Msg 6522, Level 16, State 1, Line 406
A.NET Framework error occurred during execution of user-defined routine or aggregate "ObjDb":
  System.Data.SqlClient.SqlException:
  System.Data.SqlClient.SqlException:
    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 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.

发生的任何事情

现在,避免这种 should 很简单,只需将以下条件添加到 WHERE 子句 if 模式名称是 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)

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

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

虽然看起来 ColumnPropertyEx 函数可能不应该按原样运行,但我认为主要问题是 pdw_nodes_pdw_physical_databases 的 3 列应该从 sys.all_columns 返回首先。 pdw_nodes_pdw_physical_databases 在 Azure SQL 数据仓库和并行数据仓库之外甚至不可用。事实上,对象名称 pdw_nodes_pdw_physical_databasesOBJECT_NAME 函数返回,却没有出现在 sys.all_objects ;-).

中,这已经够奇怪了