Updated checks to distinguish smalldatetime, datetime and datetime2 fields (#1175)
This commit is contained in:
parent
9365fc5201
commit
284aca85ce
|
@ -746,19 +746,40 @@ void core_sqlsrv_bind_param( _Inout_ sqlsrv_stmt* stmt, _In_ SQLUSMALLINT param_
|
|||
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.
|
||||
// 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.
|
||||
// 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 (decimal_digits == 3)
|
||||
core::SQLSetDescField(stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_DATETIME, SQL_IS_INTEGER);
|
||||
else if (decimal_digits == 0)
|
||||
core::SQLSetDescField( stmt, param_num + 1, SQL_CA_SS_SERVER_TYPE, (SQLPOINTER)SQL_SS_TYPE_SMALLDATETIME, SQL_IS_INTEGER );
|
||||
if (decimal_digits == 0 || decimal_digits == 3) {
|
||||
SQLHDESC hIpd = NULL;
|
||||
core::SQLGetStmtAttr(stmt, SQL_ATTR_IMP_PARAM_DESC, &hIpd, 0, 0);
|
||||
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 ){
|
||||
stmt->free_param_data();
|
||||
|
|
|
@ -31,7 +31,7 @@ function compareDate($dtout, $dtin, $dataType) {
|
|||
}
|
||||
|
||||
$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"),
|
||||
"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"));
|
||||
|
@ -101,6 +101,10 @@ try {
|
|||
}
|
||||
?>
|
||||
--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):
|
||||
****Retrieving datetime2(1) as PDO::PARAM_STR 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_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):
|
||||
****Retrieving datetimeoffset(1) as PDO::PARAM_STR 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_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):
|
||||
****Retrieving time(1) as PDO::PARAM_STR is supported****
|
||||
****Retrieving time(1) as PDO::PARAM_LOB is supported****
|
||||
|
|
|
@ -63,7 +63,7 @@ try {
|
|||
dropTable($conn, $tableName);
|
||||
|
||||
// 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) {
|
||||
$tsql = createTableEncryptedQuery($conn, $tableName, $columns);
|
||||
|
@ -75,14 +75,16 @@ try {
|
|||
// Insert values that cause errors
|
||||
$val1 = '9999-12-31 23:59:59';
|
||||
$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->bindParam(1, $val1);
|
||||
$stmt->bindParam(2, $val2);
|
||||
$stmt->bindParam(3, $val3);
|
||||
$stmt->bindParam(4, $val4);
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
|
@ -97,6 +99,7 @@ try {
|
|||
// These values should work
|
||||
$val1 = '2021-11-03 11:49:00';
|
||||
$val2 = '2015-10-23 07:03:00.000';
|
||||
$val3 = '0001-01-01 01:01:01';
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
|
@ -128,12 +131,14 @@ echo "Done\n";
|
|||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(3) {
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(19) "2021-11-03 11:49:00"
|
||||
[1]=>
|
||||
string(23) "2015-10-23 07:03:00.000"
|
||||
[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
|
|
@ -29,7 +29,7 @@ function compareDate($dtout, $dtin, $dataType) {
|
|||
}
|
||||
|
||||
$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"),
|
||||
"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"));
|
||||
|
@ -102,6 +102,12 @@ try {
|
|||
}
|
||||
?>
|
||||
--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):
|
||||
****Conversion from PDO::PARAM_BOOL 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_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):
|
||||
****Conversion from PDO::PARAM_BOOL 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_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):
|
||||
****Conversion from PDO::PARAM_BOOL 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);
|
||||
|
||||
// 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) {
|
||||
$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
|
||||
$val1 = '9999-12-31 23:59:59';
|
||||
$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 (?,?,?)";
|
||||
$params = array($val1, $val2, $val3);
|
||||
$tsql = "INSERT INTO $tableName (c1, c2, c3, c4) VALUES (?,?,?,?)";
|
||||
$params = array($val1, $val2, $val3, $val4);
|
||||
|
||||
$stmt = sqlsrv_prepare($conn, $tsql, $params);
|
||||
if (!$stmt) {
|
||||
|
@ -105,8 +106,9 @@ Verify that inserting into smalldatetime column might trigger "Datetime field ov
|
|||
// These values should work
|
||||
$val1 = '2021-11-03 11:49:00';
|
||||
$val2 = '2015-10-23 07:03:00.000';
|
||||
|
||||
$params = array($val1, $val2, $val3);
|
||||
$val3 = '0001-01-01 01:01:01';
|
||||
|
||||
$params = array($val1, $val2, $val3, $val4);
|
||||
$stmt = sqlsrv_prepare($conn, $tsql, $params);
|
||||
if (!$stmt) {
|
||||
fatalError("Failed to prepare insert statement");
|
||||
|
@ -138,12 +140,14 @@ Verify that inserting into smalldatetime column might trigger "Datetime field ov
|
|||
|
||||
?>
|
||||
--EXPECT--
|
||||
array(3) {
|
||||
array(4) {
|
||||
["c1"]=>
|
||||
string(19) "2021-11-03 11:49:00"
|
||||
["c2"]=>
|
||||
string(23) "2015-10-23 07:03:00.000"
|
||||
["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
|
||||
|
|
Loading…
Reference in a new issue