Updated checks to distinguish smalldatetime, datetime and datetime2 fields (#1175)
This commit is contained in:
parent
9365fc5201
commit
284aca85ce
|
@ -746,20 +746,41 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
|
||||||
ind_ptr = SQL_NULL_DATA;
|
ind_ptr = SQL_NULL_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
core::SQLBindParameter( stmt, param_num + 1, direction,
|
|
||||||
c_type, sql_type, column_size, decimal_digits, buffer, buffer_len, &ind_ptr );
|
|
||||||
|
|
||||||
// When calling SQLDescribeParam() on a parameter targeting a Datetime column, the return values for ParameterType, ColumnSize and DecimalDigits are SQL_TYPE_TIMESTAMP, 23, and 3 respectively.
|
// When calling SQLDescribeParam() on a parameter targeting a Datetime column, the return values for ParameterType, ColumnSize and DecimalDigits are SQL_TYPE_TIMESTAMP, 23, and 3 respectively.
|
||||||
// For a parameter targeting a SmallDatetime column, the return values are SQL_TYPE_TIMESTAMP, 16, and 0. Inputting these values into SQLBindParameter() results in Operand type clash error.
|
// For a parameter targeting a SmallDatetime column, the return values are SQL_TYPE_TIMESTAMP, 16, and 0. Inputting these values into SQLBindParameter() results in Operand type clash error.
|
||||||
// This is because SQL_TYPE_TIMESTAMP corresponds to Datetime2 by default, and conversion of Datetime2 to Datetime and conversion of Datetime2 to SmallDatatime is not allowed with encrypted columns.
|
// This is because SQL_TYPE_TIMESTAMP corresponds to Datetime2 by default, and conversion of Datetime2 to Datetime and conversion of Datetime2 to SmallDatatime is not allowed with encrypted columns.
|
||||||
// To fix the conversion problem, set the SQL_CA_SS_SERVER_TYPE field of the parameter to SQL_SS_TYPE_DATETIME and SQL_SS_TYPE_SMALLDATETIME respectively for a Datetime and Smalldatetime column.
|
// To fix the conversion problem, set the SQL_CA_SS_SERVER_TYPE field of the parameter to SQL_SS_TYPE_DATETIME and SQL_SS_TYPE_SMALLDATETIME respectively for a Datetime and Smalldatetime column.
|
||||||
|
// Check SQL_DESC_OCTET_LENGTH of the implementation parameter descriptor (IPD) to distinguish Smalldatetime or Datetime fields from Datetime2(0) or Datetime2(3) fields, as described in
|
||||||
|
// https://docs.microsoft.com/sql/relational-databases/native-client-odbc-date-time/metadata-parameter-and-result
|
||||||
|
// This has to be done before SQLBindParameter()
|
||||||
if (stmt->conn->ce_option.enabled && sql_type == SQL_TYPE_TIMESTAMP) {
|
if (stmt->conn->ce_option.enabled && sql_type == SQL_TYPE_TIMESTAMP) {
|
||||||
if (decimal_digits == 3)
|
if (decimal_digits == 0 || decimal_digits == 3) {
|
||||||
core::SQLSetDescField(stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, SQL_IS_INTEGER);
|
SQLHDESC hIpd = NULL;
|
||||||
else if (decimal_digits == 0)
|
core::SQLGetStmtAttr(stmt, SQL_ATTR_IMP_PARAM_DESC, &hIpd, 0, 0);
|
||||||
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, SQL_IS_INTEGER );
|
if (hIpd != NULL) {
|
||||||
|
SQLULEN octetLength = 0;
|
||||||
|
SQLINTEGER dummy = 0;
|
||||||
|
|
||||||
|
SQLRETURN r = ::SQLGetDescField(hIpd, param_num + 1, SQL_DESC_OCTET_LENGTH, (SQLPOINTER)&octetLength, 0, &dummy);
|
||||||
|
if (SQL_SUCCEEDED(r)) {
|
||||||
|
// The octet length for datetime2 is 16 but no action required
|
||||||
|
if (octetLength == 8) {
|
||||||
|
r = ::SQLSetDescField(hIpd, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, SQL_IS_INTEGER);
|
||||||
|
} else if (octetLength == 4) {
|
||||||
|
r = ::SQLSetDescField(hIpd, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, SQL_IS_INTEGER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CHECK_SQL_ERROR_OR_WARNING(r, stmt) {
|
||||||
|
throw core::CoreException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core::SQLBindParameter( stmt, param_num + 1, direction,
|
||||||
|
c_type, sql_type, column_size, decimal_digits, buffer, buffer_len, &ind_ptr );
|
||||||
|
|
||||||
|
}
|
||||||
catch( core::CoreException& e ){
|
catch( core::CoreException& e ){
|
||||||
stmt->free_param_data();
|
stmt->free_param_data();
|
||||||
SQLFreeStmt( stmt->handle(), SQL_RESET_PARAMS );
|
SQLFreeStmt( stmt->handle(), SQL_RESET_PARAMS );
|
||||||
|
|
|
@ -31,7 +31,7 @@ function compareDate($dtout, $dtin, $dataType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$dataTypes = array("datetime2", "datetimeoffset", "time");
|
$dataTypes = array("datetime2", "datetimeoffset", "time");
|
||||||
$precisions = array(/*0,*/ 1, 2, 4, 7);
|
$precisions = array(0, 1, 2, 4, 7);
|
||||||
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
|
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
|
||||||
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
|
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
|
||||||
"time" => array("00:00:00", "23:59:59"));
|
"time" => array("00:00:00", "23:59:59"));
|
||||||
|
@ -101,6 +101,10 @@ try {
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
|
Testing datetime2(0):
|
||||||
|
****Retrieving datetime2(0) as PDO::PARAM_STR is supported****
|
||||||
|
****Retrieving datetime2(0) as PDO::PARAM_LOB is supported****
|
||||||
|
|
||||||
Testing datetime2(1):
|
Testing datetime2(1):
|
||||||
****Retrieving datetime2(1) as PDO::PARAM_STR is supported****
|
****Retrieving datetime2(1) as PDO::PARAM_STR is supported****
|
||||||
****Retrieving datetime2(1) as PDO::PARAM_LOB is supported****
|
****Retrieving datetime2(1) as PDO::PARAM_LOB is supported****
|
||||||
|
@ -117,6 +121,10 @@ Testing datetime2(7):
|
||||||
****Retrieving datetime2(7) as PDO::PARAM_STR is supported****
|
****Retrieving datetime2(7) as PDO::PARAM_STR is supported****
|
||||||
****Retrieving datetime2(7) as PDO::PARAM_LOB is supported****
|
****Retrieving datetime2(7) as PDO::PARAM_LOB is supported****
|
||||||
|
|
||||||
|
Testing datetimeoffset(0):
|
||||||
|
****Retrieving datetimeoffset(0) as PDO::PARAM_STR is supported****
|
||||||
|
****Retrieving datetimeoffset(0) as PDO::PARAM_LOB is supported****
|
||||||
|
|
||||||
Testing datetimeoffset(1):
|
Testing datetimeoffset(1):
|
||||||
****Retrieving datetimeoffset(1) as PDO::PARAM_STR is supported****
|
****Retrieving datetimeoffset(1) as PDO::PARAM_STR is supported****
|
||||||
****Retrieving datetimeoffset(1) as PDO::PARAM_LOB is supported****
|
****Retrieving datetimeoffset(1) as PDO::PARAM_LOB is supported****
|
||||||
|
@ -133,6 +141,10 @@ Testing datetimeoffset(7):
|
||||||
****Retrieving datetimeoffset(7) as PDO::PARAM_STR is supported****
|
****Retrieving datetimeoffset(7) as PDO::PARAM_STR is supported****
|
||||||
****Retrieving datetimeoffset(7) as PDO::PARAM_LOB is supported****
|
****Retrieving datetimeoffset(7) as PDO::PARAM_LOB is supported****
|
||||||
|
|
||||||
|
Testing time(0):
|
||||||
|
****Retrieving time(0) as PDO::PARAM_STR is supported****
|
||||||
|
****Retrieving time(0) as PDO::PARAM_LOB is supported****
|
||||||
|
|
||||||
Testing time(1):
|
Testing time(1):
|
||||||
****Retrieving time(1) as PDO::PARAM_STR is supported****
|
****Retrieving time(1) as PDO::PARAM_STR is supported****
|
||||||
****Retrieving time(1) as PDO::PARAM_LOB is supported****
|
****Retrieving time(1) as PDO::PARAM_LOB is supported****
|
||||||
|
|
|
@ -63,7 +63,7 @@ try {
|
||||||
dropTable($conn, $tableName);
|
dropTable($conn, $tableName);
|
||||||
|
|
||||||
// Define the column definitions
|
// Define the column definitions
|
||||||
$columns = array('c1' => 'smalldatetime', 'c2' => 'datetime', 'c3' => 'datetime2(4)');
|
$columns = array('c1' => 'smalldatetime', 'c2' => 'datetime', 'c3' => 'datetime2(0)', 'c4' => 'datetime2(3)');
|
||||||
|
|
||||||
if ($qualified) {
|
if ($qualified) {
|
||||||
$tsql = createTableEncryptedQuery($conn, $tableName, $columns);
|
$tsql = createTableEncryptedQuery($conn, $tableName, $columns);
|
||||||
|
@ -75,14 +75,16 @@ try {
|
||||||
// Insert values that cause errors
|
// Insert values that cause errors
|
||||||
$val1 = '9999-12-31 23:59:59';
|
$val1 = '9999-12-31 23:59:59';
|
||||||
$val2 = null;
|
$val2 = null;
|
||||||
$val3 = '9999-12-31 23:59:59.9999';
|
$val3 = null;
|
||||||
|
$val4 = '9999-12-31 23:59:59.999';
|
||||||
|
|
||||||
$tsql = "INSERT INTO $tableName (c1, c2, c3) VALUES (?,?,?)";
|
$tsql = "INSERT INTO $tableName (c1, c2, c3, c4) VALUES (?,?,?,?)";
|
||||||
$stmt = $conn->prepare($tsql);
|
$stmt = $conn->prepare($tsql);
|
||||||
|
|
||||||
$stmt->bindParam(1, $val1);
|
$stmt->bindParam(1, $val1);
|
||||||
$stmt->bindParam(2, $val2);
|
$stmt->bindParam(2, $val2);
|
||||||
$stmt->bindParam(3, $val3);
|
$stmt->bindParam(3, $val3);
|
||||||
|
$stmt->bindParam(4, $val4);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
@ -97,6 +99,7 @@ try {
|
||||||
// These values should work
|
// These values should work
|
||||||
$val1 = '2021-11-03 11:49:00';
|
$val1 = '2021-11-03 11:49:00';
|
||||||
$val2 = '2015-10-23 07:03:00.000';
|
$val2 = '2015-10-23 07:03:00.000';
|
||||||
|
$val3 = '0001-01-01 01:01:01';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
@ -128,12 +131,14 @@ echo "Done\n";
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
array(3) {
|
array(4) {
|
||||||
[0]=>
|
[0]=>
|
||||||
string(19) "2021-11-03 11:49:00"
|
string(19) "2021-11-03 11:49:00"
|
||||||
[1]=>
|
[1]=>
|
||||||
string(23) "2015-10-23 07:03:00.000"
|
string(23) "2015-10-23 07:03:00.000"
|
||||||
[2]=>
|
[2]=>
|
||||||
string(24) "9999-12-31 23:59:59.9999"
|
string(19) "0001-01-01 01:01:01"
|
||||||
|
[3]=>
|
||||||
|
string(23) "9999-12-31 23:59:59.999"
|
||||||
}
|
}
|
||||||
Done
|
Done
|
|
@ -29,7 +29,7 @@ function compareDate($dtout, $dtin, $dataType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$dataTypes = array("datetime2", "datetimeoffset", "time");
|
$dataTypes = array("datetime2", "datetimeoffset", "time");
|
||||||
$precisions = array(/*0,*/ 1, 2, 4, 7);
|
$precisions = array(0, 1, 2, 4, 7);
|
||||||
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
|
$inputValuesInit = array("datetime2" => array("0001-01-01 00:00:00", "9999-12-31 23:59:59"),
|
||||||
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
|
"datetimeoffset" => array("0001-01-01 00:00:00 -14:00", "9999-12-31 23:59:59 +14:00"),
|
||||||
"time" => array("00:00:00", "23:59:59"));
|
"time" => array("00:00:00", "23:59:59"));
|
||||||
|
@ -102,6 +102,12 @@ try {
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
|
Testing datetime2(0):
|
||||||
|
****Conversion from PDO::PARAM_BOOL to datetime2(0) is supported****
|
||||||
|
****Conversion from PDO::PARAM_INT to datetime2(0) is supported****
|
||||||
|
****Conversion from PDO::PARAM_STR to datetime2(0) is supported****
|
||||||
|
****Conversion from PDO::PARAM_LOB to datetime2(0) is supported****
|
||||||
|
|
||||||
Testing datetime2(1):
|
Testing datetime2(1):
|
||||||
****Conversion from PDO::PARAM_BOOL to datetime2(1) is supported****
|
****Conversion from PDO::PARAM_BOOL to datetime2(1) is supported****
|
||||||
****Conversion from PDO::PARAM_INT to datetime2(1) is supported****
|
****Conversion from PDO::PARAM_INT to datetime2(1) is supported****
|
||||||
|
@ -126,6 +132,12 @@ Testing datetime2(7):
|
||||||
****Conversion from PDO::PARAM_STR to datetime2(7) is supported****
|
****Conversion from PDO::PARAM_STR to datetime2(7) is supported****
|
||||||
****Conversion from PDO::PARAM_LOB to datetime2(7) is supported****
|
****Conversion from PDO::PARAM_LOB to datetime2(7) is supported****
|
||||||
|
|
||||||
|
Testing datetimeoffset(0):
|
||||||
|
****Conversion from PDO::PARAM_BOOL to datetimeoffset(0) is supported****
|
||||||
|
****Conversion from PDO::PARAM_INT to datetimeoffset(0) is supported****
|
||||||
|
****Conversion from PDO::PARAM_STR to datetimeoffset(0) is supported****
|
||||||
|
****Conversion from PDO::PARAM_LOB to datetimeoffset(0) is supported****
|
||||||
|
|
||||||
Testing datetimeoffset(1):
|
Testing datetimeoffset(1):
|
||||||
****Conversion from PDO::PARAM_BOOL to datetimeoffset(1) is supported****
|
****Conversion from PDO::PARAM_BOOL to datetimeoffset(1) is supported****
|
||||||
****Conversion from PDO::PARAM_INT to datetimeoffset(1) is supported****
|
****Conversion from PDO::PARAM_INT to datetimeoffset(1) is supported****
|
||||||
|
@ -150,6 +162,12 @@ Testing datetimeoffset(7):
|
||||||
****Conversion from PDO::PARAM_STR to datetimeoffset(7) is supported****
|
****Conversion from PDO::PARAM_STR to datetimeoffset(7) is supported****
|
||||||
****Conversion from PDO::PARAM_LOB to datetimeoffset(7) is supported****
|
****Conversion from PDO::PARAM_LOB to datetimeoffset(7) is supported****
|
||||||
|
|
||||||
|
Testing time(0):
|
||||||
|
****Conversion from PDO::PARAM_BOOL to time(0) is supported****
|
||||||
|
****Conversion from PDO::PARAM_INT to time(0) is supported****
|
||||||
|
****Conversion from PDO::PARAM_STR to time(0) is supported****
|
||||||
|
****Conversion from PDO::PARAM_LOB to time(0) is supported****
|
||||||
|
|
||||||
Testing time(1):
|
Testing time(1):
|
||||||
****Conversion from PDO::PARAM_BOOL to time(1) is supported****
|
****Conversion from PDO::PARAM_BOOL to time(1) is supported****
|
||||||
****Conversion from PDO::PARAM_INT to time(1) is supported****
|
****Conversion from PDO::PARAM_INT to time(1) is supported****
|
||||||
|
|
|
@ -65,7 +65,7 @@ Verify that inserting into smalldatetime column might trigger "Datetime field ov
|
||||||
dropTable($conn, $tableName);
|
dropTable($conn, $tableName);
|
||||||
|
|
||||||
// Define the column definitions
|
// Define the column definitions
|
||||||
$columns = array('c1' => 'smalldatetime', 'c2' => 'datetime', 'c3' => 'datetime2(4)');
|
$columns = array('c1' => 'smalldatetime', 'c2' => 'datetime', 'c3' => 'datetime2(0)', 'c4' => 'datetime2(3)');
|
||||||
|
|
||||||
if ($qualified) {
|
if ($qualified) {
|
||||||
$tsql = createTableEncryptedQuery($conn, $tableName, $columns);
|
$tsql = createTableEncryptedQuery($conn, $tableName, $columns);
|
||||||
|
@ -81,10 +81,11 @@ Verify that inserting into smalldatetime column might trigger "Datetime field ov
|
||||||
// Insert values that cause errors
|
// Insert values that cause errors
|
||||||
$val1 = '9999-12-31 23:59:59';
|
$val1 = '9999-12-31 23:59:59';
|
||||||
$val2 = null;
|
$val2 = null;
|
||||||
$val3 = '9999-12-31 23:59:59.9999';
|
$val3 = null;
|
||||||
|
$val4 = '9999-12-31 23:59:59.999';
|
||||||
|
|
||||||
$tsql = "INSERT INTO $tableName (c1, c2, c3) VALUES (?,?,?)";
|
$tsql = "INSERT INTO $tableName (c1, c2, c3, c4) VALUES (?,?,?,?)";
|
||||||
$params = array($val1, $val2, $val3);
|
$params = array($val1, $val2, $val3, $val4);
|
||||||
|
|
||||||
$stmt = sqlsrv_prepare($conn, $tsql, $params);
|
$stmt = sqlsrv_prepare($conn, $tsql, $params);
|
||||||
if (!$stmt) {
|
if (!$stmt) {
|
||||||
|
@ -105,8 +106,9 @@ Verify that inserting into smalldatetime column might trigger "Datetime field ov
|
||||||
// These values should work
|
// These values should work
|
||||||
$val1 = '2021-11-03 11:49:00';
|
$val1 = '2021-11-03 11:49:00';
|
||||||
$val2 = '2015-10-23 07:03:00.000';
|
$val2 = '2015-10-23 07:03:00.000';
|
||||||
|
$val3 = '0001-01-01 01:01:01';
|
||||||
|
|
||||||
$params = array($val1, $val2, $val3);
|
$params = array($val1, $val2, $val3, $val4);
|
||||||
$stmt = sqlsrv_prepare($conn, $tsql, $params);
|
$stmt = sqlsrv_prepare($conn, $tsql, $params);
|
||||||
if (!$stmt) {
|
if (!$stmt) {
|
||||||
fatalError("Failed to prepare insert statement");
|
fatalError("Failed to prepare insert statement");
|
||||||
|
@ -138,12 +140,14 @@ Verify that inserting into smalldatetime column might trigger "Datetime field ov
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
array(3) {
|
array(4) {
|
||||||
["c1"]=>
|
["c1"]=>
|
||||||
string(19) "2021-11-03 11:49:00"
|
string(19) "2021-11-03 11:49:00"
|
||||||
["c2"]=>
|
["c2"]=>
|
||||||
string(23) "2015-10-23 07:03:00.000"
|
string(23) "2015-10-23 07:03:00.000"
|
||||||
["c3"]=>
|
["c3"]=>
|
||||||
string(24) "9999-12-31 23:59:59.9999"
|
string(19) "0001-01-01 01:01:01"
|
||||||
|
["c4"]=>
|
||||||
|
string(23) "9999-12-31 23:59:59.999"
|
||||||
}
|
}
|
||||||
Done
|
Done
|
||||||
|
|
Loading…
Reference in a new issue