Revised a few existing tests that are flawed (#1103)
This commit is contained in:
parent
cd64173f95
commit
8bb6cef33c
|
@ -16,7 +16,7 @@ trigger:
|
||||||
jobs:
|
jobs:
|
||||||
- job: macOS
|
- job: macOS
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'macOS-10.13'
|
vmImage: 'macOS-10.14'
|
||||||
steps:
|
steps:
|
||||||
- checkout: self
|
- checkout: self
|
||||||
clean: true
|
clean: true
|
||||||
|
|
|
@ -84,11 +84,9 @@ $sqlTypes = array(
|
||||||
function is_incompatible_types_error( $dataType, $sqlType )
|
function is_incompatible_types_error( $dataType, $sqlType )
|
||||||
{
|
{
|
||||||
$errors = sqlsrv_errors();
|
$errors = sqlsrv_errors();
|
||||||
foreach ( $errors as $error )
|
foreach ($errors as $error) {
|
||||||
{
|
|
||||||
// 22018 is the SQLSTATE for the operand crash error for incompatible types
|
// 22018 is the SQLSTATE for the operand crash error for incompatible types
|
||||||
if ( $error['SQLSTATE'] == 22018 )
|
if ($error['SQLSTATE'] == '22018') {
|
||||||
{
|
|
||||||
echo "Encrypted $sqlType is incompatible with encrypted $dataType\n";
|
echo "Encrypted $sqlType is incompatible with encrypted $dataType\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +107,6 @@ function get_sqlType_constant( $sqlType )
|
||||||
{
|
{
|
||||||
switch ( $sqlType ) {
|
switch ( $sqlType ) {
|
||||||
case 'SQLSRV_SQLTYPE_BIGINT':
|
case 'SQLSRV_SQLTYPE_BIGINT':
|
||||||
case 'SQLSRV_SQLTYPE_BINARY':
|
|
||||||
case 'SQLSRV_SQLTYPE_BIT':
|
case 'SQLSRV_SQLTYPE_BIT':
|
||||||
case 'SQLSRV_SQLTYPE_DATE':
|
case 'SQLSRV_SQLTYPE_DATE':
|
||||||
case 'SQLSRV_SQLTYPE_DATETIME':
|
case 'SQLSRV_SQLTYPE_DATETIME':
|
||||||
|
@ -135,6 +132,10 @@ function get_sqlType_constant( $sqlType )
|
||||||
case 'SQLSRV_SQLTYPE_XML':
|
case 'SQLSRV_SQLTYPE_XML':
|
||||||
return constant( $sqlType );
|
return constant( $sqlType );
|
||||||
break;
|
break;
|
||||||
|
case 'SQLSRV_SQLTYPE_BINARY':
|
||||||
|
// our tests always use precision 5 for SQLSRV_SQLTYPE_BINARY
|
||||||
|
return SQLSRV_SQLTYPE_BINARY(5);
|
||||||
|
break;
|
||||||
case 'SQLSRV_SQLTYPE_CHAR':
|
case 'SQLSRV_SQLTYPE_CHAR':
|
||||||
// our tests always use precision 5 for SQLSRV_SQLTYPE_CHAR
|
// our tests always use precision 5 for SQLSRV_SQLTYPE_CHAR
|
||||||
return SQLSRV_SQLTYPE_CHAR(5);
|
return SQLSRV_SQLTYPE_CHAR(5);
|
||||||
|
@ -157,7 +158,7 @@ function get_sqlType_constant( $sqlType )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isDateTimeType( $sqlType )
|
function isDateTimeType($sqlType)
|
||||||
{
|
{
|
||||||
return ($sqlType == 'SQLSRV_SQLTYPE_DATE' ||
|
return ($sqlType == 'SQLSRV_SQLTYPE_DATE' ||
|
||||||
$sqlType == 'SQLSRV_SQLTYPE_DATETIME' ||
|
$sqlType == 'SQLSRV_SQLTYPE_DATETIME' ||
|
||||||
|
@ -167,4 +168,20 @@ function isDateTimeType( $sqlType )
|
||||||
$sqlType == 'SQLSRV_SQLTYPE_TIME');
|
$sqlType == 'SQLSRV_SQLTYPE_TIME');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isLOBType($sqlType)
|
||||||
|
{
|
||||||
|
return ($sqlType == 'SQLSRV_SQLTYPE_TEXT' || $sqlType == 'SQLSRV_SQLTYPE_NTEXT' || $sqlType == 'SQLSRV_SQLTYPE_IMAGE');
|
||||||
|
}
|
||||||
|
|
||||||
|
function isCompatible($compatList, $dataType, $sqlType)
|
||||||
|
{
|
||||||
|
foreach ($compatList[$dataType] as $compatType) {
|
||||||
|
if (stripos($compatType, $sqlType) !== false) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -52,7 +52,7 @@ foreach ($dataTypes as $dataType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 22018 is the SQLSTATE for any incompatible conversion errors
|
// 22018 is the SQLSTATE for any incompatible conversion errors
|
||||||
if ($isCompatible && sqlsrv_errors()[0]['SQLSTATE'] == 22018) {
|
if ($isCompatible && sqlsrv_errors()[0]['SQLSTATE'] == '22018') {
|
||||||
echo "$sqlType should be compatible with $dataType\n";
|
echo "$sqlType should be compatible with $dataType\n";
|
||||||
$success = false;
|
$success = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
--TEST--
|
--TEST--
|
||||||
Test for inserting and retrieving encrypted data of datetime types
|
Test for inserting and retrieving encrypted data of datetime types
|
||||||
--DESCRIPTION--
|
--DESCRIPTION--
|
||||||
Bind output params using sqlsrv_prepare with all sql_type
|
Bind output/inout params using sqlsrv_prepare with all sql_type
|
||||||
--SKIPIF--
|
--SKIPIF--
|
||||||
<?php require('skipif_versions_old.inc'); ?>
|
<?php require('skipif_versions_old.inc'); ?>
|
||||||
--FILE--
|
--FILE--
|
||||||
|
@ -11,7 +11,8 @@ require_once('AEData.inc');
|
||||||
|
|
||||||
date_default_timezone_set("Canada/Pacific");
|
date_default_timezone_set("Canada/Pacific");
|
||||||
$dataTypes = array("date", "datetime", "datetime2", "smalldatetime", "time", "datetimeoffset");
|
$dataTypes = array("date", "datetime", "datetime2", "smalldatetime", "time", "datetimeoffset");
|
||||||
$directions = array("SQLSRV_PARAM_OUT", "SQLSRV_PARAM_INOUT");
|
|
||||||
|
$directions = array(SQLSRV_PARAM_OUT, SQLSRV_PARAM_INOUT);
|
||||||
|
|
||||||
// this is a list of implicit datatype conversion that SQL Server allows (https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine)
|
// this is a list of implicit datatype conversion that SQL Server allows (https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine)
|
||||||
$compatList = array("date" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"),
|
$compatList = array("date" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"),
|
||||||
|
@ -21,6 +22,79 @@ $compatList = array("date" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARC
|
||||||
"time" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"),
|
"time" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"),
|
||||||
"datetimeoffset" => array("SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIMEOFFSET") );
|
"datetimeoffset" => array("SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIMEOFFSET") );
|
||||||
|
|
||||||
|
function testOutputParam($conn, $spname, $direction, $dataType, $sqlType)
|
||||||
|
{
|
||||||
|
// The driver does not support these types as output params, simply return
|
||||||
|
if (isDateTimeType($sqlType) || isLOBType($sqlType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
global $compatList;
|
||||||
|
|
||||||
|
$sqlTypeConstant = get_sqlType_constant($sqlType);
|
||||||
|
|
||||||
|
// Call store procedure
|
||||||
|
$outSql = AE\getCallProcSqlPlaceholders($spname, 2);
|
||||||
|
|
||||||
|
// Set these to NULL such that the PHP type of each output parameter is inferred
|
||||||
|
// from the SQLSRV_SQLTYPE_* constant
|
||||||
|
$c_detOut = null;
|
||||||
|
$c_randOut = null;
|
||||||
|
$stmt = sqlsrv_prepare(
|
||||||
|
$conn,
|
||||||
|
$outSql,
|
||||||
|
array(array( &$c_detOut, $direction, null, $sqlTypeConstant),
|
||||||
|
array(&$c_randOut, $direction, null, $sqlTypeConstant ))
|
||||||
|
);
|
||||||
|
if (!$stmt) {
|
||||||
|
die(print_r(sqlsrv_errors(), true));
|
||||||
|
}
|
||||||
|
sqlsrv_execute($stmt);
|
||||||
|
|
||||||
|
$success = false;
|
||||||
|
$errors = sqlsrv_errors();
|
||||||
|
if (AE\IsDataEncrypted()) {
|
||||||
|
// With data encrypted, errors are totally expected
|
||||||
|
if (empty($errors)) {
|
||||||
|
echo "Encrypted data: $dataType should NOT be compatible with $sqlType\n";
|
||||||
|
} else {
|
||||||
|
// This should return 22018, the SQLSTATE for any incompatible conversion,
|
||||||
|
// except the XML type
|
||||||
|
$success = ($errors[0]['SQLSTATE'] === '22018');
|
||||||
|
if (!$success) {
|
||||||
|
if ($sqlType === 'SQLSRV_SQLTYPE_XML') {
|
||||||
|
$success = ($errors[0]['SQLSTATE'] === '42000');
|
||||||
|
} else {
|
||||||
|
echo "Encrypted data: unexpected errors with SQL type: $sqlType\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$compatible = isCompatible($compatList, $dataType, $sqlType);
|
||||||
|
if ($compatible) {
|
||||||
|
if (!empty($errors)) {
|
||||||
|
echo "$dataType should be compatible with $sqlType.\n";
|
||||||
|
} else {
|
||||||
|
$success = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$implicitConv = 'Implicit conversion from data type ';
|
||||||
|
|
||||||
|
// 22018 is the SQLSTATE for any incompatible conversion errors
|
||||||
|
if ($errors[0]['SQLSTATE'] === '22018') {
|
||||||
|
$success = true;
|
||||||
|
} elseif (strpos($errors[0]['message'], $implicitConv) !== false) {
|
||||||
|
$success = true;
|
||||||
|
} else {
|
||||||
|
echo "Failed with SQL type: $sqlType\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
$conn = AE\connect();
|
$conn = AE\connect();
|
||||||
|
|
||||||
foreach ($dataTypes as $dataType) {
|
foreach ($dataTypes as $dataType) {
|
||||||
|
@ -32,61 +106,33 @@ foreach ($dataTypes as $dataType) {
|
||||||
$colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false));
|
$colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false));
|
||||||
AE\createTable($conn, $tbname, $colMetaArr);
|
AE\createTable($conn, $tbname, $colMetaArr);
|
||||||
|
|
||||||
if (AE\isColEncrypted()) {
|
// Create a Store Procedure
|
||||||
// Create a Store Procedure
|
$spname = 'selectAllColumns';
|
||||||
$spname = 'selectAllColumns';
|
createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname");
|
||||||
createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname");
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert a row
|
// insert a row
|
||||||
|
// Take the second and third entres (some edge cases) from the various
|
||||||
|
// $[$dataType]_params in AEData.inc
|
||||||
|
// e.g. with $dataType = 'date', use $date_params[1] and $date_params[2]
|
||||||
|
// to form an array, namely ["0001-01-01", "9999-12-31"]
|
||||||
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
||||||
$r;
|
$r;
|
||||||
$stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r);
|
$stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r);
|
||||||
if ($r === false) {
|
if ($r === false) {
|
||||||
is_incompatible_types_error($dataType, "default type");
|
fatalError("Failed to insert data of type $dataType\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($directions as $direction) {
|
foreach ($directions as $direction) {
|
||||||
echo "Testing as $direction:\n";
|
$dir = ($direction == SQLSRV_PARAM_OUT) ? 'SQLSRV_PARAM_OUT' : 'SQLSRV_PARAM_INOUT';
|
||||||
|
echo "Testing as $dir:\n";
|
||||||
|
|
||||||
// test each SQLSRV_SQLTYPE_ constants
|
// test each SQLSRV_SQLTYPE_* constants
|
||||||
foreach ($sqlTypes as $sqlType) {
|
foreach ($sqlTypes as $sqlType) {
|
||||||
if (!AE\isColEncrypted()) {
|
$success = testOutputParam($conn, $spname, $direction, $dataType, $sqlType);
|
||||||
$isCompatible = false;
|
if (!$success) {
|
||||||
foreach ($compatList[$dataType] as $compatType) {
|
// No point to continue looping
|
||||||
if (stripos($compatType, $sqlType) !== false) {
|
echo("Test failed: $dataType as $sqlType\n");
|
||||||
$isCompatible = true;
|
die(print_r(sqlsrv_errors(), true));
|
||||||
}
|
|
||||||
}
|
|
||||||
// 22018 is the SQLSTATE for any incompatible conversion errors
|
|
||||||
$errors = sqlsrv_errors();
|
|
||||||
if (!empty($errors) && $isCompatible && $errors[0]['SQLSTATE'] == 22018) {
|
|
||||||
echo "$sqlType should be compatible with $dataType\n";
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// skip unsupported datetime types
|
|
||||||
if (!isDateTimeType($sqlType)) {
|
|
||||||
$sqlTypeConstant = get_sqlType_constant($sqlType);
|
|
||||||
|
|
||||||
// Call store procedure
|
|
||||||
$outSql = AE\getCallProcSqlPlaceholders($spname, 2);
|
|
||||||
$c_detOut = '';
|
|
||||||
$c_randOut = '';
|
|
||||||
$stmt = sqlsrv_prepare( $conn, $outSql,
|
|
||||||
array(array( &$c_detOut, SQLSRV_PARAM_OUT, null, $sqlTypeConstant),
|
|
||||||
array(&$c_randOut, SQLSRV_PARAM_OUT, null, $sqlTypeConstant )));
|
|
||||||
if (!$stmt) {
|
|
||||||
die(print_r(sqlsrv_errors(), true));
|
|
||||||
}
|
|
||||||
sqlsrv_execute($stmt);
|
|
||||||
$errors = sqlsrv_errors();
|
|
||||||
if (empty($errors) && AE\IsDataEncrypted()) {
|
|
||||||
// SQLSRV_PHPTYPE_DATETIME not supported
|
|
||||||
echo "$dataType should not be compatible with any datetime type.\n";
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,13 +141,10 @@ foreach ($dataTypes as $dataType) {
|
||||||
sqlsrv_free_stmt($stmt);
|
sqlsrv_free_stmt($stmt);
|
||||||
sqlsrv_query($conn, "TRUNCATE TABLE $tbname");
|
sqlsrv_query($conn, "TRUNCATE TABLE $tbname");
|
||||||
|
|
||||||
|
dropProc($conn, $spname);
|
||||||
if ($success) {
|
if ($success) {
|
||||||
echo "Test successfully done.\n";
|
echo "Test successfully done.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AE\isColEncrypted()) {
|
|
||||||
dropProc($conn, $spname);
|
|
||||||
}
|
|
||||||
dropTable($conn, $tbname);
|
dropTable($conn, $tbname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ require_once('MsCommon.inc');
|
||||||
require_once('AEData.inc');
|
require_once('AEData.inc');
|
||||||
|
|
||||||
$dataTypes = array("bit", "tinyint", "smallint", "int", "bigint", "decimal(18,5)", "numeric(10,5)", "float", "real" );
|
$dataTypes = array("bit", "tinyint", "smallint", "int", "bigint", "decimal(18,5)", "numeric(10,5)", "float", "real" );
|
||||||
$directions = array("SQLSRV_PARAM_OUT", "SQLSRV_PARAM_INOUT");
|
$directions = array(SQLSRV_PARAM_OUT, SQLSRV_PARAM_INOUT);
|
||||||
|
|
||||||
// this is a list of implicit datatype conversion that SQL Server allows (https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine)
|
// this is a list of implicit datatype conversion that SQL Server allows (https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine)
|
||||||
$compatList = array("bit" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"),
|
$compatList = array("bit" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"),
|
||||||
|
@ -22,7 +22,107 @@ $compatList = array("bit" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VAR
|
||||||
"numeric(10,5)" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"),
|
"numeric(10,5)" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT", "SQLSRV_SQLTYPE_TIMESTAMP"),
|
||||||
"float" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT"),
|
"float" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT"),
|
||||||
"real" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT"));
|
"real" => array( "SQLSRV_SQLTYPE_BINARY", "SQLSRV_SQLTYPE_VARBINARY", "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DECIMAL(18,5)", "SQLSRV_SQLTYPE_NUMERIC(10,5)", "SQLSRV_SQLTYPE_FLOAT", "SQLSRV_SQLTYPE_REAL", "SQLSRV_SQLTYPE_BIGINT", "SQLSRV_SQLTYPE_INT", "SQLSRV_SQLTYPE_SMALLINT", "SQLSRV_SQLTYPE_TINYINT", "SQLSRV_SQLTYPE_MONEY", "SQLSRV_SQLTYPE_SMALLMONEY", "SQLSRV_SQLTYPE_BIT"));
|
||||||
$epsilon = 0.0001;
|
|
||||||
|
function compareResults($dataType, $sqlType, $c_detOut, $c_randOut, $inputValues)
|
||||||
|
{
|
||||||
|
$epsilon = 0.0001;
|
||||||
|
$success = true;
|
||||||
|
|
||||||
|
if ($dataType == "float" || $dataType == "real") {
|
||||||
|
if (abs($c_detOut - $inputValues[0]) > $epsilon || abs($c_randOut - $inputValues[1]) > $epsilon) {
|
||||||
|
echo "Incorrect output retrieved for datatype $dataType and sqlType $sqlType:\n";
|
||||||
|
print(" c_det: " . $c_detOut . "\n");
|
||||||
|
print(" c_rand: " . $c_randOut . "\n");
|
||||||
|
$success = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($c_detOut != $inputValues[0] || $c_randOut != $inputValues[1]) {
|
||||||
|
echo "Incorrect output retrieved for datatype $dataType and sqlType $sqlType:\n";
|
||||||
|
print(" c_det: " . $c_detOut . "\n");
|
||||||
|
print(" c_rand: " . $c_randOut . "\n");
|
||||||
|
$success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
function testOutputParam($conn, $spname, $direction, $dataType, $sqlType, $inputValues)
|
||||||
|
{
|
||||||
|
// The driver does not support these types as output params, simply return
|
||||||
|
if (isDateTimeType($sqlType) || isLOBType($sqlType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
global $compatList;
|
||||||
|
|
||||||
|
$sqlTypeConstant = get_sqlType_constant($sqlType);
|
||||||
|
|
||||||
|
// Call store procedure
|
||||||
|
$outSql = AE\getCallProcSqlPlaceholders($spname, 2);
|
||||||
|
|
||||||
|
// Set these to NULL such that the PHP type of each output parameter is inferred
|
||||||
|
// from the SQLSRV_SQLTYPE_* constant
|
||||||
|
$c_detOut = null;
|
||||||
|
$c_randOut = null;
|
||||||
|
$stmt = sqlsrv_prepare(
|
||||||
|
$conn,
|
||||||
|
$outSql,
|
||||||
|
array(array( &$c_detOut, $direction, null, $sqlTypeConstant),
|
||||||
|
array(&$c_randOut, $direction, null, $sqlTypeConstant ))
|
||||||
|
);
|
||||||
|
if (!$stmt) {
|
||||||
|
die(print_r(sqlsrv_errors(), true));
|
||||||
|
}
|
||||||
|
sqlsrv_execute($stmt);
|
||||||
|
|
||||||
|
$success = false;
|
||||||
|
$errors = sqlsrv_errors();
|
||||||
|
if (AE\IsDataEncrypted()) {
|
||||||
|
if (empty($errors)) {
|
||||||
|
// With data encrypted, it's a lot stricter, so the results are expected
|
||||||
|
// to be numeric and comparable
|
||||||
|
$success = compareResults($dataType, $sqlType, $c_detOut, $c_randOut, $inputValues);
|
||||||
|
} else {
|
||||||
|
// This should return 22018, the SQLSTATE for any incompatible conversion,
|
||||||
|
// except the XML type
|
||||||
|
$success = ($errors[0]['SQLSTATE'] === '22018');
|
||||||
|
if (!$success) {
|
||||||
|
if ($sqlType === 'SQLSRV_SQLTYPE_XML') {
|
||||||
|
$success = ($errors[0]['SQLSTATE'] === '42000');
|
||||||
|
} else {
|
||||||
|
echo "Encrypted data: unexpected errors with SQL type: $sqlType\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$compatible = isCompatible($compatList, $dataType, $sqlType);
|
||||||
|
if ($compatible && empty($errors)) {
|
||||||
|
$success = true;
|
||||||
|
} else {
|
||||||
|
// Even if $dataType is compatible with $sqlType sometimes
|
||||||
|
// we still get errors from the server -- if so, it might
|
||||||
|
// return either SQLSTATE '42000' or '22018' (operand type
|
||||||
|
// clash but only happens with some certain types)
|
||||||
|
// E.g. when converting a bigint to int or an int to numeric,
|
||||||
|
// SQLSTATE '42000' is returned, indicating an error when
|
||||||
|
// converting from one type to another.
|
||||||
|
// TODO 11559: investigate if SQLSTATE '42000' is indeed acceptable
|
||||||
|
$success = ($errors[0]['SQLSTATE'] === '42000' || ($errors[0]['SQLSTATE'] === '22018' && in_array($sqlType, ['SQLSRV_SQLTYPE_XML', 'SQLSRV_SQLTYPE_BINARY', 'SQLSRV_SQLTYPE_VARBINARY', 'SQLSRV_SQLTYPE_UNIQUEIDENTIFIER', 'SQLSRV_SQLTYPE_TIMESTAMP'])));
|
||||||
|
if (!$success) {
|
||||||
|
if ($compatible) {
|
||||||
|
echo "$dataType should be compatible with $sqlType.\n";
|
||||||
|
} else {
|
||||||
|
echo "Failed with SQL type: $sqlType\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
$conn = AE\connect();
|
$conn = AE\connect();
|
||||||
|
|
||||||
|
@ -35,14 +135,15 @@ foreach ($dataTypes as $dataType) {
|
||||||
$colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false));
|
$colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false));
|
||||||
AE\createTable($conn, $tbname, $colMetaArr);
|
AE\createTable($conn, $tbname, $colMetaArr);
|
||||||
|
|
||||||
// TODO: It's a good idea to test conversions between different datatypes when AE is off as well.
|
// Create a Store Procedure
|
||||||
if (AE\isColEncrypted()) {
|
$spname = 'selectAllColumns';
|
||||||
// Create a Store Procedure
|
createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname");
|
||||||
$spname = 'selectAllColumns';
|
|
||||||
createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname");
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert a row
|
// insert a row
|
||||||
|
// Take the second and third entres (some edge cases) from the various
|
||||||
|
// $[$dataType]_params in AEData.inc
|
||||||
|
// e.g. with $dataType = 'decimal(18,5)', use $decimal_params[1] and $decimal_params[2]
|
||||||
|
// to form an array, namely [-9223372036854.80000, 9223372036854.80000]
|
||||||
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
||||||
$r;
|
$r;
|
||||||
// convert input values to strings for decimals and numerics
|
// convert input values to strings for decimals and numerics
|
||||||
|
@ -52,88 +153,25 @@ foreach ($dataTypes as $dataType) {
|
||||||
$stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r);
|
$stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r);
|
||||||
}
|
}
|
||||||
if ($r === false) {
|
if ($r === false) {
|
||||||
is_incompatible_types_error($dataType, "default type");
|
fatalError("Failed to insert data of type $dataType\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($directions as $direction) {
|
foreach ($directions as $direction) {
|
||||||
echo "Testing as $direction:\n";
|
$dir = ($direction == SQLSRV_PARAM_OUT) ? 'SQLSRV_PARAM_OUT' : 'SQLSRV_PARAM_INOUT';
|
||||||
|
echo "Testing as $dir:\n";
|
||||||
|
|
||||||
// test each SQLSRV_SQLTYPE_ constants
|
// test each SQLSRV_SQLTYPE_ constants
|
||||||
foreach ($sqlTypes as $sqlType) {
|
foreach ($sqlTypes as $sqlType) {
|
||||||
|
$success = testOutputParam($conn, $spname, $direction, $dataType, $sqlType, $inputValues);
|
||||||
if (!AE\isColEncrypted()) {
|
if (!$success) {
|
||||||
$isCompatible = false;
|
// No point to continue looping
|
||||||
foreach ($compatList[$dataType] as $compatType) {
|
echo("Test failed: $dataType as $sqlType\n");
|
||||||
if (stripos($compatType, $sqlType) !== false) {
|
die(print_r(sqlsrv_errors(), true));
|
||||||
$isCompatible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 22018 is the SQLSTATE for any incompatible conversion errors
|
|
||||||
$errors = sqlsrv_errors();
|
|
||||||
if (!empty($errors) && $isCompatible && $errors[0]['SQLSTATE'] == 22018) {
|
|
||||||
echo "$sqlType should be compatible with $dataType\n";
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// skip unsupported datetime types
|
|
||||||
if (!isDateTimeType($sqlType)) {
|
|
||||||
$sqlTypeConstant = get_sqlType_constant($sqlType);
|
|
||||||
|
|
||||||
// Call store procedure
|
|
||||||
$outSql = AE\getCallProcSqlPlaceholders($spname, 2);
|
|
||||||
if ($sqlType == 'SQLSRV_SQLTYPE_FLOAT' || $sqlType == 'SQLSRV_SQLTYPE_REAL') {
|
|
||||||
$c_detOut = 0.0;
|
|
||||||
$c_randOut = 0.0;
|
|
||||||
} else {
|
|
||||||
$c_detOut = 0;
|
|
||||||
$c_randOut = 0;
|
|
||||||
}
|
|
||||||
$stmt = sqlsrv_prepare($conn, $outSql,
|
|
||||||
array(array( &$c_detOut, constant($direction), null, $sqlTypeConstant),
|
|
||||||
array(&$c_randOut, constant($direction), null, $sqlTypeConstant)));
|
|
||||||
|
|
||||||
if (!$stmt) {
|
|
||||||
die(print_r(sqlsrv_errors(), true));
|
|
||||||
}
|
|
||||||
sqlsrv_execute($stmt);
|
|
||||||
$errors = sqlsrv_errors();
|
|
||||||
|
|
||||||
if (!empty($errors)) {
|
|
||||||
if (stripos("SQLSRV_SQLTYPE_" . $dataType, $sqlType) !== false) {
|
|
||||||
var_dump(sqlsrv_errors());
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (AE\IsDataEncrypted() || stripos("SQLSRV_SQLTYPE_" . $dataType, $sqlType) !== false) {
|
|
||||||
if ($dataType == "float" || $dataType == "real") {
|
|
||||||
if (abs($c_detOut - $inputValues[0]) > $epsilon || abs($c_randOut - $inputValues[1]) > $epsilon) {
|
|
||||||
echo "Incorrect output retrieved for datatype $dataType and sqlType $sqlType:\n";
|
|
||||||
print(" c_det: " . $c_detOut . "\n");
|
|
||||||
print(" c_rand: " . $c_randOut . "\n");
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ($c_detOut != $inputValues[0] || $c_randOut != $inputValues[1]) {
|
|
||||||
echo "Incorrect output retrieved for datatype $dataType and sqlType $sqlType:\n";
|
|
||||||
print(" c_det: " . $c_detOut . "\n");
|
|
||||||
print(" c_rand: " . $c_randOut . "\n");
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlsrv_free_stmt($stmt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AE\isColEncrypted()) {
|
dropProc($conn, $spname);
|
||||||
dropProc($conn, $spname);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($success) {
|
if ($success) {
|
||||||
echo "Test successfully done.\n";
|
echo "Test successfully done.\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ require_once('MsCommon.inc');
|
||||||
require_once('AEData.inc');
|
require_once('AEData.inc');
|
||||||
|
|
||||||
$dataTypes = array("char(5)", "varchar(max)", "nchar(5)", "nvarchar(max)");
|
$dataTypes = array("char(5)", "varchar(max)", "nchar(5)", "nvarchar(max)");
|
||||||
$directions = array("SQLSRV_PARAM_OUT", "SQLSRV_PARAM_INOUT");
|
$directions = array(SQLSRV_PARAM_OUT, SQLSRV_PARAM_INOUT);
|
||||||
|
|
||||||
// this is a list of implicit datatype conversion that SQL Server allows (https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine)
|
// this is a list of implicit datatype conversion that SQL Server allows (https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine)
|
||||||
$compatList = array("char(5)" => array( "SQLSRV_SQLTYPE_CHAR(5)", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR(5)", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DECIMAL", "SQLSRV_SQLTYPE_NUMERIC", "SQLSRV_SQLTYPE_NTEXT", "SQLSRV_SQLTYPE_TEXT", "SQLSRV_SQLTYPE_XML"),
|
$compatList = array("char(5)" => array( "SQLSRV_SQLTYPE_CHAR(5)", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR(5)", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DECIMAL", "SQLSRV_SQLTYPE_NUMERIC", "SQLSRV_SQLTYPE_NTEXT", "SQLSRV_SQLTYPE_TEXT", "SQLSRV_SQLTYPE_XML"),
|
||||||
|
@ -20,6 +20,93 @@ $compatList = array("char(5)" => array( "SQLSRV_SQLTYPE_CHAR(5)", "SQLSRV_SQLTYP
|
||||||
|
|
||||||
$conn = AE\connect();
|
$conn = AE\connect();
|
||||||
|
|
||||||
|
function compareResults($dataType, $sqlType, $c_detOut, $c_randOut, $inputValues)
|
||||||
|
{
|
||||||
|
$success = true;
|
||||||
|
if ($c_detOut != $inputValues[0] || $c_randOut != $inputValues[1]) {
|
||||||
|
echo "Incorrect output retrieved for datatype $dataType and sqlType $sqlType:\n";
|
||||||
|
print(" c_det: " . $c_detOut . "\n");
|
||||||
|
print(" c_rand: " . $c_randOut . "\n");
|
||||||
|
|
||||||
|
$success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
function testOutputParam($conn, $spname, $direction, $dataType, $sqlType, $inputValues)
|
||||||
|
{
|
||||||
|
// The driver does not support these types as output params, simply return
|
||||||
|
if (isDateTimeType($sqlType) || isLOBType($sqlType)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
global $compatList;
|
||||||
|
|
||||||
|
$sqlTypeConstant = get_sqlType_constant($sqlType);
|
||||||
|
|
||||||
|
// Call store procedure
|
||||||
|
$outSql = AE\getCallProcSqlPlaceholders($spname, 2);
|
||||||
|
|
||||||
|
// Set these to NULL such that the PHP type of each output parameter is inferred
|
||||||
|
// from the SQLSRV_SQLTYPE_* constant
|
||||||
|
$c_detOut = null;
|
||||||
|
$c_randOut = null;
|
||||||
|
|
||||||
|
$stmt = sqlsrv_prepare(
|
||||||
|
$conn,
|
||||||
|
$outSql,
|
||||||
|
array(array(&$c_detOut, SQLSRV_PARAM_INOUT, null, $sqlTypeConstant),
|
||||||
|
array(&$c_randOut, SQLSRV_PARAM_INOUT, null, $sqlTypeConstant))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$stmt) {
|
||||||
|
die(print_r(sqlsrv_errors(), true));
|
||||||
|
}
|
||||||
|
sqlsrv_execute($stmt);
|
||||||
|
|
||||||
|
$success = false;
|
||||||
|
$errors = sqlsrv_errors();
|
||||||
|
if (AE\IsDataEncrypted()) {
|
||||||
|
if (empty($errors)) {
|
||||||
|
// With data encrypted, it's a lot stricter, so the results are expected
|
||||||
|
// to be comparable
|
||||||
|
$success = compareResults($dataType, $sqlType, $c_detOut, $c_randOut, $inputValues);
|
||||||
|
} else {
|
||||||
|
// This should return 22018, the SQLSTATE for any incompatible conversion,
|
||||||
|
// except the XML type
|
||||||
|
$success = ($errors[0]['SQLSTATE'] === '22018');
|
||||||
|
if (!$success) {
|
||||||
|
if ($sqlType === 'SQLSRV_SQLTYPE_XML') {
|
||||||
|
$success = ($errors[0]['SQLSTATE'] === '42000');
|
||||||
|
} else {
|
||||||
|
echo "Encrypted data: unexpected errors with SQL type: $sqlType\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$compatible = isCompatible($compatList, $dataType, $sqlType);
|
||||||
|
if ($compatible && empty($errors)) {
|
||||||
|
$success = true;
|
||||||
|
} else {
|
||||||
|
// Even if $dataType is compatible with $sqlType sometimes
|
||||||
|
// we still get errors from the server -- if so, it should
|
||||||
|
// return SQLSTATE '42000', indicating an error when
|
||||||
|
// converting from one type to another
|
||||||
|
// With data NOT encrypted, converting string types to other
|
||||||
|
// types will not return '22018'
|
||||||
|
$success = ($errors[0]['SQLSTATE'] === '42000');
|
||||||
|
if (!$success) {
|
||||||
|
echo "Failed with SQL type: $sqlType\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $success;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
foreach ($dataTypes as $dataType) {
|
foreach ($dataTypes as $dataType) {
|
||||||
echo "\nTesting $dataType:\n";
|
echo "\nTesting $dataType:\n";
|
||||||
$success = true;
|
$success = true;
|
||||||
|
@ -29,86 +116,37 @@ foreach ($dataTypes as $dataType) {
|
||||||
$colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false));
|
$colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false));
|
||||||
AE\createTable($conn, $tbname, $colMetaArr);
|
AE\createTable($conn, $tbname, $colMetaArr);
|
||||||
|
|
||||||
// TODO: It's a good idea to test conversions between different datatypes when AE is off as well.
|
// Create a Store Procedure
|
||||||
if (AE\isColEncrypted()) {
|
$spname = 'selectAllColumns';
|
||||||
// Create a Store Procedure
|
createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname");
|
||||||
$spname = 'selectAllColumns';
|
|
||||||
createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname");
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert a row
|
// insert a row
|
||||||
|
// Take the second and third entres from the various $[$dataType]_params in AEData.inc
|
||||||
|
// e.g. with $dataType = 'varchar(max)', use $varchar_params[1] and $varchar_params[2]
|
||||||
|
// to form an array
|
||||||
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
$inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
||||||
$r;
|
$r;
|
||||||
$stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r);
|
$stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r);
|
||||||
if ($r === false) {
|
if ($r === false) {
|
||||||
is_incompatible_types_error($dataType, "default type");
|
fatalError("Failed to insert data of type $dataType\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($directions as $direction) {
|
foreach ($directions as $direction) {
|
||||||
echo "Testing as $direction:\n";
|
$dir = ($direction == SQLSRV_PARAM_OUT) ? 'SQLSRV_PARAM_OUT' : 'SQLSRV_PARAM_INOUT';
|
||||||
|
echo "Testing as $dir:\n";
|
||||||
|
|
||||||
// test each SQLSRV_SQLTYPE_ constants
|
// test each SQLSRV_SQLTYPE_ constants
|
||||||
foreach ($sqlTypes as $sqlType) {
|
foreach ($sqlTypes as $sqlType) {
|
||||||
if (!AE\isColEncrypted()) {
|
$success = testOutputParam($conn, $spname, $direction, $dataType, $sqlType, $inputValues);
|
||||||
$isCompatible = false;
|
if (!$success) {
|
||||||
foreach ($compatList[$dataType] as $compatType) {
|
// No point to continue looping
|
||||||
if (stripos($compatType, $sqlType) !== false) {
|
echo("Test failed: $dataType as $sqlType\n");
|
||||||
$isCompatible = true;
|
die(print_r(sqlsrv_errors(), true));
|
||||||
}
|
|
||||||
}
|
|
||||||
// 22018 is the SQLSTATE for any incompatible conversion errors
|
|
||||||
$errors = sqlsrv_errors();
|
|
||||||
if (!empty($errors) && $isCompatible && $errors[0]['SQLSTATE'] == 22018) {
|
|
||||||
echo "$sqlType should be compatible with $dataType\n";
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// skip unsupported datetime types
|
|
||||||
if (!isDateTimeType($sqlType)) {
|
|
||||||
$sqlTypeConstant = get_sqlType_constant($sqlType);
|
|
||||||
|
|
||||||
// Call store procedure
|
|
||||||
$outSql = AE\getCallProcSqlPlaceholders($spname, 2);
|
|
||||||
$c_detOut = '';
|
|
||||||
$c_randOut = '';
|
|
||||||
$stmt = sqlsrv_prepare($conn, $outSql,
|
|
||||||
array(array(&$c_detOut, SQLSRV_PARAM_INOUT, null, $sqlTypeConstant),
|
|
||||||
array(&$c_randOut, SQLSRV_PARAM_INOUT, null, $sqlTypeConstant)));
|
|
||||||
|
|
||||||
if (!$stmt) {
|
|
||||||
die(print_r(sqlsrv_errors(), true));
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlsrv_execute($stmt);
|
|
||||||
$errors = sqlsrv_errors();
|
|
||||||
|
|
||||||
if (!empty($errors) ) {
|
|
||||||
if (stripos("SQLSRV_SQLTYPE_" . $dataType, $sqlType) !== false) {
|
|
||||||
var_dump(sqlsrv_errors());
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (AE\IsDataEncrypted() || stripos("SQLSRV_SQLTYPE_" . $dataType, $sqlType) !== false) {
|
|
||||||
if ($c_detOut != $inputValues[0] || $c_randOut != $inputValues[1]) {
|
|
||||||
echo "Incorrect output retrieved for datatype $dataType and sqlType $sqlType:\n";
|
|
||||||
print(" c_det: " . $c_detOut . "\n");
|
|
||||||
print(" c_rand: " . $c_randOut . "\n");
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlsrv_free_stmt($stmt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AE\isColEncrypted()) {
|
dropProc($conn, $spname);
|
||||||
dropProc($conn, $spname);
|
|
||||||
}
|
|
||||||
if ($success) {
|
if ($success) {
|
||||||
echo "Test successfully done.\n";
|
echo "Test successfully done.\n";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue