]> granicus.if.org Git - php/commitdiff
Add PDO parameter types for national character set strings
authorAdam Baratz <adambaratz@php.net>
Mon, 20 Mar 2017 22:25:50 +0000 (18:25 -0400)
committerAdam Baratz <adambaratz@php.net>
Mon, 20 Mar 2017 22:25:50 +0000 (18:25 -0400)
NEWS
ext/pdo/pdo_dbh.c
ext/pdo/php_pdo_driver.h
ext/pdo_dblib/dblib_driver.c
ext/pdo_dblib/php_pdo_dblib_int.h
ext/pdo_dblib/tests/pdo_dblib_param_str_natl.phpt [new file with mode: 0644]
ext/pdo_dblib/tests/pdo_dblib_quote.phpt
ext/pdo_mysql/mysql_driver.c
ext/pdo_mysql/php_pdo_mysql_int.h
ext/pdo_mysql/tests/pdo_mysql_param_str_natl.phpt [new file with mode: 0644]
ext/pdo_mysql/tests/pdo_mysql_quote.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index bd66e018170031fb540077b02f3e6256b1e17c2a..7a28686f0755702c6b747cf2972626aeae632862 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -112,6 +112,7 @@ PHP                                                                        NEWS
 
 - PDO:
   . Add "Sent SQL" to debug dump for emulated prepares. (Adam Baratz)
+  . Add parameter types for national character set strings. (Adam Baratz)
 
 - PDO_DBlib:
   . Fixed bug #73234 (Emulated statements let value dictate parameter type).
index 4cfd01020fae4f2a00fb36c789e0dd6ab0726200..cb5f1e1bc3d3158747e519bcd813d827e31fa6f3 100644 (file)
@@ -1413,6 +1413,9 @@ void pdo_dbh_init(void)
        REGISTER_PDO_CLASS_CONST_LONG("PARAM_LOB",  (zend_long)PDO_PARAM_LOB);
        REGISTER_PDO_CLASS_CONST_LONG("PARAM_STMT", (zend_long)PDO_PARAM_STMT);
        REGISTER_PDO_CLASS_CONST_LONG("PARAM_INPUT_OUTPUT", (zend_long)PDO_PARAM_INPUT_OUTPUT);
+       REGISTER_PDO_CLASS_CONST_LONG("PARAM_STR_NATL", (zend_long)PDO_PARAM_STR_NATL);
+       REGISTER_PDO_CLASS_CONST_LONG("PARAM_STR_CHAR", (zend_long)PDO_PARAM_STR_CHAR);
+
 
        REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_ALLOC",                (zend_long)PDO_PARAM_EVT_ALLOC);
        REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FREE",                 (zend_long)PDO_PARAM_EVT_FREE);
@@ -1462,6 +1465,7 @@ void pdo_dbh_init(void)
        REGISTER_PDO_CLASS_CONST_LONG("ATTR_MAX_COLUMN_LEN", (zend_long)PDO_ATTR_MAX_COLUMN_LEN);
        REGISTER_PDO_CLASS_CONST_LONG("ATTR_EMULATE_PREPARES", (zend_long)PDO_ATTR_EMULATE_PREPARES);
        REGISTER_PDO_CLASS_CONST_LONG("ATTR_DEFAULT_FETCH_MODE", (zend_long)PDO_ATTR_DEFAULT_FETCH_MODE);
+       REGISTER_PDO_CLASS_CONST_LONG("ATTR_DEFAULT_STR_PARAM", (zend_long)PDO_ATTR_DEFAULT_STR_PARAM);
 
        REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_SILENT", (zend_long)PDO_ERRMODE_SILENT);
        REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_WARNING",        (zend_long)PDO_ERRMODE_WARNING);
index 9d5753ef9e482d5a205fb989df5ddceebe092947..bcbe5b367256b8953688526666bc9768095d5875 100644 (file)
@@ -46,7 +46,7 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64);
 # define FALSE 0
 #endif
 
-#define PDO_DRIVER_API 20161020
+#define PDO_DRIVER_API 20170320
 
 enum pdo_param_type {
        PDO_PARAM_NULL,
@@ -77,7 +77,15 @@ enum pdo_param_type {
        PDO_PARAM_ZVAL,
 
        /* magic flag to denote a parameter as being input/output */
-       PDO_PARAM_INPUT_OUTPUT = 0x80000000
+       PDO_PARAM_INPUT_OUTPUT = 0x80000000,
+
+       /* magic flag to denote a string that uses the national character set
+          see section 4.2.1 of SQL-92: http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
+        */
+       PDO_PARAM_STR_NATL = 0x40000000,
+
+       /* magic flag to denote a string that uses the regular character set */
+       PDO_PARAM_STR_CHAR = 0x20000000,
 };
 
 #define PDO_PARAM_FLAGS                        0xFFFF0000
@@ -140,6 +148,7 @@ enum pdo_attribute_type {
        PDO_ATTR_MAX_COLUMN_LEN,        /* make database calculate maximum length of data found in a column */
        PDO_ATTR_DEFAULT_FETCH_MODE, /* Set the default fetch mode */
        PDO_ATTR_EMULATE_PREPARES,  /* use query emulation rather than native */
+       PDO_ATTR_DEFAULT_STR_PARAM, /* set the default string parameter type (see the PDO::PARAM_STR_* magic flags) */
 
        /* this defines the start of the range for driver specific options.
         * Drivers should define their own attribute constants beginning with this
index bb37ace47a1e1fc49405eb8533246ec0563ad048..efc8dc119782cc94a3ed7f62da732f1bff489a4f 100644 (file)
@@ -151,10 +151,23 @@ static zend_long dblib_handle_doer(pdo_dbh_t *dbh, const char *sql, size_t sql_l
 
 static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unquotedlen, char **quoted, size_t *quotedlen, enum pdo_param_type paramtype)
 {
+       pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
+       zend_bool use_national_character_set = 0;
+
        size_t i;
        char * q;
        *quotedlen = 0;
 
+       if (H->assume_national_character_set_strings) {
+               use_national_character_set = 1;
+       }
+       if ((paramtype & PDO_PARAM_STR_NATL) == PDO_PARAM_STR_NATL) {
+               use_national_character_set = 1;
+       }
+       if ((paramtype & PDO_PARAM_STR_CHAR) == PDO_PARAM_STR_CHAR) {
+               use_national_character_set = 0;
+       }
+
        /* Detect quoted length, adding extra char for doubled single quotes */
        for (i = 0; i < unquotedlen; i++) {
                if (unquoted[i] == '\'') ++*quotedlen;
@@ -162,7 +175,13 @@ static int dblib_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unqu
        }
 
        *quotedlen += 2; /* +2 for opening, closing quotes */
+       if (use_national_character_set) {
+               ++*quotedlen; /* N prefix */
+       }
        q = *quoted = emalloc(*quotedlen + 1); /* Add byte for terminal null */
+       if (use_national_character_set) {
+               *q++ = 'N';
+       }
        *q++ = '\'';
 
        for (i = 0; i < unquotedlen; i++) {
@@ -256,12 +275,17 @@ char *dblib_handle_last_id(pdo_dbh_t *dbh, const char *name, size_t *len)
 
 static int dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
 {
+       pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
+
        switch(attr) {
+               case PDO_ATTR_DEFAULT_STR_PARAM:
+                       H->assume_national_character_set_strings = zval_get_long(val) == PDO_PARAM_STR_NATL ? 1 : 0;
+                       return 1;
                case PDO_ATTR_TIMEOUT:
                case PDO_DBLIB_ATTR_QUERY_TIMEOUT:
                        return SUCCEED == dbsettime(zval_get_long(val)) ? 1 : 0;
                case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER:
-                       ((pdo_dblib_db_handle *)dbh->driver_data)->stringify_uniqueidentifier = zval_get_long(val);
+                       H->stringify_uniqueidentifier = zval_get_long(val);
                        return 1;
                default:
                        return 0;
@@ -270,14 +294,20 @@ static int dblib_set_attr(pdo_dbh_t *dbh, zend_long attr, zval *val)
 
 static int dblib_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_value)
 {
+       pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;
+
        switch (attr) {
+               case PDO_ATTR_DEFAULT_STR_PARAM:
+                       ZVAL_LONG(return_value, H->assume_national_character_set_strings ? PDO_PARAM_STR_NATL : PDO_PARAM_STR_CHAR);
+                       break;
+
                case PDO_ATTR_EMULATE_PREPARES:
                        /* this is the only option available, but expose it so common tests and whatever else can introspect */
                        ZVAL_TRUE(return_value);
                        break;
 
                case PDO_DBLIB_ATTR_STRINGIFY_UNIQUEIDENTIFIER:
-                       ZVAL_BOOL(return_value, ((pdo_dblib_db_handle *)dbh->driver_data)->stringify_uniqueidentifier);
+                       ZVAL_BOOL(return_value, H->stringify_uniqueidentifier);
                        break;
 
                case PDO_DBLIB_ATTR_VERSION:
@@ -355,6 +385,7 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
        H = pecalloc(1, sizeof(*H), dbh->is_persistent);
        H->login = dblogin();
        H->err.sqlstate = dbh->error_code;
+       H->assume_national_character_set_strings = 0;
        H->stringify_uniqueidentifier = 0;
 
        if (!H->login) {
@@ -376,6 +407,7 @@ static int pdo_dblib_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
                dbsetlogintime(connect_timeout); /* Connection/Login Timeout */
                dbsettime(query_timeout); /* Statement Timeout */
 
+               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);
        }
 
index 7eb6b1d9a13974741ac49a08cb4d9eea4a9950de..c40697680f3162185427e8efba006d9f45cb5b15 100644 (file)
@@ -116,6 +116,7 @@ typedef struct {
        DBPROCESS       *link;
 
        pdo_dblib_err err;
+       unsigned assume_national_character_set_strings:1;
        unsigned stringify_uniqueidentifier:1;
 } pdo_dblib_db_handle;
 
diff --git a/ext/pdo_dblib/tests/pdo_dblib_param_str_natl.phpt b/ext/pdo_dblib/tests/pdo_dblib_param_str_natl.phpt
new file mode 100644 (file)
index 0000000..4753a91
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+PDO_DBLIB: national character set values are quoted correctly in queries
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_dblib')) die('skip not loaded');
+require dirname(__FILE__) . '/config.inc';
+?>
+--FILE--
+<?php
+require dirname(__FILE__) . '/config.inc';
+
+$stmt = $db->prepare('SELECT :value');
+$stmt->bindValue(':value', 'foo', PDO::PARAM_STR | PDO::PARAM_STR_NATL);
+$stmt->execute();
+
+var_dump($stmt->debugDumpParams());
+?>
+--EXPECT--
+SQL: [13] SELECT :value
+Sent SQL: [13] SELECT N'foo'
+Params:  1
+Key: Name: [6] :value
+paramno=-1
+name=[6] ":value"
+is_param=1
+param_type=1073741826
+NULL
index 543093d6ce6d34e4674d2b865dc8402db3a857cc..854e14cb9dfe85c03cb876b916b0c9953f54c943 100644 (file)
@@ -14,7 +14,20 @@ var_dump($db->quote(42, PDO::PARAM_INT));
 var_dump($db->quote(null, PDO::PARAM_NULL));
 var_dump($db->quote('\'', PDO::PARAM_STR));
 var_dump($db->quote('foo', PDO::PARAM_STR));
+var_dump($db->quote('foo', PDO::PARAM_STR | PDO::PARAM_STR_CHAR));
+var_dump($db->quote('über', PDO::PARAM_STR | PDO::PARAM_STR_NATL));
+
+var_dump($db->getAttribute(PDO::ATTR_DEFAULT_STR_PARAM) === PDO::PARAM_STR_CHAR);
+$db->setAttribute(PDO::ATTR_DEFAULT_STR_PARAM, PDO::PARAM_STR_NATL);
+var_dump($db->getAttribute(PDO::ATTR_DEFAULT_STR_PARAM) === PDO::PARAM_STR_NATL);
+
+var_dump($db->quote('foo', PDO::PARAM_STR | PDO::PARAM_STR_CHAR));
 var_dump($db->quote('über', PDO::PARAM_STR));
+var_dump($db->quote('über', PDO::PARAM_STR | PDO::PARAM_STR_NATL));
+
+$db = new PDO($dsn, $user, $pass, [PDO::ATTR_DEFAULT_STR_PARAM => PDO::PARAM_STR_NATL]);
+var_dump($db->getAttribute(PDO::ATTR_DEFAULT_STR_PARAM) === PDO::PARAM_STR_NATL);
+
 ?>
 --EXPECT--
 string(3) "'1'"
@@ -23,4 +36,11 @@ string(4) "'42'"
 string(2) "''"
 string(4) "''''"
 string(5) "'foo'"
-string(7) "'über'"
+string(5) "'foo'"
+string(8) "N'über'"
+bool(true)
+bool(true)
+string(5) "'foo'"
+string(8) "N'über'"
+string(8) "N'über'"
+bool(true)
index a716c7b1e71754f97015d39be462a89968c9a9b9..08b546ce10cbe65159574cffbd369ee6a0cdd02c 100644 (file)
@@ -300,12 +300,35 @@ static char *pdo_mysql_last_insert_id(pdo_dbh_t *dbh, const char *name, size_t *
 static int mysql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, size_t unquotedlen, char **quoted, size_t *quotedlen, enum pdo_param_type paramtype )
 {
        pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
+       zend_bool use_national_character_set = 0;
+
+       if (H->assume_national_character_set_strings) {
+               use_national_character_set = 1;
+       }
+       if ((paramtype & PDO_PARAM_STR_NATL) == PDO_PARAM_STR_NATL) {
+               use_national_character_set = 1;
+       }
+       if ((paramtype & PDO_PARAM_STR_CHAR) == PDO_PARAM_STR_CHAR) {
+               use_national_character_set = 0;
+       }
+
        PDO_DBG_ENTER("mysql_handle_quoter");
        PDO_DBG_INF_FMT("dbh=%p", dbh);
        PDO_DBG_INF_FMT("unquoted=%.*s", (int)unquotedlen, unquoted);
-       *quoted = safe_emalloc(2, unquotedlen, 3);
-       *quotedlen = mysql_real_escape_string(H->server, *quoted + 1, unquoted, unquotedlen);
-       (*quoted)[0] =(*quoted)[++*quotedlen] = '\'';
+       *quoted = safe_emalloc(2, unquotedlen, 3 + (use_national_character_set ? 1 : 0));
+
+       if (use_national_character_set) {
+               *quotedlen = mysql_real_escape_string(H->server, *quoted + 2, unquoted, unquotedlen);
+               (*quoted)[0] = 'N';
+               (*quoted)[1] = '\'';
+
+               ++*quotedlen; /* N prefix */
+       } else {
+               *quotedlen = mysql_real_escape_string(H->server, *quoted + 1, unquoted, unquotedlen);
+               (*quoted)[0] = '\'';
+       }
+
+       (*quoted)[++*quotedlen] = '\'';
        (*quoted)[++*quotedlen] = '\0';
        PDO_DBG_INF_FMT("quoted=%.*s", (int)*quotedlen, *quoted);
        PDO_DBG_RETURN(1);
@@ -369,7 +392,7 @@ static inline int mysql_handle_autocommit(pdo_dbh_t *dbh)
 static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val)
 {
        zend_long lval = zval_get_long(val);
-       zend_bool bval = lval? 1 : 0;
+       zend_bool bval = lval ? 1 : 0;
        PDO_DBG_ENTER("pdo_mysql_set_attribute");
        PDO_DBG_INF_FMT("dbh=%p", dbh);
        PDO_DBG_INF_FMT("attr=%l", attr);
@@ -382,18 +405,25 @@ static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, zend_long attr, zval *val)
                        }
                        PDO_DBG_RETURN(1);
 
+               case PDO_ATTR_DEFAULT_STR_PARAM:
+                       ((pdo_mysql_db_handle *)dbh->driver_data)->assume_national_character_set_strings = lval == PDO_PARAM_STR_NATL ? 1 : 0;
+                       PDO_DBG_RETURN(1);
+
                case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
                        /* ignore if the new value equals the old one */
                        ((pdo_mysql_db_handle *)dbh->driver_data)->buffered = bval;
                        PDO_DBG_RETURN(1);
+
                case PDO_MYSQL_ATTR_DIRECT_QUERY:
                case PDO_ATTR_EMULATE_PREPARES:
                        /* ignore if the new value equals the old one */
                        ((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = bval;
                        PDO_DBG_RETURN(1);
+
                case PDO_ATTR_FETCH_TABLE_NAMES:
                        ((pdo_mysql_db_handle *)dbh->driver_data)->fetch_table_names = bval;
                        PDO_DBG_RETURN(1);
+
 #ifndef PDO_USE_MYSQLND
                case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
                        if (lval < 0) {
@@ -450,10 +480,15 @@ static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, zend_long attr, zval *return_
                        }
                }
                        break;
+
                case PDO_ATTR_AUTOCOMMIT:
                        ZVAL_LONG(return_value, dbh->auto_commit);
                        break;
 
+               case PDO_ATTR_DEFAULT_STR_PARAM:
+                       ZVAL_LONG(return_value, H->assume_national_character_set_strings ? PDO_PARAM_STR_NATL : PDO_PARAM_STR_CHAR);
+                       break;
+
                case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
                        ZVAL_LONG(return_value, H->buffered);
                        break;
@@ -597,6 +632,7 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
        H->max_buffer_size = 1024*1024;
 #endif
 
+       H->assume_national_character_set_strings = 0;
        H->buffered = H->emulate_prepare = 1;
 
        /* handle MySQL options */
@@ -616,6 +652,9 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
                H->emulate_prepare = pdo_attr_lval(driver_options,
                        PDO_ATTR_EMULATE_PREPARES, H->emulate_prepare);
 
+               H->assume_national_character_set_strings = pdo_attr_lval(driver_options,
+                       PDO_ATTR_DEFAULT_STR_PARAM, 0) == PDO_PARAM_STR_NATL ? 1 : 0;
+
 #ifndef PDO_USE_MYSQLND
                H->max_buffer_size = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE, H->max_buffer_size);
 #endif
index cf3ad9deb8a21225ca03e524e172015109b401e7..32e79e111c3aef448346ac81ce1e915d27ca5748 100644 (file)
@@ -104,6 +104,7 @@ typedef struct {
 typedef struct {
        MYSQL           *server;
 
+       unsigned assume_national_character_set_strings:1;
        unsigned attached:1;
        unsigned buffered:1;
        unsigned emulate_prepare:1;
diff --git a/ext/pdo_mysql/tests/pdo_mysql_param_str_natl.phpt b/ext/pdo_mysql/tests/pdo_mysql_param_str_natl.phpt
new file mode 100644 (file)
index 0000000..56b9448
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+PDO MySQL national character set parameters don't affect true prepared statements
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
+require dirname(__FILE__) . '/config.inc';
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+PDOTest::skip();
+?>
+--FILE--
+<?php
+require dirname(__FILE__) . '/config.inc';
+require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
+$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
+
+$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
+
+$db->exec('CREATE TABLE test (bar NCHAR(4) NOT NULL)');
+
+$stmt = $db->prepare('INSERT INTO test VALUES(?)');
+$stmt->bindValue(1, 'foo', PDO::PARAM_STR | PDO::PARAM_STR_NATL);
+$stmt->execute();
+
+var_dump($db->query('SELECT * from test'));
+foreach ($db->query('SELECT * from test') as $row) {
+       print_r($row);
+}
+
+?>
+--CLEAN--
+<?php
+require dirname(__FILE__) . '/mysql_pdo_test.inc';
+MySQLPDOTest::dropTestTable();
+?>
+--EXPECTF--
+object(PDOStatement)#%d (1) {
+  ["queryString"]=>
+  string(18) "SELECT * from test"
+}
+Array
+(
+    [bar] => foo
+    [0] => foo
+)
diff --git a/ext/pdo_mysql/tests/pdo_mysql_quote.phpt b/ext/pdo_mysql/tests/pdo_mysql_quote.phpt
new file mode 100644 (file)
index 0000000..3d094a4
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+MySQL ensure quote function returns expected results
+--SKIPIF--
+<?php
+require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
+require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+MySQLPDOTest::skip();
+?>
+--FILE--
+<?php
+require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+$db = MySQLPDOTest::factory();
+
+var_dump($db->quote('foo', PDO::PARAM_STR));
+var_dump($db->quote('foo', PDO::PARAM_STR | PDO::PARAM_STR_CHAR));
+var_dump($db->quote('über', PDO::PARAM_STR | PDO::PARAM_STR_NATL));
+
+var_dump($db->getAttribute(PDO::ATTR_DEFAULT_STR_PARAM) === PDO::PARAM_STR_CHAR);
+$db->setAttribute(PDO::ATTR_DEFAULT_STR_PARAM, PDO::PARAM_STR_NATL);
+var_dump($db->getAttribute(PDO::ATTR_DEFAULT_STR_PARAM) === PDO::PARAM_STR_NATL);
+
+var_dump($db->quote('foo', PDO::PARAM_STR | PDO::PARAM_STR_CHAR));
+var_dump($db->quote('über', PDO::PARAM_STR));
+var_dump($db->quote('über', PDO::PARAM_STR | PDO::PARAM_STR_NATL));
+?>
+--EXPECT--
+string(5) "'foo'"
+string(5) "'foo'"
+string(8) "N'über'"
+bool(true)
+bool(true)
+string(5) "'foo'"
+string(8) "N'über'"
+string(8) "N'über'"