ดังนั้นฉันสามารถทำซ้ำข้อผิดพลาดหลังจากทราบว่าCAST
กำลังทำในเครื่องไม่ใช่ในอินสแตนซ์ระยะไกล ก่อนหน้านี้ฉันแนะนำให้เลื่อนไปที่ SP3 โดยหวังว่าจะแก้ไขปัญหานี้ (บางส่วนเนื่องจากไม่สามารถทำซ้ำข้อผิดพลาดใน SP3 และบางส่วนเนื่องจากเป็นความคิดที่ดีโดยไม่คำนึงถึง) อย่างไรก็ตามตอนนี้ฉันสามารถทำซ้ำข้อผิดพลาดได้ชัดเจนว่าการย้ายขึ้นไปที่ SP3 ในขณะที่ยังคงเป็นความคิดที่ดีจะไม่สามารถแก้ไขปัญหานี้ได้ และฉันยังทำซ้ำข้อผิดพลาดใน SQL Server 2008 R2 RTM และ 2014 SP1 (โดยใช้เซิร์ฟเวอร์ที่เชื่อมโยงแบบ "วนกลับ" ในทั้งสามกรณี)
ดูเหมือนว่าปัญหานี้จะทำอย่างไรกับที่แบบสอบถามจะดำเนินการหรืออย่างน้อยที่เป็นส่วนหนึ่ง (s)ของมันกำลังดำเนินการ ฉันพูดแบบนี้เพราะฉันสามารถทำให้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 จัดการได้สำเร็จดังที่แสดงในการทดสอบอย่างใดอย่างหนึ่ง)
ฉันทำการทดสอบสามครั้ง สำหรับทั้งสองที่ประสบความสำเร็จฉันดูแผนการดำเนินการ XML ซึ่งแสดงแบบสอบถามที่กำลังดำเนินการจากระยะไกล สำหรับทั้งสามฉันจับข้อยกเว้นหรือเหตุการณ์ OLEDB ผ่าน SQL Profiler:
กิจกรรม:
- ข้อผิดพลาดและคำเตือน
- ความสนใจ
- ข้อยกเว้น
- คำเตือนการดำเนินการ
- ข้อความแสดงความผิดพลาดของผู้ใช้
- 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)
ทดสอบ 3
CAST(NULL AS DATE)
ที่ได้ผล
SELECT TOP (2) CAST(NULL AS DATE) AS [Something]
-- , (SELECT COUNT(*) FROM sys.[data_spaces]) AS [lcl]
FROM [Local].[TEMPTEST].[sys].[objects] rmt;
(หมายเหตุ: ฉันเก็บแบบสอบถามย่อยไว้ที่นั่นใส่เครื่องหมายคอมเม้นต์เพื่อให้มันแตกต่างกันเล็กน้อยเมื่อฉันเปรียบเทียบไฟล์ติดตาม XML)
ส่วนที่เกี่ยวข้องของแผนการดำเนินการ 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 Profiler INT
ร่องรอยแสดงให้เห็นว่าชนิดข้อมูลของเขตข้อมูลระยะไกลนี้ในความเป็นจริง การติดตามยังแสดงให้เห็นว่าเขตข้อมูลในฝั่งไคลเอ็นต์ (เช่นที่ที่ฉันเรียกใช้แบบสอบถามจาก) เป็นDATE
ไปตามที่คาดไว้ การแปลงจากINT
เป็นDATE
สิ่งที่จะได้รับข้อผิดพลาดใน SQL Server ทำงานได้ดีภายในไดรเวอร์ OLEDB ค่าระยะไกลจึงถูกส่งกลับโดยตรงดังนั้นNULL
<ColumnReference Column="Expr1002" />
ถ้าคุณดูที่การทดสอบ # 1 มันกำลังทำSELECT 1
บนระบบ "ระยะไกล" ของ SQL Profiler INT
ร่องรอยแสดงให้เห็นว่าชนิดข้อมูลของเขตข้อมูลระยะไกลนี้ในความเป็นจริง การติดตามยังแสดงให้เห็นว่าเขตข้อมูลในฝั่งไคลเอ็นต์ (เช่นที่ที่ฉันเรียกใช้แบบสอบถามจาก) เป็นGUID
ไปตามที่คาดไว้ การแปลงจากINT
เป็นGUID
(โปรดจำไว้ว่าจะดำเนินการภายในไดร์เวอร์และ OLEDB เรียกมันว่า "GUID") ซึ่งเป็นสิ่งที่จะได้รับข้อผิดพลาดใน SQL Server ทำงานได้ดีในไดรเวอร์ OLEDB ค่าระยะไกลไม่ได้ NULL
จึงถูกแทนที่ด้วยอักษรจึงNULL
<Const ConstValue="NULL" />
การทดสอบ # 2 ล้มเหลวดังนั้นจึงไม่มีแผนการดำเนินการ อย่างไรก็ตามมันทำการสืบค้นระบบ "ระยะไกล" ได้สำเร็จ แต่ไม่สามารถส่งคืนชุดผลลัพธ์ได้ แบบสอบถามที่จับ SQL Profiler คือ:
SELECT TOP (2) NULL "Expr1002" FROM "TEMPTEST"."sys"."objects" "Tbl1001"
นั่นคือแบบสอบถามเดียวกันที่ทำใน Test # 1 แต่ที่นี่มันล้มเหลว มีความแตกต่างเล็กน้อยอื่น ๆ แต่ฉันไม่สามารถตีความการสื่อสาร OLEDB ได้อย่างสมบูรณ์ อย่างไรก็ตามฟิลด์ระยะไกลยังคงแสดงเป็นINT
(จำนวนเต็ม wType = 3 = adInteger / สี่ไบต์ลงนาม / DBTYPE_I4) ในขณะที่ฟิลด์ "ลูกค้า" ยังคงแสดงเป็นGUID
(wType = 72 = adGUID / ตัวระบุที่ไม่ซ้ำกันทั่วโลก / DBTYPE_GUID) เอกสาร OLE DB ไม่ได้ช่วยมากเป็นประเภท GUID ข้อมูลการแปลง , DBDATE ชนิดข้อมูลการแปลงและI4 ชนิดข้อมูล Conversion ที่แสดงให้เห็นว่าการแปลงจากI4ทั้งGUIDหรือDBDATEได้รับการสนับสนุนยังDATE
งานแบบสอบถาม
ไฟล์ Trace XML สำหรับการทดสอบทั้งสามนั้นอยู่ใน PasteBin หากคุณต้องการดูรายละเอียดว่าแต่ละการทดสอบนั้นแตกต่างจากที่อื่นหรือไม่คุณสามารถบันทึกไว้ในเครื่องแล้วทำ "diff" ไฟล์คือ:
- NullGuidSuccess.xml
- NullGuidError.xml
- NullDateSuccess.xml
ERGO?
จะทำอย่างไรกับมัน? อาจเป็นเพียงแค่การแก้ไขปัญหาที่ฉันระบุไว้ในส่วนบนที่ระบุว่า SQL Native Client - SQLNCLI11
- ถูกคัดค้าน ณ SQL Server 2012 หน้า MSDN ส่วนใหญ่ในหัวข้อของ SQL Server Native Client มีการแจ้งเตือนดังต่อไปนี้ที่ tOP:
การเตือน
SQL Server Native Client (SNAC) ไม่รองรับเกินกว่า SQL Server 2012 หลีกเลี่ยงการใช้ SNAC ในงานพัฒนาใหม่และวางแผนที่จะปรับเปลี่ยนแอปพลิเคชันที่ใช้งานอยู่ในปัจจุบัน Microsoft โปรแกรมควบคุม ODBC สำหรับ SQL Serverให้การเชื่อมต่อพื้นเมืองจาก Windows ไป Microsoft SQL Server และฐานข้อมูล Microsoft SQL Azure
สำหรับข้อมูลเพิ่มเติมโปรดดู:
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;
และได้รับข้อผิดพลาดต่อไปนี้:
ผู้ให้บริการ OLE DB "MSDASQL" สำหรับเซิร์ฟเวอร์ที่เชื่อมโยง "LocalODBC" ข้อความที่ส่งคืน "ไม่รองรับการแปลงที่ร้องขอ"
ข่าวสารเกี่ยวกับ 7341 ระดับ 16 สถานะ 2 บรรทัด 53
ไม่สามารถรับค่าแถวปัจจุบันของคอลัมน์ "(นิพจน์ที่ผู้ใช้สร้างขึ้น). Expr1002" จากผู้ให้บริการ OLE DB "MSDASQL" สำหรับเซิร์ฟเวอร์ที่เชื่อมโยง "LocalODBC"
PS
เนื่องจากเกี่ยวข้องกับการขนส่ง GUID ระหว่างเซิร์ฟเวอร์ระยะไกลและเซิร์ฟเวอร์ท้องถิ่นค่าที่ไม่ใช่ NULL จะถูกจัดการผ่านทางไวยากรณ์พิเศษ ฉันสังเกตเห็นข้อมูล OLE DB Event ต่อไปนี้ในการติดตาม SQL Profiler เมื่อฉันวิ่ง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;
และมันก็ประสบความสำเร็จแม้ว่าจะไม่มีการอ้างอิงวัตถุท้องถิ่น ไฟล์ XML การติดตามของผู้สร้างโปรไฟล์ SQL ได้รับการโพสต์ไปยัง PasteBin ที่:
NullGuidSuccessOPENQUERY.xml
แผนการดำเนินการ XML แสดงโดยใช้NULL
ค่าคงที่เช่นเดียวกับใน Test # 1