SSVARIANT 結構
適用於:SQL Server Azure SQL 資料 Azure SQL 受控執行個體 Azure Synapse Analytics Analytics Platform System (PDW)
定義於 msoledbsql.h 中的 SSVARIANT 結構會對應至 OLE DB Driver for SQL Server 中的 DBTYPE_SQLVARIANT 值。
SSVARIANT 是一個區分集合聯集。 根據 vt 成員的值而定,取用者可以判斷要讀取的成員。 vt 值會對應至 SQL Server 資料類型。 因此,SSVARIANT 結構可以保留任何 SQL Server 類型。 如需適用於標準 OLE DB 類型之資料結構的詳細資訊,請參閱類型指示器 \(英文\)。
備註
當 DataTypeCompat==80 時,數個 SSVARIANT 子類型會變成字串。 例如,下列 vt 值在 SSVARIANT 中會顯示為 VT_SS_WVARSTRING:
VT_SS_DATETIMEOFFSET
VT_SS_DATETIME2
VT_SS_TIME2
VT_SS_DATE
當 DateTypeCompat == 0 時,這些類型都會以原生形式出現。
如需 SSPROP_INIT_DATATYPECOMPATIBILITY 的詳細資訊,請參閱利用 OLE DB Driver for SQL Server 使用連接字串關鍵字。
msoledbsql.h 檔案包含變數存取巨集,可簡化 SSVARIANT 結構中成員類型的取值 (Dereference)。 V_SS_DATETIMEOFFSET 即為一例,可以按照下列方式使用:
memcpy(&V_SS_DATETIMEOFFSET(pssVar).tsoDateTimeOffsetVal, pDTO, cbNative);
V_SS_DATETIMEOFFSET(pssVar).bScale = bScale;
如需適用於 SSVARIANT 結構中每個成員的完整存取巨集集合,請參考 msoledbsql.h 檔案。
下表將描述 SSVARIANT 結構的成員:
member | OLE DB 類型指標 | OLE DB C 資料類型 | vt 值 | 註解 |
---|---|---|---|---|
vt | SSVARTYPE | 指定包含在 SSVARIANT 結構中的值類型。 | ||
bTinyIntVal | DBTYPE_UI1 | BYTE | VT_SS_UI1 | 支援 Tinyint SQL Server 資料類型。 |
sShortIntVal | DBTYPE_I2 | SHORT | VT_SS_I2 | 支援 Smallint SQL Server 資料類型。 |
lIntVal | DBTYPE_I4 | LONG | VT_SS_I4 | 支援 int SQL Server 資料類型。 |
llBigIntVal | DBTYPE_I8 | LARGE_INTEGER | VT_SS_I8 | 支援 Bigint SQL Server 資料類型。 |
fltRealVal | DBTYPE_R4 | float | VT_SS_R4 | 支援 real SQL Server 資料類型。 |
dblFloatVal | DBTYPE_R8 | double | VT_SS_R8 | 支援 float SQL Server 資料類型。 |
cyMoneyVal | DBTYPE_CY | LARGE_INTEGER | VT_SS_MONEY VT_SS_SMALLMONEY | 支援 money 與 smallmoney SQL Server 資料類型。 |
fBitVal | DBTYPE_BOOL | VARIANT_BOOL | VT_SS_BIT | 支援 bit SQL Server 資料類型。 |
rgbGuidVal | DBTYPE_GUID | GUID | VT_SS_GUID | 支援 uniqueidentifier SQL Server 資料類型。 |
numNumericVal | DBTYPE_NUMERIC | DB_NUMERIC | VT_SS_NUMERIC | 支援 numeric SQL Server 資料類型。 |
dDateVal | DBTYPE_DATE | DBDATE | VT_SS_DATE | 支援 date SQL Server 資料類型。 |
tsDateTimeVal | DBTYPE_DBTIMESTAMP | DBTIMESTAMP | VT_SS_SMALLDATETIME VT_SS_DATETIME VT_SS_DATETIME2 | 支援 smalldatetime、datetime 與 datetime2 SQL Server 資料類型。 |
Time2Val | DBTYPE_DBTIME2 | DBTIME2 | VT_SS_TIME2 | 支援 time SQL Server 資料類型。 包括下列成員: tTime2Val (DBTIME2) bScale (BYTE) 指定 tTime2Val 值的範圍。 |
DateTimeVal | DBTYPE_DBTIMESTAMP | DBTIMESTAMP | VT_SS_DATETIME2 | 支援 datetime2 SQL Server 資料類型。 包括下列成員: tsDataTimeVal (DBTIMESTAMP) bScale (BYTE) 指定 tsDataTimeVal 值的範圍。 |
DateTimeOffsetVal | DBTYPE_DBTIMESTAMPOFSET | DBTIMESTAMPOFFSET | VT_SS_DATETIMEOFFSET | 支援 datetimeoffset SQL Server 資料類型。 包括下列成員: tsoDateTimeOffsetVal (DBTIMESTAMPOFFSET) bScale (BYTE) 指定 tsoDateTimeOffsetVal 值的範圍。 |
NCharVal | 沒有對應的 OLE DB 類型指標。 | struct _NCharVal | VT_SS_WVARSTRING, VT_SS_WSTRING |
支援 Nchar 與 Nvarchar SQL Server 資料類型。 包括下列成員: sActualLength (SHORT) 指定 pwchNCharVal 指向之字串的實際長度。 不包括結尾的零。 sMaxLength (SHORT) 指定 pwchNCharVal 指向之字串的最大長度。 pwchNCharVal (WCHAR *) 指向字串的指標。 rgbReserved (BYTE[5] ) 指定定序資訊。 未使用的成員:dwReserved 及 pwchReserved。 |
CharVal | 沒有對應的 OLE DB 類型指標。 | struct _CharVal | VT_SS_STRING, VT_SS_VARSTRING |
支援 char 與 varchar SQL Server 資料類型。 包括下列成員: sActualLength (SHORT) 指定 pchCharVal 指向之字串的實際長度。 不包括結尾的零。 sMaxLength (SHORT) 指定 pchCharVal 指向之字串的最大長度。 pchCharVal (CHAR *) 指向字串的指標。 rgbReserved (BYTE[5] ) 指定定序資訊。 未使用的成員: dwReserved 及 pwchReserved。 |
BinaryVal | 沒有對應的 OLE DB 類型指標。 | struct _BinaryVal | VT_SS_VARBINARY, VT_SS_BINARY |
支援 binary 與 varbinary SQL Server 資料類型。 包括下列成員: sActualLength (SHORT) 指定 prgbBinaryVal 指向之資料的實際長度。 sMaxLength (SHORT) 指定 prgbBinaryVal 指向之資料的最大長度。 prgbBinaryVal (BYTE *) 指向二進位資料的指標。 未使用的成員:dwReserved。 |
UnknownType | 未使用 | 未使用 | 未使用 | 未使用 |
BLOBType | 未使用 | 未使用 | 未使用 | 未使用 |
已知問題
可能的窄字串資料損毀
在 OLE DB 驅動程式 18.4 版之前,若下列所有條件都成立,則 sql_variant
資料行中的插入可能會導致伺服器上的資料損毀:
- 用戶端電腦字碼頁不符合資料庫定序字碼頁。
- 要插入的用戶端緩衝區,包含以用戶端字碼頁編碼的非 ASCII 窄字串字元。
- 下列任一條件都成立:
DBPARAMBINDINFO
結構中的pwszDataSourceType
欄位,其描述對應至sql_variant
資料行的參數已設定為L"DBTYPE_SQLVARIANT"
、L"DBTYPE_VARIANT"
或L"sql_variant"
。 如需詳細資料,請參閱:ICommandWithParameters::SetParameterInfo。or
用於插入的參數化 SQL 查詢已準備妥當。
更明確的說,OLE DB 驅動程式不會在插入資料之前,將其翻譯成資料庫定序字碼頁。 然而,此驅動程式錯誤地向伺服器指出,資料庫定序字碼頁中的資料已編碼。 此行為導致資料與其儲存在 sql_variant
欄中的對應字碼頁不相符。
同樣地,在擷取相同的值時,OLE DB 驅動程式不會將字串翻譯成用戶端字碼頁。 然而,由於插入的資料已經在用戶端字碼頁中 (請參閱上面的段落),因此用戶端應用程式可正確地解譯資料。 就算如此,使用其他驅動程式的應用程式,也會以損毀的格式擷取這些值。 會發生損毀是因為其他驅動程式在資料庫定序字碼頁中解譯了字串,並嘗試將其翻譯成用戶端字碼頁。
自 18.4 版起,OLE DB Driver 會在插入之前,將窄字串翻譯成資料庫定序字碼頁。 同樣地,驅動程式也會在擷取時,將資料翻譯回用戶端字碼頁。 因此,依賴上述 Bug 的用戶端應用程式,可能會在擷取使用舊版 OLE DB Driver 插入的資料時遇到問題。 下方復原程序旨在提供解決這些問題的指引。
復原程序
重要
執行下列復原步驟之前,請務必備份現有的資料。
若應用程式在切換至 OLE DB 驅動程式 18.4 版之後,在從 sql_variant
資料行擷取資料時遇到問題,則必須修改損毀的資料,使其定序與儲存資料的資料庫相同。 下列指令碼可用來從 sql_variant
資料行復原單一值。 指令碼是範本,必須加以調整以符合情況。
重要
由於不會儲存資料的原始字碼頁,因此必須告知伺服器初始如何編碼資料。 若要執行這項操作,請在資料庫的內容中執行指令碼,其字碼頁與初始插入資料的用戶端其字碼頁相同。 例如,若從使用字碼頁 932
所設定用戶端插入損毀的資料,則必須在具有日文定序的資料庫內容 (例如 Japanese_XJIS_100_CS_AI
) 中執行下列指令碼。
/*
Description:
Template that can be used to recover the corrupted value inserted into the sql_variant column.
Scenario:
The database is named [YourDatabase] and it contains a table named [YourTable], which contains the corrupted value.
Schema is named [dbo].
The corrupted value is stored in a column of type sql_variant named [YourColumn].
The corrupted value is sql_variant of BaseType char. For details on sql_variant properties, see:
https://zcusa.951200.xyz/sql/t-sql/functions/sql-variant-property-transact-sql
*/
-- Base type in sql_variant can hold a maximum of 8000 bytes
-- For details see:
-- https://zcusa.951200.xyz/sql/t-sql/data-types/sql-variant-transact-sql#remarks
DECLARE @bin VARBINARY(8000)
-- In the following lines we convert the sql_variant base type to binary.
-- <FilterExpression>
-- Is a placeholder and must be replaced with an expression that filters a single corrupted value to be recovered.
-- Therefore, the expression must result in a single value being returned only.
SET @bin = (SELECT CAST([YourColumn] AS VARBINARY(8000)) FROM [YourDatabase].[dbo].[YourTable] WHERE <FilterExpression>)
-- In the following lines we store the binary value in char(59) (a fixed-size character data type).
-- IMPORTANT NOTE:
-- This example assumes the corrupted sql_variant's base type is char(59).
-- You MUST adjust the type (that is, char/varchar) and size to match your scenario exactly.
DECLARE @char CHAR(59)
SET @char = CAST((@bin) AS CHAR(59))
DECLARE @sqlvariant sql_variant
-- The following lines recover the corrupted value by translating the value to the collation of the database.
-- <DBCollation>
-- Must be replaced with the collation (for example, Latin1_General_100_CI_AS_SC_UTF8) of the database holding the data.
SET @sqlvariant = @char collate <DBCollation>
-- Finally, we update the corrupted value with the recovered value.
-- "<FilterExpression>"
-- Is a placeholder and must be replaced with an expression that filters a single corrupted value to be recovered.
-- Therefore, the expression must result in a single value being returned only.
UPDATE [YourDatabase].[dbo].[YourTable] SET [YourColumn] = @sqlvariant WHERE <FilterExpression>