|
1 | 1 | --TEST--
|
2 | 2 | Test for inserting and retrieving encrypted data of datetime types
|
3 | 3 | --DESCRIPTION--
|
4 |
| -Bind output params using sqlsrv_prepare with all sql_type |
| 4 | +Bind output/inout params using sqlsrv_prepare with all sql_type |
5 | 5 | --SKIPIF--
|
6 | 6 | <?php require('skipif_versions_old.inc'); ?>
|
7 | 7 | --FILE--
|
8 |
| -<?php |
9 |
| -require_once('MsCommon.inc'); |
10 |
| -require_once('AEData.inc'); |
11 |
| - |
12 |
| -date_default_timezone_set("Canada/Pacific"); |
13 |
| -$dataTypes = array("date", "datetime", "datetime2", "smalldatetime", "time", "datetimeoffset"); |
14 |
| -$directions = array("SQLSRV_PARAM_OUT", "SQLSRV_PARAM_INOUT"); |
15 |
| - |
16 |
| -// this is a list of implicit datatype conversion that SQL Server allows (https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine) |
17 |
| -$compatList = array("date" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
18 |
| - "datetime" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
19 |
| - "datetime2" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
20 |
| - "smalldatetime" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
21 |
| - "time" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
22 |
| - "datetimeoffset" => array("SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIMEOFFSET") ); |
23 |
| - |
24 |
| -$conn = AE\connect(); |
25 |
| - |
26 |
| -foreach ($dataTypes as $dataType) { |
27 |
| - echo "\nTesting $dataType:\n"; |
28 |
| - $success = true; |
29 |
| - |
30 |
| - // create table |
31 |
| - $tbname = GetTempTableName("", false); |
32 |
| - $colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false)); |
33 |
| - AE\createTable($conn, $tbname, $colMetaArr); |
34 |
| - |
35 |
| - if (AE\isColEncrypted()) { |
36 |
| - // Create a Store Procedure |
37 |
| - $spname = 'selectAllColumns'; |
38 |
| - createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"); |
39 |
| - } |
40 |
| - |
| 8 | +<?php |
| 9 | +require_once('MsCommon.inc'); |
| 10 | +require_once('AEData.inc'); |
| 11 | + |
| 12 | +date_default_timezone_set("Canada/Pacific"); |
| 13 | +$dataTypes = array("date", "datetime", "datetime2", "smalldatetime", "time", "datetimeoffset"); |
| 14 | + |
| 15 | +$directions = array(SQLSRV_PARAM_OUT, SQLSRV_PARAM_INOUT); |
| 16 | + |
| 17 | +// this is a list of implicit datatype conversion that SQL Server allows (https://docs.microsoft.com/en-us/sql/t-sql/data-types/data-type-conversion-database-engine) |
| 18 | +$compatList = array("date" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
| 19 | + "datetime" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
| 20 | + "datetime2" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
| 21 | + "smalldatetime" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_DATE", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
| 22 | + "time" => array( "SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIME", "SQLSRV_SQLTYPE_SMALLDATETIME", "SQLSRV_SQLTYPE_TIME", "SQLSRV_SQLTYPE_DATETIMEOFFSET", "SQLSRV_SQLTYPE_DATETIME2"), |
| 23 | + "datetimeoffset" => array("SQLSRV_SQLTYPE_CHAR", "SQLSRV_SQLTYPE_VARCHAR", "SQLSRV_SQLTYPE_NCHAR", "SQLSRV_SQLTYPE_NVARCHAR", "SQLSRV_SQLTYPE_DATETIMEOFFSET") ); |
| 24 | + |
| 25 | +function testOutputParam($conn, $spname, $direction, $dataType, $sqlType) |
| 26 | +{ |
| 27 | + // The driver does not support these types as output params, simply return |
| 28 | + if (isDateTimeType($sqlType) || isLOBType($sqlType)) { |
| 29 | + return true; |
| 30 | + } |
| 31 | + |
| 32 | + global $compatList; |
| 33 | + |
| 34 | + $sqlTypeConstant = get_sqlType_constant($sqlType); |
| 35 | + |
| 36 | + // Call store procedure |
| 37 | + $outSql = AE\getCallProcSqlPlaceholders($spname, 2); |
| 38 | + |
| 39 | + // Set these to NULL such that the PHP type of each output parameter is inferred |
| 40 | + // from the SQLSRV_SQLTYPE_* constant |
| 41 | + $c_detOut = null; |
| 42 | + $c_randOut = null; |
| 43 | + $stmt = sqlsrv_prepare( |
| 44 | + $conn, |
| 45 | + $outSql, |
| 46 | + array(array( &$c_detOut, $direction, null, $sqlTypeConstant), |
| 47 | + array(&$c_randOut, $direction, null, $sqlTypeConstant )) |
| 48 | + ); |
| 49 | + if (!$stmt) { |
| 50 | + die(print_r(sqlsrv_errors(), true)); |
| 51 | + } |
| 52 | + sqlsrv_execute($stmt); |
| 53 | + |
| 54 | + $success = false; |
| 55 | + $errors = sqlsrv_errors(); |
| 56 | + if (AE\IsDataEncrypted()) { |
| 57 | + // With data encrypted, errors are totally expected |
| 58 | + if (empty($errors)) { |
| 59 | + echo "Encrypted data: $dataType should NOT be compatible with $sqlType\n"; |
| 60 | + } else { |
| 61 | + // This should return 22018, the SQLSTATE for any incompatible conversion, |
| 62 | + // except the XML type |
| 63 | + $success = ($errors[0]['SQLSTATE'] === '22018'); |
| 64 | + if (!$success) { |
| 65 | + if ($sqlType === 'SQLSRV_SQLTYPE_XML') { |
| 66 | + $success = ($errors[0]['SQLSTATE'] === '42000'); |
| 67 | + } else { |
| 68 | + echo "Encrypted data: unexpected errors with SQL type: $sqlType\n"; |
| 69 | + } |
| 70 | + } |
| 71 | + } |
| 72 | + } else { |
| 73 | + $compatible = isCompatible($compatList, $dataType, $sqlType); |
| 74 | + if ($compatible) { |
| 75 | + if (!empty($errors)) { |
| 76 | + echo "$dataType should be compatible with $sqlType.\n"; |
| 77 | + } else { |
| 78 | + $success = true; |
| 79 | + } |
| 80 | + } else { |
| 81 | + $implicitConv = 'Implicit conversion from data type '; |
| 82 | + |
| 83 | + // 22018 is the SQLSTATE for any incompatible conversion errors |
| 84 | + if ($errors[0]['SQLSTATE'] === '22018') { |
| 85 | + $success = true; |
| 86 | + } elseif (strpos($errors[0]['message'], $implicitConv) !== false) { |
| 87 | + $success = true; |
| 88 | + } else { |
| 89 | + echo "Failed with SQL type: $sqlType\n"; |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + return $success; |
| 94 | +} |
| 95 | + |
| 96 | +//////////////////////////////////////////////////////////////////////////////////////// |
| 97 | + |
| 98 | +$conn = AE\connect(); |
| 99 | + |
| 100 | +foreach ($dataTypes as $dataType) { |
| 101 | + echo "\nTesting $dataType:\n"; |
| 102 | + $success = true; |
| 103 | + |
| 104 | + // create table |
| 105 | + $tbname = GetTempTableName("", false); |
| 106 | + $colMetaArr = array(new AE\ColumnMeta($dataType, "c_det"), new AE\ColumnMeta($dataType, "c_rand", null, false)); |
| 107 | + AE\createTable($conn, $tbname, $colMetaArr); |
| 108 | + |
| 109 | + // Create a Store Procedure |
| 110 | + $spname = 'selectAllColumns'; |
| 111 | + createProc($conn, $spname, "@c_det $dataType OUTPUT, @c_rand $dataType OUTPUT", "SELECT @c_det = c_det, @c_rand = c_rand FROM $tbname"); |
| 112 | + |
41 | 113 | // insert a row
|
| 114 | + // Take the second and third entres (some edge cases) from the various |
| 115 | + // $[$dataType]_params in AEData.inc |
| 116 | + // e.g. with $dataType = 'date', use $date_params[1] and $date_params[2] |
| 117 | + // to form an array, namely ["0001-01-01", "9999-12-31"] |
42 | 118 | $inputValues = array_slice(${explode("(", $dataType)[0] . "_params"}, 1, 2);
|
43 |
| - $r; |
44 |
| - $stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r); |
45 |
| - if ($r === false) { |
46 |
| - is_incompatible_types_error($dataType, "default type"); |
47 |
| - } |
48 |
| - |
49 |
| - foreach($directions as $direction) { |
50 |
| - echo "Testing as $direction:\n"; |
51 |
| - |
52 |
| - // test each SQLSRV_SQLTYPE_ constants |
53 |
| - foreach ($sqlTypes as $sqlType) { |
54 |
| - if (!AE\isColEncrypted()) { |
55 |
| - $isCompatible = false; |
56 |
| - foreach ($compatList[$dataType] as $compatType) { |
57 |
| - if (stripos($compatType, $sqlType) !== false) { |
58 |
| - $isCompatible = true; |
59 |
| - } |
60 |
| - } |
61 |
| - // 22018 is the SQLSTATE for any incompatible conversion errors |
62 |
| - $errors = sqlsrv_errors(); |
63 |
| - if (!empty($errors) && $isCompatible && $errors[0]['SQLSTATE'] == 22018) { |
64 |
| - echo "$sqlType should be compatible with $dataType\n"; |
65 |
| - $success = false; |
66 |
| - } |
67 |
| - } else { |
68 |
| - // skip unsupported datetime types |
69 |
| - if (!isDateTimeType($sqlType)) { |
70 |
| - $sqlTypeConstant = get_sqlType_constant($sqlType); |
71 |
| - |
72 |
| - // Call store procedure |
73 |
| - $outSql = AE\getCallProcSqlPlaceholders($spname, 2); |
74 |
| - $c_detOut = ''; |
75 |
| - $c_randOut = ''; |
76 |
| - $stmt = sqlsrv_prepare( $conn, $outSql, |
77 |
| - array(array( &$c_detOut, SQLSRV_PARAM_OUT, null, $sqlTypeConstant), |
78 |
| - array(&$c_randOut, SQLSRV_PARAM_OUT, null, $sqlTypeConstant ))); |
79 |
| - if (!$stmt) { |
80 |
| - die(print_r(sqlsrv_errors(), true)); |
81 |
| - } |
82 |
| - sqlsrv_execute($stmt); |
83 |
| - $errors = sqlsrv_errors(); |
84 |
| - if (empty($errors) && AE\IsDataEncrypted()) { |
85 |
| - // SQLSRV_PHPTYPE_DATETIME not supported |
86 |
| - echo "$dataType should not be compatible with any datetime type.\n"; |
87 |
| - $success = false; |
88 |
| - } |
89 |
| - } |
90 |
| - } |
91 |
| - } |
92 |
| - } |
93 |
| - |
94 |
| - // cleanup |
95 |
| - sqlsrv_free_stmt($stmt); |
96 |
| - sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); |
97 |
| - |
98 |
| - if ($success) { |
99 |
| - echo "Test successfully done.\n"; |
100 |
| - } |
101 |
| - |
102 |
| - if (AE\isColEncrypted()) { |
103 |
| - dropProc($conn, $spname); |
104 |
| - } |
105 |
| - dropTable($conn, $tbname); |
106 |
| -} |
107 |
| - |
108 |
| -sqlsrv_close($conn); |
| 119 | + $r; |
| 120 | + $stmt = AE\insertRow($conn, $tbname, array( $colMetaArr[0]->colName => $inputValues[0], $colMetaArr[1]->colName => $inputValues[1] ), $r); |
| 121 | + if ($r === false) { |
| 122 | + fatalError("Failed to insert data of type $dataType\n"); |
| 123 | + } |
| 124 | + |
| 125 | + foreach ($directions as $direction) { |
| 126 | + $dir = ($direction == SQLSRV_PARAM_OUT) ? 'SQLSRV_PARAM_OUT' : 'SQLSRV_PARAM_INOUT'; |
| 127 | + echo "Testing as $dir:\n"; |
| 128 | + |
| 129 | + // test each SQLSRV_SQLTYPE_* constants |
| 130 | + foreach ($sqlTypes as $sqlType) { |
| 131 | + $success = testOutputParam($conn, $spname, $direction, $dataType, $sqlType); |
| 132 | + if (!$success) { |
| 133 | + // No point to continue looping |
| 134 | + echo("Test failed: $dataType as $sqlType\n"); |
| 135 | + die(print_r(sqlsrv_errors(), true)); |
| 136 | + } |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + // cleanup |
| 141 | + sqlsrv_free_stmt($stmt); |
| 142 | + sqlsrv_query($conn, "TRUNCATE TABLE $tbname"); |
| 143 | + |
| 144 | + dropProc($conn, $spname); |
| 145 | + if ($success) { |
| 146 | + echo "Test successfully done.\n"; |
| 147 | + } |
| 148 | + dropTable($conn, $tbname); |
| 149 | +} |
| 150 | + |
| 151 | +sqlsrv_close($conn); |
109 | 152 | ?>
|
110 | 153 | --EXPECT--
|
111 | 154 |
|
|
0 commit comments