Fixed memory issues with data classification (#985)
This commit is contained in:
parent
e02db623df
commit
ffd9849750
|
@ -282,7 +282,7 @@ class BuildUtil(object):
|
||||||
else: # pdo_sqlsrv
|
else: # pdo_sqlsrv
|
||||||
cmd_line = ' --enable-pdo --with-pdo-sqlsrv=shared ' + cmd_line
|
cmd_line = ' --enable-pdo --with-pdo-sqlsrv=shared ' + cmd_line
|
||||||
|
|
||||||
cmd_line = 'cscript configure.js --disable-all --enable-cli --enable-cgi --enable-embed' + cmd_line
|
cmd_line = 'cscript configure.js --disable-all --enable-cli --enable-cgi --enable-json --enable-embed' + cmd_line
|
||||||
if self.thread == 'nts':
|
if self.thread == 'nts':
|
||||||
cmd_line = cmd_line + ' --disable-zts'
|
cmd_line = cmd_line + ' --disable-zts'
|
||||||
return cmd_line
|
return cmd_line
|
||||||
|
|
|
@ -1436,7 +1436,7 @@ namespace data_classification {
|
||||||
struct sensitivity_metadata;
|
struct sensitivity_metadata;
|
||||||
|
|
||||||
void name_id_pair_free(name_id_pair * pair);
|
void name_id_pair_free(name_id_pair * pair);
|
||||||
void parse_sensitivity_name_id_pairs(_Inout_ sqlsrv_stmt* stmt, _Inout_ USHORT& numpairs, _Inout_ std::vector<name_id_pair*, sqlsrv_allocator<name_id_pair*>>& pairs, _Inout_ unsigned char **pptr TSRMLS_CC);
|
void parse_sensitivity_name_id_pairs(_Inout_ sqlsrv_stmt* stmt, _Inout_ USHORT& numpairs, _Inout_ std::vector<name_id_pair*, sqlsrv_allocator<name_id_pair*>>* pairs, _Inout_ unsigned char **pptr TSRMLS_CC);
|
||||||
void parse_column_sensitivity_props(_Inout_ sensitivity_metadata* meta, _Inout_ unsigned char **pptr);
|
void parse_column_sensitivity_props(_Inout_ sensitivity_metadata* meta, _Inout_ unsigned char **pptr);
|
||||||
USHORT fill_column_sensitivity_array(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno, _Inout_ zval *column_data TSRMLS_CC);
|
USHORT fill_column_sensitivity_array(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSMALLINT colno, _Inout_ zval *column_data TSRMLS_CC);
|
||||||
|
|
||||||
|
|
|
@ -262,8 +262,7 @@ void sqlsrv_stmt::clean_up_sensitivity_metadata()
|
||||||
{
|
{
|
||||||
if (current_sensitivity_metadata) {
|
if (current_sensitivity_metadata) {
|
||||||
current_sensitivity_metadata->~sensitivity_metadata();
|
current_sensitivity_metadata->~sensitivity_metadata();
|
||||||
sqlsrv_free(current_sensitivity_metadata);
|
current_sensitivity_metadata.reset();
|
||||||
current_sensitivity_metadata = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -968,7 +967,7 @@ field_meta_data* core_sqlsrv_field_metadata( _Inout_ sqlsrv_stmt* stmt, _In_ SQL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the field name lenth
|
// Set the field name length
|
||||||
meta_data->field_name_len = static_cast<SQLSMALLINT>( field_name_len );
|
meta_data->field_name_len = static_cast<SQLSMALLINT>( field_name_len );
|
||||||
|
|
||||||
field_meta_data* result_field_meta_data = meta_data;
|
field_meta_data* result_field_meta_data = meta_data;
|
||||||
|
@ -1052,8 +1051,8 @@ void core_sqlsrv_sensitivity_metadata( _Inout_ sqlsrv_stmt* stmt TSRMLS_DC )
|
||||||
sensitivity_meta = new (sqlsrv_malloc(sizeof(sensitivity_metadata))) sensitivity_metadata();
|
sensitivity_meta = new (sqlsrv_malloc(sizeof(sensitivity_metadata))) sensitivity_metadata();
|
||||||
|
|
||||||
// Parse the name id pairs for labels first then info types
|
// Parse the name id pairs for labels first then info types
|
||||||
parse_sensitivity_name_id_pairs(stmt, sensitivity_meta->num_labels, sensitivity_meta->labels, &dcptr);
|
parse_sensitivity_name_id_pairs(stmt, sensitivity_meta->num_labels, &sensitivity_meta->labels, &dcptr);
|
||||||
parse_sensitivity_name_id_pairs(stmt, sensitivity_meta->num_infotypes, sensitivity_meta->infotypes, &dcptr);
|
parse_sensitivity_name_id_pairs(stmt, sensitivity_meta->num_infotypes, &sensitivity_meta->infotypes, &dcptr);
|
||||||
|
|
||||||
// Next parse the sensitivity properties
|
// Next parse the sensitivity properties
|
||||||
parse_column_sensitivity_props(sensitivity_meta, &dcptr);
|
parse_column_sensitivity_props(sensitivity_meta, &dcptr);
|
||||||
|
|
|
@ -426,12 +426,18 @@ namespace data_classification {
|
||||||
void convert_sensivity_field(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSRV_ENCODING encoding, _In_ unsigned char *ptr, _In_ int len, _Inout_updates_bytes_(cchOutLen) char** field_name)
|
void convert_sensivity_field(_Inout_ sqlsrv_stmt* stmt, _In_ SQLSRV_ENCODING encoding, _In_ unsigned char *ptr, _In_ int len, _Inout_updates_bytes_(cchOutLen) char** field_name)
|
||||||
{
|
{
|
||||||
sqlsrv_malloc_auto_ptr<SQLWCHAR> temp_field_name;
|
sqlsrv_malloc_auto_ptr<SQLWCHAR> temp_field_name;
|
||||||
int temp_field_len = len * 2;
|
int temp_field_len = len * sizeof(SQLWCHAR);
|
||||||
SQLLEN field_name_len = 0;
|
SQLLEN field_name_len = 0;
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
*field_name = reinterpret_cast<char*>(sqlsrv_malloc(1));
|
||||||
|
*field_name[0] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
temp_field_name = static_cast<SQLWCHAR*>(sqlsrv_malloc((len + 1) * sizeof(SQLWCHAR)));
|
temp_field_name = static_cast<SQLWCHAR*>(sqlsrv_malloc((len + 1) * sizeof(SQLWCHAR)));
|
||||||
|
memset(temp_field_name, L'\0', len + 1);
|
||||||
memcpy_s(temp_field_name, temp_field_len, ptr, temp_field_len);
|
memcpy_s(temp_field_name, temp_field_len, ptr, temp_field_len);
|
||||||
temp_field_name[temp_field_len] = '\0';
|
|
||||||
|
|
||||||
bool converted = convert_string_from_utf16(encoding, temp_field_name, len, field_name, field_name_len);
|
bool converted = convert_string_from_utf16(encoding, temp_field_name, len, field_name, field_name_len);
|
||||||
|
|
||||||
|
@ -451,13 +457,15 @@ namespace data_classification {
|
||||||
sqlsrv_free(pair);
|
sqlsrv_free(pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
void parse_sensitivity_name_id_pairs(_Inout_ sqlsrv_stmt* stmt, _Inout_ USHORT& numpairs, _Inout_ std::vector<name_id_pair*, sqlsrv_allocator<name_id_pair*>>& pairs, _Inout_ unsigned char **pptr)
|
void parse_sensitivity_name_id_pairs(_Inout_ sqlsrv_stmt* stmt, _Inout_ USHORT& numpairs, _Inout_ std::vector<name_id_pair*, sqlsrv_allocator<name_id_pair*>>* pairs, _Inout_ unsigned char **pptr)
|
||||||
{
|
{
|
||||||
unsigned char *ptr = *pptr;
|
unsigned char *ptr = *pptr;
|
||||||
unsigned short npairs;
|
unsigned short npairs;
|
||||||
numpairs = npairs = *(unsigned short*)ptr;
|
numpairs = npairs = *(reinterpret_cast<unsigned short*>(ptr));
|
||||||
SQLSRV_ENCODING encoding = ((stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) ? stmt->conn->encoding() : stmt->encoding());
|
SQLSRV_ENCODING encoding = ((stmt->encoding() == SQLSRV_ENCODING_DEFAULT ) ? stmt->conn->encoding() : stmt->encoding());
|
||||||
|
|
||||||
|
pairs->reserve(numpairs);
|
||||||
|
|
||||||
ptr += sizeof(unsigned short);
|
ptr += sizeof(unsigned short);
|
||||||
while (npairs--) {
|
while (npairs--) {
|
||||||
int namelen, idlen;
|
int namelen, idlen;
|
||||||
|
@ -485,7 +493,7 @@ namespace data_classification {
|
||||||
convert_sensivity_field(stmt, encoding, idptr, idlen, (char**)&id);
|
convert_sensivity_field(stmt, encoding, idptr, idlen, (char**)&id);
|
||||||
pair->id = id;
|
pair->id = id;
|
||||||
|
|
||||||
pairs.push_back(pair.get());
|
pairs->push_back(pair.get());
|
||||||
pair.transferred();
|
pair.transferred();
|
||||||
}
|
}
|
||||||
*pptr = ptr;
|
*pptr = ptr;
|
||||||
|
|
|
@ -538,7 +538,7 @@ PHP_FUNCTION( sqlsrv_field_metadata )
|
||||||
TSRMLS_CC );
|
TSRMLS_CC );
|
||||||
|
|
||||||
if (stmt->data_classification) {
|
if (stmt->data_classification) {
|
||||||
data_classification::fill_column_sensitivity_array(stmt, f, &field_array);
|
data_classification::fill_column_sensitivity_array(stmt, f, &field_array TSRMLS_CC);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add this field's meta data to the result set meta data
|
// add this field's meta data to the result set meta data
|
||||||
|
|
|
@ -11,6 +11,8 @@ PHPT_EXEC=true
|
||||||
require_once('MsSetup.inc');
|
require_once('MsSetup.inc');
|
||||||
require_once('MsCommon_mid-refactor.inc');
|
require_once('MsCommon_mid-refactor.inc');
|
||||||
|
|
||||||
|
$dataClassKey = 'Data Classification';
|
||||||
|
|
||||||
function testConnAttrCases()
|
function testConnAttrCases()
|
||||||
{
|
{
|
||||||
// Attribute PDO::SQLSRV_ATTR_DATA_CLASSIFICATION is limited to statement level only
|
// Attribute PDO::SQLSRV_ATTR_DATA_CLASSIFICATION is limited to statement level only
|
||||||
|
@ -157,8 +159,10 @@ function verifyClassInfo($input, $actual)
|
||||||
|
|
||||||
function compareDataClassification($stmt1, $stmt2, $classData)
|
function compareDataClassification($stmt1, $stmt2, $classData)
|
||||||
{
|
{
|
||||||
|
global $dataClassKey;
|
||||||
|
|
||||||
$numCol = $stmt1->columnCount();
|
$numCol = $stmt1->columnCount();
|
||||||
$noClassInfo = array('Data Classification' => array());
|
$noClassInfo = array($dataClassKey => array());
|
||||||
|
|
||||||
for ($i = 0; $i < $numCol; $i++) {
|
for ($i = 0; $i < $numCol; $i++) {
|
||||||
$metadata1 = $stmt1->getColumnMeta($i);
|
$metadata1 = $stmt1->getColumnMeta($i);
|
||||||
|
@ -176,7 +180,7 @@ function compareDataClassification($stmt1, $stmt2, $classData)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Verify the classification metadata
|
// Verify the classification metadata
|
||||||
if (!verifyClassInfo($classData[$i], $value['Data Classification'])) {
|
if (!verifyClassInfo($classData[$i], $value[$dataClassKey])) {
|
||||||
var_dump($value);
|
var_dump($value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,6 +194,45 @@ function compareDataClassification($stmt1, $stmt2, $classData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function runBatchQuery($conn, $tableName)
|
||||||
|
{
|
||||||
|
global $dataClassKey;
|
||||||
|
|
||||||
|
$options = array(PDO::SQLSRV_ATTR_DATA_CLASSIFICATION => true);
|
||||||
|
$tsql = "SELECT SSN, BirthDate FROM $tableName";
|
||||||
|
|
||||||
|
// Run a batch query
|
||||||
|
$batchQuery = $tsql . ';' . $tsql;
|
||||||
|
$stmt = $conn->prepare($batchQuery, $options);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$numCol = $stmt->columnCount();
|
||||||
|
|
||||||
|
// The metadata returned should be the same
|
||||||
|
$c = rand(0, $numCol - 1);
|
||||||
|
$metadata1 = $stmt->getColumnMeta($c);
|
||||||
|
$stmt->nextRowset();
|
||||||
|
$metadata2 = $stmt->getColumnMeta($c);
|
||||||
|
|
||||||
|
// Check the returned flags
|
||||||
|
$data1 = $metadata1['flags'];
|
||||||
|
$data2 = $metadata2['flags'];
|
||||||
|
|
||||||
|
if (!array_key_exists($dataClassKey, $data1) || !array_key_exists($dataClassKey, $data2)) {
|
||||||
|
echo "Metadata returned with no classification data\n";
|
||||||
|
var_dump($data1);
|
||||||
|
var_dump($data2);
|
||||||
|
} else {
|
||||||
|
$jstr1 = json_encode($data1[$dataClassKey]);
|
||||||
|
$jstr2 = json_encode($data2[$dataClassKey]);
|
||||||
|
if ($jstr1 !== $jstr2) {
|
||||||
|
echo "The JSON encoded strings should be identical\n";
|
||||||
|
var_dump($jstr1);
|
||||||
|
var_dump($jstr2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
try {
|
try {
|
||||||
testConnAttrCases();
|
testConnAttrCases();
|
||||||
|
@ -254,6 +297,8 @@ try {
|
||||||
|
|
||||||
unset($stmt1);
|
unset($stmt1);
|
||||||
unset($stmt2);
|
unset($stmt2);
|
||||||
|
|
||||||
|
runBatchQuery($conn, $tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
dropTable($conn, $tableName);
|
dropTable($conn, $tableName);
|
||||||
|
|
|
@ -8,6 +8,8 @@ PHPT_EXEC=true
|
||||||
<?php require('skipif_versions_old.inc'); ?>
|
<?php require('skipif_versions_old.inc'); ?>
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
|
$dataClassKey = 'Data Classification';
|
||||||
|
|
||||||
function testErrorCases($conn, $tableName, $isSupported)
|
function testErrorCases($conn, $tableName, $isSupported)
|
||||||
{
|
{
|
||||||
// This function will check two error cases:
|
// This function will check two error cases:
|
||||||
|
@ -136,6 +138,8 @@ function verifyClassInfo($input, $actual)
|
||||||
|
|
||||||
function compareDataClassification($stmt1, $stmt2, $classData)
|
function compareDataClassification($stmt1, $stmt2, $classData)
|
||||||
{
|
{
|
||||||
|
global $dataClassKey;
|
||||||
|
|
||||||
$numCol = sqlsrv_num_fields($stmt1);
|
$numCol = sqlsrv_num_fields($stmt1);
|
||||||
|
|
||||||
$metadata1 = sqlsrv_field_metadata($stmt1);
|
$metadata1 = sqlsrv_field_metadata($stmt1);
|
||||||
|
@ -152,7 +156,7 @@ function compareDataClassification($stmt1, $stmt2, $classData)
|
||||||
// empty array. Otherwise, it should contain an array with one set of
|
// empty array. Otherwise, it should contain an array with one set of
|
||||||
// Label (name, id) and Information Type (name, id)
|
// Label (name, id) and Information Type (name, id)
|
||||||
|
|
||||||
$noClassInfo = array('Data Classification' => array());
|
$noClassInfo = array($dataClassKey => array());
|
||||||
for ($i = 0; $i < $numCol; $i++) {
|
for ($i = 0; $i < $numCol; $i++) {
|
||||||
$diff = array_diff_assoc($metadata2[$i], $metadata1[$i]);
|
$diff = array_diff_assoc($metadata2[$i], $metadata1[$i]);
|
||||||
|
|
||||||
|
@ -164,13 +168,51 @@ function compareDataClassification($stmt1, $stmt2, $classData)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Verify the classification metadata
|
// Verify the classification metadata
|
||||||
if (!verifyClassInfo($classData[$i], $diff['Data Classification'])) {
|
if (!verifyClassInfo($classData[$i], $diff[$dataClassKey])) {
|
||||||
var_dump($diff);
|
var_dump($diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function runBatchQuery($conn, $tableName)
|
||||||
|
{
|
||||||
|
global $dataClassKey;
|
||||||
|
|
||||||
|
$options = array('DataClassification' => true);
|
||||||
|
$tsql = "SELECT SSN, BirthDate FROM $tableName";
|
||||||
|
$batchQuery = $tsql . ';' . $tsql;
|
||||||
|
|
||||||
|
$stmt = sqlsrv_query($conn, $batchQuery, array(), $options);
|
||||||
|
if (!$stmt) {
|
||||||
|
fatalError("Error when calling sqlsrv_query '$tsql'.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
$numCol = sqlsrv_num_fields($stmt);
|
||||||
|
$c = rand(0, $numCol - 1);
|
||||||
|
|
||||||
|
$metadata1 = sqlsrv_field_metadata($stmt);
|
||||||
|
if (!$metadata1 || !array_key_exists($dataClassKey, $metadata1[$c])) {
|
||||||
|
fatalError("runBatchQuery(1): failed to get metadata");
|
||||||
|
}
|
||||||
|
$result = sqlsrv_next_result($stmt);
|
||||||
|
if (is_null($result) || !$result) {
|
||||||
|
fatalError("runBatchQuery: failed to get next result");
|
||||||
|
}
|
||||||
|
$metadata2 = sqlsrv_field_metadata($stmt);
|
||||||
|
if (!$metadata2 || !array_key_exists($dataClassKey, $metadata2[$c])) {
|
||||||
|
fatalError("runBatchQuery(2): failed to get metadata");
|
||||||
|
}
|
||||||
|
|
||||||
|
$jstr1 = json_encode($metadata1[$c][$dataClassKey]);
|
||||||
|
$jstr2 = json_encode($metadata2[$c][$dataClassKey]);
|
||||||
|
if ($jstr1 !== $jstr2) {
|
||||||
|
echo "The JSON encoded strings should be identical\n";
|
||||||
|
var_dump($jstr1);
|
||||||
|
var_dump($jstr2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////
|
||||||
require_once('MsCommon.inc');
|
require_once('MsCommon.inc');
|
||||||
|
|
||||||
|
@ -248,6 +290,8 @@ if ($isSupported) {
|
||||||
|
|
||||||
compareDataClassification($stmt, $stmt2, $classData);
|
compareDataClassification($stmt, $stmt2, $classData);
|
||||||
sqlsrv_free_stmt($stmt2);
|
sqlsrv_free_stmt($stmt2);
|
||||||
|
|
||||||
|
runBatchQuery($conn, $tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlsrv_free_stmt($stmt);
|
sqlsrv_free_stmt($stmt);
|
||||||
|
|
Loading…
Reference in a new issue