]> granicus.if.org Git - php/commitdiff
Fix #74243: allow locales.conf to drive datetime format
authorfandrieu <fandrieu@gmail.com>
Tue, 31 Oct 2017 21:33:10 +0000 (17:33 -0400)
committerAdam Baratz <adambaratz@php.net>
Tue, 31 Oct 2017 21:52:59 +0000 (17:52 -0400)
Add a driver attribute, PDO::DBLIB_ATTR_DATETIME_CONVERT, to control.

NEWS
ext/pdo_dblib/dblib_driver.c
ext/pdo_dblib/dblib_stmt.c
ext/pdo_dblib/pdo_dblib.c
ext/pdo_dblib/php_pdo_dblib_int.h
ext/pdo_dblib/tests/datetime_convert.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 7834c293d2a2fa2d2eceb26e7a416ba4c9f30daa..35b828e359ae04d23e53e6a6175b903e1543c9e6 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -79,6 +79,7 @@ PHP                                                                        NEWS
 - PDO_DBlib:
   . Implemented request #69592 (allow 0-column rowsets to be skipped
     automatically). (fandrieu)
+  . Fixed bug #74243 (allow locales.conf to drive datetime format). (fandrieu)
 
 - PDO_OCI:
   . Fixed bug #74631 (PDO_PCO with PHP-FPM: OCI environment initialized
index e8c010c5630ff2e6849e24d6541ac65b94994596..f66e83734ceddbb9bae60d4b5ffe8951779dd782 100644 (file)
@@ -290,6 +290,9 @@ static int dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
                case PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS:
                        H->skip_empty_rowsets = zval_is_true(val);
                        return 1;
+               case PDO_DBLIB_ATTR_DATETIME_CONVERT:
+                       H->datetime_convert = zval_get_long(val);
+                       return 1;
                default:
                        return 0;
        }
@@ -321,6 +324,10 @@ static int dblib_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_valu
                        ZVAL_BOOL(return_value, H->skip_empty_rowsets);
                        break;
 
+               case PDO_DBLIB_ATTR_DATETIME_CONVERT:
+                       ZVAL_BOOL(return_value, H->datetime_convert);
+                       break;
+
                default:
                        return 0;
        }
@@ -395,6 +402,7 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
        H->assume_national_character_set_strings = 0;
        H->stringify_uniqueidentifier = 0;
        H->skip_empty_rowsets = 0;
+       H->datetime_convert = 0;
 
        if (!H->login) {
                goto cleanup;
@@ -418,6 +426,7 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
                H->assume_national_character_set_strings = pdo_attr_lval(driver_options, PDO_ATTR_DEFAULT_STR_PARAM, 0) == PDO_PARAM_STR_NATL ? 1 : 0;
                H->stringify_uniqueidentifier = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER, 0);
                H->skip_empty_rowsets = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS, 0);
+               H->datetime_convert = pdo_attr_lval(driver_options, PDO_DBLIB_ATTR_DATETIME_CONVERT, 0);
        }
 
        DBERRHANDLE(H->login, (EHANDLEFUNC) pdo_dblib_error_handler);
index 2cebe982e41ba1f023fc0ffd0d81605a449b7240..175cb303326270e4f7f007ff844569210eaac025 100644 (file)
@@ -260,6 +260,51 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno)
        return 1;
 }
 
+static int pdo_dblib_stmt_stringify_col(pdo_stmt_t *stmt, int coltype)
+{
+       pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
+       pdo_dblib_db_handle *H = S->H;
+
+       switch (coltype) {
+               case SQLDECIMAL:
+               case SQLNUMERIC:
+               case SQLMONEY:
+               case SQLMONEY4:
+               case SQLMONEYN:
+               case SQLFLT4:
+               case SQLFLT8:
+               case SQLINT4:
+               case SQLINT2:
+               case SQLINT1:
+               case SQLBIT:
+                       if (stmt->dbh->stringify) {
+                               return 1;
+                       }
+                       break;
+
+               case SQLINT8:
+                       if (stmt->dbh->stringify) {
+                               return 1;
+                       }
+
+                       /* force stringify if DBBIGINT won't fit in zend_long */
+                       /* this should only be an issue for 32-bit machines */
+                       if (sizeof(zend_long) < sizeof(DBBIGINT)) {
+                               return 1;
+                       }
+                       break;
+
+               case SQLDATETIME:
+               case SQLDATETIM4:
+                       if (H->datetime_convert) {
+                               return 1;
+                       }
+                       break;
+       }
+
+       return 0;
+}
+
 static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
         zend_ulong *len, int *caller_frees)
 {
@@ -278,35 +323,15 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr,
        data_len = dbdatlen(H->link, colno+1);
 
        if (data_len != 0 || data != NULL) {
-               /* force stringify if DBBIGINT won't fit in zend_long */
-               /* this should only be an issue for 32-bit machines */
-               if (stmt->dbh->stringify || (coltype == SQLINT8 && sizeof(zend_long) < sizeof(DBBIGINT))) {
-                       switch (coltype) {
-                               case SQLDECIMAL:
-                               case SQLNUMERIC:
-                               case SQLMONEY:
-                               case SQLMONEY4:
-                               case SQLMONEYN:
-                               case SQLFLT4:
-                               case SQLFLT8:
-                               case SQLINT8:
-                               case SQLINT4:
-                               case SQLINT2:
-                               case SQLINT1:
-                               case SQLBIT: {
-                                       if (dbwillconvert(coltype, SQLCHAR)) {
-                                               tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */
-                                               tmp_data = emalloc(tmp_data_len);
-                                               data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, -1);
+               if (pdo_dblib_stmt_stringify_col(stmt, coltype) && dbwillconvert(coltype, SQLCHAR)) {
+                       tmp_data_len = 32 + (2 * (data_len)); /* FIXME: We allocate more than we need here */
+                       tmp_data = emalloc(tmp_data_len);
+                       data_len = dbconvert(NULL, coltype, data, data_len, SQLCHAR, (LPBYTE) tmp_data, -1);
 
-                                               zv = emalloc(sizeof(zval));
-                                               ZVAL_STRING(zv, tmp_data);
+                       zv = emalloc(sizeof(zval));
+                       ZVAL_STRING(zv, tmp_data);
 
-                                               efree(tmp_data);
-                                       }
-                                       break;
-                               }
-                       }
+                       efree(tmp_data);
                }
 
                if (!zv) {
index d6a0eda07b47f4e83c97fb5274c8926fca831668..98e21c9d86cea8eb5dd1dbdf97934f531a00e28c 100644 (file)
@@ -196,6 +196,7 @@ PHP_MINIT_FUNCTION(pdo_dblib)
        REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER", (long) PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER);
        REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_VERSION", (long) PDO_DBLIB_ATTR_VERSION);
        REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_SKIP_EMPTY_ROWSETS", (long) PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS);
+       REGISTER_PDO_CLASS_CONST_LONG("DBLIB_ATTR_DATETIME_CONVERT", (long) PDO_DBLIB_ATTR_DATETIME_CONVERT);
 
        if (FAIL == dbinit()) {
                return FAILURE;
index 1b59dd3a38164b039c7008df5b9fa94d572d2aa7..805435a1c2e4597aca1a1e840716a63014a9d01a 100644 (file)
@@ -119,6 +119,7 @@ typedef struct {
        unsigned assume_national_character_set_strings:1;
        unsigned stringify_uniqueidentifier:1;
        unsigned skip_empty_rowsets:1;
+       unsigned datetime_convert:1;
 } pdo_dblib_db_handle;
 
 typedef struct {
@@ -152,6 +153,7 @@ enum {
        PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER,
        PDO_DBLIB_ATTR_VERSION,
        PDO_DBLIB_ATTR_SKIP_EMPTY_ROWSETS,
+       PDO_DBLIB_ATTR_DATETIME_CONVERT,
 };
 
 #endif
diff --git a/ext/pdo_dblib/tests/datetime_convert.phpt b/ext/pdo_dblib/tests/datetime_convert.phpt
new file mode 100644 (file)
index 0000000..13f7db2
--- /dev/null
@@ -0,0 +1,36 @@
+--TEST--
+PDO_DBLIB: PDO::DBLIB_ATTR_DATETIME_CONVERT
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_dblib')) die('skip not loaded');
+require __DIR__ . '/config.inc';
+?>
+--FILE--
+<?php
+require __DIR__ . '/config.inc';
+
+$sql = "SELECT convert(datetime, '20171027 10:22:44.135') AS [d]";
+
+var_dump($db->getAttribute(PDO::DBLIB_ATTR_DATETIME_CONVERT));
+
+$stmt = $db->query($sql);
+var_dump($stmt->fetch(PDO::FETCH_ASSOC));
+
+// assume default date format: %b %e %Y %I:%M:%S:%z%p
+$db->setAttribute(PDO::DBLIB_ATTR_DATETIME_CONVERT, 1);
+var_dump($db->getAttribute(PDO::DBLIB_ATTR_DATETIME_CONVERT));
+$stmt = $db->query($sql);
+var_dump($stmt->fetch(PDO::FETCH_ASSOC));
+
+?>
+--EXPECT--
+bool(false)
+array(1) {
+  ["d"]=>
+  string(19) "2017-10-27 10:22:44"
+}
+bool(true)
+array(1) {
+  ["d"]=>
+  string(26) "Oct 27 2017 10:22:44:137AM"
+}