そのCAST
ため、リモートインスタンスではなくローカルで実行されていることに気付いた後、エラーを再現することができました。これを修正することを期待して、以前はSP3に移行することをお勧めしていました(SP3でエラーを再現できないこと、および一部に関係なく良いアイデアであることが原因です)。ただし、エラーを再現できるようになったので、SP3に移行しても、おそらく良い考えではありますが、これを修正できないことは明らかです。また、SQL Server 2008 R2 RTMおよび2014 SP1でエラーを再現しました(3つのケースすべてで「ループバック」ローカルリンクサーバーを使用)。
この問題は、クエリが実行されている場所、または少なくともクエリの一部が実行されている場所に関係しているようです。これは、ローカルDBオブジェクトへの参照を含めることによってのみ、操作を機能させることができたためです。CAST
SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
FROM [Local].[database_name].[dbo].[table_name] rmt
CROSS JOIN (SELECT TOP (1) 1 FROM [sys].[data_spaces]) tmp(dummy);
それは実際に動作します。ただし、次のエラーは元のエラーになります。
SELECT rmt.*, CAST(NULL AS UNIQUEIDENTIFIER) AS [GUID]
FROM [Local].[database_name].[dbo].[table_name] rmt
CROSS JOIN (VALUES (1)) tmp(dummy);
ローカル参照がない場合、クエリ全体がリモートシステムに送られて実行され、何らかの理由NULL
でに変換できないUNIQUEIDENTIFIER
か、おそらくNULL
OLE DBドライバーによって誤って変換されていると推測しています。
私が行ったテストに基づいて、これはバグのように見えますが、バグがSQL Serverにあるのか、SQL Server Native Client / OLEDBドライバーにあるのかはわかりません。しかし、変換誤差は、OLEDBドライバ内で発生などからの変換の問題は必ずしもないINT
とUNIQUEIDENTIFIER
運転者が変換を行うために、SQL Serverを使用していないので(SQL Serverで許可されていない変換)(SQL Serverがありません変換を可能にINT
するDATE
試験のいずれかに示されるように)、まだ正常OLEDBドライバハンドル。
3つのテストを実行しました。成功した2つについては、リモートで実行されているクエリを示すXML実行計画を確認しました。3つすべてについて、SQLプロファイラーを介して例外またはOLEDBイベントをキャプチャしました。
イベント:
- エラーと警告
- OLEDB
- TSQL
- 以下を除くすべて:
- SQL:StmtRecompile
- XQuery静的タイプ
列フィルター:
テスト
テスト1
CAST(NULL AS UNIQUEIDENTIFIER)
うまくいく
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
, (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
XML実行計画の関連部分:
<DefinedValue>
<ColumnReference Column="Expr1002" />
<ScalarOperator ScalarString="NULL">
<Const ConstValue="NULL" />
</ScalarOperator>
</DefinedValue>
...
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT 1 FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
テスト2
CAST(NULL AS UNIQUEIDENTIFIER)
失敗する
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
(注:XMLトレースファイルを比較したときの差が1つ小さくなるように、サブクエリをコメントアウトのままにしておきました)
テスト3
SELECT TOP (2) CAST(NULL AS DATE) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
(注:XMLトレースファイルを比較したときの差が1つ小さくなるように、サブクエリをコメントアウトのままにしておきました)
XML実行計画の関連部分:
<DefinedValue>
<ColumnReference Column="Expr1002" />
<ScalarOperator ScalarString="[Expr1002]">
<Identifier>
<ColumnReference Column="Expr1002" />
</Identifier>
</ScalarOperator>
</DefinedValue>
...
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
テスト#3を見るとSELECT TOP (2) NULL
、「リモート」システムで実行されています。SQLプロファイラトレースは、このリモートフィールドのデータ型が実際にあることを示していINT
ます。トレースは、クライアント側のフィールド(つまり、クエリを実行している場所)がDATE
予想どおりであることも示しています。からINT
への変換はDATE
、SQL Serverでエラーが発生するもので、OLEDBドライバー内で正常に機能します。リモート値はですNULL
ので、直接返されるため、<ColumnReference Column="Expr1002" />
です。
テスト#1を見るとSELECT 1
、「リモート」システムで実行されています。SQLプロファイラトレースは、このリモートフィールドのデータ型が実際にあることを示していINT
ます。トレースは、クライアント側のフィールド(つまり、クエリを実行している場所)がGUID
予想どおりであることも示しています。以下からの変換INT
にGUID
(これはドライバ内で行われ、覚えている、とOLEDBは、「GUID」と呼んでいます)、SQL Serverでエラーが発生します何かが、OLEDBドライバ内だけで罰金に動作します。リモート値はそう NULL
ではないので、リテラルNULL
に置き換えられ<Const ConstValue="NULL" />
ます。
テスト#2は失敗するため、実行計画はありません。ただし、「リモート」システムに正常にクエリを実行しますが、結果セットを返すことはできません。SQLプロファイラがキャプチャしたクエリは次のとおりです。
SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001"
これはテスト#1で行われているのとまったく同じクエリですが、ここでは失敗しています。他にも小さな違いがありますが、OLEDB通信を完全に解釈することはできません。ただし、リモートフィールドはINT
(wType = 3 = adInteger / 4バイト符号付き整数/ DBTYPE_I4)と表示され、「クライアント」フィールドはGUID
(wType = 72 = adGUID /グローバル一意識別子/ DBTYPE_GUID)と表示されます。OLE DBのドキュメントは、GUIDデータ型変換、DBDATEデータ型変換、およびI4データ型変換がI4からGUIDまたはDBDATEへの変換がサポートされていないことを示しているため、DATE
クエリは機能するため、あまり役に立ちません。
3つのテストのTrace XMLファイルはPasteBinにあります。各テストが他のテストとどこが異なるかの詳細を確認したい場合は、それらをローカルに保存し、それらに対して「diff」を実行できます。ファイルは次のとおりです。
- NullGuidSuccess.xml
- NullGuidError.xml
- NullDateSuccess.xml
エルゴ?
それについてどうすればいいですか?おそらく、SQL Native Client SQLNCLI11
がSQL Server 2012で廃止されていることを考えると、一番上のセクションで述べた回避策にすぎません。SQLServer Native Client のトピックに関するMSDNページのほとんどは、上:
警告
SQL Server Native Client(SNAC)は、SQL Server 2012以降ではサポートされません。SNACを新しい開発作業で使用することは避け、現在SNACを使用しているアプリケーションを変更することを計画してください。SQL Server用のMicrosoft ODBCドライバは、 WindowsのからのMicrosoft SQL ServerおよびMicrosoft AzureのSQLデータベースへのネイティブ接続を提供します。
詳細については、以下を参照してください。
ODBC ??
ODBCリンクサーバーを次の方法でセットアップしました。
EXEC master.dbo.sp_addlinkedserver
@server = N'LocalODBC',
@srvproduct=N'{my_server_name}',
@provider=N'MSDASQL',
@provstr=N'Driver={SQL Server};Server=(local);Trusted_Connection=Yes;';
EXEC master.dbo.sp_addlinkedsrvlogin
@rmtsrvname=N'LocalODBC',
@useself=N'True',
@locallogin=NULL,
@rmtuser=NULL,
@rmtpassword=NULL;
そして、試した:
SELECT CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
FROM [LocalODBC].[tempdb].[sys].[objects] rmt;
次のエラーを受け取りました:
リンクサーバー "LocalODBC"のOLE DBプロバイダー "MSDASQL"は、 "要求された変換はサポートされていません。"というメッセージを返しました。
Msg 7341、レベル16、状態2、行53
リンクサーバー "LocalODBC"のOLE DBプロバイダー "MSDASQL"から列 "(ユーザー生成式).Expr1002"の現在の行値を取得できません。
PS
リモートサーバーとローカルサーバー間のGUIDの転送に関連するため、非NULL値は特別な構文を介して処理されます。実行したときに、SQLプロファイラトレースで次のOLE DBイベント情報に気付きましたCAST(0x00 AS UNIQUEIDENTIFIER)
。
<RemoteQuery RemoteSource="Local" RemoteQuery=
"SELECT {guid'00000000-0000-0000-0000-000000000000'} "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001""
/>
PPS
またOPENQUERY
、次のクエリを使用してテストしました。
SELECT TOP (2) CAST(NULL AS UNIQUEIDENTIFIER) AS [Something]
--, (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM OPENQUERY([Local], N'SELECT 705 AS [dummy] FROM [TEMPTEST].[sys].[objects];') rmt;
また、ローカルオブジェクト参照がなくても成功しました。SQLプロファイラトレースXMLファイルは、次の場所のPasteBinに投稿されています。
NullGuidSuccessOPENQUERY.xml
XML実行計画ではNULL
、テスト#1と同じ定数を使用してそれを示しています。