summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Baratz <adambaratz@php.net>2017-03-20 18:25:50 -0400
committerAdam Baratz <adambaratz@php.net>2017-03-20 18:25:50 -0400
commit4afce8ec8c6660ebd9f9eb174d2614361d1c6129 (patch)
treef2aa7f76460de262f8c93358133d7f4b2e2bf885
parent3817cba7863f1cfa077baa3bb492c4eaf9f95bf3 (diff)
downloadphp-git-4afce8ec8c6660ebd9f9eb174d2614361d1c6129.tar.gz
Add PDO parameter types for national character set strings
-rw-r--r--NEWS1
-rw-r--r--ext/pdo/pdo_dbh.c4
-rw-r--r--ext/pdo/php_pdo_driver.h13
-rw-r--r--ext/pdo_dblib/dblib_driver.c36
-rw-r--r--ext/pdo_dblib/php_pdo_dblib_int.h1
-rw-r--r--ext/pdo_dblib/tests/pdo_dblib_param_str_natl.phpt27
-rw-r--r--ext/pdo_dblib/tests/pdo_dblib_quote.phpt22
-rw-r--r--ext/pdo_mysql/mysql_driver.c47
-rw-r--r--ext/pdo_mysql/php_pdo_mysql_int.h1
-rw-r--r--ext/pdo_mysql/tests/pdo_mysql_param_str_natl.phpt44
-rw-r--r--ext/pdo_mysql/tests/pdo_mysql_quote.phpt34
11 files changed, 221 insertions, 9 deletions
diff --git a/NEWS b/NEWS
index bd66e01817..7a28686f07 100644
--- 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).
diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c
index 4cfd01020f..cb5f1e1bc3 100644
--- a/ext/pdo/pdo_dbh.c
+++ b/ext/pdo/pdo_dbh.c
@@ -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);
diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h
index 9d5753ef9e..bcbe5b3672 100644
--- a/ext/pdo/php_pdo_driver.h
+++ b/ext/pdo/php_pdo_driver.h
@@ -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
diff --git a/ext/pdo_dblib/dblib_driver.c b/ext/pdo_dblib/dblib_driver.c
index bb37ace47a..efc8dc1197 100644
--- a/ext/pdo_dblib/dblib_driver.c
+++ b/ext/pdo_dblib/dblib_driver.c
@@ -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);
}
diff --git a/ext/pdo_dblib/php_pdo_dblib_int.h b/ext/pdo_dblib/php_pdo_dblib_int.h
index 7eb6b1d9a1..c40697680f 100644
--- a/ext/pdo_dblib/php_pdo_dblib_int.h
+++ b/ext/pdo_dblib/php_pdo_dblib_int.h
@@ -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
index 0000000000..4753a91a51
--- /dev/null
+++ b/ext/pdo_dblib/tests/pdo_dblib_param_str_natl.phpt
@@ -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
diff --git a/ext/pdo_dblib/tests/pdo_dblib_quote.phpt b/ext/pdo_dblib/tests/pdo_dblib_quote.phpt
index 543093d6ce..854e14cb9d 100644
--- a/ext/pdo_dblib/tests/pdo_dblib_quote.phpt
+++ b/ext/pdo_dblib/tests/pdo_dblib_quote.phpt
@@ -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)
diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c
index a716c7b1e7..08b546ce10 100644
--- a/ext/pdo_mysql/mysql_driver.c
+++ b/ext/pdo_mysql/mysql_driver.c
@@ -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
diff --git a/ext/pdo_mysql/php_pdo_mysql_int.h b/ext/pdo_mysql/php_pdo_mysql_int.h
index cf3ad9deb8..32e79e111c 100644
--- a/ext/pdo_mysql/php_pdo_mysql_int.h
+++ b/ext/pdo_mysql/php_pdo_mysql_int.h
@@ -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
index 0000000000..56b94483f3
--- /dev/null
+++ b/ext/pdo_mysql/tests/pdo_mysql_param_str_natl.phpt
@@ -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
index 0000000000..3d094a4136
--- /dev/null
+++ b/ext/pdo_mysql/tests/pdo_mysql_quote.phpt
@@ -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'"