為什麼 sqlcmd 會截斷 varbinary(max)?
在
sys.assembly_files
目錄內部,我可以看到一個名為content
1> SELECT assembly_id, LEFT(name, 50), file_id, content FROM sys.assembly_files; 2> GO assembly_id file_id content ----------- -------------------------------------------------- ----------- ------- 1 microsoft.sqlserver.types.dll 1 0x4D5A90x07585 (1 rows affected)
然而,即使
sqlcmd -Y 8000 -y 5000
我不能得到更多0x4D5A90x075850x167D00x043CB
assembly_id file_id content ----------- -------------------------------------------------- ----------- ------- 1 microsoft.sqlserver.types.dll 1 0x4D5A90x075850x167D00x043CB
想知道發生了什麼並懷疑客戶端沒有將所有內容都返回給我,我嘗試了SQL Server
mssql-cli
的埠。pg-cli
使用mssql-cli
,我看到了整個內容欄位,實際上它看起來確實是位內容的正確大小。這讓我相信這是sqlcmd.exe
截斷或其他破壞和摻假程序集的字節碼表示的問題。使用mssql-cli
,我明白了master>SELECT assembly_id, LEFT(name, 50), file_id, content FROM sys.assembly_files; ...... -[ RECORD 1 ]------------------------- assembly_id | 1 (No column name) | microsoft.sqlserver.types.dll file_id | 1 content | 0x4D5A90000300000004000000FFFF0000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000D00000000E1FBA0E00B409CD21B........ and on and on (1 row affected)
為什麼 sqlcmd 會截斷 varbinary(max)?
因為它可能是 GB 的數據,所以 SQLCMD 和 SSMS 等查詢工具會截斷結果以顯示。
您可以使用 bcp.exe 轉儲到文件,將“前綴長度”設置為 0。
bcp "select content from sys.assembly_files where name = 'microsoft.sqlserver.types.dll'" queryout microsoft.sqlserver.types.dll -T Enter the file storage type of field content [varbinary(max)]: Enter prefix-length of field content [8]: 0 Enter length of field content [0]: Enter field terminator [none]: Do you want to save this format information in a file? [Y/n] n Starting copy... 1 rows copied. Network packet size (bytes): 4096 Clock Time (ms.) Total : 62 Average : (16.13 rows per sec.)
您看到的不是截斷;它一定是一個錯誤。既不
0x4D5A90x07585
是也不0x4D5A90x075850x167D00x043CB
是有效的二進制值。應該只出現0x
一次(最多),在最左邊,並表示後面的值是二進制值。對於二進制值來說,再顯示一次或兩次是不可能的,因為在十六進制/以 16 為基數的符號中不能有“x”。截斷將是值的前 N 個字節,而您看到的不是。如果執行以下操作:SELECT CHARINDEX(N'07585', CONVERT(NVARCHAR(MAX), [content], 1)) FROM sys.assembly_files;
您應該返回值 8003,表明輸出中的第二組 5 位十六進制數字不是該程序集中的第二組 5 位數字。而且,當實際字節需要 2 個十六進制數字時,每個“片段”(以 開頭
0x
)只有 5 個十六進制數字,因此它們應該始終以 2 個為一組,這也很奇怪。SQLCMD(至少在 Windows 上)似乎有 524,287 字節的限制,這足以輸出您正在使用的 392,376 字節程序集的全部內容(即
microsoft.sqlserver.types.dll
)。使用 SQLCMD,您可以使用該
-y
開關設置可變長度欄位的最大大小,即該[content]
欄位。您可以設置的最大值-y
為8000,但如果您使用0的值,那麼它將達到 524,287 字節。嘗試以下操作,看看你會得到什麼:
sqlcmd -S server auth_stuff -y 0 -Q "SELECT [content] FROM sys.assembly_files;" -o .\binary_truncation.txt
該查詢假定您沒有載入任何自定義程序集。如果這樣做,則可以通過在該查詢的末尾添加以下內容來縮小特定範圍:
WHERE assembly_id = 1 AND [file_id] = 1
每個大會的
[file_id] = 1
行是大會本身。附加文件(如果有)將從[file_id] = 2
.當我在 Windows 上執行該命令行時,我得到了一個 784,777 字節的文件。去掉幾個換行符的 25 個字節,“(受影響的 1 行)”行和開頭的“0x”,剩下 784,752 個字節。二進制的每個字節佔用 2 個單字節字元,00 - FF,因此將該文件大小(減去 25 個字節)除以 2 得到 392,376 個字節。執行以下操作:
SELECT LEN([content]) FROM sys.assembly_files;
回報:392,376。因此,我們提取了整個程序集。
現在,如果確實存在僅
VARBINARY
輸出的錯誤,我們可以先NVARCHAR
通過執行以下命令將其轉換為數據來進行測試:sqlcmd -S server auth_stuff -y 0 -Q "SELECT CONVERT(NVARCHAR(MAX), [content], 1) FROM sys.assembly_files;" -o .\binary_truncation.txt
對我來說,這會返回相同的 784,777 字節文件。