Modified some tests to work cross platforms (locales and floats) (#1135)

This commit is contained in:
Jenny Tam 2020-05-14 20:47:40 -07:00 committed by GitHub
parent 7e58d1aa92
commit d308aa4d0f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 429 additions and 207 deletions

View file

@ -484,6 +484,17 @@ function getSeqPlaceholders($num)
return $placeholderStr;
}
/**
* Compare two floating point numbers and return true if the difference is minimal
* @param float $expected : expected value
* @param float $actual : actual value
*/
function compareFloats($expected, $actual)
{
$epsilon = 0.00001;
$diff = abs(($actual - $expected) / $expected);
return ($diff < $epsilon);
}
/**
* Fetch all rows and all columns given a table name, and print them

View file

@ -18,9 +18,15 @@ $p = '銀河galaxy';
$p1 = '??galaxy';
$tableName = 'test1018';
// in Alpine Linux, instead of '?', it replaces inexact conversions with asterisks
// reference: read the ICONV section in
// https://wiki.musl-libc.org/functional-differences-from-glibc.html
$p2 = '**galaxy';
function insertRead($conn, $pdoStrParam, $value, $testCase, $id, $encoding = false)
{
global $p, $tableName;
global $p1, $p2;
$sql = "INSERT INTO $tableName (Col1) VALUES (:value)";
$options = array(PDO::ATTR_EMULATE_PREPARES => false); // it's false by default anyway
@ -45,8 +51,11 @@ function insertRead($conn, $pdoStrParam, $value, $testCase, $id, $encoding = fal
$result = $stmt->fetch(PDO::FETCH_NUM);
trace("$testCase: expected $value and returned $result[0]\n");
if ($result[0] !== $value) {
echo("$testCase: expected $value but returned:\n");
var_dump($result);
// Also check the other exception
if ($value === $p1 && $result[0] !== $p2) {
echo("$testCase: expected $value or $p2 but returned:\n");
var_dump($result);
}
}
}

View file

@ -10,6 +10,37 @@ require_once("MsCommon_mid-refactor.inc");
require_once("AEData.inc");
$dataTypes = array("bit", "tinyint", "smallint", "int", "bigint", "decimal(18,5)", "numeric(10,5)", "float", "real");
function fetchFields($conn, $tbname, $inputValues = null)
{
try {
$sql = "SELECT * FROM $tbname";
$stmt = $conn->query($sql);
if (is_null($inputValues)) {
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
foreach ($row as $key => $value) {
print("$key: $value\n");
}
}
} else {
while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
for ($i = 0; $i < 2; $i++) {
if (!compareFloats($inputValues[$i], $row[$i])) {
echo "Expected similar to $inputValues[$i] but got $row[$i]\n";
} else {
echo "Values matched\n";
}
}
}
}
} catch (PDOException $e) {
var_dump($e->errorInfo);
} catch (Exception $e) {
var_dump($e->errorInfo);
exit;
}
}
// Note the size of a float is platform dependent, with a precision of roughly 14 digits
// http://php.net/manual/en/language.types.float.php
try {
@ -28,9 +59,12 @@ try {
$stmt = insertRow($conn, $tbname, array( "c_det" => $inputValues[0], "c_rand" => $inputValues[1] ), null, $r);
if ($r === false) {
isIncompatibleTypesError($stmt, $dataType, "default type");
} elseif ($dataType == 'float' || $dataType == 'real') {
echo "-----Encrypted default type is compatible with encrypted $dataType-----\n";
fetchFields($conn, $tbname, $inputValues);
} else {
echo "-----Encrypted default type is compatible with encrypted $dataType-----\n";
fetchAll($conn, $tbname);
fetchFields($conn, $tbname);
}
dropTable($conn, $tbname);
}
@ -79,10 +113,10 @@ c_rand: 21474\.83647
Testing float:
-----Encrypted default type is compatible with encrypted float-----
c_det: (-9223372036\.8547993|-9223372036\.8547992)
c_rand: (9223372036\.8547993|9223372036\.8547992)
Values matched
Values matched
Testing real:
-----Encrypted default type is compatible with encrypted real-----
c_det: (-2147\.4829|-2147\.483)
c_rand: (2147\.4829|2147\.483)
Values matched
Values matched

View file

@ -51,16 +51,19 @@ $spSql = "CREATE PROCEDURE $spname (
@c17_nchar = c17_nchar, @c18_nvarchar = c18_nvarchar
FROM $tbname";
$conn->query($spSql);
// Insert data
// Insert data, for bigint, decimal and numeric, should insert as strings
$floatInput = 9223372036.8548;
$realInput = 2147.483;
$inputs = array( "c1_int" => 2147483647,
"c2_smallint" => 32767,
"c3_tinyint" => 255,
"c4_bit" => 1,
"c5_bigint" => 922337203685479936,
"c6_decimal" => 9223372036854.80000,
"c7_numeric" => 21474.83647,
"c8_float" => 9223372036.8548,
"c9_real" => 2147.483,
"c5_bigint" => '922337203685479936',
"c6_decimal" => '9223372036854.80000',
"c7_numeric" => '21474.83647',
"c8_float" => $floatInput,
"c9_real" => $realInput,
"c10_date" => '9999-12-31',
"c11_datetime" => '9999-12-31 23:59:59.997',
"c12_datetime2" => '9999-12-31 23:59:59.9999999',
@ -72,15 +75,18 @@ $inputs = array( "c1_int" => 2147483647,
"c18_nvarchar" => 'When prefixing a string constant with the letter N, the implicit conversion will result in a Unicode string if the constant to convert does not exceed the max length for a Unicode string data type (4,000).' );
$r;
$stmt = insertRow($conn, $tbname, $inputs, null, $r);
// Call store procedure
$outSql = getCallProcSqlPlaceholders($spname, count($inputs));
// Initialize all inputs, set bigint, decimal and numeric as empty strings
$intOut = 0;
$smallintOut = 0;
$tinyintOut = 0;
$bitOut = 0;
$bigintOut = 0.0;
$decimalOut = 0.0;
$numericOut = 0.0;
$bigintOut = '';
$decimalOut = '';
$numericOut = '';
$floatOut = 0.0;
$realOut = 0.0;
$dateOut = '0001-01-01';
@ -119,8 +125,14 @@ print("bitOut: " . $bitOut . "\n");
print("bigintOut: " . $bigintOut . "\n");
print("decimalOut: " . $decimalOut . "\n");
print("numericOut: " . $numericOut . "\n");
print("floatOut: " . $floatOut . "\n");
print("realOut: " . $realOut . "\n");
if (!compareFloats($floatInput, $floatOut)) {
// Should not expect float values to match exactly
print("Expected $floatInput but got $floatOut\n");
}
if (!compareFloats($realInput, $realOut)) {
// Should not expect real values to match exactly
print("Expected $realInput but got $realOut\n");
}
print("dateOut: " . $dateOut . "\n");
print("datetimeOut: " . $datetimeOut . "\n");
print("datetime2Out: " . $datetime2Out . "\n");
@ -143,8 +155,6 @@ bitOut: 1
bigintOut: 922337203685479936
decimalOut: 9223372036854\.80000
numericOut: 21474\.83647
floatOut: (9223372036\.8547993|9\.22337e\+009)
realOut: (2147\.4829|2147\.48)
dateOut: 9999-12-31
datetimeOut: (9999-12-31 23:59:59\.997|Dec 31 9999 11:59PM)
datetime2Out: 9999-12-31 23:59:59\.9999999

View file

@ -37,14 +37,6 @@ function printValues($msg, $det, $rand, $inputValues)
echo "fetched: "; var_dump($rand);
}
// this function returns true if the floats are more different than expected
function compareFloats($actual, $expected)
{
$epsilon = 0.00001;
$diff = abs(($actual - $expected) / $expected);
return ($diff > $epsilon);
}
// function compareIntegers() returns false when the fetched values
// are different from the expected inputs
function compareIntegers($det, $rand, $inputValues, $pdoParamType)
@ -52,8 +44,8 @@ function compareIntegers($det, $rand, $inputValues, $pdoParamType)
///////////////////////////////////////////////////////////////////////
// Assume $pdoParamType is PDO::PARAM_BOOL or PDO::PARAM_INT
if (is_string($det)) {
return (!compareFloats(floatval($det), $inputValues[0])
&& !compareFloats(floatval($rand), $inputValues[1]));
return (compareFloats($inputValues[0], floatval($det))
&& compareFloats($inputValues[1], floatval($rand)));
} else {
// if $pdoParamType is PDO::PARAM_BOOL, expect bool(true) or bool(false)
// depending on the rounded input values

View file

@ -22,14 +22,6 @@ $pdoParamTypes = array(
//////////////////////////////////////////////////////////////////////////////////
// this function returns true if the floats are more different than expected
function compareFloats($actual, $expected)
{
$epsilon = 0.0001;
$diff = abs(($actual - $expected) / $expected);
return ($diff > $epsilon);
}
function printValues($msg, $det, $rand, $inputValues)
{
echo $msg;
@ -118,8 +110,8 @@ function testOutputFloats($fetchNumeric, $inout)
} else {
// Compare the retrieved values against the input values
// if either of them is very different, print them all
if (compareFloats(floatval($det), $inputValues[0]) ||
compareFloats(floatval($rand), $inputValues[1])) {
if (!compareFloats($inputValues[0], floatval($det)) ||
!compareFloats($inputValues[1], floatval($rand))) {
printValues($errMsg, $det, $rand, $inputValues);
}
}

View file

@ -33,8 +33,14 @@ function dropTable($conn, $tableName)
require_once('MsSetup.inc');
try {
$locale = 'fr_FR@euro';
setlocale(LC_ALL, $locale);
$r = setlocale(LC_ALL, 'fr_FR@euro');
if (empty($r)) {
// Some platforms use a different locale name
$r = setlocale(LC_ALL, 'fr_FR.ISO8859-15');
if (empty($r)) {
die("The required French locale is not available");
}
}
$conn = new PDO("sqlsrv:server = $server; database=$databaseName; driver=$driver", $uid, $pwd);
$conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);

View file

@ -25,7 +25,13 @@ function fetchAsUTF8($conn, $tableName, $inputs)
$stmt->execute();
$f = $stmt->fetchColumn($i);
if ($f !== $inputs[$i]) {
if ($i == 2) {
if (!compareFloats(floatval($inputs[$i]), floatval($f))) {
echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n";
var_dump($f);
}
} elseif ($f !== $inputs[$i]) {
echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n";
var_dump($f);
}
}
@ -45,8 +51,16 @@ function fetchArray($conn, $tableName, $inputs)
// By default, even numeric or datetime fields are fetched as strings
$result = $stmt->fetch(PDO::FETCH_NUM);
for ($i = 0; $i < count($inputs); $i++) {
if ($result[$i] !== $inputs[$i]) {
var_dump($f);
if ($i == 2) {
$expected = floatval($inputs[$i]);
if (!compareFloats($expected, floatval($result[$i]))) {
echo "in fetchArray: for column $i expected $expected but got: ";
var_dump($result[$i]);
}
}
elseif ($result[$i] !== $inputs[$i]) {
echo "in fetchArray: for column $i expected $inputs[$i] but got: ";
var_dump($result[$i]);
}
}
} catch (PdoException $e) {

View file

@ -27,10 +27,19 @@ function verifyColumnData($columns, $results, $utf8)
var_dump($results[$i]);
} else {
$arr = explode('?', $results[$i]);
// in Alpine Linux, data returned is diffferent with always encrypted:
// something like '**** *ä**** *****-**×*'
// instead of '?', it replaces inexact conversions with asterisks
// reference: read the ICONV section in
// https://wiki.musl-libc.org/functional-differences-from-glibc.html
if (count($arr) == 1) {
// this means there is no question mark in $t
echo $columns[$i]->colName . " value is unexpected";
var_dump($results[$i]);
// then try to find a substring of some asterisks
$asterisks = '****';
if(strpos($results[$i], '****') === false) {
echo $columns[$i]->colName . " value is unexpected";
var_dump($results[$i]);
}
}
}
}

View file

@ -85,7 +85,7 @@ try {
exit();
}
?>
--EXPECT--
--EXPECTF--
Test_1 : Test with no parameters :
array(8) {
["IntCol"]=>
@ -101,7 +101,7 @@ array(8) {
["NVarCharCol"]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}

View file

@ -6,6 +6,22 @@ prepare with emulate prepare and binding integer
<?php
require_once("MsCommon_mid-refactor.inc");
function printRow($row, $inputValues)
{
if (empty($row)) {
return; // do nothing
}
$key = 'c3_float';
if (!compareFloats($inputValues[$key], $row[$key])) {
echo "Expected $inputValues[$key] but got $row[$key]\n";
}
// should not expect the floats to exactly match, so
// remove the last element from the array for printing
array_pop($row);
print_r($row);
}
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
@ -17,9 +33,13 @@ try {
createTable($conn, $tableName, array("c1_decimal" => "decimal", "c2_money" => "decimal(19,4)", "c3_float" => "float"));
}
insertRow($conn, $tableName, array("c1_decimal" => 411.1, "c2_money" => 131.11, "c3_float" => 611.111));
insertRow($conn, $tableName, array("c1_decimal" => 422.2222, "c2_money" => 132.222, "c3_float" => 622.22));
insertRow($conn, $tableName, array("c1_decimal" => 433.333, "c2_money" => 133.3333, "c3_float" => 633.33333));
$inputValues = array( array('c1_decimal' => '411.1', 'c2_money' => '131.11', 'c3_float' => 611.111),
array('c1_decimal' => '422.2222', 'c2_money' => '132.222', 'c3_float' => 622.22),
array('c1_decimal' => '433.333', 'c2_money' => '133.3333', 'c3_float' => 633.33333));
for ($i = 0; $i < count($inputValues); $i++) {
insertRow($conn, $tableName, $inputValues[$i]);
}
$query = "SELECT * FROM [$tableName] WHERE c1_decimal = :c1";
@ -27,11 +47,11 @@ try {
print_r("Prepare without emulate prepare:\n");
$options = array(PDO::ATTR_EMULATE_PREPARES => false);
$stmt = $conn->prepare($query, $options);
$c1 = 422.2222;
$c1 = '422.2222';
$stmt->bindParam(':c1', $c1);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[1]);
//with emulate prepare and no bind param options
print_r("Prepare with emulate prepare and no bind param options:\n");
@ -43,7 +63,7 @@ try {
$stmt->bindParam(':c1', $c1);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[1]);
//with emulate prepare and encoding SQLSRV_ENCODING_SYSTEM
print_r("Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM:\n");
@ -51,7 +71,7 @@ try {
$stmt->bindParam(':c1', $c1, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[1]);
//prepare with emulate prepare and encoding SQLSRV_ENCODING_UTF8
print_r("Prepare with emulate prepare and SQLSRV_ENCODING_UTF8:\n");
@ -59,7 +79,7 @@ try {
$stmt->bindParam(':c1', $c1, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_UTF8);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[1]);
//prepare with emulate prepare and encoding SQLSRV_ENCODING_BINARY
print_r("Prepare with emulate prepare and SQLSRV_ENCODING_BINARY:\n");
@ -67,7 +87,7 @@ try {
$stmt->bindParam(':c1', $c1, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[1]);
if ($stmt->rowCount() == 0) {
print_r("No results for this query\n");
}
@ -86,28 +106,24 @@ Array
(
[c1_decimal] => 422
[c2_money] => 132.2220
[c3_float] => 622.22%S
)
Prepare with emulate prepare and no bind param options:
Array
(
[c1_decimal] => 422
[c2_money] => 132.2220
[c3_float] => 622.22%S
)
Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM:
Array
(
[c1_decimal] => 422
[c2_money] => 132.2220
[c3_float] => 622.22%S
)
Prepare with emulate prepare and SQLSRV_ENCODING_UTF8:
Array
(
[c1_decimal] => 422
[c2_money] => 132.2220
[c3_float] => 622.22%S
)
Prepare with emulate prepare and SQLSRV_ENCODING_BINARY:
No results for this query

View file

@ -1,11 +1,35 @@
--TEST--
prepare with emulate prepare and binding integer
--DESCRIPTION--
This test is similar to pdo_prepare_emulatePrepare_decimal.phpt and
pdo_prepare_emulatePrepare_money.phpt but binding parameters with
floating point numbers. However, checking equality of floating point
numbers may not guarantee same results across platforms. Incorrect
results often occurred with implicit rounding when converting string
to floats.
See https://news-web.php.net/php.internals/11502 for in-depth explanation.
--SKIPIF--
<?php require('skipif_mid-refactor.inc'); ?>
--FILE--
<?php
require_once('MsCommon_mid-refactor.inc');
function printRow($row, $inputValues)
{
if (empty($row)) {
return; // do nothing
}
$key = 'c3_float';
if (!compareFloats($inputValues[$key], $row[$key])) {
echo "Expected $inputValues[$key] but got $row[$key]\n";
}
// should not expect the floats to exactly match, so
// remove the last element from the array for printing
array_pop($row);
print_r($row);
}
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
@ -17,21 +41,30 @@ try {
createTable($conn, $tableName, array("c1_decimal" => "decimal", "c2_money" => "decimal(19,4)", "c3_float" => "float"));
}
insertRow($conn, $tableName, array("c1_decimal" => 411.1, "c2_money" => 131.11, "c3_float" => 611.111));
insertRow($conn, $tableName, array("c1_decimal" => 422.2222, "c2_money" => 132.22, "c3_float" => 622.22));
insertRow($conn, $tableName, array("c1_decimal" => 433.333, "c2_money" => 133.3333, "c3_float" => 633.33333));
$inputValues = array( array('c1_decimal' => '411.1', 'c2_money' => '131.11', 'c3_float' => 611.111),
array('c1_decimal' => '422.2222', 'c2_money' => '132.222', 'c3_float' => 622.22),
array('c1_decimal' => '433.333', 'c2_money' => '133.3333', 'c3_float' => 633.33333));
$query = "SELECT * FROM [$tableName] WHERE c3_float = :c3";
for ($i = 0; $i < count($inputValues); $i++) {
insertRow($conn, $tableName, $inputValues[$i]);
}
// With data encrypted, there will be no conversion
if (isColEncrypted()) {
$query = "SELECT * FROM [$tableName] WHERE c3_float = :c3";
} else {
$query = "SELECT * FROM [$tableName] WHERE c3_float < :c3";
}
// prepare without emulate prepare
print_r("Prepare without emulate prepare:\n");
$options = array(PDO::ATTR_EMULATE_PREPARES => false);
$stmt = $conn->prepare($query, $options);
$c3 = 611.111;
$c3 = (isColEncrypted())? 611.111 : 620.00;
$stmt->bindParam(':c3', $c3);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[0]);
//with emulate prepare and no bind param options
print_r("Prepare with emulate prepare and no bind param options:\n");
@ -43,7 +76,7 @@ try {
$stmt->bindParam(':c3', $c3);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[0]);
//with emulate prepare and encoding SQLSRV_ENCODING_SYSTEM
print_r("Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM:\n");
@ -51,7 +84,7 @@ try {
$stmt->bindParam(':c3', $c3, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[0]);
//prepare with emulate prepare and encoding SQLSRV_ENCODING_UTF8
print_r("Prepare with emulate prepare and SQLSRV_ENCODING_UTF8:\n");
@ -59,7 +92,7 @@ try {
$stmt->bindParam(':c3', $c3, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_UTF8);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[0]);
//prepare with emulate prepare and encoding SQLSRV_ENCODING_BINARY
print_r("Prepare with emulate prepare and SQLSRV_ENCODING_BINARY:\n");
@ -67,7 +100,7 @@ try {
$stmt->bindParam(':c3', $c3, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[0]);
if ($stmt->rowCount() == 0) {
print_r("No results for this query\n");
}
@ -85,28 +118,24 @@ Array
(
[c1_decimal] => 411
[c2_money] => 131.1100
[c3_float] => 611.1109999999999%d
)
Prepare with emulate prepare and no bind param options:
Array
(
[c1_decimal] => 411
[c2_money] => 131.1100
[c3_float] => 611.1109999999999%d
)
Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM:
Array
(
[c1_decimal] => 411
[c2_money] => 131.1100
[c3_float] => 611.1109999999999%d
)
Prepare with emulate prepare and SQLSRV_ENCODING_UTF8:
Array
(
[c1_decimal] => 411
[c2_money] => 131.1100
[c3_float] => 611.1109999999999%d
)
Prepare with emulate prepare and SQLSRV_ENCODING_BINARY:
No results for this query

View file

@ -6,6 +6,22 @@ prepare with emulate prepare and binding integer
<?php
require_once('MsCommon_mid-refactor.inc');
function printRow($row, $inputValues)
{
if (empty($row)) {
return; // do nothing
}
$key = 'c3_float';
if (!compareFloats($inputValues[$key], $row[$key])) {
echo "Expected $inputValues[$key] but got $row[$key]\n";
}
// should not expect the floats to exactly match, so
// remove the last element from the array for printing
array_pop($row);
print_r($row);
}
try {
$conn = connect("", array(), PDO::ERRMODE_SILENT);
@ -17,9 +33,13 @@ try {
createTable($conn, $tableName, array("c1_decimal" => "decimal", "c2_money" => "decimal(19,4)", "c3_float" => "float"));
}
insertRow($conn, $tableName, array("c1_decimal" => 411.1, "c2_money" => 131.11, "c3_float" => 611.111));
insertRow($conn, $tableName, array("c1_decimal" => 422.2222, "c2_money" => 132.22, "c3_float" => 622.22));
insertRow($conn, $tableName, array("c1_decimal" => 433.333, "c2_money" => 133.3333, "c3_float" => 633.33333));
$inputValues = array( array('c1_decimal' => '411.1', 'c2_money' => '131.11', 'c3_float' => 611.111),
array('c1_decimal' => '422.2222', 'c2_money' => '132.222', 'c3_float' => 622.22),
array('c1_decimal' => '433.333', 'c2_money' => '133.3333', 'c3_float' => 633.33333));
for ($i = 0; $i < count($inputValues); $i++) {
insertRow($conn, $tableName, $inputValues[$i]);
}
$query = "SELECT * FROM [$tableName] WHERE c2_money = :c2";
@ -27,11 +47,11 @@ try {
print_r("Prepare without emulate prepare:\n");
$options = array(PDO::ATTR_EMULATE_PREPARES => false);
$stmt = $conn->prepare($query, $options);
$c2 = 133.3333;
$c2 = '133.3333';
$stmt->bindParam(':c2', $c2);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[2]);
//with emulate prepare and no bind param options
print_r("Prepare with emulate prepare and no bind param options:\n");
@ -43,7 +63,7 @@ try {
$stmt->bindParam(':c2', $c2);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[2]);
//with emulate prepare and encoding SQLSRV_ENCODING_SYSTEM
print_r("Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM:\n");
@ -51,7 +71,7 @@ try {
$stmt->bindParam(':c2', $c2, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_SYSTEM);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[2]);
//prepare with emulate prepare and encoding SQLSRV_ENCODING_UTF8
print_r("Prepare with emulate prepare and SQLSRV_ENCODING_UTF8:\n");
@ -59,7 +79,7 @@ try {
$stmt->bindParam(':c2', $c2, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_UTF8);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[2]);
//prepare with emulate prepare and encoding SQLSRV_ENCODING_BINARY
print_r("Prepare with emulate prepare and SQLSRV_ENCODING_BINARY:\n");
@ -67,7 +87,7 @@ try {
$stmt->bindParam(':c2', $c2, PDO::PARAM_STR, 0, PDO::SQLSRV_ENCODING_BINARY);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($row);
printRow($row, $inputValues[2]);
if ($stmt->rowCount() == 0) {
print_r("No results for this query\n");
}
@ -86,28 +106,24 @@ Array
(
[c1_decimal] => 433
[c2_money] => 133.3333
[c3_float] => 633.3333300000000%d
)
Prepare with emulate prepare and no bind param options:
Array
(
[c1_decimal] => 433
[c2_money] => 133.3333
[c3_float] => 633.3333300000000%d
)
Prepare with emulate prepare and SQLSRV_ENCODING_SYSTEM:
Array
(
[c1_decimal] => 433
[c2_money] => 133.3333
[c3_float] => 633.3333300000000%d
)
Prepare with emulate prepare and SQLSRV_ENCODING_UTF8:
Array
(
[c1_decimal] => 433
[c2_money] => 133.3333
[c3_float] => 633.3333300000000%d
)
Prepare with emulate prepare and SQLSRV_ENCODING_BINARY:
No results for this query

View file

@ -77,7 +77,7 @@ try {
?>
--EXPECT--
--EXPECTF--
TEST_1 : query with default fetch style :
array(16) {
["IntCol"]=>
@ -105,9 +105,9 @@ array(16) {
[5]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[6]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
[7]=>
@ -122,7 +122,7 @@ string(10) "STRINGCOL1"
string(23) "2000-11-11 11:11:11.110"
string(10) "STRINGCOL1"
string(10) "STRINGCOL1"
string(7) "111.111"
string(%d) "111.111%S"
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
TEST_4 : query with FETCH_INTO :
string(1) "1"
@ -131,7 +131,7 @@ string(10) "STRINGCOL1"
string(23) "2000-11-11 11:11:11.110"
string(10) "STRINGCOL1"
string(10) "STRINGCOL1"
string(7) "111.111"
string(%d) "111.111%S"
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
TEST_5 : query an empty table :
bool(false)

View file

@ -33,7 +33,7 @@ try {
}
?>
--EXPECT--
--EXPECTF--
Test_1 : BigIntCol :
array(1) {
["BigIntCol"]=>
@ -82,7 +82,7 @@ array(1) {
Test_10 : FloatCol :
array(1) {
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
}
Test_11 : RealCol :
array(1) {

View file

@ -48,7 +48,7 @@ try {
var_dump($e);
}
?>
--EXPECT--
--EXPECTF--
array(8) {
["IntCol"]=>
string(1) "1"
@ -63,7 +63,7 @@ array(8) {
["NVarCharCol"]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}

View file

@ -145,9 +145,9 @@ array(2) {
[5]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[6]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
[7]=>
@ -237,9 +237,9 @@ array(1) {
[8]=>
string(3) "111"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[9]=>
string(7) "111.111"
string(%d) "111.111%S"
["ImageCol"]=>
string(5) "abcde"
[10]=>
@ -273,9 +273,9 @@ array(1) {
[17]=>
string(420) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417."
["RealCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[18]=>
string(7) "111.111"
string(%d) "111.111%S"
["SmallDTCol"]=>
string(19) "2000-11-11 11:11:00"
[19]=>
@ -353,9 +353,9 @@ array(16) {
[5]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[6]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
[7]=>
@ -376,7 +376,7 @@ array(8) {
["NVarCharCol"]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}

View file

@ -54,7 +54,7 @@ try {
var_dump($e);
}
?>
--EXPECT--
--EXPECTF--
1
abcde
0
@ -64,7 +64,7 @@ STRINGCOL1
2000-11-11 11:11:11.1110000
2000-11-11 11:11:11.1110000 +00:00
111
111.111
111.111%S
abcde
1
111.1110

View file

@ -140,9 +140,9 @@ array(16) {
[5]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[6]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
[7]=>
@ -163,7 +163,7 @@ array(8) {
["NVarCharCol"]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}
@ -184,7 +184,7 @@ object(PDORow)#%x (%x) {
["NVarCharCol"]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}
@ -203,7 +203,7 @@ object(stdClass)#%x (%x) {
["NVarCharCol"]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}
@ -222,7 +222,7 @@ array(8) {
[5]=>
string(10) "STRINGCOL1"
[6]=>
string(7) "111.111"
string(%d) "111.111%S"
[7]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}
@ -233,7 +233,7 @@ string(10) "STRINGCOL1"
string(23) "2000-11-11 11:11:11.110"
string(10) "STRINGCOL1"
string(10) "STRINGCOL1"
string(7) "111.111"
string(%d) "111.111%S"
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
Test_7 : FETCH_CLASS :
string(1) "1"
@ -242,7 +242,7 @@ string(10) "STRINGCOL1"
string(23) "2000-11-11 11:11:11.110"
string(10) "STRINGCOL1"
string(10) "STRINGCOL1"
string(7) "111.111"
string(%d) "111.111%S"
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
Test_8 : FETCH_INTO :
string(1) "1"
@ -251,7 +251,7 @@ string(10) "STRINGCOL1"
string(23) "2000-11-11 11:11:11.110"
string(10) "STRINGCOL1"
string(10) "STRINGCOL1"
string(7) "111.111"
string(%d) "111.111%S"
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
Test_9 : FETCH_INVALID :

View file

@ -72,9 +72,9 @@ array(1) {
[8]=>
string(3) "111"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[9]=>
string(7) "111.111"
string(%d) "111.111%S"
["ImageCol"]=>
string(5) "abcde"
[10]=>
@ -108,9 +108,9 @@ array(1) {
[17]=>
string(420) " 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417."
["RealCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[18]=>
string(7) "111.111"
string(%d) "111.111%S"
["SmallDTCol"]=>
string(19) "2000-11-11 11:11:00"
[19]=>
@ -189,9 +189,9 @@ array(2) {
[5]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[6]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
[7]=>

View file

@ -25,7 +25,7 @@ try {
}
?>
--EXPECT--
--EXPECTF--
Set Fetch Mode for PDO::FETCH_ASSOC
array(8) {
["IntCol"]=>
@ -41,7 +41,7 @@ array(8) {
["NVarCharCol"]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}
@ -60,7 +60,7 @@ array(8) {
[5]=>
string(10) "STRINGCOL1"
[6]=>
string(7) "111.111"
string(%d) "111.111%S"
[7]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}
@ -91,9 +91,9 @@ array(16) {
[5]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
[6]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
[7]=>
@ -116,7 +116,7 @@ object(PDORow)#3 (9) {
["NVarCharCol"]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}
@ -135,7 +135,7 @@ object(stdClass)#5 (8) {
["NVarCharCol"]=>
string(10) "STRINGCOL1"
["FloatCol"]=>
string(7) "111.111"
string(%d) "111.111%S"
["XmlCol"]=>
string(431) "<xml> 1 This is a really large string used to test certain large data types like xml data type. The length of this string is greater than 256 to correctly test a large data type. This is currently used by atleast varchar type and by xml type. The fetch tests are the primary consumer of this string to validate that fetch on large types work fine. The length of this string as counted in terms of number of characters is 417.</xml>"
}

View file

@ -14,7 +14,8 @@ if ($localeDisabled) {
}
$loc = setlocale(LC_ALL, 'fr_FR@euro');
if (empty($loc)) {
$loc1 = setlocale(LC_ALL, 'fr_FR.ISO8859-15');
if (empty($loc) && empty($loc1)) {
die("skip required French locale not available");
}

View file

@ -84,9 +84,18 @@ if (!AE\isColEncrypted() && $t !== "So?e sä???? ?SCII-te×t") {
die("varchar(100) \'$t\' doesn't match So?e sä???? ?SCII-te×t");
} else {
$arr = explode('?', $t);
// in Alpine Linux, data returned is diffferent with always encrypted:
// something like '**** *ä**** *****-**×*'
// instead of '?', it replaces inexact conversions with asterisks
// reference: read the ICONV section in
// https://wiki.musl-libc.org/functional-differences-from-glibc.html
if (count($arr) == 1) {
// this means there is no question mark in $t
die("varchar(100) value \'$t\' is unexpected");
// then try to find a substring of some asterisks
$asterisks = '****';
if(strpos($t, '****') === false) {
die("varchar(100) value \'$t\' is unexpected");
}
}
}

View file

@ -14,7 +14,8 @@ if ($localeDisabled) {
}
$loc = setlocale(LC_ALL, 'fr_FR@euro');
if (empty($loc)) {
$loc1 = setlocale(LC_ALL, 'fr_FR.ISO8859-15');
if (empty($loc) && empty($loc1)) {
die("skip required French locale not available");
}

View file

@ -6,6 +6,13 @@ Test for binding output parameter of encrypted values for all types
<?php
require_once('MsCommon.inc');
function compareFloats($expected, $actual)
{
$epsilon = 0.00001;
$diff = abs(($actual - $expected) / $expected);
return ($diff < $epsilon);
}
$conn = AE\connect();
// Create the table
@ -50,16 +57,19 @@ createProc($conn, $spname, "@c1_int int OUTPUT, @c2_smallint smallint OUTPUT,
@c15_char = c15_char, @c16_varchar = c16_varchar,
@c17_nchar = c17_nchar, @c18_nvarchar = c18_nvarchar
FROM $tbname");
// Insert data
// Insert data, for bigint, decimal and numeric, should insert as strings
$floatInput = 9223372036.8548;
$realInput = 2147.483;
$inputs = array( "c1_int" => 2147483647,
"c2_smallint" => 32767,
"c3_tinyint" => 255,
"c4_bit" => 1,
"c5_bigint" => 922337203685479936,
"c6_decimal" => 9223372036854.80000,
"c7_numeric" => 21474.83647,
"c8_float" => 9223372036.8548,
"c9_real" => 2147.483,
"c5_bigint" => '922337203685479936',
"c6_decimal" => '9223372036854.80000',
"c7_numeric" => '21474.83647',
"c8_float" => $floatInput,
"c9_real" => $realInput,
"c10_date" => '9999-12-31',
"c11_datetime" => '9999-12-31 23:59:59.997',
"c12_datetime2" => '9999-12-31 23:59:59.9999999',
@ -74,13 +84,14 @@ $stmt = AE\insertRow($conn, $tbname, $inputs);
// Call store procedure
$outSql = AE\getCallProcSqlPlaceholders($spname, count($inputs));
// Initialize all inputs, set bigint, decimal and numeric as empty strings
$intOut = 0;
$smallintOut = 0;
$tinyintOut = 0;
$bitOut = 0;
$bigintOut = 0.0;
$decimalOut = 0.0;
$numericOut = 0.0;
$bigintOut = '';
$decimalOut = '';
$numericOut = '';
$floatOut = 0.0;
$realOut = 0.0;
$dateOut = '';
@ -119,8 +130,14 @@ print("bitOut: " . $bitOut . "\n");
print("bigintOut: " . $bigintOut . "\n");
print("decimalOut: " . $decimalOut . "\n");
print("numericOut: " . $numericOut . "\n");
print("floatOut: " . $floatOut . "\n");
print("realOut: " . $realOut . "\n");
if (!compareFloats($floatInput, $floatOut)) {
// Should not expect float values to match exactly
print("Expected $floatInput but got $floatOut\n");
}
if (!compareFloats($realInput, $realOut)) {
// Should not expect real values to match exactly
print("Expected $realInput but got $realOut\n");
}
print("dateOut: " . $dateOut . "\n");
print("datetimeOut: " . $datetimeOut . "\n");
print("datetime2Out: " . $datetime2Out . "\n");
@ -142,11 +159,9 @@ intOut: 2147483647
smallintOut: 32767
tinyintOut: 255
bitOut: 1
bigintOut: 9.2233720368548E\+17
decimalOut: 9223372036854\.8
bigintOut: 922337203685479936
decimalOut: (9223372036854\.8|9223372036854\.80000)
numericOut: 21474\.83647
floatOut: 9223372036\.8548
realOut: 2147\.4829101562
dateOut: 9999-12-31
datetimeOut: (9999-12-31 23:59:59\.997|Dec 31 9999 11:59PM)
datetime2Out: 9999-12-31 23:59:59\.9999999

View file

@ -42,8 +42,14 @@ function dropTable($conn, $tableName)
require_once('MsSetup.inc');
$tableName = "srv_ansitest_FR";
$locale = 'fr_FR@euro';
setlocale(LC_ALL, $locale);
$r = setlocale(LC_ALL, 'fr_FR@euro');
if (empty($r)) {
// Some platforms use a different locale name
$r = setlocale(LC_ALL, 'fr_FR.ISO8859-15');
if (empty($r)) {
die("The required French locale is not available");
}
}
$conn = sqlsrv_connect($server, $connectionOptions);
if( $conn === false ) {

View file

@ -10,7 +10,15 @@ Test various conversion functionalites for buffered queries with SQLSRV.
$violation = 'Restricted data type attribute violation';
$outOfRange = 'Numeric value out of range';
$truncation = 'Fractional truncation';
$epsilon = 0.00001;
function compareFloats($expected, $actual)
{
$epsilon = 0.00001;
$diff = abs(($actual - $expected) / $expected);
return ($diff < $epsilon);
}
function fetchAsUTF8($conn, $tableName, $inputs)
{
@ -29,10 +37,17 @@ function fetchAsUTF8($conn, $tableName, $inputs)
$f = sqlsrv_get_field($stmt, $i, SQLSRV_PHPTYPE_STRING('utf-8'));
if ($i == 0) {
if ($inputs[$i] !== hex2bin($f)) {
echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n";
var_dump(hex2bin($f));
}
} elseif ($i == 2) {
if (!compareFloats(floatval($inputs[$i]), floatval($f))) {
echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n";
var_dump($f);
}
} else {
if ($f !== $inputs[$i]) {
echo "In fetchAsUTF8 ($i): expected $inputs[$i]\n";
var_dump($f);
}
}
@ -59,15 +74,26 @@ function fetchArray($conn, $tableName, $inputs)
}
for ($i = 0; $i < count($inputs); $i++) {
$matched = true;
if ($i == 1) {
$expected = intval($inputs[$i]);
if ($results[$i] !== $expected) {
$matched = false;
}
} elseif ($i == 2) {
$expected = floatval($inputs[$i]);
if (!compareFloats($expected, $results[$i])) {
$matched = false;
}
} else {
$expected = $inputs[$i];
if ($results[$i] !== $expected) {
$matched = false;
}
}
if ($results[$i] !== $expected) {
// if ($results[$i] !== $expected) {
if (!$matched) {
echo "in fetchArray: for column $i expected $expected but got: ";
var_dump($results[$i]);
}
@ -100,9 +126,7 @@ function fetchAsFloats($conn, $tableName, $inputs)
}
} elseif ($i < 5) {
$expected = floatval($inputs[$i]);
$diff = abs(($f - $expected) / $expected);
if ($diff > $epsilon) {
if (!compareFloats($expected, $f)) {
echo "in fetchAsFloats: for column $i expected $expected but got: ";
var_dump($f);
}

View file

@ -24,7 +24,7 @@ class Product
return $this->UnitPrice." [CAD]";
}
public function report_output()
public function report_output($dummy)
{
echo "Object ID: ".$this->objID."\n";
echo "Internal Name: ".$this->name."\n";
@ -49,11 +49,20 @@ class Sample extends Product
return $this->UnitPrice ." [EUR]";
}
public function report_output()
public function report_output($unitPrice)
{
echo "ID: ".$this->objID."\n";
echo "Name: ".$this->личное_имя."\n";
echo "Unit Price: ".$this->getPrice()."\n";
// Since UnitPrice column is of type FLOAT,
// should not expect the values to match exactly
$epsilon = 0.00001;
$diff = abs(($this->UnitPrice - $unitPrice) / $unitPrice);
if ($diff > $epsilon) {
echo "Expected $unitPrice [EUR] but got ";
echo "Unit Price: ".$this->getPrice()."\n";
}
}
}
@ -74,6 +83,50 @@ function getInputData2($inputs)
'Code'=> $inputs[1]);
}
function insertInputsSimple($conn, $tableName, $data)
{
$sql = "INSERT INTO $tableName VALUES \n";
for ($i = 0; $i < count($data); $i++) {
$sql .= '(';
for ($j = 0; $j < count($data[$i]); $j++) {
if (is_null($data[$i][$j])) {
$sql .= 'NULL';
} else {
$sql .= "'" . $data[$i][$j] . "'";
}
if ($j < count($data[$i]) - 1) {
$sql .= ",";
}
}
if ($i < count($data) - 1) {
$sql .= "),\n";
} else {
$sql .= ") \n";
}
}
return sqlsrv_query($conn, $sql);
}
function insertInputsWithSQLTypes($conn, $tableName, $data, $sqlTypes)
{
$sql = "INSERT INTO $tableName VALUES
(?, ?, ?, ?, ?, ?, ?),
(?, ?, ?, ?, ?, ?, ?),
(?, ?, ?, ?, ?, ?, ?),
(?, ?, ?, ?, ?, ?, ?)";
$params = array();
for ($i = 0; $i < count($data); $i++) {
for ($j = 0; $j < count($data[$i]); $j++) {
$params2 = array($data[$i][$j], null, null, $sqlTypes[$j]);
array_push($params, $params2);
}
}
return sqlsrv_query($conn, $sql, $params);
}
require_once('MsCommon.inc');
$conn = AE\connect(array('CharacterSet'=>'UTF-8'));
@ -90,48 +143,24 @@ $columns = array(new AE\ColumnMeta('CHAR(4)', 'ID'),
new AE\ColumnMeta('VARCHAR(20)', 'Color'));
AE\createTable($conn, $tableName1, $columns);
// Insert data
// Input data for $tableName1
$data = array(array('P001', 'Pencil 2B', '102', '24', '0.24', '2016-02-01', 'Red'),
array('P002', 'Notepad', '102', '12', '3.87', '2016-02-21', Null),
array('P001', 'Mirror 2\"', '652', '3', '15.99', '2016-02-01', NULL),
array('P003', 'USB connector', '1652', '31', '9.99', '2016-02-01', NULL));
$sqlTypes = array(SQLSRV_SQLTYPE_CHAR(4),
SQLSRV_SQLTYPE_VARCHAR(128),
SQLSRV_SQLTYPE_SMALLINT,
SQLSRV_SQLTYPE_INT,
SQLSRV_SQLTYPE_FLOAT,
SQLSRV_SQLTYPE_DATETIME,
SQLSRV_SQLTYPE_VARCHAR(20));
if (AE\isColEncrypted()) {
$sql = "INSERT INTO $tableName1 VALUES
(?, ?, ?, ?, ?, ?, ?),
(?, ?, ?, ?, ?, ?, ?),
(?, ?, ?, ?, ?, ?, ?),
(?, ?, ?, ?, ?, ?, ?)";
$stmt = sqlsrv_query($conn, $sql, array(array('P001', null, null, SQLSRV_SQLTYPE_CHAR(4)),
array('Pencil 2B', null, null, SQLSRV_SQLTYPE_VARCHAR(128)),
array('102', null, null, SQLSRV_SQLTYPE_SMALLINT),
array('24', null, null, SQLSRV_SQLTYPE_INT),
array('0.24', null, null, SQLSRV_SQLTYPE_FLOAT),
array('2016-02-01', null, null, SQLSRV_SQLTYPE_DATETIME),
array('Red', null, null, SQLSRV_SQLTYPE_VARCHAR(20)),
array('P002', null, null, SQLSRV_SQLTYPE_CHAR(4)),
array('Notepad', null, null, SQLSRV_SQLTYPE_VARCHAR(128)),
array('102', null, null, SQLSRV_SQLTYPE_SMALLINT),
array('12', null, null, SQLSRV_SQLTYPE_INT),
array('3.87', null, null, SQLSRV_SQLTYPE_FLOAT),
array('2016-02-21', null, null, SQLSRV_SQLTYPE_DATETIME),
array(null, null, null, SQLSRV_SQLTYPE_VARCHAR(20)),
array('P001', null, null, SQLSRV_SQLTYPE_CHAR(4)),
array('Mirror 2\"', null, null, SQLSRV_SQLTYPE_VARCHAR(128)),
array('652', null, null, SQLSRV_SQLTYPE_SMALLINT),
array('3', null, null, SQLSRV_SQLTYPE_INT),
array('15.99', null, null, SQLSRV_SQLTYPE_FLOAT),
array('2016-02-01', null, null, SQLSRV_SQLTYPE_DATETIME),
array(null, null, null, SQLSRV_SQLTYPE_VARCHAR(20)),
array('P003', null, null, SQLSRV_SQLTYPE_CHAR(4)),
array('USB connector', null, null, SQLSRV_SQLTYPE_VARCHAR(128)),
array('1652', null, null, SQLSRV_SQLTYPE_SMALLINT),
array('31', null, null, SQLSRV_SQLTYPE_INT),
array('9.99', null, null, SQLSRV_SQLTYPE_FLOAT),
array('2016-02-01', null, null, SQLSRV_SQLTYPE_DATETIME),
array(null, null, null, SQLSRV_SQLTYPE_VARCHAR(20))));
$stmt = insertInputsWithSQLTypes($conn, $tableName1, $data, $sqlTypes);
} else {
$sql = "INSERT INTO $tableName1 VALUES
('P001', 'Pencil 2B', '102', '24', '0.24', '2016-02-01', 'Red'),
('P002', 'Notepad', '102', '12', '3.87', '2016-02-21', Null),
('P001', 'Mirror 2\"', '652', '3', '15.99', '2016-02-01', NULL),
('P003', 'USB connector', '1652', '31', '9.99', '2016-02-01', NULL)";
$stmt = sqlsrv_query($conn, $sql);
$stmt = insertInputsSimple($conn, $tableName1, $data);
}
if (!$stmt) {
fatalError("Failed to insert test data into $tableName1\n");
@ -142,7 +171,7 @@ $columns = array(new AE\ColumnMeta('CHAR(4)', 'SerialNumber'),
new AE\ColumnMeta('VARCHAR(2)', 'Code'));
AE\createTable($conn, $tableName2, $columns);
// Insert data
// Insert data for for $tableName2
if (AE\isColEncrypted()) {
$sql = "INSERT INTO $tableName2 VALUES (?, ?), (?, ?), (?, ?)";
$stmt = sqlsrv_query($conn, $sql, array(array('P001', null, null, SQLSRV_SQLTYPE_CHAR(4)),
@ -159,7 +188,7 @@ if (!$stmt) {
fatalError("Failed to insert test data into $tableName2\n");
}
// With AE enabled, we cannot do comparisons with encrypted columns
// With AE enabled (without secure enclave), do not do comparisons with encrypted columns
// Also, only forward cursor or client buffer is supported
if (AE\isColEncrypted()) {
$sql = "SELECT личное_имя, SafetyStockLevel, StockedQty, UnitPrice, Color, Code
@ -196,18 +225,19 @@ if (AE\isColEncrypted()) {
}
}
// Iterate through the result set
// Iterate through the result set - expect only the first and last sets of input $data
// $product is an instance of the Product class
$i=0;
$hasNext = true;
$expected = array(getInputData1($data[0]), getInputData1($data[count($data)-1]));
$i = 0;
$hasNext = true;
while ($hasNext) {
$sample = sqlsrv_fetch_object($stmt, "Sample", array($i+1000), SQLSRV_SCROLL_ABSOLUTE, $i);
if (!$sample) {
$hasNext = false;
} else {
$sample->report_output();
$sample->report_output($expected[$i]['UnitPrice']);
$i++;
}
}
@ -225,8 +255,6 @@ print "Done";
--EXPECT--
ID: 1000
Name: Pencil 2B
Unit Price: 0.24 [EUR]
ID: 1001
Name: USB connector
Unit Price: 9.99 [EUR]
Done