【发布时间】:2020-05-27 22:46:37
【问题描述】:
标题 ##MS-SQL - ODBC - 应用于“始终加密”的 VARCHAR(MAX) 列时插入失败
以下程序尝试使用 ODBC 将文本文件加载到 VARCHAR(max) 列中。 VARCHAR(MAX) 列已加密 - 使用“始终加密”功能。
create table clobTable
(
id integer identity(1,1) primary key not null,
--clobCol varchar(max)
clobCol [varchar](max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK1], ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL
);
INSERT 语句在执行时失败,同时通知以下错误消息:
Native error = 206
Message text = [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Operand type clash: varchar(max) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK1', column_encryption_key_database_name = 'AEdemo') collation_name = 'Compatibility_136_8200_0' is incompatible with varchar(max) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK1',
SQLState = 37000
Native error = 8180
Message text = [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Statement(s) could not be prepared.
注意事项:
- 将这个程序应用到一个表中,其中 VARCHAR(MAX) 列 没有加密 - 它工作得很好。
- 以下是通过 MS-SQL 服务器管理工作室发布的,并且运行良好:
declare @v varchar(max) = '111111111111111111222222222222222222222223333333333333333333333334444444444444444'
insert into clobTable (clobCol) values (@v)
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <stdio.h>
#include <stdlib.h>
/*
MS-SQL - ODBC - INSERT fails when applied on an "Always Encrypted" VARCHAR(MAX) column
The following program attempts to load a text file into a VARCHAR(max) column - using ODBC.
The VARCHAR(MAX) column is encrypted - using 'Always Encrypted' feature.
create table clobTable
(
id integer identity(1,1) primary key not null,
--clobCol varchar(max)
clobCol [varchar](max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [CEK1], ENCRYPTION_TYPE = Deterministic, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256') NULL
);
The INSERT statement fails upon execution while informing the following error message:
SQLState = 22005
Native error = 206
Message text = [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Operand type clash: varchar(max) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK1', column_encryption_key_database_name = 'AEdemo') collation_name = 'Compatibility_136_8200_0' is incompatible with varchar(max) encrypted with (encryption_type = 'DETERMINISTIC', encryption_algorithm_name = 'AEAD_AES_256_CBC_HMAC_SHA_256', column_encryption_key_name = 'CEK1',
SQLState = 37000
Native error = 8180
Message text = [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Statement(s) could not be prepared.
Notes:
1. When applying this program on a table in which VARCHAR(MAX) column is not encrypted - it works perfectly fine.
2. Following is issued via MS-SQL server management studio and it works fine:
declare @v varchar(max) = '111111111111111111222222222222222222222223333333333333333333333334444444444444444'
insert into clobTable (clobCol) values (@v)
*/
#define __CON_STR__ "DRIVER={ODBC Driver 17 for SQL Server};Server=sql16-w16.qa.int\\mssqlserver2016;Database=AEdemo;UID=xx;PWD=yyyyyyyy;ColumnEncryption=Enabled;"
#define __THE_FILE__ "..\\DevProjects\\mssql-load-file-to-varchar-max\\big-text-file.txt"
static int SQL_OK(SQLRETURN result);
static int printErrors(SQLHENV envHandle, SQLHDBC conHandle, SQLHSTMT stmtHandle);
static char * loadedFile(char *pszTheFile);
int main(int argc, char * argv[])
{
char* pszBigString = NULL;
const char* pszSQL = "INSERT INTO clobTable (clobCol) VALUES (?)";
HSTMT hStmt = NULL;
SQLHENV hEnv = NULL;
SQLRETURN iError = SQLAllocEnv(&hEnv);
SQLLEN * len;
HDBC hDbc = NULL;
SQLAllocConnect(hEnv, &hDbc);
const char* pszConnStr = __CON_STR__;
UCHAR szConnectOut[SQL_MAX_MESSAGE_LENGTH];
SWORD iConnectOutLen = 0;
iError = SQLDriverConnectA(hDbc, NULL, (unsigned char*)pszConnStr,
SQL_NTS, szConnectOut,
(SQL_MAX_MESSAGE_LENGTH - 1), &iConnectOutLen,
SQL_DRIVER_COMPLETE);
if (!SQL_OK(iError))
{
printErrors(SQL_NULL_HENV, hDbc, SQL_NULL_HSTMT);
exit(-1);
}
iError = SQLAllocStmt(hDbc, &hStmt);
iError = SQLPrepareA(hStmt, (SQLCHAR*)pszSQL, SQL_NTS);
if (!SQL_OK(iError))
{
printErrors(SQL_NULL_HENV, SQL_NULL_HDBC, hStmt);
exit(-1);
}
pszBigString = loadedFile(__THE_FILE__); // __THE_FILE__;
len = strlen(pszBigString);
iError = SQLSetParam(hStmt, 1, SQL_C_CHAR, SQL_VARCHAR, 0, 0, (SQLPOINTER)pszBigString, NULL);
iError = SQLExecute(hStmt);
if (!SQL_OK(iError))
{
printErrors(SQL_NULL_HENV, SQL_NULL_HDBC, hStmt);
exit(-1);
}
iError = SQLDisconnect(hDbc);
if (!SQL_OK(iError))
{
printErrors(SQL_NULL_HENV, hDbc, SQL_NULL_HSTMT);
exit(-4);
}
SQLFreeHandle(SQL_HANDLE_STMT, hStmt);
SQLFreeHandle(SQL_HANDLE_DBC, hDbc);
SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
}
static /*bool*/ int SQL_OK(SQLRETURN result)
{
if (result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO)
return(TRUE);
else
return(FALSE);
}
static /*bool*/ int printErrors(SQLHENV envHandle,
SQLHDBC conHandle,
SQLHSTMT stmtHandle)
{
SQLRETURN result;
SQLWCHAR sqlState[6];
SQLINTEGER nativeError;
SQLSMALLINT requiredLength;
SQLWCHAR messageText[1024 + 1];
do
{
result = SQLError(envHandle,
conHandle,
stmtHandle,
sqlState,
&nativeError,
messageText,
sizeof(messageText),
&requiredLength);
if (SQL_OK(result))
{
printf("SQLState = %S\n", sqlState);
printf("Native error = %d\n", nativeError);
printf("Message text = %S\n", messageText);
}
} while (SQL_OK(result));
return 0;
}
#include <sys/stat.h>
#include <sys/types.h>
static char * loadedFile(char *pszTheFile)
{
struct stat st;
int statRes;
_off_t fileSize = 0;
char *pszFileContents;
FILE *fp;
memset(&st, 0, sizeof(st));
statRes = stat(pszTheFile, &st);
if (statRes == 0)
fileSize = st.st_size;
else
return NULL;
pszFileContents = calloc(1, fileSize);
fp = fopen(pszTheFile, "r");
fread(pszFileContents, 1, fileSize, fp);
fclose(fp);
return pszFileContents;
}
【问题讨论】:
标签: sql-server odbc