Tests for phptypes, select conversions, and datetimes

This commit is contained in:
David Puglielli 2018-03-09 11:37:44 -08:00
parent a24a8a7035
commit 194d4fe0d6
4 changed files with 1951 additions and 0 deletions

View file

@ -0,0 +1,595 @@
--TEST--
Test various date and time types with AE and ReturnDatesAsStrings set to true
--SKIPIF--
<?php require('skipif_versions_old.inc'); ?>
--FILE--
<?php
// Check for expected errors. These are expected in cases where the dates and
// times do not comply with ODBC standards.
function ExecutePreparedStmt($stmt)
{
if ($stmt == false) {
fatalError("Failure in sqlsrv_prepare");
} else {
$r = sqlsrv_execute($stmt);
if ($r == false) {
$errors = sqlsrv_errors();
if ($errors[0]['SQLSTATE'] != '22018' and
$errors[0]['SQLSTATE'] != '22008' and
$errors[0]['SQLSTATE'] != '22007' and
$errors[0]['SQLSTATE'] != '07006') {
print_r($errors);
fatalError("Unexpected error");
}
}
}
}
// Compare dates retrieved from the database with the date used for testing.
// $testingDate is an array of strings like '2002-01-31 23:59:59.049876' and
// $retrieved_date is the string date of the format 'Y-m-d H:i:s.u', which
// the format returned by the date_format() calls below or by retrieval as
// strings, unless $datetimetype is date or time. In that case, if
// $returnStrings is false and $datetimetype is 'date', the time defaults to
// 00:00:00.0000, and if $datetimetype is 'time' and $returnStrings is false,
// the date defaults to the current date. If however $returnStrings is true
// and $datetimetype is 'date', $retrieved_date is only a date,
// and if $datetimetype is 'time' and $returnStrings is true, $retrieved_date
// only a time.
// The concatenations involving zeroes below are to make direct string
// comparisons feasible. Also, because PHP maxes out at microsecond precision
// and SQL Server maxes out at 0.1 microsecond precision, the more precise
// types require an extra 0 for some comparisons.
function CompareDateTime($datetimetype, $returnStrings, &$testingDate, $retrievedDate)
{
$test_date_time = array();
for ($i=0; $i<sizeof($testingDate); ++$i) {
$test_date_time[] = explode(" ", $testingDate[$i]);
}
$ret_date_time = explode(" ", $retrievedDate);
if (sizeof($ret_date_time)>1) {
$datetimeonly = $ret_date_time[0]." ".$ret_date_time[1];
}
if (sizeof($ret_date_time)>2) {
$timezone = $ret_date_time[2];
$dtoffset = $ret_date_time[0]." ".substr($ret_date_time[1], 0, -1)." ".$ret_date_time[2];
}
if ($returnStrings == true) {
switch ($datetimetype) {
case 'date':
if ($retrievedDate != $test_date_time[0][0]) {
fatalError("Dates do not match!");
}
break;
case 'time':
if ($retrievedDate != $test_date_time[0][1]."0" and
$retrievedDate != $test_date_time[1][1]."0" and
$retrievedDate != $test_date_time[2][1]."0" and
$retrievedDate != $test_date_time[3][1]."0" ) {
fatalError("Times do not match!");
}
break;
case 'datetime':
if ($retrievedDate."000" != $testingDate[0] and
$retrievedDate."000" != $testingDate[1] and
$retrievedDate."000" != $testingDate[2] and
$retrievedDate."000" != $testingDate[3] ) {
fatalError("Datetimes do not match!");
}
break;
case 'datetime2':
if ($retrievedDate != $testingDate[0]."0" and
$retrievedDate != $testingDate[1]."0" and
$retrievedDate != $testingDate[2]."0" and
$retrievedDate != $testingDate[3]."0" ) {
fatalError("Datetime2s do not match!");
}
break;
case 'datetimeoffset':
if ($dtoffset != $testingDate[4] and
$dtoffset != $testingDate[5] and
$dtoffset != $testingDate[6] and
$dtoffset != $testingDate[7] ) {
fatalError("Datetimeoffsets do not match!");
}
break;
case 'smalldatetime':
if ($retrievedDate.".000000" != $testingDate[0] and
$retrievedDate.".000000" != $testingDate[1] and
$retrievedDate.".000000" != $testingDate[2] and
$retrievedDate.".000000" != $testingDate[3] ) {
fatalError("Smalldatetimes do not match!");
}
break;
}
}
else {
switch ($datetimetype) {
case 'date':
if ($ret_date_time[0] != $test_date_time[0][0]) {
fatalError("Dates do not match!");
}
break;
case 'time':
if ($ret_date_time[1] != $test_date_time[0][1] and
$ret_date_time[1] != $test_date_time[1][1] and
$ret_date_time[1] != $test_date_time[2][1] and
$ret_date_time[1] != $test_date_time[3][1] ) {
fatalError("Times do not match!");
}
break;
case 'datetime':
if ($datetimeonly != $testingDate[0] and
$datetimeonly != $testingDate[1] and
$datetimeonly != $testingDate[2] and
$datetimeonly != $testingDate[3] ) {
fatalError("Datetimes do not match!");
}
break;
case 'datetime2':
if ($datetimeonly != $testingDate[0] and
$datetimeonly != $testingDate[1] and
$datetimeonly != $testingDate[2] and
$datetimeonly != $testingDate[3] ) {
fatalError("Datetime2s do not match!");
}
break;
case 'datetimeoffset':
if ($retrievedDate != $testingDate[4] and
$retrievedDate != $testingDate[5] and
$retrievedDate != $testingDate[6] and
$retrievedDate != $testingDate[7] ) {
fatalError("Datetimeoffsets do not match!");
}
break;
case 'smalldatetime':
if ($datetimeonly != $testingDate[0] and
$datetimeonly != $testingDate[1] and
$datetimeonly != $testingDate[2] and
$datetimeonly != $testingDate[3] ) {
fatalError("Smalldatetimes do not match!");
}
break;
}
}
}
function InsertDatesAndOrTimes($conn, $datetimetype, &$formats_array, $array_size, $SQLSRV_SQLTYPE_CONST)
{
$tableName = "table_of_$datetimetype";
$columns = array(new AE\ColumnMeta('int', 'id'),
new AE\ColumnMeta("$datetimetype", "c1_$datetimetype"));
$stmt = AE\createTable($conn, $tableName, $columns);
if (!$stmt) {
fatalError("Failed to create table $tableName\n");
}
$insertSql = "INSERT INTO [$tableName] (id, [c1_$datetimetype]) VALUES (?, ?)";
for ($i=0; $i<$array_size; $i++)
{
$stmt = sqlsrv_prepare($conn, $insertSql, array($i, array($formats_array[$i], SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), $SQLSRV_SQLTYPE_CONST)));
ExecutePreparedStmt($stmt);
$stmt = sqlsrv_prepare($conn, $insertSql, array($i, $formats_array[$i]));
ExecutePreparedStmt($stmt);
// date_create can fail if the argument is not a format PHP recognises;
// this is not a problem for this test.
if (date_create($formats_array[$i]) != false) {
$stmt = sqlsrv_prepare($conn, $insertSql, array($i, array(date_create($formats_array[$i]), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STRING('utf-8'), $SQLSRV_SQLTYPE_CONST)));
ExecutePreparedStmt($stmt);
$stmt = sqlsrv_prepare($conn, $insertSql, array($i, date_create($formats_array[$i])));
ExecutePreparedStmt($stmt);
}
}
}
function FetchDatesAndOrTimes($conn, $datetimetype, &$testingDate, $returnDatesAsStrings)
{
$tableName = "table_of_$datetimetype";
echo "Select fields as strings:\n";
$stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]");
if ($stmt === false) {
fatalError("Select from $tableName failed");
}
while (sqlsrv_fetch($stmt)) {
$idnum = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
$datetime = sqlsrv_get_field($stmt, 1, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
if (!is_string($datetime)) {
fatalError("sqlsrv_get_field did not return string but string was specified");
}
CompareDateTime($datetimetype, true, $testingDate, $datetime);
}
// retrieve date time fields as DateTime objects
echo "Select fields as DateTime objects:\n";
$stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]");
if ($stmt === false) {
fatalError("Select from $tableName failed");
}
while (sqlsrv_fetch($stmt)) {
$idnum = sqlsrv_get_field($stmt, 0, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR));
$datetime = sqlsrv_get_field($stmt, 1, SQLSRV_PHPTYPE_DATETIME);
if (!($datetime instanceof DateTime)) {
fatalError("sqlsrv_get_field did not return DateTime but DateTime was specified");
}
$datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u');
CompareDateTime($datetimetype, false, $testingDate, $datetime);
}
// retrieve date time fields without explicitly requesting the type
echo "Select fields with no type information provided:\n";
$stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]");
if ($stmt === false) {
fatalError("Select from $tableName failed");
}
while (sqlsrv_fetch($stmt)) {
$idnum = sqlsrv_get_field($stmt, 0);
$datetime = sqlsrv_get_field($stmt, 1);
if ($returnDatesAsStrings == true) {
if (!is_string($datetime)) {
fatalError("String for date expected, not a string");
}
CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $datetime);
}
else { // ReturnsDatesAsStrings is false
if (!($datetime instanceof DateTime)) {
fatalError("DateTime object expected, not a DateTime");
}
$datetime = ($datetimetype == 'datetimeoffset') ? date_format($datetime, 'Y-m-d H:i:s.u P') : date_format($datetime, 'Y-m-d H:i:s.u');
CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $datetime);
}
}
// retrieve date time fields as default
echo "Select using fetch_array:\n";
$stmt = sqlsrv_query($conn, "SELECT * FROM [$tableName]");
if ($stmt === false) {
fatalError("Select from $tableName failed");
}
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC)) {
$idnum = $row[0];
if ($returnDatesAsStrings == true) {
if (!is_string($row[1])) {
fatalError("String for date expected, not a string");
}
CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $row[1]);
}
else {
if (!($row[1] instanceof DateTime)) {
fatalError("DateTime object expected, not a DateTime");
}
$datetime = ($datetimetype == 'datetimeoffset') ? date_format($row[1], 'Y-m-d H:i:s.u P') : date_format($row[1], 'Y-m-d H:i:s.u');
CompareDateTime($datetimetype, $returnDatesAsStrings, $testingDate, $datetime);
}
}
print_r(sqlsrv_field_metadata($stmt)[1]);
}
// The date used for the test will be Januray 31, 2002, or 2002/01/31.
// This will sidestep issues involving the use of two digit years since
// SQL Server defaults to 19 as the first two digits.
// Time is 23:59:29.049876
// Note that smalldatetime rounds to the nearest minute, and that may cause
// this test to fail if it rolls over to the next day.
// Incidentally, this datetime corresponds to a timestamp of 1012521599.
$year = '2002';
$month = '01';
$month_name = 'January';
$month_abbr = 'Jan';
$day = '31';
$hour = '23';
$hour12 = '11';
$meridian = 'PM';
$minute = '59';
$second = '29';
$frac = '04';
$frac2 = '9876';
$tz_correction = '+08:00';
$testingDate = array($year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2,
$year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000",
$year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000",
$year."-".$month."-".$day." ".$hour.":".$minute.":00.000000",
$year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac.$frac2." ".$tz_correction,
$year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".".$frac."0000 ".$tz_correction,
$year."-".$month."-".$day." ".$hour.":".$minute.":".$second.".000000 ".$tz_correction,
$year."-".$month."-".$day." ".$hour.":".$minute.":00.000000 ".$tz_correction,
);
// These formats are for the ODBC driver with types specified in sqlsrv_prepare()
$date_formats = array($year."-".$month."-".$day
);
$time_formats = array($hour.":".$minute.":".$second,
$hour.":".$minute.":".$second.".".$frac,
$hour.":".$minute.":".$second.".".$frac.$frac2
);
// These formats are not accepted by either the ODBC driver or by PHP, but
// can possibly be wrangled in sqlsrv_prepare() using strings instead of
// the dedicated date and time types.
$date_formats_nonODBC = array($year."/".$month."/".$day,
$month."/".$day."/".$year,
$month."-".$day."-".$year,
$day."/".$month."/".$year,
$day."-".$month."-".$year,
$month_name." ".$day.", ".$year,
$day."-".$month_name."-".$year,
$day."-".$month_abbr."-".$year
);
$time_formats_nonODBC = array($hour12.":".$minute." ".$meridian,
$hour12.":".$minute.":".$second." ".$meridian,
$hour12.":".$minute.":".$second.".".$frac." ".$meridian,
$hour12.":".$minute.":".$second.".".$frac.$frac2." ".$meridian,
$hour.":".$minute
);
// Create arrays containing the ODBC-standard formats, and larger arrays
// containing the non-standard formats, for the supported SQL Server
// date and time types.
$date_formats_all = array_merge($date_formats, $date_formats_nonODBC);
$time_formats_all = array_merge($time_formats, $time_formats_nonODBC);
$datetime_formats_all = array();
$datetime2_formats_all = array();
$datetimeoffset_formats_all = array();
$datetimesmall_formats_all = array();
$SZ_TIME_all = sizeof($time_formats_all);
$SZ_DATE_all = sizeof($date_formats_all);
$SZ_DATETIME_all = $SZ_TIME_all*$SZ_DATE_all;
// Create compound date/time types. For datetime, remove the extra precision
// of $frac2. For smalldatetime, remove the extra precision of $frac and $frac2.
// If the data in $frac and/or $frac2 is found elsewhere in the date/time, the
// data will be garbled. For example, if the year is 2002 and $frac2 is 2002,
// the code below will remove any instances of '2002' in the datetime and
// smalldatetime strings, producing garbage for those types. User must be
// cognizant of this when testing different dates and times.
for ($i=0; $i<$SZ_DATE_all; $i++)
{
for ($j=0; $j<$SZ_TIME_all; $j++)
{
$datetime_formats_all[] = str_replace($frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]);
$datetime2_formats_all[] = $date_formats_all[$i]." ".$time_formats_all[$j];
$datetimeoffset_formats_all[] = $date_formats_all[$i]." ".$time_formats_all[$j].$tz_correction;
if (str_replace(".".$frac.$frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]) == ($date_formats_all[$i]." ".$time_formats_all[$j])) {
$datetimesmall_formats_all[] = str_replace(".".$frac, "", $date_formats_all[$i]." ".$time_formats_all[$j]);
}
else {
$datetimesmall_formats_all[] = str_replace(".".$frac.$frac2, "", $date_formats_all[$i]." ".$time_formats_all[$j]);
}
}
}
date_default_timezone_set('Canada/Pacific');
sqlsrv_configure('WarningsReturnAsErrors', 0);
sqlsrv_configure('LogSeverity', SQLSRV_LOG_SEVERITY_ALL);
sqlsrv_configure('LogSubsystems', SQLSRV_LOG_SYSTEM_OFF);
require_once('MsCommon.inc');
$returnDatesAsStrings = true;
$conn = AE\connect(array('ReturnDatesAsStrings' => $returnDatesAsStrings));
InsertDatesAndOrTimes($conn, 'date', $date_formats_all, $SZ_DATE_all, SQLSRV_SQLTYPE_DATE);
InsertDatesAndOrTimes($conn, 'time', $time_formats_all, $SZ_TIME_all, SQLSRV_SQLTYPE_TIME);
InsertDatesAndOrTimes($conn, 'datetime', $datetime_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME);
InsertDatesAndOrTimes($conn, 'datetime2', $datetime2_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME2);
InsertDatesAndOrTimes($conn, 'datetimeoffset', $datetimeoffset_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIMEOFFSET);
InsertDatesAndOrTimes($conn, 'smalldatetime', $datetimesmall_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_SMALLDATETIME);
FetchDatesAndOrTimes($conn, 'date', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'time', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'datetime', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'datetime2', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'datetimeoffset', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'smalldatetime', $testingDate, $returnDatesAsStrings);
sqlsrv_close($conn);
$returnDatesAsStrings = false;
$conn = AE\connect(array('ReturnDatesAsStrings' => $returnDatesAsStrings));
InsertDatesAndOrTimes($conn, 'date', $date_formats_all, $SZ_DATE_all, SQLSRV_SQLTYPE_DATE);
InsertDatesAndOrTimes($conn, 'time', $time_formats_all, $SZ_TIME_all, SQLSRV_SQLTYPE_TIME);
InsertDatesAndOrTimes($conn, 'datetime', $datetime_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME);
InsertDatesAndOrTimes($conn, 'datetime2', $datetime2_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIME2);
InsertDatesAndOrTimes($conn, 'datetimeoffset', $datetimeoffset_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_DATETIMEOFFSET);
InsertDatesAndOrTimes($conn, 'smalldatetime', $datetimesmall_formats_all, $SZ_DATETIME_all, SQLSRV_SQLTYPE_SMALLDATETIME);
FetchDatesAndOrTimes($conn, 'date', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'time', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'datetime', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'datetime2', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'datetimeoffset', $testingDate, $returnDatesAsStrings);
FetchDatesAndOrTimes($conn, 'smalldatetime', $testingDate, $returnDatesAsStrings);
sqlsrv_close($conn);
?>
--EXPECT--
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_date
[Type] => 91
[Size] =>
[Precision] => 10
[Scale] => 0
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_time
[Type] => -154
[Size] =>
[Precision] => 16
[Scale] => 7
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_datetime
[Type] => 93
[Size] =>
[Precision] => 23
[Scale] => 3
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_datetime2
[Type] => 93
[Size] =>
[Precision] => 27
[Scale] => 7
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_datetimeoffset
[Type] => -155
[Size] =>
[Precision] => 34
[Scale] => 7
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_smalldatetime
[Type] => 93
[Size] =>
[Precision] => 16
[Scale] => 0
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_date
[Type] => 91
[Size] =>
[Precision] => 10
[Scale] => 0
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_time
[Type] => -154
[Size] =>
[Precision] => 16
[Scale] => 7
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_datetime
[Type] => 93
[Size] =>
[Precision] => 23
[Scale] => 3
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_datetime2
[Type] => 93
[Size] =>
[Precision] => 27
[Scale] => 7
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_datetimeoffset
[Type] => -155
[Size] =>
[Precision] => 34
[Scale] => 7
[Nullable] => 1
)
Select fields as strings:
Select fields as DateTime objects:
Select fields with no type information provided:
Select using fetch_array:
Array
(
[Name] => c1_smalldatetime
[Type] => 93
[Size] =>
[Precision] => 16
[Scale] => 0
[Nullable] => 1
)

View file

@ -0,0 +1,211 @@
--TEST--
Test insert various data types and fetch as strings
--FILE--
<?php
require_once('MsCommon.inc');
require_once('tools.inc');
require_once('values.php');
// Set up the columns and build the insert query. Each data type has an
// AE-encrypted and a non-encrypted column side by side in the table.
function FormulateSetupQuery($tableName, &$dataTypes, &$columns, &$insertQuery, $strsize, $strsize2)
{
$columns = array();
$queryTypes = "(";
$queryTypesAE = "(";
$valuesString = "VALUES (";
$numTypes = sizeof($dataTypes);
for ($i=0; $i<$numTypes; ++$i) {
// Replace parentheses for column names
$colname = str_replace("($strsize)", "_$strsize", $dataTypes[$i]);
$colname = str_replace("($strsize2)", "_$strsize2", $colname);
$colname = str_replace("(max)", "_max", $colname);
$colname = str_replace("(5)", "_5", $colname);
$colname = str_replace("(36,4)", "_36_4", $colname);
$colname = str_replace("(32,4)", "_32_4", $colname);
$colname = str_replace("(28,4)", "_28_4", $colname);
$columns[] = new AE\ColumnMeta($dataTypes[$i], "c_".$colname."_AE");
$columns[] = new AE\ColumnMeta($dataTypes[$i], "c_".$colname, null, true, true);
$queryTypes .= "c_"."$colname, ";
$queryTypes .= "c_"."$colname"."_AE, ";
$valuesString .= "?, ?, ";
}
$queryTypes = substr($queryTypes, 0, -2).")";
$valuesString = substr($valuesString, 0, -2).")";
$insertQuery = "INSERT INTO $tableName ".$queryTypes." ".$valuesString;
}
$SQLSRV_PHPTYPE_CONST = array(SQLSRV_PHPTYPE_INT,
SQLSRV_PHPTYPE_DATETIME,
SQLSRV_PHPTYPE_FLOAT,
SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY),
SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_CHAR),
SQLSRV_PHPTYPE_STREAM("UTF-8"),
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_BINARY),
SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_CHAR),
SQLSRV_PHPTYPE_STRING("UTF-8")
);
// Two sizes for the string types so we can test conversion from
// a shorter type to a longer type
$strsize = 512;
$strsize2 = 768;
$dataTypes = array ("binary($strsize)", "varbinary($strsize)", "varbinary(max)", "char($strsize)",
"varchar($strsize)", "varchar(max)", "nchar($strsize)", "nvarchar($strsize)",
"nvarchar(max)", "datetime", "smalldatetime", "date", "time(5)", "datetimeoffset(5)",
"datetime2(5)", "decimal(28,4)", "numeric(32,4)", "float", "real", "bigint", "int",
"smallint", "tinyint", "bit", "uniqueidentifier", "hierarchyid",
"binary($strsize2)", "varbinary($strsize2)", "char($strsize2)",
"varchar($strsize2)", "nchar($strsize2)", "nvarchar($strsize2)",
"time", "datetimeoffset", "datetime2", "decimal(32,4)", "numeric(36,4)"
);
set_time_limit(0);
sqlsrv_configure('WarningsReturnAsErrors', 1);
// Connect
$connectionInfo = array("CharacterSet"=>"UTF-8", "ColumnEncryption"=>"enabled");
$conn = AE\connect($connectionInfo);
if (!$conn) {
fatalError("Could not connect.\n");
}
$tableName = "type_conversion_table";
$stmt = sqlsrv_query($conn, "IF OBJECT_ID('$tableName', 'U') IS NOT NULL DROP TABLE $tableName");
$columns = array();
$insertQuery = "";
FormulateSetupQuery($tableName, $dataTypes, $columns, $insertQuery, $strsize, $strsize2);
$stmt = AE\createTable($conn, $tableName, $columns);
if (!$stmt) {
fatalError("Failed to create table $tableName\n");
}
// The data we test against is in values.php
for ($v=0; $v<sizeof($values);++$v)
{
// Each value must be inserted twice because the AE and non-AE column are side by side.
$testValues = array();
for ($i=0; $i<sizeof($values[$v]); ++$i)
{
$testValues[] = $values[$v][$i];
$testValues[] = $values[$v][$i];
}
// Insert the data using sqlsrv_prepare()
// Insert one set of data for each PHPTYPE
$stmt = sqlsrv_prepare($conn, $insertQuery, $testValues);
if ($stmt == false) {
print_r(sqlsrv_errors());
fatalError("sqlsrv_prepare failed\n");
}
for ($i=0; $i<sizeof($SQLSRV_PHPTYPE_CONST); ++$i) {
if (sqlsrv_execute($stmt) == false) {
print_r(sqlsrv_errors());
fatalError("sqlsrv_execute failed\n");
}
}
$selectQuery = "SELECT * FROM $tableName";
// Two select statements for selection using
// sqlsrv_get_field and sqlsrv_fetch_array
$stmt = sqlsrv_query($conn, $selectQuery);
if ($stmt == false) {
print_r(sqlsrv_errors());
fatalError("First sqlsrv_prepare failed\n");
}
$stmt2 = sqlsrv_query($conn, $selectQuery);
if ($stmt2 == false) {
print_r(sqlsrv_errors());
fatalError("Second sqlsrv_prepare failed\n");
}
$metadata = sqlsrv_field_metadata($stmt);
$numFields = count($metadata);
$i=0;
$valueAE = null;
$valueArrayAE = null;
while ($result = sqlsrv_fetch($stmt))
{
$dataArray = sqlsrv_fetch_array($stmt2, SQLSRV_FETCH_NUMERIC);
for ($j = 0; $j < $numFields; $j++)
{
$value = sqlsrv_get_field($stmt, $j, $SQLSRV_PHPTYPE_CONST[$i]);
$valueArray = $dataArray[$j];
// PHPTYPE_STREAM returns a PHP resource, so check the type
if (is_resource($value)) $value = get_resource_type($value);
// For each type, the AE values come first and non-AE values second
// So let's do the comparison every second field
if ($j%2 == 0)
{
$valueAE = $value;
$valueArrayAE = $valueArray;
}
else if ($j%2 == 1)
{
// If returning a DateTime PHP type from a date only SQL type,
// PHP adds the current timestamp to make a DateTime object,
// and in this case the AE and non-AE times may be off by a
// fraction of a second since they are retrieved at ever-so-slightly
// different times. This not a test-failing discrepancy, so
// below the DateTime objects are made equal again for the next if
// block.
if ($value instanceof DateTime)
{
// date_diff returns a DateInterval object, and f is
// the difference expressed as a fraction of a second
$datediff = date_diff($value, $valueAE);
$diff = $datediff->f;
if ($diff < 1.0 and $diff > -1.0)
{
$value = $valueAE;
}
}
if ($valueAE != $value or $valueArrayAE != $valueArray)
{
echo "Values do not match! PHPType $i Field $j\n";
print_r($valueAE);echo "\n";
print_r($value);echo "\n";
print_r($valueArrayAE);echo "\n";
print_r($valueArray);echo "\n";
print_r(sqlsrv_errors());
fatalError("Test failed, values do not match.\n");
}
}
}
++$i;
}
sqlsrv_free_stmt($stmt);
sqlsrv_free_stmt($stmt2);
$deleteQuery = "DELETE FROM $tableName";
$stmt = sqlsrv_query($conn, $deleteQuery);
if ($stmt == false) {
print_r(sqlsrv_errors());
fatalError("Delete statement failed");
}
sqlsrv_free_stmt($stmt);
}
sqlsrv_close($conn);
echo "Test successful\n";
?>
--EXPECT--
Test successful

View file

@ -0,0 +1,325 @@
--TEST--
Test insert various data types and fetch as strings
--FILE--
<?php
require_once('MsCommon.inc');
require_once('tools.inc');
require_once('values.php');
// Set up the columns and build the insert query. Each data type has an
// AE-encrypted and a non-encrypted column side by side in the table.
function FormulateSetupQuery($tableName, &$dataTypes, &$columns, &$insertQuery, $strsize, $strsize2)
{
$columns = array();
$queryTypes = "(";
$valuesString = "VALUES (";
$numTypes = sizeof($dataTypes);
for ($i=0; $i<$numTypes; ++$i) {
// Replace parentheses for column names
$colname = str_replace("($strsize)", "_$strsize", $dataTypes[$i]);
$colname = str_replace("($strsize2)", "_$strsize2", $colname);
$colname = str_replace("(max)", "_max", $colname);
$colname = str_replace("(5)", "_5", $colname);
$colname = str_replace("(36,4)", "_36_4", $colname);
$colname = str_replace("(32,4)", "_32_4", $colname);
$colname = str_replace("(28,4)", "_28_4", $colname);
$columns[] = new AE\ColumnMeta($dataTypes[$i], "c_".$colname."_AE"); // encrypted column
$columns[] = new AE\ColumnMeta($dataTypes[$i], "c_".$colname, null, true, true);// non-encrypted column
$queryTypes .= "c_"."$colname, ";
$queryTypes .= "c_"."$colname"."_AE, ";
$valuesString .= "?, ?, ";
}
$queryTypes = substr($queryTypes, 0, -2).")";
$valuesString = substr($valuesString, 0, -2).")";
$insertQuery = "INSERT INTO $tableName ".$queryTypes." ".$valuesString;
}
// Build the select queries. We want every combination of types for conversion
// testing, so the matrix of queries selects every type from every column
// and convert using CAST.
function FormulateSelectQuery($tableName, &$selectQuery, &$selectQueryAE, &$dataTypes, $strsize, $strsize2)
{
$numTypes = sizeof($dataTypes);
for ($i=0; $i<$numTypes; ++$i)
{
$selectQuery[] = array();
for ($j=0; $j<sizeof($dataTypes); ++$j)
{
$colnamei = str_replace("($strsize)", "_$strsize", $dataTypes[$i]);
$colnamei = str_replace("($strsize2)", "_$strsize2", $colnamei);
$colnamei = str_replace("(max)", "_max", $colnamei);
$colnamei = str_replace("(5)", "_5", $colnamei);
$colnamei = str_replace("(36,4)", "_36_4", $colnamei);
$colnamei = str_replace("(32,4)", "_32_4", $colnamei);
$colnamei = str_replace("(28,4)", "_28_4", $colnamei);
$selectQuery[$i][] = "SELECT CAST(c_".$colnamei." AS $dataTypes[$j]) FROM $tableName";
$selectQueryAE[$i][] = "SELECT CAST(c_".$colnamei."_AE AS $dataTypes[$j]) FROM $tableName";
}
}
}
// Two sizes for the string types so we can test conversion from
// a shorter type to a longer type
$strsize = 512;
$strsize2 = 768;
$dataTypes = array ("binary($strsize)", "varbinary($strsize)", "varbinary(max)", "char($strsize)",
"varchar($strsize)", "varchar(max)", "nchar($strsize)", "nvarchar($strsize)",
"nvarchar(max)", "datetime", "smalldatetime", "date", "time(5)", "datetimeoffset(5)",
"datetime2(5)", "decimal(28,4)", "numeric(32,4)", "float", "real", "bigint", "int",
"smallint", "tinyint", "bit", "uniqueidentifier", "hierarchyid",
"binary($strsize2)", "varbinary($strsize2)", "char($strsize2)",
"varchar($strsize2)", "nchar($strsize2)", "nvarchar($strsize2)",
"time", "datetimeoffset", "datetime2", "decimal(32,4)", "numeric(36,4)"
);
// Conversion matrix for SQL types, based on the conversion chart
// at https://www.microsoft.com/en-us/download/details.aspx?id=35834
// i = implicit conversion
// e = explicit conversion
// x = conversion not allowed
// @ = not applicable
// c = explicit CAST required
// m = misc
$conversionMatrix = array(array('@','i','i','i','i','i','i','i','i','i','i','e','e','e','e','i','i','x','x','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','e','i','i'),//binary
array('i','@','i','i','i','i','i','i','i','i','i','e','e','e','e','i','i','x','x','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','e','i','i'),//varbinary
array('i','i','@','i','i','i','i','i','i','i','i','e','e','e','e','i','i','x','x','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','e','i','i'),//varbinary(max)
array('e','e','e','@','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','i','i','i','i','i','i','i','i','i'),//char
array('e','e','e','i','@','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','i','i','i','i','i','i','i','i','i'),//varchar
array('e','e','e','i','i','@','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','i','i','i','i','i','i','i','i','i'),//varchar(max)
array('e','e','e','i','i','i','@','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','i','i','i','i','i','i','i','i','i'),//nchar
array('e','e','e','i','i','i','i','@','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','i','i','i','i','i','i','i','i','i'),//nvarchar
array('e','e','e','i','i','i','i','i','@','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','i','i','i','i','i','i','i','i','i'),//nvarchar(max)
array('e','e','e','i','i','i','i','i','i','@','i','i','i','i','i','e','e','e','e','e','e','e','e','e','x','x','e','e','i','i','i','i','i','i','i','e','e'),//datetime
array('e','e','e','i','i','i','i','i','i','i','@','i','i','i','i','e','e','e','e','e','e','e','e','e','x','x','e','e','i','i','i','i','i','i','i','e','e'),//samlldatetime
array('e','e','e','i','i','i','i','i','i','i','i','@','x','i','i','x','x','x','x','x','x','x','x','x','x','x','e','e','i','i','i','i','x','i','i','x','x'),//date
array('e','e','e','i','i','i','i','i','i','i','i','x','@','i','i','x','x','x','x','x','x','x','x','x','x','x','e','e','i','i','i','i','i','i','i','x','x'),//time
array('e','e','e','i','i','i','i','i','i','i','i','i','i','@','i','x','x','x','x','x','x','x','x','x','x','x','e','e','i','i','i','i','i','i','i','x','x'),//datetimeoffset
array('e','e','e','i','i','i','i','i','i','i','i','i','i','i','@','x','x','x','x','x','x','x','x','x','x','x','e','e','i','i','i','i','i','i','i','x','x'),//datetime2
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','c','c','i','i','i','i','i','i','i','x','x','i','i','i','i','i','i','x','x','x','c','c'),//decimal
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','c','c','i','i','i','i','i','i','i','x','x','i','i','i','i','i','i','x','x','x','c','c'),//numeric
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','i','i','c','i','i','i','i','i','i','x','x','i','i','i','i','i','i','x','x','x','i','i'),//float
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','i','i','i','@','i','i','i','i','i','x','x','i','i','i','i','i','i','x','x','x','i','i'),//real
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','i','i','i','i','@','i','i','i','i','x','x','i','i','i','i','i','i','x','x','x','i','i'),//bigint
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','i','i','i','i','i','@','i','i','i','x','x','i','i','i','i','i','i','x','x','x','i','i'),//int
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','i','i','i','i','i','i','@','i','i','x','x','i','i','i','i','i','i','x','x','x','i','i'),//smallint
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','i','i','i','i','i','i','i','@','i','x','x','i','i','i','i','i','i','x','x','x','i','i'),//tinyint
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','i','i','i','i','i','i','i','i','@','x','x','i','i','i','i','i','i','x','x','x','i','i'),//bit
array('i','i','i','i','i','i','i','i','i','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','@','x','i','i','i','i','i','i','x','x','x','x','x'),//uniqueid
array('e','e','e','e','e','e','e','e','e','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','m','e','e','e','e','e','e','x','x','x','x','x'),//hierarchyid
array('i','i','i','i','i','i','i','i','i','i','i','e','e','e','e','i','i','x','x','i','i','i','i','i','i','i','@','i','i','i','i','i','e','e','e','i','i'),//binary
array('i','i','i','i','i','i','i','i','i','i','i','e','e','e','e','i','i','x','x','i','i','i','i','i','i','i','i','@','i','i','i','i','e','e','e','i','i'),//varbinary
array('e','e','e','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','@','i','i','i','i','i','i','i','i'),//char
array('e','e','e','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','i','@','i','i','i','i','i','i','i'),//varchar
array('e','e','e','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','i','i','@','i','i','i','i','i','i'),//nchar
array('e','e','e','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','i','e','e','i','i','i','@','i','i','i','i','i'),//nvarchar
array('e','e','e','i','i','i','i','i','i','i','i','x','i','i','i','x','x','x','x','x','x','x','x','x','x','x','e','e','i','i','i','i','@','i','i','x','x'),//time
array('e','e','e','i','i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','x','x','x','x','x','x','x','e','e','i','i','i','i','i','@','i','x','x'),//datetimeoffset
array('e','e','e','i','i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','x','x','x','x','x','x','x','e','e','i','i','i','i','i','i','@','x','x'),//datetime2
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','c','c','i','i','i','i','i','i','i','x','x','i','i','i','i','i','i','x','x','x','c','c'),//decimal
array('i','i','i','i','i','i','i','i','i','i','i','x','x','x','x','c','c','i','i','i','i','i','i','i','x','x','i','i','i','i','i','i','x','x','x','c','c'),//numeric
);
// The conversion matrix for AE is more restrictive
// y = allowed conversion
// x = not allowed
$conversionMatrixAE = array(array('y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x','x','x','x','x'),//binary
array('y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x','x','x','x','x'),//varbinary
array('x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//varbinary(max)
array('x','x','x','y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x','x','x'),//char
array('x','x','x','y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x','x','x'),//varchar
array('x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//varchar(max)
array('x','x','x','x','x','x','y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x'),//nchar
array('x','x','x','x','x','x','y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x'),//nvarchar
array('x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//nvarchar(max)
array('x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//datetime
array('x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//samlldatetime
array('x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//date
array('x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x'),//time
array('x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x'),//datetimeoffset
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x'),//datetime2
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//decimal
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x'),//numeric
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//float
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//real
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//bigint
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//int
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//smallint
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x'),//tinyint
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x'),//bit
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x'),//uniqueid
array('y','y','y','y','y','y','y','y','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','y','y','y','y','y','x','x','x','x','x'),//hierarchyid
array('x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x','x','x','x','x'),//binary
array('x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x','x','x','x','x'),//varbinary
array('x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x','x','x'),//char
array('x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x','x','x'),//varchar
array('x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x'),//nchar
array('x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','y','x','x','x','x','x'),//nvarchar
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x'),//time
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x'),//datetimeoffset
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x'),//datetime2
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y','x'),//decimal
array('x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','y'),//numeric
);
set_time_limit(0);
sqlsrv_configure('WarningsReturnAsErrors', 1);
$connectionInfo = array("CharacterSet"=>"UTF-8", "ColumnEncryption"=>"enabled");
$conn = AE\connect($connectionInfo);
if (!$conn) {
fatalError("Could not connect.\n");
}
$tableName = "type_conversion_table";
$stmt = sqlsrv_query($conn, "IF OBJECT_ID('$tableName', 'U') IS NOT NULL DROP TABLE $tableName");
$columns = array();
$insertQuery = "";
FormulateSetupQuery($tableName, $dataTypes, $columns, $insertQuery, $strsize, $strsize2);
$stmt = AE\createTable($conn, $tableName, $columns);
if (!$stmt) {
fatalError("Failed to create table $tableName\n");
}
// The data we test against is in values.php
for ($v=0; $v<sizeof($values); ++$v)
{
// Each value must be inserted twice because the AE and non-AE column are side by side.
$testValues = array();
for ($i=0; $i<sizeof($values[$v]); ++$i)
{
$testValues[] = $values[$v][$i];
$testValues[] = $values[$v][$i];
}
// Insert the data using sqlsrv_prepare()
$stmt = sqlsrv_prepare($conn, $insertQuery, $testValues);
if ($stmt == false) {
print_r(sqlsrv_errors());
fatalError("sqlsrv_prepare failed\n");
}
if (!sqlsrv_execute($stmt)) {
print_r(sqlsrv_errors());
fatalError("sqlsrv_execute failed\n");
}
sqlsrv_free_stmt($stmt);
// Formulate the matrix of SELECT queries and iterate over each index.
$selectQuery = array();
$selectQueryAE = array();
FormulateSelectQuery($tableName, $selectQuery, $selectQueryAE, $dataTypes, $strsize, $strsize2);
for ($i=0; $i<sizeof($dataTypes); ++$i)
{
for ($j=0; $j<sizeof($dataTypes); ++$j)
{
$stmt = sqlsrv_query($conn, $selectQuery[$i][$j]);
if ($stmt == false)
{
$convError = sqlsrv_errors();
// These are the errors we expect to see if a conversion fails.
if ($convError[0][0] != '22018' and
$convError[0][0] != '22001' and
$convError[0][0] != '22003' and
$convError[0][0] != '22007' and
$convError[0][0] != '42S22' and
$convError[0][1] != '6234' and
$convError[0][1] != '6522' and
$convError[0][1] != '8114' and
$convError[0][1] != '8169')
{
print_r($convError);
fatalError("Conversion failed with unexpected error message. i=$i, j=$j\n");
}
$stmtAE = sqlsrv_query($conn, $selectQueryAE[$i][$j]);
$convError = sqlsrv_errors();
// if the non-AE conversion fails, certainly the AE conversion
// should fail but only with error 22018.
if ($stmtAE != false) fatalError("AE conversion should have failed. i=$i, j=$j\n\n");
if ($convError[0][0] != '22018')
{
print_r($convError);
fatalError("AE conversion failed with unexpected error message. i=$i, j=$j\n");
}
}
else
{
if ($conversionMatrix[$i][$j] == 'x') fatalError("Conversion succeeded, should have failed. i=$i, j=$j\n");
$stmtAE = sqlsrv_query($conn, $selectQueryAE[$i][$j]);
// Check every combination of statement value and conversion.
// The last else if block covers the case where the select
// query worked and the retrieved values are compared.
if ($stmtAE == false and $conversionMatrixAE[$i][$j] == 'x')
{
$convError = sqlsrv_errors();
if ($convError[0][0] != '22018')
{
print_r($convError);
fatalError("AE conversion failed with unexpected error message. i=$i, j=$j\n");
}
}
else if ($stmtAE == false and $conversionMatrixAE[$i][$j] == 'y')
{
print_r(sqlsrv_errors());
fatalError("AE conversion failed, should have succeeded. i=$i, j=$j\n");
}
else if ($stmtAE != false and $conversionMatrixAE[$i][$j] == 'x')
{
fatalError("AE conversion succeeded, should have failed. i=$i, j=$j\n");
}
else if ($stmtAE != false and $conversionMatrixAE[$i][$j] == 'y')
{
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_NUMERIC);
$rowAE = sqlsrv_fetch_array($stmtAE, SQLSRV_FETCH_NUMERIC);
// rtrim strips whitespace from the end of the string, which
// takes care of a bug where some conversions lead to extraneous
// whitespace padding the end of the string
if (is_string($row[0]))
{
$row[0] = rtrim($row[0]);
$rowAE[0] = rtrim($rowAE[0]);
}
if ($row[0] != $rowAE[0])
{
echo "Values do not match! i=$i, j=$j\n";
print_r($row[0]);
print_r($rowAE[0]);
print_r($selectQuery[$i][$j]);echo "\n";
print_r($selectQueryAE[$i][$j]);echo "\n";
fatalError("Test failed, values do not match\n");
}
}
}
}
}
$deleteQuery = "DELETE FROM $tableName";
$stmt = sqlsrv_query($conn, $deleteQuery);
if ($stmt == false)
{
print_r(sqlsrv_errors());
fatalError("Delete statement failed");
}
}
sqlsrv_close($conn);
echo "Test successful\n";
?>
--EXPECT--
Test successful

File diff suppressed because one or more lines are too long