Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Обзор
Для управления конфиденциальными данными в SQL Server и Azure SQL Server появилась возможность предоставлять столбцы базы данных с конфиденциальными метаданными, что позволяет клиентскому приложению обрабатывать различные типы конфиденциальных данных (например, данные о состоянии здоровья, финансовые данные и т. д.) в соответствии с политикой защиты данных.
Дополнительные сведения о назначении классификации столбцам см. в статье Обнаружение и классификация данных SQL.
Microsoft ODBC Driver 17.2 или более поздней версии позволяет получать эти метаданные через SQLGetDescField, используя идентификатор поля SQL_CA_SS_DATA_CLASSIFICATION.
Формат
Синтаксис SQLGetDescField имеет следующий вид:
SQLRETURN SQLGetDescField(
SQLHDESC DescriptorHandle,
SQLSMALLINT RecNumber,
SQLSMALLINT FieldIdentifier,
SQLPOINTER ValuePtr,
SQLINTEGER BufferLength,
SQLINTEGER * StringLengthPtr);
DescriptorHandle
[Вход] Дескриптор строки реализации (IRD). Можно получить с помощью вызова SQLGetStmtAttr с атрибутом инструкции SQL_ATTR_IMP_ROW_DESC.
RecNumber
[Вход] 0
FieldIdentifier
[Вход] SQL_CA_SS_DATA_CLASSIFICATION.
ValuePtr
[Выход] Выходной буфер.
BufferLength
[Вход] Длина выходного буфера в байтах.
StringLengthPtr [Выход] Указатель на буфер, в котором будет возвращаться общее число байтов, доступных для получения из параметра ValuePtr.
Примечание.
Если размер буфера неизвестен, его можно определить путем вызова строки SQLGetDescField со значением NULL для параметра ValuePtr и проверки значения StringLengthPtr.
Если сведения о классификации данных недоступны, будет возвращена ошибка Недопустимое поле дескриптора.
При успешном вызове SQLGetDescField буфер, на который указывает параметр ValuePtr, будет содержать следующие данные:
nn nn [n sensitivitylabels] tt tt [t informationtypes] cc cc [c columnsensitivitys]
Примечание.
Значения nn nn, tt tt и cc cc являются многобайтовыми целыми числами, которые хранятся с наименее значимым байтом в нижнем адресе.
Значения sensitivitylabel и informationtype имеют формат:
nn [n bytes name] ii [i bytes id]
Значение columnsensitivity имеет формат:
nn nn [n sensitivityprops]
Для каждого столбца (c) имеется n длиной 4 байта sensitivityprops.
ss ss tt tt
s — индекс для массива sensitivitylabels (значение FF FF, если он не помечен).
t — индекс для массива informationtypes (значение FF FF, если он не помечен).
Формат данных может выражаться в виде следующих псевдоструктур:
struct IDnamePair {
BYTE nameLen;
USHORT name[nameLen];
BYTE idLen;
USHORT id[idLen];
};
struct SensitivityProp {
USHORT labelIdx;
USHORT infoTypeIdx;
};
USHORT nLabels;
struct IDnamePair labels[nLabels];
USHORT nInfoTypes;
struct IDnamePair infotypes[nInfoTypes];
USHORT nColumns;
struct {
USHORT nProps;
struct SensitivityProp[nProps];
} columnClassification[nColumns];
Пример кода
Тестовое приложение, которое показывает, как считывать метаданные классификации данных. В Windows его можно скомпилировать с помощью cl /MD dataclassification.c /I (directory of msodbcsql.h) /link odbc32.lib и выполнить с использованием строки подключения и SQL-запроса (который возвращает классифицированные столбцы) в качестве параметров:
#ifdef _WIN32
#include <windows.h>
#endif
#include <sql.h>
#include <sqlext.h>
#include <msodbcsql.h>
#include <stdio.h>
SQLHANDLE env, dbc, stmt;
void checkRC_exit(SQLRETURN rc, SQLHANDLE hand, SQLSMALLINT htype, int retcode, char *action)
{
if ((rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO) && hand)
{
char msg[1024], state[6];
int i = 0;
SQLRETURN rc2;
SQLINTEGER err;
SQLSMALLINT lenout;
while ((rc2 = SQLGetDiagRec(htype, hand, ++i, state, &err, msg, sizeof(msg), &lenout)) == SQL_SUCCESS ||
rc2 == SQL_SUCCESS_WITH_INFO)
printf("%d (%d)[%s]%s\n", i, err, state, msg);
}
if (rc == SQL_ERROR && retcode)
{
printf("Error occurred%s%s\n", action ? " upon " : "", action ? action : "");
exit(retcode);
}
}
void printLabelInfo(char *type, char **pptr)
{
char *ptr = *pptr;
unsigned short nlabels;
printf("----- %s(%u) -----\n", type, nlabels = *(unsigned short*)ptr);
ptr += sizeof(unsigned short);
while (nlabels--)
{
int namelen, idlen;
char *nameptr, *idptr;
namelen = *ptr++;
nameptr = ptr;
ptr += namelen * 2;
idlen = *ptr++;
idptr = ptr;
ptr += idlen * 2;
wprintf(L"Name: \"%.*s\" Id: \"%.*s\"\n", namelen, nameptr, idlen, idptr);
}
*pptr = ptr;
}
int main(int argc, char **argv)
{
unsigned char *dcbuf;
unsigned int dclen = 0;
SQLRETURN rc;
SQLHANDLE ird;
if (argc < 3)
{
fprintf(stderr, "usage: dataclassification connstr query\n");
return 1;
}
checkRC_exit(SQLAllocHandle(SQL_HANDLE_ENV, 0, &env), 0, 0,
2, "allocate environment");
checkRC_exit(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0), env, SQL_HANDLE_ENV,
3, "set ODBC version");
checkRC_exit(SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc), env, SQL_HANDLE_ENV,
4, "allocate connection");
checkRC_exit(SQLDriverConnect(dbc, 0, argv[1], SQL_NTS, 0, 0, 0, SQL_DRIVER_NOPROMPT), dbc, SQL_HANDLE_DBC,
5, "connect to server");
checkRC_exit(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt), dbc, SQL_HANDLE_DBC,
6, "allocate statement");
checkRC_exit(SQLExecDirect(stmt, argv[2], SQL_NTS), stmt, SQL_HANDLE_STMT,
7, "execute query");
checkRC_exit(SQLGetStmtAttr(stmt, SQL_ATTR_IMP_ROW_DESC, (SQLPOINTER)&ird, SQL_IS_POINTER, 0), stmt, SQL_HANDLE_STMT,
8, "get IRD handle");
rc = SQLGetDescFieldW(ird, 0, SQL_CA_SS_DATA_CLASSIFICATION, dcbuf, 0, &dclen);
checkRC_exit(rc, ird, SQL_HANDLE_DESC, 0, 0);
SQLINTEGER dclenout;
unsigned char *dcptr;
unsigned short ncols;
printf("Data Classification information (%u bytes):\n", dclen);
if (!(dcbuf = malloc(dclen)))
{
printf("Memory Allocation Error");
return 9;
}
checkRC_exit(SQLGetDescFieldW(ird, 0, SQL_CA_SS_DATA_CLASSIFICATION, dcbuf, dclen, &dclenout),
ird, SQL_HANDLE_DESC, 10, "reading SQL_CA_SS_DATA_CLASSIFICATION");
dcptr = dcbuf;
printLabelInfo("Labels", &dcptr);
printLabelInfo("Information Types", &dcptr);
printf("----- Column Sensitivities(%u) -----\n", ncols = *(unsigned short*)dcptr);
dcptr += sizeof(unsigned short);
while (ncols--)
{
unsigned short nprops = *(unsigned short*)dcptr;
dcptr += sizeof(unsigned short);
while (nprops--)
{
unsigned short labelidx, typeidx;
labelidx = *(unsigned short*)dcptr; dcptr += sizeof(unsigned short);
typeidx = *(unsigned short*)dcptr; dcptr += sizeof(unsigned short);
printf(labelidx == 0xFFFF ? "(none) " : "%u ", labelidx);
printf(typeidx == 0xFFFF ? "(none)\n" : "%u\n", typeidx);
}
printf("-----\n");
}
if (dcptr != dcbuf + dclen)
{
printf("Error: unexpected parse of DATACLASSIFICATION data\n");
return 11;
}
free(dcbuf);
return 0;
}
Поддерживаемая версия
Microsoft ODBC Driver 17.2 позволяет получить сведения о классификации данных с помощью SQLGetDescField, если FieldIdentifier имеет значение SQL_CA_SS_DATA_CLASSIFICATION (1237).
Начиная с версии Microsoft ODBC Driver 17.4.1.1 можно извлекать версию классификации данных, поддерживаемую сервером, с помощью SQLGetDescField и идентификатора поля SQL_CA_SS_DATA_CLASSIFICATION_VERSION (1238). В версии 17.4.1.1 для поддерживаемой версии классификации данных указано значение "2".
Начиная с версии 17.4.2.1 поддерживается версия классификации данных по умолчанию, которая имеет значение "1" и является версией, которую драйвер указывает SQL Server как поддерживаемую. Новый атрибут подключения SQL_COPT_SS_DATACLASSIFICATION_VERSION (1400) позволяет приложению изменять поддерживаемую версию классификации данных со значения "1" до максимальной поддерживаемой версии.
Пример:
Чтобы задать версию, этот вызов требуется выполнить сразу перед вызовом SQLConnect или SQLDriverConnect:
ret = SQLSetConnectAttr(dbc, SQL_COPT_SS_DATACLASSIFICATION_VERSION, (SQLPOINTER)2, SQL_IS_INTEGER);
Значение поддерживаемой в настоящее время версии классификации данных можно получить с помощью вызова SQLGetConnectAttr:
ret = SQLGetConnectAttr(dbc, SQL_COPT_SS_DATACLASSIFICATION_VERSION, (SQLPOINTER)&dataClassVersion, SQL_IS_INTEGER, 0);