Заголовок ## MS- SQL - ODB C - сбой INSERT при применении к столбцу VARCHAR (MAX) «Всегда зашифровано»
Следующая программа пытается загрузить текстовый файл в VARCHAR (max) столбец - с использованием ODB C. Столбец VARCHAR (MAX) зашифрован с использованием функции «Always Encrypted».
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 Studio Management Server и работает нормально:
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;
}