mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
PDO MySQL: Use native types for results
Previously, PDO MySQL only fetched data as native int/float if native prepared statements were used. This patch updates PDO to have the same behavior for emulated prepared statements, and thus removes the largest remaining discrepancy between these two modes. Note that PDO already has a ATTR_STRINGIFY_FETCHES option to control whether native types are desired or not. The previous output can be restored by enabling this option. Most of the tests make use of that option, because this allows the tests to work under libmysqlclient as well, which currently always returns string results (independently of whether native or emulated PS are used).
This commit is contained in:
parent
33e904915e
commit
c18b1aea28
28 changed files with 161 additions and 61 deletions
|
@ -31,6 +31,12 @@ PHP 8.1 UPGRADE NOTES
|
||||||
. The mysqlnd.fetch_copy_data ini setting has been removed. However, this
|
. The mysqlnd.fetch_copy_data ini setting has been removed. However, this
|
||||||
should not result in user-visible behavior changes.
|
should not result in user-visible behavior changes.
|
||||||
|
|
||||||
|
- PDO MySQL:
|
||||||
|
. Integers and floats in result sets will now be returned using native PHP
|
||||||
|
types instead of strings when using emulated prepared statements. This
|
||||||
|
matches the behavior of native prepared statements. You can restore the
|
||||||
|
previous behavior by enabling the PDO::ATTR_STRINGIFY_FETCHES option.
|
||||||
|
|
||||||
- Standard:
|
- Standard:
|
||||||
. version_compare() no longer accepts undocumented operator abbreviations.
|
. version_compare() no longer accepts undocumented operator abbreviations.
|
||||||
|
|
||||||
|
|
|
@ -100,6 +100,8 @@ PHPAPI void mysqlnd_debug(const char *mode);
|
||||||
/* Query */
|
/* Query */
|
||||||
#define mysqlnd_fetch_into(result, flags, ret_val) (result)->m.fetch_into((result), (flags), (ret_val) ZEND_FILE_LINE_CC)
|
#define mysqlnd_fetch_into(result, flags, ret_val) (result)->m.fetch_into((result), (flags), (ret_val) ZEND_FILE_LINE_CC)
|
||||||
#define mysqlnd_fetch_row_c(result) (result)->m.fetch_row_c((result))
|
#define mysqlnd_fetch_row_c(result) (result)->m.fetch_row_c((result))
|
||||||
|
#define mysqlnd_fetch_row_zval(result, row_ptr, fetched) \
|
||||||
|
(result)->m.fetch_row((result), (row_ptr), 0, (fetched))
|
||||||
#define mysqlnd_fetch_all(result, flags, return_value) (result)->m.fetch_all((result), (flags), (return_value) ZEND_FILE_LINE_CC)
|
#define mysqlnd_fetch_all(result, flags, return_value) (result)->m.fetch_all((result), (flags), (return_value) ZEND_FILE_LINE_CC)
|
||||||
#define mysqlnd_get_connection_stats(conn, values) ((conn)->data)->m->get_statistics((conn)->data, (values) ZEND_FILE_LINE_CC)
|
#define mysqlnd_get_connection_stats(conn, values) ((conn)->data)->m->get_statistics((conn)->data, (values) ZEND_FILE_LINE_CC)
|
||||||
#define mysqlnd_get_client_stats(values) _mysqlnd_get_client_stats(mysqlnd_global_stats, (values) ZEND_FILE_LINE_CC)
|
#define mysqlnd_get_client_stats(values) _mysqlnd_get_client_stats(mysqlnd_global_stats, (values) ZEND_FILE_LINE_CC)
|
||||||
|
|
|
@ -826,6 +826,14 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef PDO_USE_MYSQLND
|
||||||
|
bool int_and_float_native = true;
|
||||||
|
if (mysql_options(H->server, MYSQLND_OPT_INT_AND_FLOAT_NATIVE, (const char *) &int_and_float_native)) {
|
||||||
|
pdo_mysql_error(dbh);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (vars[0].optval && mysql_options(H->server, MYSQL_SET_CHARSET_NAME, vars[0].optval)) {
|
if (vars[0].optval && mysql_options(H->server, MYSQL_SET_CHARSET_NAME, vars[0].optval)) {
|
||||||
pdo_mysql_error(dbh);
|
pdo_mysql_error(dbh);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
# define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt)
|
# define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void pdo_mysql_free_result(pdo_mysql_stmt *S)
|
static void pdo_mysql_free_result(pdo_mysql_stmt *S)
|
||||||
{
|
{
|
||||||
if (S->result) {
|
if (S->result) {
|
||||||
|
@ -52,8 +51,16 @@ static void pdo_mysql_free_result(pdo_mysql_stmt *S)
|
||||||
efree(S->out_length);
|
efree(S->out_length);
|
||||||
S->bound_result = NULL;
|
S->bound_result = NULL;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if (S->current_row) {
|
||||||
|
unsigned column_count = mysql_num_fields(S->result);
|
||||||
|
for (unsigned i = 0; i < column_count; i++) {
|
||||||
|
zval_ptr_dtor_nogc(&S->current_row[i]);
|
||||||
|
}
|
||||||
|
efree(S->current_row);
|
||||||
|
S->current_row = NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mysql_free_result(S->result);
|
mysql_free_result(S->result);
|
||||||
S->result = NULL;
|
S->result = NULL;
|
||||||
}
|
}
|
||||||
|
@ -104,12 +111,6 @@ static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef PDO_USE_MYSQLND
|
|
||||||
if (!S->stmt && S->current_data) {
|
|
||||||
mnd_efree(S->current_data);
|
|
||||||
}
|
|
||||||
#endif /* PDO_USE_MYSQLND */
|
|
||||||
|
|
||||||
efree(S);
|
efree(S);
|
||||||
PDO_DBG_RETURN(1);
|
PDO_DBG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
@ -553,9 +554,24 @@ static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori
|
||||||
PDO_DBG_RETURN(1);
|
PDO_DBG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!S->stmt && S->current_data) {
|
zval *row_data;
|
||||||
mnd_efree(S->current_data);
|
if (mysqlnd_fetch_row_zval(S->result, &row_data, &fetched_anything) == FAIL) {
|
||||||
|
pdo_mysql_error_stmt(stmt);
|
||||||
|
PDO_DBG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fetched_anything) {
|
||||||
|
PDO_DBG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S->current_row) {
|
||||||
|
S->current_row = ecalloc(sizeof(zval), stmt->column_count);
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < stmt->column_count; i++) {
|
||||||
|
zval_ptr_dtor_nogc(&S->current_row[i]);
|
||||||
|
ZVAL_COPY_VALUE(&S->current_row[i], &row_data[i]);
|
||||||
|
}
|
||||||
|
PDO_DBG_RETURN(1);
|
||||||
#else
|
#else
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -577,7 +593,6 @@ static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori
|
||||||
|
|
||||||
PDO_DBG_RETURN(1);
|
PDO_DBG_RETURN(1);
|
||||||
}
|
}
|
||||||
#endif /* PDO_USE_MYSQLND */
|
|
||||||
|
|
||||||
if ((S->current_data = mysql_fetch_row(S->result)) == NULL) {
|
if ((S->current_data = mysql_fetch_row(S->result)) == NULL) {
|
||||||
if (!S->H->buffered && mysql_errno(S->H->server)) {
|
if (!S->H->buffered && mysql_errno(S->H->server)) {
|
||||||
|
@ -588,6 +603,7 @@ static int pdo_mysql_stmt_fetch(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori
|
||||||
|
|
||||||
S->current_lengths = mysql_fetch_lengths(S->result);
|
S->current_lengths = mysql_fetch_lengths(S->result);
|
||||||
PDO_DBG_RETURN(1);
|
PDO_DBG_RETURN(1);
|
||||||
|
#endif /* PDO_USE_MYSQLND */
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -630,13 +646,10 @@ static int pdo_mysql_stmt_describe(pdo_stmt_t *stmt, int colno) /* {{{ */
|
||||||
cols[i].maxlen = S->fields[i].length;
|
cols[i].maxlen = S->fields[i].length;
|
||||||
|
|
||||||
#ifdef PDO_USE_MYSQLND
|
#ifdef PDO_USE_MYSQLND
|
||||||
if (S->stmt) {
|
cols[i].param_type = PDO_PARAM_ZVAL;
|
||||||
cols[i].param_type = PDO_PARAM_ZVAL;
|
#else
|
||||||
} else
|
cols[i].param_type = PDO_PARAM_STR;
|
||||||
#endif
|
#endif
|
||||||
{
|
|
||||||
cols[i].param_type = PDO_PARAM_STR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
PDO_DBG_RETURN(1);
|
PDO_DBG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
@ -652,13 +665,6 @@ static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_
|
||||||
PDO_DBG_RETURN(0);
|
PDO_DBG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* With mysqlnd data is stored inside mysqlnd, not S->current_data */
|
|
||||||
if (!S->stmt) {
|
|
||||||
if (S->current_data == NULL || !S->result) {
|
|
||||||
PDO_DBG_RETURN(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colno >= stmt->column_count) {
|
if (colno >= stmt->column_count) {
|
||||||
/* error invalid column */
|
/* error invalid column */
|
||||||
PDO_DBG_RETURN(0);
|
PDO_DBG_RETURN(0);
|
||||||
|
@ -667,9 +673,12 @@ static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_
|
||||||
if (S->stmt) {
|
if (S->stmt) {
|
||||||
Z_TRY_ADDREF(S->stmt->data->result_bind[colno].zv);
|
Z_TRY_ADDREF(S->stmt->data->result_bind[colno].zv);
|
||||||
*ptr = (char*)&S->stmt->data->result_bind[colno].zv;
|
*ptr = (char*)&S->stmt->data->result_bind[colno].zv;
|
||||||
*len = sizeof(zval);
|
} else {
|
||||||
PDO_DBG_RETURN(1);
|
Z_TRY_ADDREF(S->current_row[colno]);
|
||||||
|
*ptr = (char*)&S->current_row[colno];
|
||||||
}
|
}
|
||||||
|
*len = sizeof(zval);
|
||||||
|
PDO_DBG_RETURN(1);
|
||||||
#else
|
#else
|
||||||
if (S->stmt) {
|
if (S->stmt) {
|
||||||
if (S->out_null[colno]) {
|
if (S->out_null[colno]) {
|
||||||
|
@ -688,10 +697,14 @@ static int pdo_mysql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_
|
||||||
*len = S->out_length[colno];
|
*len = S->out_length[colno];
|
||||||
PDO_DBG_RETURN(1);
|
PDO_DBG_RETURN(1);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
if (S->current_data == NULL) {
|
||||||
|
PDO_DBG_RETURN(0);
|
||||||
|
}
|
||||||
*ptr = S->current_data[colno];
|
*ptr = S->current_data[colno];
|
||||||
*len = S->current_lengths[colno];
|
*len = S->current_lengths[colno];
|
||||||
PDO_DBG_RETURN(1);
|
PDO_DBG_RETURN(1);
|
||||||
|
#endif
|
||||||
} /* }}} */
|
} /* }}} */
|
||||||
|
|
||||||
static char *type_to_name_native(int type) /* {{{ */
|
static char *type_to_name_native(int type) /* {{{ */
|
||||||
|
|
|
@ -120,12 +120,6 @@ typedef struct {
|
||||||
pdo_mysql_db_handle *H;
|
pdo_mysql_db_handle *H;
|
||||||
MYSQL_RES *result;
|
MYSQL_RES *result;
|
||||||
const MYSQL_FIELD *fields;
|
const MYSQL_FIELD *fields;
|
||||||
MYSQL_ROW current_data;
|
|
||||||
#ifdef PDO_USE_MYSQLND
|
|
||||||
const size_t *current_lengths;
|
|
||||||
#else
|
|
||||||
unsigned long *current_lengths;
|
|
||||||
#endif
|
|
||||||
pdo_mysql_error_info einfo;
|
pdo_mysql_error_info einfo;
|
||||||
#ifdef PDO_USE_MYSQLND
|
#ifdef PDO_USE_MYSQLND
|
||||||
MYSQLND_STMT *stmt;
|
MYSQLND_STMT *stmt;
|
||||||
|
@ -137,10 +131,14 @@ typedef struct {
|
||||||
#ifndef PDO_USE_MYSQLND
|
#ifndef PDO_USE_MYSQLND
|
||||||
my_bool *in_null;
|
my_bool *in_null;
|
||||||
zend_ulong *in_length;
|
zend_ulong *in_length;
|
||||||
#endif
|
|
||||||
PDO_MYSQL_PARAM_BIND *bound_result;
|
PDO_MYSQL_PARAM_BIND *bound_result;
|
||||||
my_bool *out_null;
|
my_bool *out_null;
|
||||||
zend_ulong *out_length;
|
zend_ulong *out_length;
|
||||||
|
MYSQL_ROW current_data;
|
||||||
|
unsigned long *current_lengths;
|
||||||
|
#else
|
||||||
|
zval *current_row;
|
||||||
|
#endif
|
||||||
unsigned max_length:1;
|
unsigned max_length:1;
|
||||||
/* Whether all result sets have been fully consumed.
|
/* Whether all result sets have been fully consumed.
|
||||||
* If this flag is not set, they need to be consumed during destruction. */
|
* If this flag is not set, they need to be consumed during destruction. */
|
||||||
|
|
|
@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
$stmt = $db->prepare("SELECT 1 AS \"one\"");
|
$stmt = $db->prepare("SELECT 1 AS \"one\"");
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
@ -51,7 +52,7 @@ string(1) "1"
|
||||||
string(1) "1"
|
string(1) "1"
|
||||||
string(17) "SELECT 1 AS "one""
|
string(17) "SELECT 1 AS "one""
|
||||||
----------------------------------
|
----------------------------------
|
||||||
object(PDORow)#%d (2) {
|
object(PDORow)#5 (2) {
|
||||||
["queryString"]=>
|
["queryString"]=>
|
||||||
string(19) "SELECT id FROM test"
|
string(19) "SELECT id FROM test"
|
||||||
["id"]=>
|
["id"]=>
|
||||||
|
|
|
@ -14,6 +14,7 @@ require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$attr = array(
|
$attr = array(
|
||||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||||
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci; SET SESSION sql_mode=traditional',
|
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci; SET SESSION sql_mode=traditional',
|
||||||
|
PDO::ATTR_STRINGIFY_FETCHES => true,
|
||||||
);
|
);
|
||||||
putenv('PDOTEST_ATTR=' . serialize($attr));
|
putenv('PDOTEST_ATTR=' . serialize($attr));
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ PDO MySQL Bug #75177 Type 'bit' is fetched as unexpected string
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc');
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
MySQLPDOTest::skip();
|
MySQLPDOTest::skip();
|
||||||
|
if (!MySQLPDOTest::isPDOMySQLnd()) die('skip only for mysqlnd');
|
||||||
?>
|
?>
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
|
@ -18,14 +19,23 @@ $pdo->query("INSERT INTO $tbl (`bit`) VALUES (1)");
|
||||||
$pdo->query("INSERT INTO $tbl (`bit`) VALUES (0b011)");
|
$pdo->query("INSERT INTO $tbl (`bit`) VALUES (0b011)");
|
||||||
$pdo->query("INSERT INTO $tbl (`bit`) VALUES (0b01100)");
|
$pdo->query("INSERT INTO $tbl (`bit`) VALUES (0b01100)");
|
||||||
|
|
||||||
|
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
|
||||||
$ret = $pdo->query("SELECT * FROM $tbl")->fetchAll();
|
$ret = $pdo->query("SELECT * FROM $tbl")->fetchAll();
|
||||||
|
foreach ($ret as $i) {
|
||||||
|
var_dump($i["bit"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
||||||
|
$ret = $pdo->query("SELECT * FROM $tbl")->fetchAll();
|
||||||
foreach ($ret as $i) {
|
foreach ($ret as $i) {
|
||||||
var_dump($i["bit"]);
|
var_dump($i["bit"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
string(1) "1"
|
int(1)
|
||||||
string(1) "3"
|
int(3)
|
||||||
string(2) "12"
|
int(12)
|
||||||
|
int(1)
|
||||||
|
int(3)
|
||||||
|
int(12)
|
||||||
|
|
|
@ -14,6 +14,7 @@ require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
$db->query('DROP TABLE IF EXISTS test');
|
$db->query('DROP TABLE IF EXISTS test');
|
||||||
$db->query('CREATE TABLE test (first int) ENGINE = InnoDB');
|
$db->query('CREATE TABLE test (first int) ENGINE = InnoDB');
|
||||||
|
@ -127,9 +128,9 @@ array(1) {
|
||||||
[0]=>
|
[0]=>
|
||||||
array(2) {
|
array(2) {
|
||||||
["first"]=>
|
["first"]=>
|
||||||
int(5)
|
string(1) "5"
|
||||||
[0]=>
|
[0]=>
|
||||||
int(5)
|
string(1) "5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
array(0) {
|
array(0) {
|
||||||
|
@ -138,9 +139,9 @@ array(1) {
|
||||||
[0]=>
|
[0]=>
|
||||||
array(2) {
|
array(2) {
|
||||||
["first"]=>
|
["first"]=>
|
||||||
int(7)
|
string(1) "7"
|
||||||
[0]=>
|
[0]=>
|
||||||
int(7)
|
string(1) "7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
array(0) {
|
array(0) {
|
||||||
|
@ -179,8 +180,8 @@ array(1) {
|
||||||
[0]=>
|
[0]=>
|
||||||
array(2) {
|
array(2) {
|
||||||
["first"]=>
|
["first"]=>
|
||||||
int(16)
|
string(2) "16"
|
||||||
[0]=>
|
[0]=>
|
||||||
int(16)
|
string(2) "16"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ $stmt->execute();
|
||||||
$tmp = $stmt->getColumnMeta(0);
|
$tmp = $stmt->getColumnMeta(0);
|
||||||
|
|
||||||
// libmysql and mysqlnd will show the pdo_type entry at a different position in the hash
|
// libmysql and mysqlnd will show the pdo_type entry at a different position in the hash
|
||||||
if (!isset($tmp['pdo_type']) || (isset($tmp['pdo_type']) && $tmp['pdo_type'] != 2))
|
if (!isset($tmp['pdo_type']) || (isset($tmp['pdo_type']) && $tmp['pdo_type'] != 1))
|
||||||
printf("Expecting pdo_type = 2 got %s\n", $tmp['pdo_type']);
|
printf("Expecting pdo_type = 1 got %s\n", $tmp['pdo_type']);
|
||||||
else
|
else
|
||||||
unset($tmp['pdo_type']);
|
unset($tmp['pdo_type']);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ if ($version < 40100)
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
$db->exec("DROP TABLE IF EXISTS test");
|
$db->exec("DROP TABLE IF EXISTS test");
|
||||||
|
|
||||||
// And now allow the evil to do his work
|
// And now allow the evil to do his work
|
||||||
|
|
|
@ -21,6 +21,7 @@ if ($version < 50000)
|
||||||
<?php
|
<?php
|
||||||
require __DIR__ . '/mysql_pdo_test.inc';
|
require __DIR__ . '/mysql_pdo_test.inc';
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
$db->exec('DROP PROCEDURE IF EXISTS p');
|
$db->exec('DROP PROCEDURE IF EXISTS p');
|
||||||
$db->exec('CREATE PROCEDURE p() BEGIN SELECT 1 AS "one"; END');
|
$db->exec('CREATE PROCEDURE p() BEGIN SELECT 1 AS "one"; END');
|
||||||
|
|
|
@ -30,6 +30,7 @@ if (!$attr) {
|
||||||
}
|
}
|
||||||
$attr[PDO::ATTR_PERSISTENT] = true;
|
$attr[PDO::ATTR_PERSISTENT] = true;
|
||||||
$attr[PDO::ATTR_EMULATE_PREPARES] = false;
|
$attr[PDO::ATTR_EMULATE_PREPARES] = false;
|
||||||
|
$attr[PDO::ATTR_STRINGIFY_FETCHES] = true;
|
||||||
putenv('PDOTEST_ATTR='.serialize($attr));
|
putenv('PDOTEST_ATTR='.serialize($attr));
|
||||||
|
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
@ -46,8 +47,8 @@ print "done!";
|
||||||
--EXPECT--
|
--EXPECT--
|
||||||
array(2) {
|
array(2) {
|
||||||
[1]=>
|
[1]=>
|
||||||
int(1)
|
string(1) "1"
|
||||||
[0]=>
|
[0]=>
|
||||||
int(1)
|
string(1) "1"
|
||||||
}
|
}
|
||||||
done!
|
done!
|
||||||
|
|
|
@ -12,7 +12,8 @@ MySQLPDOTest::skip();
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
|
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
$db->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
$db->exec('DROP TABLE IF EXISTS test');
|
$db->exec('DROP TABLE IF EXISTS test');
|
||||||
$db->exec('CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(255) NOT NULL)');
|
$db->exec('CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(255) NOT NULL)');
|
||||||
|
|
50
ext/pdo_mysql/tests/native_types.phpt
Normal file
50
ext/pdo_mysql/tests/native_types.phpt
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
--TEST--
|
||||||
|
PDO MySQL should use native types if ATTR_STRINGIFY_FETCHES is not enabled
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc');
|
||||||
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
|
MySQLPDOTest::skip();
|
||||||
|
if (!MySQLPDOTest::isPDOMySQLnd()) die('skip mysqlnd only');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
|
|
||||||
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
|
$db->exec('DROP TABLE IF EXISTS test');
|
||||||
|
$db->exec('CREATE TABLE test (i INT, f FLOAT)');
|
||||||
|
$db->exec('INSERT INTO test VALUES (42, 42.5)');
|
||||||
|
|
||||||
|
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
||||||
|
var_dump($db->query('SELECT * FROM test')->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
|
||||||
|
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
|
||||||
|
var_dump($db->query('SELECT * FROM test')->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
?>
|
||||||
|
--CLEAN--
|
||||||
|
<?php
|
||||||
|
require __DIR__ . '/mysql_pdo_test.inc';
|
||||||
|
MySQLPDOTest::dropTestTable();
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
array(2) {
|
||||||
|
["i"]=>
|
||||||
|
int(42)
|
||||||
|
["f"]=>
|
||||||
|
float(42.5)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
array(1) {
|
||||||
|
[0]=>
|
||||||
|
array(2) {
|
||||||
|
["i"]=>
|
||||||
|
int(42)
|
||||||
|
["f"]=>
|
||||||
|
float(42.5)
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
MySQLPDOTest::createTestTable($db);
|
MySQLPDOTest::createTestTable($db);
|
||||||
|
|
||||||
$default = $db->getAttribute(PDO::ATTR_CASE);
|
$default = $db->getAttribute(PDO::ATTR_CASE);
|
||||||
|
|
|
@ -24,6 +24,7 @@ error_reporting=E_ALL
|
||||||
$create = sprintf('CREATE TABLE %s(id INT)', $table);
|
$create = sprintf('CREATE TABLE %s(id INT)', $table);
|
||||||
var_dump($create);
|
var_dump($create);
|
||||||
$db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => $create));
|
$db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => $create));
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
$info = $db->errorInfo();
|
$info = $db->errorInfo();
|
||||||
var_dump($info[0]);
|
var_dump($info[0]);
|
||||||
|
|
|
@ -20,6 +20,7 @@ error_reporting=E_ALL
|
||||||
$table = sprintf("test_%s", md5(mt_rand(0, PHP_INT_MAX)));
|
$table = sprintf("test_%s", md5(mt_rand(0, PHP_INT_MAX)));
|
||||||
$db = new PDO($dsn, $user, $pass);
|
$db = new PDO($dsn, $user, $pass);
|
||||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
$db->exec(sprintf('DROP TABLE IF EXISTS %s', $table));
|
$db->exec(sprintf('DROP TABLE IF EXISTS %s', $table));
|
||||||
$create = sprintf('CREATE TABLE %s(id INT)', $table);
|
$create = sprintf('CREATE TABLE %s(id INT)', $table);
|
||||||
$db->exec($create);
|
$db->exec($create);
|
||||||
|
@ -37,6 +38,7 @@ error_reporting=E_ALL
|
||||||
// New connection, does not allow multiple statements.
|
// New connection, does not allow multiple statements.
|
||||||
$db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => false));
|
$db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_MULTI_STATEMENTS => false));
|
||||||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
|
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
$stmt = $db->query(sprintf('SELECT * FROM %s; INSERT INTO %s(id) VALUES (3)', $table, $table));
|
$stmt = $db->query(sprintf('SELECT * FROM %s; INSERT INTO %s(id) VALUES (3)', $table, $table));
|
||||||
var_dump($stmt);
|
var_dump($stmt);
|
||||||
$info = $db->errorInfo();
|
$info = $db->errorInfo();
|
||||||
|
|
|
@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
MySQLPDOTest::createTestTable($db);
|
MySQLPDOTest::createTestTable($db);
|
||||||
|
|
||||||
$default = $db->getAttribute(PDO::ATTR_STATEMENT_CLASS);
|
$default = $db->getAttribute(PDO::ATTR_STATEMENT_CLASS);
|
||||||
|
|
|
@ -13,6 +13,7 @@ if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
|
||||||
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
|
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
|
||||||
|
|
||||||
if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
|
if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
|
||||||
|
@ -31,6 +32,7 @@ if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
|
||||||
/* This is the PDO way to close a connection */
|
/* This is the PDO way to close a connection */
|
||||||
$db = null;
|
$db = null;
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
/* Autocommit was off - by definition. Commit was not issued. DELETE should have been rolled back. */
|
/* Autocommit was off - by definition. Commit was not issued. DELETE should have been rolled back. */
|
||||||
if (!($stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC')))
|
if (!($stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC')))
|
||||||
|
|
|
@ -10,6 +10,7 @@ MySQLPDOTest::skip();
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
$stmt = $db->query('SELECT 1; SELECT x FROM does_not_exist');
|
$stmt = $db->query('SELECT 1; SELECT x FROM does_not_exist');
|
||||||
var_dump($stmt->fetchAll());
|
var_dump($stmt->fetchAll());
|
||||||
|
|
|
@ -23,7 +23,7 @@ MySQLPDOTest::skip();
|
||||||
$db1->exec('SET @pdo_persistent_connection=1');
|
$db1->exec('SET @pdo_persistent_connection=1');
|
||||||
$stmt = $db2->query('SELECT @pdo_persistent_connection as _pers');
|
$stmt = $db2->query('SELECT @pdo_persistent_connection as _pers');
|
||||||
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
|
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
if ($tmp['_pers'] !== '1')
|
if ($tmp['_pers'] != 1)
|
||||||
printf("[001] Both handles should use the same connection.");
|
printf("[001] Both handles should use the same connection.");
|
||||||
|
|
||||||
$stmt = $db1->query('SELECT CONNECTION_ID() as _con1');
|
$stmt = $db1->query('SELECT CONNECTION_ID() as _con1');
|
||||||
|
|
|
@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
function prepex($offset, &$db, $query, $input_params = null, $error_info = null) {
|
function prepex($offset, &$db, $query, $input_params = null, $error_info = null) {
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ $db = MySQLPDOTest::factory();
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@ $db = MySQLPDOTest::factory();
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
|
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
|
||||||
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
|
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
|
||||||
|
@ -41,16 +43,7 @@ $db = MySQLPDOTest::factory();
|
||||||
var_export($stmt->errorCode(), true),
|
var_export($stmt->errorCode(), true),
|
||||||
var_export($stmt->errorInfo(), true));
|
var_export($stmt->errorInfo(), true));
|
||||||
|
|
||||||
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
if (!MySQLPDOTest::isPDOMySQLnd()) {
|
|
||||||
if (isset($tmp[0]['id'])) {
|
|
||||||
// libmysql should return a string here whereas mysqlnd returns a native int
|
|
||||||
if (gettype($tmp[0]['id']) == 'string')
|
|
||||||
// convert to int for the test output...
|
|
||||||
settype($tmp[0]['id'], 'integer');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var_dump($tmp);
|
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
printf("[001] %s [%s] %s\n",
|
printf("[001] %s [%s] %s\n",
|
||||||
|
@ -82,7 +75,7 @@ array(1) {
|
||||||
["?"]=>
|
["?"]=>
|
||||||
string(2) "id"
|
string(2) "id"
|
||||||
["id"]=>
|
["id"]=>
|
||||||
int(1)
|
string(1) "1"
|
||||||
["label"]=>
|
["label"]=>
|
||||||
string(4) "row1"
|
string(4) "row1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ if (!$ok)
|
||||||
<?php
|
<?php
|
||||||
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
|
||||||
$db = MySQLPDOTest::factory();
|
$db = MySQLPDOTest::factory();
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
MySQLPDOTest::createTestTable($db);
|
MySQLPDOTest::createTestTable($db);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -51,6 +51,7 @@ MySQLPDOTest::skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
$db = new MyPDO(PDO_MYSQL_TEST_DSN, PDO_MYSQL_TEST_USER, PDO_MYSQL_TEST_PASS);
|
$db = new MyPDO(PDO_MYSQL_TEST_DSN, PDO_MYSQL_TEST_USER, PDO_MYSQL_TEST_PASS);
|
||||||
|
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
|
||||||
$db->exec('DROP TABLE IF EXISTS test');
|
$db->exec('DROP TABLE IF EXISTS test');
|
||||||
$db->exec('CREATE TABLE test(id INT)');
|
$db->exec('CREATE TABLE test(id INT)');
|
||||||
$db->exec('INSERT INTO test(id) VALUES (1), (2)');
|
$db->exec('INSERT INTO test(id) VALUES (1), (2)');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue