- Add mysqlnd support for PDO_mysql, fixes at least bug#41997,#42499,

pecl#12794, pecl#12401

# Running the tests:
# (Note: Doesn't work currnetly on HEAD, see:
#  http://news.php.net/php.qa/64378)
#
#  PDO_MYSQL_TEST_DSN  - DSN
#    For example: mysql:dbname=test;host=localhost;port=3306
#
#  PDO_MYSQL_TEST_HOST    - database host
#  PDO_MYSQL_TEST_DB      - database (schema) name
#  PDO_MYSQL_TEST_SOCKET  - database server socket
#  PDO_MYSQL_TEST_ENGINE  - storage engine to use
#  PDO_MYSQL_TEST_USER    - database user
#  PDO_MYSQL_TEST_PASS    - database user password
#  PDO_MYSQL_TEST_CHARSET - database charset
#
#  NOTE: if any of PDO_MYSQL_TEST_[HOST|DB|SOCKET|ENGINE|CHARSET] is
#  part of PDO_MYSQL_TEST_DSN, the values must match. That is, for example,
#  for PDO_MYSQL_TEST_DSN = mysql:dbname=test you MUST set PDO_MYSQL_TEST_DB=test.
This commit is contained in:
Johannes Schlüter 2008-07-21 13:05:51 +00:00
parent 0df974b7a5
commit ae1cd8e253
105 changed files with 10872 additions and 458 deletions

View file

@ -538,6 +538,20 @@ static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *typ
stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees TSRMLS_CC);
switch (type) {
case PDO_PARAM_ZVAL:
if (value && value_len == sizeof(zval)) {
int need_copy = (new_type != PDO_PARAM_ZVAL || stmt->dbh->stringify) ? 1 : 0;
zval *zv = *(zval**)value;
ZVAL_ZVAL(dest, zv, need_copy, 1);
} else {
ZVAL_NULL(dest);
}
if (Z_TYPE_P(dest) == IS_NULL) {
type = new_type;
}
break;
case PDO_PARAM_INT:
if (value && value_len == sizeof(long)) {
ZVAL_LONG(dest, *(long*)value);
@ -1879,7 +1893,10 @@ static PHP_METHOD(PDOStatement, getColumnMeta)
add_assoc_string(return_value, "name", col->name, 1);
add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
add_assoc_long(return_value, "precision", col->precision);
add_assoc_long(return_value, "pdo_type", col->param_type);
if (col->param_type != PDO_PARAM_ZVAL) {
/* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
add_assoc_long(return_value, "pdo_type", col->param_type);
}
}
/* }}} */

View file

@ -45,7 +45,7 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC);
# define FALSE 0
#endif
#define PDO_DRIVER_API 20061209
#define PDO_DRIVER_API 20080721
enum pdo_param_type {
PDO_PARAM_NULL,
@ -68,7 +68,12 @@ enum pdo_param_type {
PDO_PARAM_STMT, /* hierarchical result set */
/* get_col ptr should point to a zend_bool */
PDO_PARAM_BOOL
PDO_PARAM_BOOL,
/* get_col ptr should point to a zval*
and the driver is responsible for adding correct type information to get_column_meta()
*/
PDO_PARAM_ZVAL
};
/* magic flag to denote a parameter as being input/output */

View file

@ -1,3 +1,3 @@
mySQL driver for PDO
George Schlossnagle, Wez Furlong, Ilia Alshanetsky
MySQL driver for PDO
George Schlossnagle, Wez Furlong, Ilia Alshanetsky, Johannes Schlueter

View file

@ -2,68 +2,143 @@ dnl
dnl $Id$
dnl
if test "$PHP_PDO" != "no"; then
AC_DEFUN([PDO_MYSQL_LIB_CHK], [
str="$PDO_MYSQL_DIR/$1/libmysqlclient.*"
for j in `echo $str`; do
if test -r $j; then
PDO_MYSQL_LIB_DIR=$MYSQL_DIR/$1
break 2
fi
done
])
dnl TODO Rename when moving to pdo_mysql
PHP_ARG_WITH(pdo-mysql, for MySQL support for PDO,
[ --with-pdo-mysql[=DIR] PDO: MySQL support. DIR is the MySQL base directory])
[ --with-pdo-mysql[=DIR] PDO: MySQL support. DIR is the MySQL base directoy
If mysqlnd is passed as DIR, the MySQL native
native driver will be used [/usr/local]])
if test -z "$PHP_ZLIB_DIR"; then
PHP_ARG_WITH(zlib-dir, for the location of libz,
[ --with-zlib-dir[=DIR] PDO_MySQL: Set the path to libz install prefix], no, no)
fi
if test "$PHP_PDO_MYSQL" != "no"; then
AC_DEFINE(HAVE_MYSQL, 1, [Whether you have MySQL])
PHP_MYSQLND_ENABLED=yes
for i in $PHP_PDO_MYSQL /usr/local /usr ; do
PDO_MYSQL_DIR=$i
PDO_MYSQL_CONFIG=$PDO_MYSQL_DIR/bin/mysql_config
if test -r $i/include/mysql; then
PDO_MYSQL_INC_DIR=$i/include/mysql
else
PDO_MYSQL_INC_DIR=$i/include
fi
if test -r $i/lib/mysql; then
PDO_MYSQL_LIB_DIR=$i/lib/mysql
else
PDO_MYSQL_LIB_DIR=$i/lib
fi
if test -x $PDO_MYSQL_CONFIG; then
break
fi
done
AC_DEFUN([PDO_MYSQL_LIB_CHK], [
str="$PDO_MYSQL_DIR/$1/libmysqlclient*"
for j in `echo $str`; do
if test -r $j; then
PDO_MYSQL_LIB_DIR=$PDO_MYSQL_DIR/$1
break 2
fi
done
])
if test -z "$PDO_MYSQL_DIR"; then
AC_MSG_ERROR([Cannot find MySQL header files under $PHP_MYSQL.
Note that the MySQL client library is not bundled anymore!])
fi
if test -x $PDO_MYSQL_CONFIG; then
PDO_MYSQL_SOCKET=`$PDO_MYSQL_CONFIG --socket`
fi
if test "$PHP_MYSQL_SOCK" != "no" && test "$PHP_MYSQL_SOCK" != "yes"; then
AC_DEFINE_UNQUOTED(PDO_MYSQL_UNIX_ADDR, "$PHP_MYSQL_SOCK", [ ])
if test "$PHP_PDO_MYSQL" = "mysqlnd"; then
dnl enables build of mysqnd library
PHP_MYSQL_ENABLED=yes
AC_DEFINE([PDO_USE_MYSQLND], 1, [Whether pdo_mysql uses mysqlnd])
else
AC_DEFINE(HAVE_MYSQL, 1, [Whether you have MySQL])
AC_MSG_CHECKING([for mysql_config])
if test -f $PHP_PDO_MYSQL && test -x $PHP_PDO_MYSQL ; then
PDO_MYSQL_CONFIG=$PHP_PDO_MYSQL
elif test "$PHP_PDO_MYSQL" != "yes"; then
if test -d "$PHP_PDO_MYSQL" ; then
if test -x "$PHP_PDO_MYSQL/bin/mysql_config" ; then
PDO_MYSQL_CONFIG="$PHP_PDO_MYSQL/bin/mysql_config"
else
PDO_MYSQL_DIR="$PHP_PDO_MYSQL"
fi
else
AC_MSG_RESULT([$PHP_PDO_MYSQL is not a directory])
AC_MSG_ERROR([can not find mysql under the "$PHP_PDO_MYSQL" that you specified])
fi
else
for i in /usr/local /usr ; do
if test -x "$i/bin/mysql_config" ; then
PDO_MYSQL_CONFIG="$i/bin/mysql_config"
break;
fi
if test -r $i/include/mysql/mysql.h || test -r $i/include/mysql.h ; then
PDO_MYSQL_DIR="$i"
break;
fi
done
fi
if test -n "$PDO_MYSQL_CONFIG" && test -x "$PDO_MYSQL_CONFIG" ; then
AC_MSG_RESULT($PDO_MYSQL_CONFIG)
if test "x$SED" = "x"; then
AC_PATH_PROG(SED, sed)
fi
if test "$enable_maintainer_zts" = "yes"; then
PDO_MYSQL_LIBNAME=mysqlclient_r
PDO_MYSQL_LIBS=`$PDO_MYSQL_CONFIG --libs_r | $SED -e "s/'//g"`
else
PDO_MYSQL_LIBNAME=mysqlclient
PDO_MYSQL_LIBS=`$PDO_MYSQL_CONFIG --libs | $SED -e "s/'//g"`
fi
PDO_MYSQL_INCLUDE=`$PDO_MYSQL_CONFIG --cflags | $SED -e "s/'//g"`
PDO_MYSQL_SOCKET=`$PDO_MYSQL_CONFIG --socket`
elif test -z "$PDO_MYSQL_DIR"; then
AC_MSG_RESULT([not found])
AC_MSG_ERROR([Cannot find MySQL header files under $PDO_MYSQL_DIR])
else
AC_MSG_RESULT([not found])
AC_MSG_CHECKING([for mysql install under $PDO_MYSQL_DIR])
if test -r $PDO_MYSQL_DIR/include/mysql; then
PDO_MYSQL_INC_DIR=$PDO_MYSQL_DIR/include/mysql
else
PDO_MYSQL_INC_DIR=$PDO_MYSQL_DIR/include
fi
if test -r $PDO_MYSQL_DIR/$PHP_LIBDIR/mysql; then
PDO_MYSQL_LIB_DIR=$PDO_MYSQL_DIR/$PHP_LIBDIR/mysql
else
PDO_MYSQL_LIB_DIR=$PDO_MYSQL_DIR/$PHP_LIBDIR
fi
if test -r "$PDO_MYSQL_LIB_DIR"; then
AC_MSG_RESULT([libs under $PDO_MYSQL_LIB_DIR; seems promising])
else
AC_MSG_RESULT([can not find it])
AC_MSG_ERROR([Unable to find your mysql installation])
fi
PHP_ADD_INCLUDE($PDO_MYSQL_INC_DIR)
PDO_MYSQL_INCLUDE=-I$PDO_MYSQL_INC_DIR
fi
AC_DEFINE_UNQUOTED(PDO_MYSQL_UNIX_ADDR, "$PDO_MYSQL_SOCKET", [ ])
fi
PHP_ADD_LIBRARY_WITH_PATH(mysqlclient, $PDO_MYSQL_LIB_DIR, PDO_MYSQL_SHARED_LIBADD)
PHP_ADD_INCLUDE($PDO_MYSQL_INC_DIR)
if test -x $PDO_MYSQL_CONFIG; then
PDO_MYSQL_LIBS=`$PDO_MYSQL_CONFIG --libs`
PHP_SUBST_OLD(PDO_MYSQL_LIBS)
fi
PHP_CHECK_LIBRARY($PDO_MYSQL_LIBNAME, mysql_query,
[
PHP_EVAL_INCLINE($PDO_MYSQL_INCLUDE)
PHP_EVAL_LIBLINE($PDO_MYSQL_LIBS, PDO_MYSQL_SHARED_LIBADD)
],[
if test "$PHP_ZLIB_DIR" != "no"; then
PHP_ADD_LIBRARY_WITH_PATH(z, $PHP_ZLIB_DIR, PDO_MYSQL_SHARED_LIBADD)
PHP_CHECK_LIBRARY($PDO_MYSQL_LIBNAME, mysql_query, [], [
AC_MSG_ERROR([PDO_MYSQL configure failed. Please check config.log for more information.])
], [
-L$PHP_ZLIB_DIR/$PHP_LIBDIR -L$PDO_MYSQL_LIB_DIR
])
PDO_MYSQL_LIBS="$PDO_MYSQL_LIBS -L$PHP_ZLIB_DIR/$PHP_LIBDIR -lz"
else
PHP_ADD_LIBRARY(z,, PDO_MYSQL_SHARED_LIBADD)
PHP_CHECK_LIBRARY($PDO_MYSQL_LIBNAME, mysql_query, [], [
AC_MSG_ERROR([Try adding --with-zlib-dir=<DIR>. Please check config.log for more information.])
], [
-L$PDO_MYSQL_LIB_DIR
])
PDO_MYSQL_LIBS="$PDO_MYSQL_LIBS -lz"
fi
_SAVE_LDFLAGS=$LDFLAGS
LDFLAGS="$LDFLAGS $PDO_MYSQL_LIBS"
AC_CHECK_FUNCS([mysql_commit mysql_stmt_prepare mysql_next_result mysql_sqlstate])
LDFLAGS=$_SAVE_LDFLAGS
PHP_EVAL_INCLINE($PDO_MYSQL_INCLUDE)
PHP_EVAL_LIBLINE($PDO_MYSQL_LIBS, PDO_MYSQL_SHARED_LIBADD)
],[
$PDO_MYSQL_LIBS
])
_SAVE_LIBS=$LIBS
LIBS="$LIBS $PDO_MYSQL_LIBS"
AC_CHECK_FUNCS([mysql_commit mysql_stmt_prepare mysql_next_result mysql_sqlstate])
LIBS=$_SAVE_LIBS
fi
ifdef([PHP_CHECK_PDO_INCLUDES],
[
@ -82,18 +157,19 @@ Note that the MySQL client library is not bundled anymore!])
AC_MSG_RESULT($pdo_inc_path)
])
PHP_NEW_EXTENSION(pdo_mysql, pdo_mysql.c mysql_driver.c mysql_statement.c, $ext_shared,,-I$pdo_inc_path)
dnl fix after renaming to pdo_mysql
PHP_NEW_EXTENSION(pdo_mysql, pdo_mysql.c mysql_driver.c mysql_statement.c, $ext_shared,,-I$pdo_inc_path -I)
ifdef([PHP_ADD_EXTENSION_DEP],
[
PHP_ADD_EXTENSION_DEP(pdo_mysql, pdo)
PHP_ADD_EXTENSION_DEP(pdo_mysql, pdo)
if test "$PHP_MYSQL" = "mysqlnd"; then
PHP_ADD_EXTENSION_DEP(pdo_mysql, mysqlnd)
fi
])
PDO_MYSQL_MODULE_TYPE=external
PDO_MYSQL_INCLUDE=-I$PDO_MYSQL_INC_DIR
PHP_SUBST(PDO_MYSQL_SHARED_LIBADD)
PHP_SUBST_OLD(PDO_MYSQL_MODULE_TYPE)
PHP_SUBST_OLD(PDO_MYSQL_LIBS)
PHP_SUBST_OLD(PDO_MYSQL_INCLUDE)
fi
fi
dnl vim: se ts=2 sw=2 et:

View file

@ -4,11 +4,17 @@
ARG_WITH("pdo-mysql", "MySQL support for PDO", "no");
if (PHP_PDO_MYSQL != "no") {
if (CHECK_LIB("libmysql.lib", "pdo_mysql", PHP_PDO_MYSQL) &&
CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_PDO_MYSQL", PHP_PHP_BUILD + "\\include\\mysql;" + PHP_PDO_MYSQL)) {
if (PHP_PDO_MYSQL == "yes" || PHP_PDO_MYSQL == "mysqlnd") {
AC_DEFINE('PDO_USE_MYSQLND', 1, 'Using MySQL native driver');
STDOUT.WriteLine("INFO: mysqlnd build");
EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c");
ADD_EXTENSION_DEP('pdo_mysql', 'pdo');
} else {
WARNING("pdo_mysql not enabled; libraries and headers not found");
if (CHECK_LIB("libmysql.lib", "pdo_mysql", PHP_PDO_MYSQL) &&
CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_PDO_MYSQL", PHP_PHP_BUILD + "\\include\\mysql;" + PHP_PDO_MYSQL)) {
EXTENSION("pdo_mysql", "pdo_mysql.c mysql_driver.c mysql_statement.c");
} else {
WARNING("pdo_mysql not enabled; libraries and headers not found");
}
}
ADD_EXTENSION_DEP('pdo_mysql', 'pdo');
}

View file

@ -14,6 +14,7 @@
+----------------------------------------------------------------------+
| Author: George Schlossnagle <george@omniti.com> |
| Wez Furlong <wez@php.net> |
| Johannes Schlueter <johannes@mysql.com> |
+----------------------------------------------------------------------+
*/
@ -30,18 +31,29 @@
#include "pdo/php_pdo_driver.h"
#include "php_pdo_mysql.h"
#include "php_pdo_mysql_int.h"
#ifndef PDO_USE_MYSQLND
#include <mysqld_error.h>
#endif
#include "zend_exceptions.h"
#if PDO_USE_MYSQLND
# define pdo_mysql_init(persistent) mysqlnd_init(persistent)
#else
# define pdo_mysql_init(persistent) mysql_init(NULL)
#endif
const char *pdo_mysql_get_sqlstate(unsigned int my_errno) {
#if !HAVE_MYSQL_SQLSTATE && !PDO_USE_MYSQLND
static const char *pdo_mysql_get_sqlstate(unsigned int my_errno) { /* {{{ */
switch (my_errno) {
/* import auto-generated case: code */
#include "php_pdo_mysql_sqlstate.h"
default: return "HY000";
}
}
/* }}} */
#endif
/* {{{ _pdo_mysql_error */
int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line TSRMLS_DC) /* {{{ */
{
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
@ -49,6 +61,8 @@ int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int lin
pdo_mysql_error_info *einfo;
pdo_mysql_stmt *S = NULL;
PDO_DBG_ENTER("_pdo_mysql_error");
PDO_DBG_INF_FMT("file=%s line=%d", file, line);
if (stmt) {
S = (pdo_mysql_stmt*)stmt->driver_data;
pdo_err = &stmt->error_code;
@ -58,7 +72,16 @@ int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int lin
einfo = &H->einfo;
}
einfo->errcode = mysql_errno(H->server);
#if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
if (S && S->stmt) {
einfo->errcode = mysql_stmt_errno(S->stmt);
}
else
#endif
{
einfo->errcode = mysql_errno(H->server);
}
einfo->file = file;
einfo->line = line;
@ -68,23 +91,29 @@ int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int lin
}
if (einfo->errcode) {
if (2014 != einfo->errcode) {
einfo->errmsg = pestrdup(mysql_error(H->server), dbh->is_persistent);
} else {
if (einfo->errcode == 2014) {
einfo->errmsg = pestrdup(
"Cannot execute queries while other unbuffered queries are active. "
"Consider using PDOStatement::fetchAll(). Alternatively, if your code "
"is only ever going to run against mysql, you may enable query "
"buffering by setting the PDO_MYSQL_ATTR_USE_BUFFERED_QUERY attribute.",
"buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.",
dbh->is_persistent);
} else if (einfo->errcode == 2057) {
einfo->errmsg = pestrdup(
"A stored procedure returning result sets of different size was called. "
"This is not supported by libmysql",
dbh->is_persistent);
} else {
einfo->errmsg = pestrdup(mysql_error(H->server), dbh->is_persistent);
}
} else { /* no error */
strcpy(*pdo_err, PDO_ERR_NONE);
return 0;
PDO_DBG_RETURN(0);
}
#if HAVE_MYSQL_SQLSTATE
# if HAVE_MYSQL_STMT_PREPARE
#if HAVE_MYSQL_SQLSTATE || PDO_USE_MYSQLND
# if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
if (S && S->stmt) {
strcpy(*pdo_err, mysql_stmt_sqlstate(S->stmt));
} else
@ -97,25 +126,23 @@ int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int lin
#endif
if (!dbh->methods) {
#if PHP_VERSION_ID > 50200
PDO_DBG_INF("Throwing exception");
zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
*pdo_err, einfo->errcode, einfo->errmsg);
#else
zend_throw_exception_ex(php_pdo_get_exception(TSRMLS_C), 0 TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
*pdo_err, einfo->errcode, einfo->errmsg);
#endif
}
/* printf("** [%s:%d] %s %s\n", file, line, *pdo_err, einfo->errmsg); */
return einfo->errcode;
PDO_DBG_RETURN(einfo->errcode);
}
/* }}} */
/* {{{ pdo_mysql_fetch_error_func */
static int pdo_mysql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC)
{
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
pdo_mysql_error_info *einfo = &H->einfo;
PDO_DBG_ENTER("pdo_mysql_fetch_error_func");
PDO_DBG_INF_FMT("dbh=%p stmt=%p", dbh, stmt);
if (stmt) {
pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
einfo = &S->einfo;
@ -128,13 +155,17 @@ static int pdo_mysql_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *in
add_next_index_string(info, einfo->errmsg, 1);
}
return 1;
PDO_DBG_RETURN(1);
}
/* }}} */
/* {{{ mysql_handle_closer */
static int mysql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
{
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
PDO_DBG_ENTER("mysql_handle_closer");
PDO_DBG_INF_FMT("dbh=%p", dbh);
if (H) {
if (H->server) {
mysql_close(H->server);
@ -147,20 +178,26 @@ static int mysql_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
pefree(H, dbh->is_persistent);
dbh->driver_data = NULL;
}
return 0;
PDO_DBG_RETURN(0);
}
/* }}} */
/* {{{ mysql_handle_preparer */
static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
{
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
pdo_mysql_stmt *S = ecalloc(1, sizeof(pdo_mysql_stmt));
#if HAVE_MYSQL_STMT_PREPARE
#if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
char *nsql = NULL;
int nsql_len = 0;
int ret;
int server_version;
#endif
PDO_DBG_ENTER("mysql_handle_preparer");
PDO_DBG_INF_FMT("dbh=%p", dbh);
PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
S->H = H;
stmt->driver_data = S;
stmt->methods = &mysql_stmt_methods;
@ -169,11 +206,11 @@ static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len,
goto end;
}
/* TODO: add runtime check to determine if the server we are talking to supports
* prepared statements; if it doesn't, we should set stmt->supports_placeholders
* to PDO_PLACEHOLDER_NONE, and have the rest of the code look at S->stmt to
* determine if we're using real prepared statements or the PDO emulated version */
#if HAVE_MYSQL_STMT_PREPARE
#if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
server_version = mysql_get_server_version(H->server);
if (server_version < 40100) {
goto fallback;
}
stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
ret = pdo_parse_params(stmt, (char*)sql, sql_len, &nsql, &nsql_len TSRMLS_CC);
@ -184,7 +221,7 @@ static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len,
} else if (ret == -1) {
/* failed to parse */
strcpy(dbh->error_code, stmt->error_code);
return 0;
PDO_DBG_RETURN(0);
}
if (!(S->stmt = mysql_stmt_init(H->server))) {
@ -192,7 +229,7 @@ static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len,
if (nsql) {
efree(nsql);
}
return 0;
PDO_DBG_RETURN(0);
}
if (mysql_stmt_prepare(S->stmt, sql, sql_len)) {
@ -208,7 +245,7 @@ static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len,
if (nsql) {
efree(nsql);
}
return 0;
PDO_DBG_RETURN(0);
}
if (nsql) {
efree(nsql);
@ -217,114 +254,199 @@ static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len,
S->num_params = mysql_stmt_param_count(S->stmt);
if (S->num_params) {
S->params_given = 0;
#if PDO_USE_MYSQLND
S->params = NULL;
#else
S->params = ecalloc(S->num_params, sizeof(MYSQL_BIND));
S->in_null = ecalloc(S->num_params, sizeof(my_bool));
S->in_length = ecalloc(S->num_params, sizeof(unsigned long));
#endif
}
dbh->alloc_own_columns = 1;
S->max_length = pdo_attr_lval(driver_options, PDO_ATTR_MAX_COLUMN_LEN, 0 TSRMLS_CC);
return 1;
PDO_DBG_RETURN(1);
fallback:
#endif
end:
stmt->supports_placeholders = PDO_PLACEHOLDER_NONE;
return 1;
PDO_DBG_RETURN(1);
}
/* }}} */
/* {{{ mysql_handle_doer */
static long mysql_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC)
{
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
PDO_DBG_ENTER("mysql_handle_doer");
PDO_DBG_INF_FMT("dbh=%p", dbh);
PDO_DBG_INF_FMT("sql=%.*s", sql_len, sql);
if (mysql_real_query(H->server, sql, sql_len)) {
pdo_mysql_error(dbh);
return -1;
PDO_DBG_RETURN(-1);
} else {
my_ulonglong c = mysql_affected_rows(H->server);
if (c == (my_ulonglong) -1) {
pdo_mysql_error(dbh);
return (H->einfo.errcode ? -1 : 0);
PDO_DBG_RETURN(H->einfo.errcode ? -1 : 0);
} else {
return c;
#if HAVE_MYSQL_NEXT_RESULT || PDO_USE_MYSQLND
/* MULTI_QUERY support - eat up all unfetched result sets */
MYSQL_RES* result;
while (mysql_more_results(H->server)) {
if (mysql_next_result(H->server)) {
PDO_DBG_RETURN(1);
}
result = mysql_store_result(H->server);
if (result) {
mysql_free_result(result);
}
}
#endif
PDO_DBG_RETURN((int)c);
}
}
}
/* }}} */
/* {{{ pdo_mysql_last_insert_id */
static char *pdo_mysql_last_insert_id(pdo_dbh_t *dbh, const char *name, unsigned int *len TSRMLS_DC)
{
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
char *id = php_pdo_int64_to_str(mysql_insert_id(H->server) TSRMLS_CC);
PDO_DBG_ENTER("pdo_mysql_last_insert_id");
*len = strlen(id);
return id;
PDO_DBG_RETURN(id);
}
/* {{{ mysql_handle_quoter */
static int mysql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
{
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
PDO_DBG_ENTER("mysql_handle_quoter");
PDO_DBG_INF_FMT("dbh=%p", dbh);
PDO_DBG_INF_FMT("unquoted=%.*s", unquotedlen, unquoted);
*quoted = safe_emalloc(2, unquotedlen, 3);
*quotedlen = mysql_real_escape_string(H->server, *quoted + 1, unquoted, unquotedlen);
(*quoted)[0] =(*quoted)[++*quotedlen] = '\'';
(*quoted)[++*quotedlen] = '\0';
return 1;
PDO_DBG_INF_FMT("quoted=%.*s", *quotedlen, *quoted);
PDO_DBG_RETURN(1);
}
/* }}} */
/* {{{ mysql_handle_begin */
static int mysql_handle_begin(pdo_dbh_t *dbh TSRMLS_DC)
{
return 0 <= mysql_handle_doer(dbh, ZEND_STRL("START TRANSACTION") TSRMLS_CC);
PDO_DBG_ENTER("mysql_handle_quoter");
PDO_DBG_INF_FMT("dbh=%p", dbh);
PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("START TRANSACTION") TSRMLS_CC));
}
/* }}} */
/* {{{ mysql_handle_commit */
static int mysql_handle_commit(pdo_dbh_t *dbh TSRMLS_DC)
{
return 0 <= mysql_handle_doer(dbh, ZEND_STRL("COMMIT") TSRMLS_CC);
PDO_DBG_ENTER("mysql_handle_commit");
PDO_DBG_INF_FMT("dbh=%p", dbh);
#if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
PDO_DBG_RETURN(0 <= mysql_commit(((pdo_mysql_db_handle *)dbh->driver_data)->server));
#else
PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("COMMIT") TSRMLS_CC));
#endif
}
/* {{{ mysql_handle_rollback */
static int mysql_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC)
{
return 0 <= mysql_handle_doer(dbh, ZEND_STRL("ROLLBACK") TSRMLS_CC);
PDO_DBG_ENTER("mysql_handle_rollback");
PDO_DBG_INF_FMT("dbh=%p", dbh);
#if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
PDO_DBG_RETURN(0 <= mysql_rollback(((pdo_mysql_db_handle *)dbh->driver_data)->server));
#else
PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("ROLLBACK") TSRMLS_CC));
#endif
}
/* }}} */
static int mysql_handle_autocommit(pdo_dbh_t *dbh TSRMLS_DC)
/* {{{ mysql_handle_autocommit */
static inline int mysql_handle_autocommit(pdo_dbh_t *dbh TSRMLS_DC)
{
PDO_DBG_ENTER("mysql_handle_autocommit");
PDO_DBG_INF_FMT("dbh=%p", dbh);
PDO_DBG_INF_FMT("dbh->autocommit=%d", dbh->auto_commit);
#if MYSQL_VERSION_ID >= 40100 || defined(PDO_USE_MYSQLND)
PDO_DBG_RETURN(0 <= mysql_autocommit(((pdo_mysql_db_handle *)dbh->driver_data)->server, dbh->auto_commit));
#else
if (dbh->auto_commit) {
return 0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=1") TSRMLS_CC);
PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=1") TSRMLS_CC));
} else {
return 0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=0") TSRMLS_CC);
PDO_DBG_RETURN(0 <= mysql_handle_doer(dbh, ZEND_STRL("SET AUTOCOMMIT=0") TSRMLS_CC));
}
#endif
}
/* }}} */
/* {{{ pdo_mysql_set_attribute */
static int pdo_mysql_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC)
{
PDO_DBG_ENTER("pdo_mysql_set_attribute");
PDO_DBG_INF_FMT("dbh=%p", dbh);
PDO_DBG_INF_FMT("attr=%l", attr);
switch (attr) {
case PDO_ATTR_AUTOCOMMIT:
convert_to_boolean(val);
case PDO_ATTR_AUTOCOMMIT:
convert_to_boolean(val);
/* ignore if the new value equals the old one */
if (dbh->auto_commit ^ Z_BVAL_P(val)) {
dbh->auto_commit = Z_BVAL_P(val);
mysql_handle_autocommit(dbh TSRMLS_CC);
}
return 1;
/* ignore if the new value equals the old one */
if (dbh->auto_commit ^ Z_BVAL_P(val)) {
dbh->auto_commit = Z_BVAL_P(val);
mysql_handle_autocommit(dbh TSRMLS_CC);
}
PDO_DBG_RETURN(1);
case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
((pdo_mysql_db_handle *)dbh->driver_data)->buffered = Z_BVAL_P(val);
return 1;
case PDO_MYSQL_ATTR_DIRECT_QUERY:
((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
return 1;
default:
return 0;
case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
((pdo_mysql_db_handle *)dbh->driver_data)->buffered = Z_BVAL_P(val);
PDO_DBG_RETURN(1);
case PDO_MYSQL_ATTR_DIRECT_QUERY:
case PDO_ATTR_EMULATE_PREPARES:
((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
PDO_DBG_RETURN(1);
case PDO_ATTR_FETCH_TABLE_NAMES:
((pdo_mysql_db_handle *)dbh->driver_data)->fetch_table_names = Z_BVAL_P(val);
PDO_DBG_RETURN(1);
#ifndef PDO_USE_MYSQLND
case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
if (Z_LVAL_P(val) < 0) {
// TODO - Johannes, can we throw a warning here?
((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size = 1024*1024;
PDO_DBG_INF_FMT("Adjusting invalid buffer size to =%l", ((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size);
} else {
((pdo_mysql_db_handle *)dbh->driver_data)->max_buffer_size = Z_LVAL_P(val);
}
PDO_DBG_RETURN(1);
break;
#endif
default:
PDO_DBG_RETURN(0);
}
}
/* }}} */
/* {{{ pdo_mysql_get_attribute */
static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value TSRMLS_DC)
{
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
PDO_DBG_ENTER("pdo_mysql_get_attribute");
PDO_DBG_INF_FMT("dbh=%p", dbh);
PDO_DBG_INF_FMT("attr=%l", attr);
switch (attr) {
case PDO_ATTR_CLIENT_VERSION:
ZVAL_STRING(return_value, (char *)mysql_get_client_info(), 1);
@ -337,42 +459,50 @@ static int pdo_mysql_get_attribute(pdo_dbh_t *dbh, long attr, zval *return_value
case PDO_ATTR_CONNECTION_STATUS:
ZVAL_STRING(return_value, (char *)mysql_get_host_info(H->server), 1);
break;
case PDO_ATTR_SERVER_INFO: {
char *tmp;
#if PDO_USE_MYSQLND
int tmp_len;
if (mysqlnd_stat(H->server, &tmp, &tmp_len) == PASS) {
ZVAL_STRINGL(return_value, tmp, tmp_len, 0);
#else
if ((tmp = (char *)mysql_stat(H->server))) {
ZVAL_STRING(return_value, tmp, 1);
#endif
} else {
pdo_mysql_error(dbh);
return -1;
PDO_DBG_RETURN(-1);
}
}
break;
case PDO_ATTR_AUTOCOMMIT:
ZVAL_LONG(return_value, dbh->auto_commit);
return 1;
break;
case PDO_MYSQL_ATTR_USE_BUFFERED_QUERY:
ZVAL_LONG(return_value, H->buffered);
return 1;
break;
case PDO_MYSQL_ATTR_DIRECT_QUERY:
ZVAL_LONG(return_value, H->emulate_prepare);
return 1;
break;
#ifndef PDO_USE_MYSQLND
case PDO_MYSQL_ATTR_MAX_BUFFER_SIZE:
ZVAL_LONG(return_value, H->max_buffer_size);
return 1;
break;
#endif
default:
return 0;
PDO_DBG_RETURN(0);
}
return 1;
PDO_DBG_RETURN(1);
}
/* }}} */
/* {{{ pdo_mysql_check_liveness */
static int pdo_mysql_check_liveness(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
{
pdo_mysql_db_handle *H = (pdo_mysql_db_handle *)dbh->driver_data;
@ -381,27 +511,31 @@ static int pdo_mysql_check_liveness(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
unsigned int my_errno;
#endif
PDO_DBG_ENTER("pdo_mysql_check_liveness");
PDO_DBG_INF_FMT("dbh=%p", dbh);
#if MYSQL_VERSION_ID > 32230
if (mysql_ping(H->server)) {
return FAILURE;
PDO_DBG_RETURN(FAILURE);
}
#else /* no mysql_ping() */
handler=signal(SIGPIPE, SIG_IGN);
handler = signal(SIGPIPE, SIG_IGN);
mysql_stat(H->server);
switch (mysql_errno(H->server)) {
case CR_SERVER_GONE_ERROR:
/* case CR_SERVER_LOST: I'm not sure this means the same as "gone" for us */
case CR_SERVER_LOST:
signal(SIGPIPE, handler);
return FAILURE;
PDO_DBG_RETURN(FAILURE);
default:
break;
}
signal(SIGPIPE, handler);
#endif /* end mysql_ping() */
return SUCCESS;
PDO_DBG_RETURN(SUCCESS);
}
/* }}} */
/* {{{ mysql_methods */
static struct pdo_dbh_methods mysql_methods = {
mysql_handle_closer,
mysql_handle_preparer,
@ -416,8 +550,17 @@ static struct pdo_dbh_methods mysql_methods = {
pdo_mysql_get_attribute,
pdo_mysql_check_liveness
};
/* }}} */
#ifndef PDO_MYSQL_UNIX_ADDR
# ifdef PHP_WIN32
# define MYSQL_UNIX_ADDR "MySQL"
# else
# define MYSQL_UNIX_ADDR PDO_MYSQL_G(default_socket)
# endif
#endif
/* {{{ pdo_mysql_handle_factory */
static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
{
pdo_mysql_db_handle *H;
@ -430,7 +573,7 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
{ "dbname", "", 0 },
{ "host", "localhost", 0 },
{ "port", "3306", 0 },
{ "unix_socket", PDO_MYSQL_UNIX_ADDR, 0 },
{ "unix_socket", MYSQL_UNIX_ADDR, 0 },
};
int connect_opts = 0
#ifdef CLIENT_MULTI_RESULTS
@ -441,48 +584,85 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
#endif
;
#if PDO_USE_MYSQLND
int dbname_len = 0;
int password_len = 0;
#endif
PDO_DBG_ENTER("pdo_mysql_handle_factory");
PDO_DBG_INF_FMT("dbh=%p", dbh);
#ifdef CLIENT_MULTI_RESULTS
PDO_DBG_INF("multi results");
#endif
php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 5);
H = pecalloc(1, sizeof(pdo_mysql_db_handle), dbh->is_persistent);
H->einfo.errcode = 0;
H->einfo.errmsg = NULL;
/* allocate an environment */
/* handle for the server */
if (!(H->server = mysql_init(NULL))) {
if (!(H->server = pdo_mysql_init(dbh->is_persistent))) {
pdo_mysql_error(dbh);
goto cleanup;
}
dbh->driver_data = H;
H->max_buffer_size = 1024 * 1024;
#ifndef PDO_USE_MYSQLND
H->max_buffer_size = 1024*1024;
#endif
H->buffered = H->emulate_prepare = 1;
/* handle MySQL options */
if (driver_options) {
long connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
long local_infile = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_LOCAL_INFILE, 0 TSRMLS_CC);
#ifndef PDO_USE_MYSQLND
char *init_cmd = NULL, *default_file = NULL, *default_group = NULL;
#endif
H->buffered = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_USE_BUFFERED_QUERY, 1 TSRMLS_CC);
H->emulate_prepare = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_DIRECT_QUERY, 1 TSRMLS_CC);
H->max_buffer_size = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE, H->max_buffer_size TSRMLS_CC);
if (PG(open_basedir) && PG(open_basedir)[0] != '\0') {
local_infile = 0;
}
H->emulate_prepare = pdo_attr_lval(driver_options,
PDO_MYSQL_ATTR_DIRECT_QUERY, H->emulate_prepare TSRMLS_CC);
H->emulate_prepare = pdo_attr_lval(driver_options,
PDO_ATTR_EMULATE_PREPARES, H->emulate_prepare TSRMLS_CC);
#ifndef PDO_USE_MYSQLND
H->max_buffer_size = pdo_attr_lval(driver_options, PDO_MYSQL_ATTR_MAX_BUFFER_SIZE, H->max_buffer_size TSRMLS_CC);
#endif
if (mysql_options(H->server, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&connect_timeout)) {
pdo_mysql_error(dbh);
goto cleanup;
}
#if PHP_MAJOR_VERSION < 6
if ((PG(open_basedir) && PG(open_basedir)[0] != '\0') || PG(safe_mode))
#else
if (PG(open_basedir) && PG(open_basedir)[0] != '\0')
#endif
{
local_infile = 0;
}
if (mysql_options(H->server, MYSQL_OPT_LOCAL_INFILE, (const char *)&local_infile)) {
pdo_mysql_error(dbh);
goto cleanup;
}
#ifdef MYSQL_OPT_RECONNECT
/* since 5.0.3, the default for this option is 0 if not specified.
* we want the old behaviour */
{
long reconnect = 1;
mysql_options(H->server, MYSQL_OPT_RECONNECT, (const char*)&reconnect);
}
#endif
#ifndef PDO_USE_MYSQLND
init_cmd = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_INIT_COMMAND, NULL TSRMLS_CC);
if (init_cmd) {
if (mysql_options(H->server, MYSQL_INIT_COMMAND, (const char *)init_cmd)) {
@ -512,6 +692,7 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
}
efree(default_group);
}
#endif
}
dbname = vars[1].optval;
@ -522,7 +703,22 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
if (vars[2].optval && !strcmp("localhost", vars[2].optval)) {
unix_socket = vars[4].optval;
}
/* TODO: - Check zval cache + ZTS */
#ifdef PDO_USE_MYSQLND
if (dbname) {
dbname_len = strlen(dbname);
}
if (dbh->password) {
password_len = strlen(dbh->password);
}
if (mysqlnd_connect(H->server, host, dbh->username, dbh->password, password_len, dbname, dbname_len,
port, unix_socket, connect_opts, PDO_MYSQL_G(mysqlnd_thd_zval_cache) TSRMLS_CC) == NULL) {
#else
if (mysql_real_connect(H->server, host, dbh->username, dbh->password, dbname, port, unix_socket, connect_opts) == NULL) {
#endif
pdo_mysql_error(dbh);
goto cleanup;
}
@ -548,7 +744,7 @@ cleanup:
dbh->methods = &mysql_methods;
return ret;
PDO_DBG_RETURN(ret);
}
/* }}} */

File diff suppressed because it is too large Load diff

View file

@ -13,6 +13,7 @@
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Author: George Schlossnagle <george@omniti.com> |
| Johannes Schlueter <johannes@mysql.com> |
+----------------------------------------------------------------------+
*/
@ -30,16 +31,185 @@
#include "php_pdo_mysql.h"
#include "php_pdo_mysql_int.h"
#ifdef COMPILE_DL_PDO_MYSQL
ZEND_GET_MODULE(pdo_mysql)
#endif
#if PDO_USE_MYSQLND
ZEND_DECLARE_MODULE_GLOBALS(pdo_mysql);
#ifndef PHP_WIN32
# ifndef PDO_MYSQL_UNIX_ADDR
# define PDO_MYSQL_UNIX_ADDR "/tmp/mysql.sock"
# endif
#endif
/* {{{ PHP_INI_BEGIN
*/
PHP_INI_BEGIN()
#ifndef PHP_WIN32
STD_PHP_INI_ENTRY("pdo_mysql.default_socket", PDO_MYSQL_UNIX_ADDR, PHP_INI_SYSTEM, OnUpdateString, default_socket, zend_pdo_mysql_globals, pdo_mysql_globals)
#endif
#if PDO_DBG_ENABLED
STD_PHP_INI_ENTRY("pdo_mysql.debug", NULL, PHP_INI_SYSTEM, OnUpdateString, debug, zend_pdo_mysql_globals, pdo_mysql_globals)
#endif
STD_PHP_INI_ENTRY("pdo_mysql.cache_size", "2000", PHP_INI_SYSTEM, OnUpdateLong, cache_size, zend_pdo_mysql_globals, pdo_mysql_globals)
PHP_INI_END()
/* }}} */
#endif
/* true global environment */
#ifdef PDO_USE_MYSQLND
static MYSQLND_ZVAL_PCACHE *mysql_mysqlnd_zval_cache;
#endif
/* {{{ PHP_MINIT_FUNCTION
*/
static PHP_MINIT_FUNCTION(pdo_mysql)
{
#if PDO_USE_MYSQLND
REGISTER_INI_ENTRIES();
#endif
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_USE_BUFFERED_QUERY", (long)PDO_MYSQL_ATTR_USE_BUFFERED_QUERY);
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_LOCAL_INFILE", (long)PDO_MYSQL_ATTR_LOCAL_INFILE);
#ifndef PDO_USE_MYSQLND
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_MAX_BUFFER_SIZE", (long)PDO_MYSQL_ATTR_MAX_BUFFER_SIZE);
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_INIT_COMMAND", (long)PDO_MYSQL_ATTR_INIT_COMMAND);
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_READ_DEFAULT_FILE", (long)PDO_MYSQL_ATTR_READ_DEFAULT_FILE);
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_READ_DEFAULT_GROUP", (long)PDO_MYSQL_ATTR_READ_DEFAULT_GROUP);
#endif
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_DIRECT_QUERY", (long)PDO_MYSQL_ATTR_DIRECT_QUERY);
#ifdef PDO_USE_MYSQLND
mysql_mysqlnd_zval_cache = mysqlnd_palloc_init_cache(PDO_MYSQL_G(cache_size));
#endif
return php_pdo_register_driver(&pdo_mysql_driver);
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
static PHP_MSHUTDOWN_FUNCTION(pdo_mysql)
{
php_pdo_unregister_driver(&pdo_mysql_driver);
#if PDO_USE_MYSQLND
UNREGISTER_INI_ENTRIES();
#endif
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
static PHP_MINFO_FUNCTION(pdo_mysql)
{
php_info_print_table_start();
#ifdef PDO_USE_MYSQLND
php_info_print_table_header(2, "PDO Driver for MySQL, mysql native driver version", mysql_get_client_info());
{
zval values;
php_info_print_table_header(2, "Persistent cache", mysql_mysqlnd_zval_cache? "enabled":"disabled");
if (mysql_mysqlnd_zval_cache) {
/* Now report cache status */
mysqlnd_palloc_stats(mysql_mysqlnd_zval_cache, &values);
mysqlnd_minfo_print_hash(&values);
zval_dtor(&values);
}
}
#else
php_info_print_table_header(2, "PDO Driver for MySQL, client library version", mysql_get_client_info());
#endif
php_info_print_table_end();
#ifdef PDO_USE_MYSQLND
DISPLAY_INI_ENTRIES();
#endif
}
/* }}} */
#if PDO_USE_MYSQLND
/* {{{ PHP_RINIT_FUNCTION
*/
static PHP_RINIT_FUNCTION(pdo_mysql)
{
PDO_MYSQL_G(mysqlnd_thd_zval_cache) = mysqlnd_palloc_rinit(mysql_mysqlnd_zval_cache);
#if PDO_DBG_ENABLED
if (PDO_MYSQL_G(debug)) {
MYSQLND_DEBUG *dbg = mysqlnd_debug_init(TSRMLS_C);
if (!dbg) {
return FAILURE;
}
dbg->m->set_mode(dbg, PDO_MYSQL_G(debug));
PDO_MYSQL_G(dbg) = dbg;
}
#endif
return SUCCESS;
}
/* }}} */
/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
static PHP_RSHUTDOWN_FUNCTION(pdo_mysql)
{
mysqlnd_palloc_rshutdown(PDO_MYSQL_G(mysqlnd_thd_zval_cache));
#if PDO_DBG_ENABLED
MYSQLND_DEBUG *dbg = PDO_MYSQL_G(dbg);
PDO_DBG_ENTER("RSHUTDOWN");
if (dbg) {
dbg->m->close(dbg);
dbg->m->free_handle(dbg);
PDO_MYSQL_G(dbg) = NULL;
}
#endif
return SUCCESS;
}
/* }}} */
/* {{{ PHP_GINIT_FUNCTION
*/
static PHP_GINIT_FUNCTION(pdo_mysql)
{
pdo_mysql_globals->mysqlnd_thd_zval_cache = NULL; /* zval cache */
pdo_mysql_globals->cache_size = 0;
#ifndef PHP_WIN32
pdo_mysql_globals->default_socket = NULL;
#endif
#if PDO_DBG_ENABLED
pdo_mysql_globals->debug = NULL; /* The actual string */
pdo_mysql_globals->dbg = NULL; /* The DBG object*/
#endif
}
/* }}} */
#endif
/* {{{ pdo_mysql_functions[] */
const zend_function_entry pdo_mysql_functions[] = {
{NULL, NULL, NULL}
};
/* }}} */
/* {{{ pdo_mysql_functions[] */
/* {{{ pdo_mysql_deps[] */
#if ZEND_MODULE_API_NO >= 20050922
static const zend_module_dep pdo_mysql_deps[] = {
ZEND_MOD_REQUIRED("pdo")
#ifdef PDO_USE_MYSQLND
ZEND_MOD_REQUIRED("mysqlnd")
#endif
{NULL, NULL, NULL}
};
#endif
@ -47,65 +217,33 @@ static const zend_module_dep pdo_mysql_deps[] = {
/* {{{ pdo_mysql_module_entry */
zend_module_entry pdo_mysql_module_entry = {
#if ZEND_MODULE_API_NO >= 20050922
STANDARD_MODULE_HEADER_EX, NULL,
pdo_mysql_deps,
#else
STANDARD_MODULE_HEADER,
#endif
"pdo_mysql",
pdo_mysql_functions,
PHP_MINIT(pdo_mysql),
PHP_MSHUTDOWN(pdo_mysql),
#if PDO_USE_MYSQLND
PHP_RINIT(pdo_mysql),
PHP_RSHUTDOWN(pdo_mysql),
#else
NULL,
NULL,
#endif
PHP_MINFO(pdo_mysql),
"0.9",
"1.0.2",
#if PDO_USE_MYSQLND
PHP_MODULE_GLOBALS(pdo_mysql),
PHP_GINIT(pdo_mysql),
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
#else
STANDARD_MODULE_PROPERTIES
#endif
};
/* }}} */
#ifdef COMPILE_DL_PDO_MYSQL
ZEND_GET_MODULE(pdo_mysql)
#endif
/* true global environment */
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(pdo_mysql)
{
REGISTER_PDO_CONST_LONG("MYSQL_ATTR_USE_BUFFERED_QUERY", (long)PDO_MYSQL_ATTR_USE_BUFFERED_QUERY);
REGISTER_PDO_CONST_LONG("MYSQL_ATTR_LOCAL_INFILE", (long)PDO_MYSQL_ATTR_LOCAL_INFILE);
REGISTER_PDO_CONST_LONG("MYSQL_ATTR_INIT_COMMAND", (long)PDO_MYSQL_ATTR_INIT_COMMAND);
REGISTER_PDO_CONST_LONG("MYSQL_ATTR_READ_DEFAULT_FILE", (long)PDO_MYSQL_ATTR_READ_DEFAULT_FILE);
REGISTER_PDO_CONST_LONG("MYSQL_ATTR_READ_DEFAULT_GROUP", (long)PDO_MYSQL_ATTR_READ_DEFAULT_GROUP);
REGISTER_PDO_CONST_LONG("MYSQL_ATTR_MAX_BUFFER_SIZE", (long)PDO_MYSQL_ATTR_MAX_BUFFER_SIZE);
REGISTER_PDO_CONST_LONG("MYSQL_ATTR_DIRECT_QUERY", (long)PDO_MYSQL_ATTR_DIRECT_QUERY);
return php_pdo_register_driver(&pdo_mysql_driver);
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(pdo_mysql)
{
php_pdo_unregister_driver(&pdo_mysql_driver);
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(pdo_mysql)
{
php_info_print_table_start();
php_info_print_table_header(2, "PDO Driver for MySQL, client library version", mysql_get_client_info());
php_info_print_table_row(2, "MYSQL_SOCKET", PDO_MYSQL_UNIX_ADDR);
php_info_print_table_end();
}
/* }}} */
/*
* Local variables:

View file

@ -24,15 +24,16 @@
extern zend_module_entry pdo_mysql_module_entry;
#define phpext_pdo_mysql_ptr &pdo_mysql_module_entry
#ifdef PHP_WIN32
#define PHP_PDO_MYSQL_API __declspec(dllexport)
#else
#define PHP_PDO_MYSQL_API
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
PHP_MINIT_FUNCTION(pdo_mysql);
PHP_MSHUTDOWN_FUNCTION(pdo_mysql);
PHP_RINIT_FUNCTION(pdo_mysql);
PHP_RSHUTDOWN_FUNCTION(pdo_mysql);
PHP_MINFO_FUNCTION(pdo_mysql);
#endif /* PHP_PDO_MYSQL_H */

View file

@ -14,6 +14,7 @@
+----------------------------------------------------------------------+
| Author: George Schlossnagle <george@omniti.com> |
| Wez Furlong <wez@php.net> |
| Johannes Schlueter <johannes@mysql.com> |
+----------------------------------------------------------------------+
*/
@ -22,7 +23,66 @@
#ifndef PHP_PDO_MYSQL_INT_H
#define PHP_PDO_MYSQL_INT_H
#include <mysql.h>
#if defined(PDO_USE_MYSQLND)
# include "ext/mysqlnd/mysqlnd.h"
# include "ext/mysql/mysql_mysqlnd.h"
# include "ext/mysqlnd/mysqlnd_libmysql_compat.h"
# define PDO_MYSQL_PARAM_BIND MYSQLND_PARAM_BIND
#else
# include <mysql.h>
# define PDO_MYSQL_PARAM_BIND MYSQL_BIND
#endif
#if defined(PDO_USE_MYSQLND) && PHP_DEBUG && !defined(PHP_WIN32)
#define PDO_DBG_ENABLED 1
#define PDO_DBG_INF(msg) do { if (dbg_skip_trace == FALSE) PDO_MYSQL_G(dbg)->m->log(PDO_MYSQL_G(dbg), __LINE__, __FILE__, -1, "info : ", (msg)); } while (0)
#define PDO_DBG_ERR(msg) do { if (dbg_skip_trace == FALSE) PDO_MYSQL_G(dbg)->m->log(PDO_MYSQL_G(dbg), __LINE__, __FILE__, -1, "error: ", (msg)); } while (0)
#define PDO_DBG_INF_FMT(...) do { if (dbg_skip_trace == FALSE) PDO_MYSQL_G(dbg)->m->log_va(PDO_MYSQL_G(dbg), __LINE__, __FILE__, -1, "info : ", __VA_ARGS__); } while (0)
#define PDO_DBG_ERR_FMT(...) do { if (dbg_skip_trace == FALSE) PDO_MYSQL_G(dbg)->m->log_va(PDO_MYSQL_G(dbg), __LINE__, __FILE__, -1, "error: ", __VA_ARGS__); } while (0)
#define PDO_DBG_ENTER(func_name) zend_bool dbg_skip_trace = TRUE; if (PDO_MYSQL_G(dbg)) dbg_skip_trace = !PDO_MYSQL_G(dbg)->m->func_enter(PDO_MYSQL_G(dbg), __LINE__, __FILE__, func_name, strlen(func_name));
#define PDO_DBG_RETURN(value) do { if (PDO_MYSQL_G(dbg)) PDO_MYSQL_G(dbg)->m->func_leave(PDO_MYSQL_G(dbg), __LINE__, __FILE__); return (value); } while (0)
#define PDO_DBG_VOID_RETURN do { if (PDO_MYSQL_G(dbg)) PDO_MYSQL_G(dbg)->m->func_leave(PDO_MYSQL_G(dbg), __LINE__, __FILE__); return; } while (0)
#else
#define PDO_DBG_ENABLED 0
static inline void PDO_DBG_INF(char *msg) {}
static inline void PDO_DBG_ERR(char *msg) {}
static inline void PDO_DBG_INF_FMT(char *format, ...) {}
static inline void PDO_DBG_ERR_FMT(char *format, ...) {}
static inline void PDO_DBG_ENTER(char *func_name) {}
#define PDO_DBG_RETURN(value) return (value)
#define PDO_DBG_VOID_RETURN return;
#endif
#if defined(PDO_USE_MYSQLND)
#include "ext/mysqlnd/mysqlnd_debug.h"
#endif
#ifdef PDO_USE_MYSQLND
ZEND_BEGIN_MODULE_GLOBALS(pdo_mysql)
MYSQLND_THD_ZVAL_PCACHE *mysqlnd_thd_zval_cache;
long cache_size;
#ifndef PHP_WIN32
char *default_socket;
#endif
#if PDO_DBG_ENABLED
char *debug; /* The actual string */
MYSQLND_DEBUG *dbg; /* The DBG object */
#endif
ZEND_END_MODULE_GLOBALS(pdo_mysql)
ZEND_EXTERN_MODULE_GLOBALS(pdo_mysql);
#endif
#ifdef ZTS
#define PDO_MYSQL_G(v) TSRMG(pdo_mysql_globals_id, zend_pdo_mysql_globals *, v)
#else
#define PDO_MYSQL_G(v) (pdo_mysql_globals.v)
#endif
typedef struct {
const char *file;
@ -38,8 +98,11 @@ typedef struct {
unsigned attached:1;
unsigned buffered:1;
unsigned emulate_prepare:1;
unsigned _reserved:31;
unsigned fetch_table_names:1;
unsigned _reserved:31;
#if !PDO_USE_MYSQLND
unsigned long max_buffer_size;
#endif
pdo_mysql_error_info einfo;
} pdo_mysql_db_handle;
@ -51,22 +114,31 @@ typedef struct {
typedef struct {
pdo_mysql_db_handle *H;
MYSQL_RES *result;
MYSQL_FIELD *fields;
const MYSQL_FIELD *fields;
MYSQL_ROW current_data;
#if PDO_USE_MYSQLND
unsigned long *current_lengths;
#else
long *current_lengths;
#endif
pdo_mysql_error_info einfo;
#if HAVE_MYSQL_STMT_PREPARE
MYSQL_STMT *stmt;
#if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
#if PDO_USE_MYSQLND
MYSQLND_STMT *stmt;
#else
MYSQL_STMT *stmt;
#endif
int num_params;
MYSQL_BIND *params;
PDO_MYSQL_PARAM_BIND *params;
#ifndef PDO_USE_MYSQLND
my_bool *in_null;
unsigned long *in_length;
MYSQL_BIND *bound_result;
unsigned long *in_length;
#endif
PDO_MYSQL_PARAM_BIND *bound_result;
my_bool *out_null;
unsigned long *out_length;
unsigned max_length:1;
unsigned long *out_length;
unsigned int params_given;
unsigned max_length:1;
#endif
} pdo_mysql_stmt;
@ -81,19 +153,13 @@ extern struct pdo_stmt_methods mysql_stmt_methods;
enum {
PDO_MYSQL_ATTR_USE_BUFFERED_QUERY = PDO_ATTR_DRIVER_SPECIFIC,
PDO_MYSQL_ATTR_LOCAL_INFILE,
#ifndef PDO_USE_MYSQLND
PDO_MYSQL_ATTR_INIT_COMMAND,
PDO_MYSQL_ATTR_READ_DEFAULT_FILE,
PDO_MYSQL_ATTR_READ_DEFAULT_GROUP,
PDO_MYSQL_ATTR_MAX_BUFFER_SIZE,
#endif
PDO_MYSQL_ATTR_DIRECT_QUERY,
};
#ifndef PDO_MYSQL_UNIX_ADDR
# ifdef PHP_WIN32
# define PDO_MYSQL_UNIX_ADDR "MySQL"
# else
# define PDO_MYSQL_UNIX_ADDR "/tmp/mysql.sock"
# endif
#endif
#endif

View file

@ -0,0 +1,16 @@
You must set the following environment variables to run the tests:
PDO_MYSQL_TEST_DSN - DSN
For example: mysql:dbname=test;host=localhost;port=3306
PDO_MYSQL_TEST_HOST - database host
PDO_MYSQL_TEST_DB - database (schema) name
PDO_MYSQL_TEST_SOCKET - database server socket
PDO_MYSQL_TEST_ENGINE - storage engine to use
PDO_MYSQL_TEST_USER - database user
PDO_MYSQL_TEST_PASS - database user password
PDO_MYSQL_TEST_CHARSET - database charset
NOTE: if any of PDO_MYSQL_TEST_[HOST|DB|SOCKET|ENGINE|CHARSET] is
part of PDO_MYSQL_TEST_DSN, the values must match. That is, for example,
for PDO_MYSQL_TEST_DSN = mysql:dbname=test you MUST set PDO_MYSQL_TEST_DB=test.

View file

@ -3,16 +3,15 @@ PDO MySQL Bug #33689 (query() execute() and fetch() return false on valid select
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
require 'ext/pdo_mysql/tests/config.inc';
require 'ext/pdo/tests/pdo_test.inc';
require dirname(__FILE__) . '/config.inc';
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--INI--
precision=14
--FILE--
<?php
require 'ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory('ext/pdo_mysql/tests/common.phpt');
require dirname(__FILE__) . '/config.inc';
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->exec('CREATE TABLE test (bar INT NOT NULL)');
$db->exec('INSERT INTO test VALUES(1)');
@ -25,12 +24,20 @@ foreach ($db->query('SELECT * from test') as $row) {
$stmt = $db->prepare('SELECT * from test');
print_r($stmt->getColumnMeta(0));
$stmt->execute();
print_r($stmt->getColumnMeta(0));
$tmp = $stmt->getColumnMeta(0);
// 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))
printf("Expecting pdo_type = 2 got %s\n", $tmp['pdo_type']);
else
unset($tmp['pdo_type']);
print_r($tmp);
?>
--EXPECTF--
object(PDOStatement)#%d (1) {
[u"queryString"]=>
unicode(18) "SELECT * from test"
["queryString"]=>
string(18) "SELECT * from test"
}
Array
(
@ -49,5 +56,4 @@ Array
[name] => bar
[len] => 11
[precision] => 0
[pdo_type] => 2
)

View file

@ -5,7 +5,6 @@ PDO MySQL Bug #37445 (Premature stmt object destruction)
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';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
PDOTest::skip();
?>
--FILE--
@ -17,5 +16,6 @@ $db->setAttribute(PDO :: ATTR_EMULATE_PREPARES, true);
$stmt = $db->prepare("SELECT 1");
$stmt->bindParam(':a', 'b');
?>
--EXPECTF--
Fatal error: Cannot pass parameter 2 by reference in %s/bug_37445.php on line %d
Fatal error: Cannot pass parameter 2 by reference in %sbug_37445.php on line %d

Binary file not shown.

View file

@ -0,0 +1,96 @@
--TEST--
Bug #39858 (http://bugs.php.net/bug.php?id=39858)
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
$row = $db->query('SELECT VERSION() as _version')->fetch(PDO::FETCH_ASSOC);
$matches = array();
if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
die(sprintf("skip Cannot determine MySQL Server version\n"));
$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
if ($version < 50000)
die(sprintf("skip Need MySQL Server 5.0.0+, found %d.%02d.%02d (%d)\n",
$matches[0], $matches[1], $matches[2], $version));
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
function bug_39858($db) {
$db->exec("DROP PROCEDURE IF EXISTS p");
$db->exec("
CREATE PROCEDURE p()
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
SELECT 2 * 2;
END;");
$stmt = $db->prepare("CALL p()");
$stmt->execute();
do {
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} while ($stmt->nextRowset());
$stmt = $db->prepare("CALL p()");
$stmt->execute();
do {
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} while ($stmt->nextRowset());
$stmt->closeCursor();
}
printf("Emulated Prepared Statements...\n");
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
bug_39858($db);
printf("Native Prepared Statements...\n");
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
bug_39858($db);
print "done!";
?>
--EXPECTF--
Emulated Prepared Statements...
array(1) {
[0]=>
array(1) {
["2 * 2"]=>
string(1) "4"
}
}
array(1) {
[0]=>
array(1) {
["2 * 2"]=>
string(1) "4"
}
}
Native Prepared Statements...
array(1) {
[0]=>
array(1) {
["2 * 2"]=>
string(1) "4"
}
}
array(1) {
[0]=>
array(1) {
["2 * 2"]=>
string(1) "4"
}
}
done!

View file

@ -0,0 +1,44 @@
--TEST--
Bug #41125 (http://bugs.php.net/bug.php?id=41125)
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
$row = $db->query('SELECT VERSION() as _version')->fetch(PDO::FETCH_ASSOC);
$matches = array();
if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
die(sprintf("skip Cannot determine MySQL Server version\n"));
$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
die("skip $version");
if ($version < 40100)
die(sprintf("skip Need MySQL Server 5.0.0+, found %d.%02d.%02d (%d)\n",
$matches[0], $matches[1], $matches[2], $version));
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
// And now allow the evil to do his work
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$sql = "CREATE TABLE IF NOT EXISTS test(id INT); INSERT INTO test(id) VALUES (1); SELECT * FROM test; INSERT INTO test(id) VALUES (2); SELECT * FROM test;";
// NOTE: This will fail, it is OK to fail - you must not mix DML/DDL and SELECT
// The PDO API does not support multiple queries properly!
// Read http://blog.ulf-wendel.de/?p=192
// Compare MySQL C-API documentation
$stmt = $db->query($sql);
do {
var_dump($stmt->fetchAll());
} while ($stmt->nextRowset());
print "done!";
?>
--EXPECTF--
Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error in %s on line %d
array(0) {
}
done!

View file

@ -0,0 +1,37 @@
--TEST--
PDO MySQL Bug #41698 (float parameters truncated to integer in 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');
setlocale(LC_ALL, "de","de_DE","de_DE.ISO8859-1","de_DE.ISO_8859-1","de_DE.UTF-8");
$db->exec('CREATE TABLE test(floatval DECIMAL(8,6))');
$db->exec('INSERT INTO test VALUES(2.34)');
$value=4.56;
$stmt = $db->prepare('INSERT INTO test VALUES(?)');
$stmt->execute(array($value));
var_dump($db->query('SELECT * from test')->fetchAll(PDO::FETCH_ASSOC));
?>
--EXPECT--
array(2) {
[0]=>
array(1) {
["floatval"]=>
string(8) "2.340000"
}
[1]=>
array(1) {
["floatval"]=>
string(8) "4.560000"
}
}

View file

@ -0,0 +1,64 @@
--TEST--
PDO MySQL Bug #41997 (stored procedure call returning single rowset blocks future queries)
--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();
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$row = $db->query('SELECT VERSION() as _version')->fetch(PDO::FETCH_ASSOC);
$matches = array();
if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
die(sprintf("skip Cannot determine MySQL Server version\n"));
$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
if ($version < 50000)
die(sprintf("skip Need MySQL Server 5.0.0+, found %d.%02d.%02d (%d)\n",
$matches[0], $matches[1], $matches[2], $version));
?>
--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->exec('DROP PROCEDURE IF EXISTS p');
$db->exec('CREATE PROCEDURE p() BEGIN SELECT 1 AS "one"; END');
$stmt = $db->query("CALL p()");
do {
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} while ($stmt->nextRowset());
var_dump($stmt->errorInfo());
$stmt = $db->query('SELECT 2 AS "two"');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
var_dump($stmt->errorInfo());
print "done!";
?>
--EXPECT--
array(1) {
[0]=>
array(1) {
["one"]=>
string(1) "1"
}
}
array(1) {
[0]=>
string(5) "00000"
}
array(1) {
[0]=>
array(1) {
["two"]=>
string(1) "2"
}
}
array(1) {
[0]=>
string(5) "00000"
}
done!

View file

@ -0,0 +1,80 @@
--TEST--
PDO MySQL Bug #42499 (http://bugs.php.net/bug.php?id=42499)
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
$stmt = $db->query('SELECT VERSION() as _version');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$matches = array();
if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
die(sprintf("skip Cannot determine MySQL Server version\n"));
$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
if ($version < 41000)
die(sprintf("skip Need MySQL Server 4.1.0+, found %d.%02d.%02d (%d)\n",
$matches[0], $matches[1], $matches[2], $version));
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
function bug_42499($db) {
$db->exec('DROP TABLE IF EXISTS test');
$db->exec('CREATE TABLE test(id CHAR(1)); INSERT INTO test(id) VALUES ("a")');
$stmt = $db->query('SELECT id AS _id FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// You must not use exec() to run statements that create a result set!
$db->exec('SELECT id FROM test');
// This will bail at you because you have not fetched the SELECT results: this is not a bug!
$db->exec('INSERT INTO test(id) VALUES ("b")');
}
print "Emulated Prepared Statements...\n";
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
bug_42499($db);
print "Native Prepared Statements...\n";
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
bug_42499($db);
$db = MySQLPDOTest::factory();
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Emulated Prepared Statements...
array(1) {
[0]=>
array(1) {
["_id"]=>
string(1) "a"
}
}
Warning: PDO::exec(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
Native Prepared Statements...
array(1) {
[0]=>
array(1) {
["_id"]=>
string(1) "a"
}
}
Warning: PDO::exec(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
done!

View file

@ -0,0 +1,20 @@
--TEST--
Bug #43371 (http://bugs.php.net/bug.php?id=43371)
--SKIPIF--
<?php
<?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');
$dsn = MySQLPDOTest::getDSN();
$db = new PDO($dsn, PDO_MYSQL_TEST_USER, PDO_MYSQL_TEST_PASS, array(PDO::ATTR_PERSISTENT => true));
print "done!";
?>
--EXPECT--
done!

View file

@ -0,0 +1,104 @@
--TEST--
Bug #44454 (http://bugs.php.net/bug.php?id=44454)
--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');
function bug_44454($db) {
try {
$db->exec('DROP TABLE IF EXISTS test');
$db->exec('CREATE TABLE test(a INT, b INT, UNIQUE KEY idx_ab (a, b))');
$db->exec('INSERT INTO test(a, b) VALUES (1, 1)');
$stmt = $db->query('SELECT a, b FROM test');
printf("... SELECT has returned %d row...\n", $stmt->rowCount());
while ($row = $stmt->fetch()) {
try {
printf("... INSERT should fail...\n");
$db->exec('INSERT INTO test(a, b) VALUES (1, 1)');
} catch (Exception $e) {
printf("... STMT - %s\n", var_export($stmt->errorCode(), true));
printf("... PDO - %s\n", var_export($db->errorInfo(), true));
}
}
} catch (Exception $e) {
printf("... While error %s\n", $e->getMessage()); ;
}
$stmt = $db->query('SELECT a, b FROM test');
printf("... SELECT has returned %d row...\n", $stmt->rowCount());
foreach ($stmt as $row) {
try {
printf("... INSERT should fail...\n");
$db->exec('INSERT INTO test(a, b) VALUES (1, 1)');
} catch (Exception $e) {
printf("... STMT - %s\n", var_export($stmt->errorCode(), true));
printf("... PDO - %s\n", var_export($db->errorInfo(), true));
}
}
}
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
print "Native Prepared Statements\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
bug_44454($db);
print "\nEmulated Prepared Statements\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
bug_44454($db);
print "done!";
?>
--XFAIL--
For some reason the exception gets thrown at the wrong place
--EXPECT--
Native Prepared Statements
... SELECT has returned 1 row...
... INSERT should fail...
... STMT - '00000'
... PDO - array (
0 => '23000',
1 => 1062,
2 => 'Duplicate entry \'1-1\' for key 1',
)
... SELECT has returned 1 row...
... INSERT should fail...
... STMT - '00000'
... PDO - array (
0 => '23000',
1 => 1062,
2 => 'Duplicate entry \'1-1\' for key 1',
)
Emulated Prepared Statements
... SELECT has returned 1 row...
... INSERT should fail...
... STMT - '00000'
... PDO - array (
0 => '23000',
1 => 1062,
2 => 'Duplicate entry \'1-1\' for key 1',
)
... SELECT has returned 1 row...
... INSERT should fail...
... STMT - '00000'
... PDO - array (
0 => '23000',
1 => 1062,
2 => 'Duplicate entry \'1-1\' for key 1',
)
done!

View file

@ -0,0 +1,92 @@
--TEST--
Bug #44707 (http://bugs.php.net/bug.php?id=44707) = ! driver bug
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
$stmt = $db->query('SELECT VERSION() as _version');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$matches = array();
if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
die(sprintf("skip Cannot determine MySQL Server version\n"));
$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
if ($version < 41000)
die(sprintf("skip Will work different with MySQL Server < 4.1.0, found %d.%02d.%02d (%d)\n",
$matches[0], $matches[1], $matches[2], $version));
?>
--FILE--
<?php
require dirname(__FILE__) . '/config.inc';
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
function bug_44707($db) {
$db->exec('DROP TABLE IF EXISTS test');
$db->exec('CREATE TABLE test(id INT, mybool TINYINT)');
$id = 1;
$mybool = false;
var_dump($mybool);
$stmt = $db->prepare('INSERT INTO test(id, mybool) VALUES (?, ?)');
$stmt->bindParam(1, $id);
// From MySQL 4.1 on boolean and TINYINT don't match! INSERT will fail.
// Versions prior to 4.1 have a weak test and will accept this.
$stmt->bindParam(2, $mybool, PDO::PARAM_BOOL);
var_dump($mybool);
$stmt->execute();
var_dump($mybool);
$stmt = $db->query('SELECT * FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt = $db->prepare('INSERT INTO test(id, mybool) VALUES (?, ?)');
$stmt->bindParam(1, $id);
// INT and integer work well together
$stmt->bindParam(2, $mybool, PDO::PARAM_INT);
$stmt->execute();
$stmt = $db->query('SELECT * FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
}
/*
// This is beyond the control of the driver... - the driver never gets in touch with bound values
print "Emulated Prepared Statements\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
bug_44707($db);
*/
print "Native Prepared Statements\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
bug_44707($db);
print "done!";
?>
--EXPECT--
Native Prepared Statements
bool(false)
bool(false)
bool(false)
array(0) {
}
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["mybool"]=>
string(1) "0"
}
}
done!

View file

@ -0,0 +1,50 @@
--TEST--
Bug #45120 (http://bugs.php.net/bug.php?id=45120)
--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');
function bug_45120($db) {
$stmt = $db->prepare("SELECT 1 AS 'one'");
if (true !== $stmt->execute())
printf("[001] Execute has failed: %s\n", var_export($stmt->errorInfo(), true));
$res = $stmt->fetch(PDO::FETCH_ASSOC);
if ($res['one'] != 1)
printf("[002] Wrong results: %s\n", var_export($res, true));
if (true !== $stmt->execute())
printf("[003] Execute has failed: %s\n", var_export($stmt->errorInfo(), true));
$res = $stmt->fetch(PDO::FETCH_ASSOC);
if ($res['one'] != 1)
printf("[004] Wrong results: %s\n", var_export($res, true));
}
print "Emulated Prepared Statements\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
bug_45120($db);
print "Native Prepared Statements\n";
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
bug_45120($db);
print "done!";
?>
--XFAIL--
This is an open PDO bug. It is not a PDO_MYSQL bug
--EXPECT--
Emulated Prepared Statements
Native Prepared Statements
done!

View file

@ -0,0 +1,62 @@
--TEST--
PDO MySQL PECL bug #1295 (http://pecl.php.net/bugs/bug.php?id=12925)
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
function bug_pecl_1295($db) {
$db->exec('DROP TABLE IF EXISTS test');
$db->exec('CREATE TABLE test(id CHAR(1))');
$db->exec('INSERT INTO test(id) VALUES ("a")');
$stmt = $db->prepare('UPDATE test SET id = "b"');
$stmt->execute();
$stmt = $db->prepare('UPDATE test SET id = "c"');
$stmt->execute();
$stmt = $db->prepare('SELECT id FROM test');
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt->closeCursor();
}
printf("Emulated...\n");
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
bug_pecl_1295($db);
printf("Native...\n");
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
bug_pecl_1295($db);
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECT--
Emulated...
array(1) {
[0]=>
array(1) {
["id"]=>
string(1) "c"
}
}
Native...
array(1) {
[0]=>
array(1) {
["id"]=>
string(1) "c"
}
}
done!

View file

@ -0,0 +1,87 @@
--TEST--
PDO MySQL Bug #42499 (http://bugs.php.net/bug.php?id=42499)
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
$row = $db->query('SELECT VERSION() as _version')->fetch(PDO::FETCH_ASSOC);
$matches = array();
if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
die(sprintf("skip Cannot determine MySQL Server version\n"));
$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
if ($version < 50000)
die(sprintf("skip Need MySQL Server 5.0.0+, found %d.%02d.%02d (%d)\n",
$matches[0], $matches[1], $matches[2], $version));
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
function bug_pecl_7976($db) {
$db->exec('DROP PROCEDURE IF EXISTS p');
$db->exec('CREATE PROCEDURE p() BEGIN SELECT "1" AS _one; END;');
$stmt = $db->query('CALL p()');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt->closeCursor();
$stmt = $db->query('CALL p()');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt->closeCursor();
}
printf("Emulated...\n");
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
bug_pecl_7976($db);
printf("Native...\n");
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
bug_pecl_7976($db);
$db->exec('DROP PROCEDURE IF EXISTS p');
print "done!";
?>
--XFAIL--
Works with mysqlnd. It is not supported by libmysql. For libmysql is good enough to see no crash.
--EXPECT--
Emulated...
array(1) {
[0]=>
array(1) {
["_one"]=>
string(1) "1"
}
}
array(1) {
[0]=>
array(1) {
["_one"]=>
string(1) "1"
}
}
Native...
array(1) {
[0]=>
array(1) {
["_one"]=>
string(1) "1"
}
}
array(1) {
[0]=>
array(1) {
["_one"]=>
string(1) "1"
}
}
done!

View file

@ -1,19 +1,52 @@
<?php
/* Overrule global settings, if need be */
if (false !== getenv('PDO_MYSQL_TEST_DSN')) {
# user set them from their shell
$config['ENV']['PDOTEST_DSN'] = getenv('PDO_MYSQL_TEST_DSN');
$config['ENV']['PDOTEST_USER'] = getenv('PDO_MYSQL_TEST_USER');
$config['ENV']['PDOTEST_PASS'] = getenv('PDO_MYSQL_TEST_PASS');
if (false !== getenv('PDO_MYSQL_TEST_ATTR')) {
$config['ENV']['PDOTEST_ATTR'] = getenv('PDO_MYSQL_TEST_ATTR');
}
# user set them from their shell
$config['ENV']['PDOTEST_DSN'] = getenv('PDO_MYSQL_TEST_DSN');
$config['ENV']['PDOTEST_USER'] = getenv('PDO_MYSQL_TEST_USER');
$config['ENV']['PDOTEST_PASS'] = getenv('PDO_MYSQL_TEST_PASS');
if (false !== getenv('PDO_MYSQL_TEST_ATTR')) {
$config['ENV']['PDOTEST_ATTR'] = getenv('PDO_MYSQL_TEST_ATTR');
}
} else {
$config['ENV']['PDOTEST_DSN'] = 'mysql:host=localhost;dbname=test';
$config['ENV']['PDOTEST_USER'] = 'root';
$config['ENV']['PDOTEST_PASS'] = '';
$config['ENV']['PDOTEST_DSN'] = 'mysql:host=localhost;dbname=test';
$config['ENV']['PDOTEST_USER'] = 'root';
$config['ENV']['PDOTEST_PASS'] = '';
}
foreach ($config['ENV'] as $k => $v) {
putenv("$k=$v");
}
/* MySQL specific settings */
define('PDO_MYSQL_TEST_ENGINE', (false !== getenv('PDO_MYSQL_TEST_ENGINE')) ? getenv('PDO_MYSQL_TEST_ENGINE') : 'MyISAM');
define('PDO_MYSQL_TEST_HOST', (false !== getenv('PDO_MYSQL_TEST_HOST')) ? getenv('PDO_MYSQL_TEST_HOST') : 'localhost');
define('PDO_MYSQL_TEST_PORT', (false !== getenv('PDO_MYSQL_TEST_PORT')) ? getenv('PDO_MYSQL_TEST_PORT') : NULL);
define('PDO_MYSQL_TEST_DB', (false !== getenv('PDO_MYSQL_TEST_DB')) ? getenv('PDO_MYSQL_TEST_DB') : 'test');
define('PDO_MYSQL_TEST_SOCKET', (false !== getenv('PDO_MYSQL_TEST_SOCKET')) ? getenv('PDO_MYSQL_TEST_SOCKET') : NULL);
define('PDO_MYSQL_TEST_DSN', (false !== getenv('PDO_MYSQL_TEST_DSN')) ? getenv('PDO_MYSQL_TEST_DSN') : $config['ENV']['PDOTEST_DSN']);
define('PDO_MYSQL_TEST_USER', (false !== getenv('PDO_MYSQL_TEST_USER')) ? getenv('PDO_MYSQL_TEST_USER') : $config['ENV']['PDOTEST_USER']);
define('PDO_MYSQL_TEST_PASS', (false !== getenv('PDO_MYSQL_TEST_PASS')) ? getenv('PDO_MYSQL_TEST_PASS') : $config['ENV']['PDOTEST_PASS']);
define('PDO_MYSQL_TEST_CHARSET', (false !== getenv('PDO_MYSQL_TEST_CHARSET')) ? getenv('PDO_MYSQL_TEST_CHARSET') : NULL);
if (!function_exists('sys_get_temp_dir')) {
function sys_get_temp_dir() {
if (!empty($_ENV['TMP']))
return realpath( $_ENV['TMP'] );
if (!empty($_ENV['TMPDIR']))
return realpath( $_ENV['TMPDIR'] );
if (!empty($_ENV['TEMP']))
return realpath( $_ENV['TEMP'] );
$temp_file = tempnam(md5(uniqid(rand(), TRUE)), '');
if ($temp_file) {
$temp_dir = realpath(dirname($temp_file));
unlink($temp_file);
return $temp_dir;
}
return FALSE;
}
}
?>

View file

@ -4,7 +4,7 @@ PDO MySQL auto_increment / last insert id
<?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';
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
@ -32,4 +32,4 @@ PDOStatement Object
(
[queryString] => INSERT INTO test (num) VALUES (451)
)
24
24

View file

@ -0,0 +1,162 @@
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'config.inc');
require_once(dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc');
class MySQLPDOTest extends PDOTest {
static function factory($classname = 'PDO', $drop_test_tables = false, $myattr = null) {
$dsn = self::getDSN();
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
$attr = getenv('PDOTEST_ATTR');
if (is_string($attr) && strlen($attr)) {
$attr = unserialize($attr);
} else {
$attr = null;
}
if ($user === false)
$user = NULL;
if ($pass === false)
$pass = NULL;
$db = new $classname($dsn, $user, $pass, $attr);
if (!$db) {
die("Could not create PDO object (DSN=$dsn, user=$user)\n");
}
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
return $db;
}
static function createTestTable($db, $engine = null) {
if (!$engine)
$engine = PDO_MYSQL_TEST_ENGINE;
$db->exec('DROP TABLE IF EXISTS test');
$db->exec('CREATE TABLE test(id INT, label CHAR(1), PRIMARY KEY(id)) ENGINE=' . $engine);
$db->exec('INSERT INTO test(id, label) VALUES (1, "a"), (2, "b"), (3, "c"), (4, "d"), (5, "e"), (6, "f")');
}
static function getTableEngine() {
return PDO_MYSQL_TEST_ENGINE;
}
static function getDSN($new_options = null, $addition = '') {
if (!$new_options)
return PDO_MYSQL_TEST_DSN . $addition;
$old_options = array();
$dsn = substr(PDO_MYSQL_TEST_DSN,
strpos(PDO_MYSQL_TEST_DSN, ':') + 1,
strlen(PDO_MYSQL_TEST_DSN));
// no real parser - any excotic setting can fool us
$parts = explode(';', $dsn);
foreach ($parts as $k => $v) {
$tmp = explode('=', $v);
if (count($tmp) == 2)
$old_options[$tmp[0]] = $tmp[1];
}
$options = $old_options;
foreach ($new_options as $k => $v)
$options[$k] = $v;
$dsn = 'mysql:';
foreach ($options as $k => $v)
$dsn .= sprintf('%s=%s;', $k, $v);
if ($addition)
$dsn .= $addition;
else
$dsn = substr($dsn, 0, strlen($dsn) -1);
return $dsn;
}
static function getClientVersion($db) {
return self::extractVersion($db->getAttribute(PDO::ATTR_CLIENT_VERSION));
}
static function getServerVersion($db) {
return self::extractVersion($db->getAttribute(PDO::ATTR_SERVER_VERSION));
}
static function extractVersion($version_string) {
/*
TODO:
We're a bit in trouble: PDO_MYSQL returns version strings.
That's wrong according to the manual. According to the manual
integers should be returned. However, this code needs to work
with stinky PDO_MYSQL and hopefully better PDO_MYSQLND.
*/
// already an int value?
if (is_int($version_string))
return $version_string;
// string but int value?
$tmp = (int)$version_string;
if (((string)$tmp) === $version_string)
return $tmp;
// stinky string which we need to parse
$parts = explode('.', $version_string);
if (count($parts) != 3)
return -1;
$version = (int)$parts[0] * 10000;
$version+= (int)$parts[1] * 100;
$version+= (int)$parts[2];
return $version;
}
static function getTempDir() {
if (!function_exists('sys_get_temp_dir')) {
if (!empty($_ENV['TMP']))
return realpath( $_ENV['TMP'] );
if (!empty($_ENV['TMPDIR']))
return realpath( $_ENV['TMPDIR'] );
if (!empty($_ENV['TEMP']))
return realpath( $_ENV['TEMP'] );
$temp_file = tempnam(md5(uniqid(rand(), TRUE)), '');
if ($temp_file) {
$temp_dir = realpath(dirname($temp_file));
unlink($temp_file);
return $temp_dir;
}
return FALSE;
} else {
return sys_get_temp_dir();
}
}
static function detect_transactional_mysql_engine($db) {
foreach ($db->query("show variables like 'have%'") as $row) {
if ($row[1] == 'YES' && ($row[0] == 'have_innodb' || $row[0] == 'have_bdb')) {
return str_replace("have_", "", $row[0]);
}
}
return false;
}
static function isPDOMySQLnd() {
ob_start();
phpinfo();
$tmp = ob_get_contents();
ob_end_clean();
return (true == stristr($tmp, 'PDO Driver for MySQL, mysql native driver version'));
}
}
?>

View file

@ -0,0 +1,303 @@
--TEST--
MySQL PDO->__construct() - Generic + DSN
--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');
function tryandcatch($offset, $code) {
try {
eval($code);
assert(sprintf("[%03d] Should have failed\n", $offset) != '');
} catch (PDOException $e) {
return sprintf("[%03d] %s, [%s] %s\n",
$offset,
$e->getMessage(),
(isset($db) && is_object($db)) ? $db->errorCode() : 'n/a',
(isset($db) && is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
}
return '';
}
try {
if (NULL !== ($db = @new PDO()))
printf("[001] Too few parameters\n");
print tryandcatch(2, '$db = new PDO(chr(0));');
print tryandcatch(3, '$db = new PDO("a" . chr(0) . "b");');
print tryandcatch(4, '$db = new PDO("MYSQL");');
print tryandcatch(5, '$db = new PDO("mysql");');
print tryandcatch(6, '$db = new PDO("mysql ");');
print tryandcatch(7, '$db = new PDO("fantasyandfriends :");');
$dsn = PDO_MYSQL_TEST_DSN;
// MySQL Server might accept anonymous connections, don't
// print anything
tryandcatch(8, '$db = new PDO("' . $dsn . '");');
$user = 'dontcreatesuchauser';
$pass = 'withthispassword';
print tryandcatch(9, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
// should fail
$dsn = 'mysql:';
print tryandcatch(10, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
$dsn = PDO_MYSQL_TEST_DSN;
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
// should work...
$db = new PDO($dsn, $user, $pass);
$dsn = 'mysql:invalid=foo';
print tryandcatch(11, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
$dsn = 'mysql:' . str_repeat('howmuch=canpdoeat;', 1000);
print tryandcatch(12, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
$dsn = 'mysql:' . str_repeat('abcdefghij', 1024 * 10) . '=somevalue';
print tryandcatch(13, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
if (PDO_MYSQL_TEST_HOST) {
$host = PDO_MYSQL_TEST_HOST;
$invalid_host = $host . 'invalid';
// last host specification should be the one used
$dsn = MySQLPDOTest::getDSN(array('host' => $host), 'host=' . $invalid_host);
try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
$tmp = $e->getMessage();
if (!stristr($tmp, 'HY000') && !stristr($tmp, '2005') && !stristr($tmp, '2002'))
printf("[014] Cannot find proper error codes: %s\n", $tmp);
}
$dsn = MySQLPDOTest::getDSN(array('host' => $invalid_host), 'host=' . $host);
try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
printf("[015] DSN=%s, %s\n", $dsn, $e->getMessage());
}
$invalid_host = '-' . chr(0);
$dsn = MySQLPDOTest::getDSN(array('host' => $invalid_host));
try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
$tmp = $e->getMessage();
if (!stristr($tmp, 'HY000') && !stristr($tmp, '2005') && !stristr($tmp, '2002'))
printf("[016] Cannot find proper error codes: %s\n", $tmp);
}
// parsing should not get confused by chr(0)
$dsn = MySQLPDOTest::getDSN(array('host' => $invalid_host), 'host=' . $host);
try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
printf("[017] DSN=%s, %s\n", $dsn, $e->getMessage());
}
}
// what about long values for a valid option ...
$dsn = MySQLPDOTest::getDSN(array('host' => str_repeat('0123456789', 1024 * 100)));
try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
$tmp = $e->getMessage();
if (!stristr($tmp, 'HY000') && !stristr($tmp, '2005') && !stristr($tmp, '2002'))
printf("[018] Cannot find proper error codes: %s\n", $tmp);
}
if (PDO_MYSQL_TEST_PORT && (PDO_MYSQL_TEST_SOCKET == '')) {
// Playing with the port makes only sense if no socket gets used
$port = PDO_MYSQL_TEST_PORT;
// let's hope we don't hit a MySQL running on that port...
$invalid_port = $port * 2;
$dsn = MySQLPDOTest::getDSN(array('port' => $port), 'port=' . $invalid_port);
try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
$tmp = $e->getMessage();
if (!stristr($tmp, 'HY000') && !stristr($tmp, '2005'))
printf("[019] Cannot find proper error codes: %s\n", $tmp);
}
$dsn = MySQLPDOTest::getDSN(array('port' => $invalid_port), 'port=' . $port);
try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
printf("[020] DSN=%s, %s\n", $dsn, $e->getMessage());
}
$invalid_port = 'abc';
$dsn = MySQLPDOTest::getDSN(array('port' => $port), 'port=' . $invalid_port);
try {
$db = @new PDO($dsn, $user, $pass);
// atoi('abc') = 0, 0 -> fallback to default 3306 -> may or may not fail!
} catch (PDOException $e) {
}
}
if (PDO_MYSQL_TEST_DB) {
$db = PDO_MYSQL_TEST_DB;
$invalid_db = 'letshopeitdoesnotexist';
$dsn = MySQLPDOTest::getDSN(array('dbname' => $db), 'dbname=' . $invalid_db);
try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
$tmp = $e->getMessage();
if (!stristr($tmp, '42000') && !stristr($tmp, '1049'))
printf("[022] Cannot find proper error codes: %s\n", $tmp);
}
$dsn = MySQLPDOTest::getDSN(array('dbname' => $invalid_db), 'dbname=' . $db);
try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
printf("[023] DSN=%s, %s\n", $dsn, $e->getMessage());
}
}
if (PDO_MYSQL_TEST_SOCKET && (stristr(PDO_MYSQL_TEST_DSN, PDO_MYSQL_TEST_SOCKET) !== false)) {
$socket = PDO_MYSQL_TEST_SOCKET;
$invalid_socket = '/lets/hope/it/does/not/exist';
$dsn = MySQLPDOTest::getDSN(array('unix_socket' => $socket), 'unix_socket=' . $invalid_socket);
try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
$tmp = $e->getMessage();
if (!stristr($tmp, 'HY000') && !stristr($tmp, '2002'))
printf("[024] Cannot find proper error codes: %s\n", $tmp);
}
$dsn = MySQLPDOTest::getDSN(array('unix_socket' => $invalid_socket), 'unix_socket=' . $socket);
try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
printf("[025] DSN=%s, %s\n", $dsn, $e->getMessage());
}
}
$have_charset_support = false;
$dsn = MySQLPDOTest::getDSN();
try {
$db = new PDO($dsn, $user, $pass);
$stmt = $db->query('SELECT VERSION() as _version');
$version = $stmt->fetch(PDO::FETCH_ASSOC);
$tmp = explode('.', $version['_version']);
if ((count($tmp) == 3) &&
(($tmp[0] >= 4 && $tmp[1] >= 1) || ($tmp[0] >= 5))) {
// MySQL Server 4.1 - charset support available
$have_charset_support = true;
}
} catch (PDOException $e) {
printf("[026] DSN=%s, %s\n", $dsn, $e->getMessage());
}
if (PDO_MYSQL_TEST_CHARSET) {
$charset = PDO_MYSQL_TEST_CHARSET;
$invalid_charset = 'invalid';
if ($have_charset_support) {
$dsn = MySQLPDOTest::getDSN();
$db = new PDO($dsn, $user, $pass);
$stmt = $db->query(sprintf('SHOW CHARACTER SET LIKE "%s"', $charset));
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
$have_charset = (empty($tmp)) ? false : true;
if ($have_charset) {
$dsn = MySQLPDOTest::getDSN(array('charset' => $charset), 'charset=' . $invalid_charset);
try {
$db = @new PDO($dsn, $user, $pass);
/* NOTE: MySQL does a fallback to the charset suggested during the handshake - no error - no bug! */
assert(false);
printf("%s\n", $dsn);
} catch (PDOException $e) {
$tmp = $e->getMessage();
/* TODO: add proper codes */
if (!stristr($tmp, 'sqlstatecode') || !stristr($tmp, 'mysqlinternalerrcode'))
printf("[027] TODO - Cannot find proper error codes: %s\n", $tmp);
}
$dsn = MySQLPDOTest::getDSN(array('charset' => $invalid_charset), 'charset=' . $charset);
try {
$db = @new PDO($dsn, $user, $pass);
/* Strictly speaking we should test more: character_set_client, character_set_results, and character_set_connection */
$stmt = $db->query('SELECT @@character_set_connection AS _charset');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
if ($tmp['_charset'] != $charset)
printf("[028] Character sets has not been set, @@character_set_connection reports '%s', expecting '%s'",
$tmp['_charset'], $charset);
} catch (PDOException $e) {
printf("[029] DSN=%s, %s\n", $dsn, $e->getMessage());
}
} else {
printf("[030] You're trying to run the tests with charset '%s' which seems not supported by the server!", $charset);
}
}
}
if ($have_charset_support) {
// In case the PDO_MYSQL_TEST_CHARSET interferes with any defaults
// we do another test to verify that the charset has been set.
$dsn = MySQLPDOTest::getDSN();
$db = new PDO($dsn, $user, $pass);
$stmt = $db->query('SHOW CHARACTER SET LIKE "latin1"');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
$have_latin1 =(empty($tmp)) ? false : true;
$stmt = $db->query('SHOW CHARACTER SET LIKE "latin2"');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
$have_latin2 =(empty($tmp)) ? false : true;
if ($have_latin1 && $have_latin2) {
// very likely we do have both of them...
try {
$dsn = MySQLPDOTest::getDSN(array('charset' => 'latin1'));
$db = new PDO($dsn, $user, $pass);
$stmt = $db->query('SELECT @@character_set_connection AS _charset');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
if ($tmp['_charset'] != 'latin1')
printf("[031] DSN = %s, Character sets has not been set, @@character_set_connection reports '%s', expecting '%s'",
$dsn, $tmp['_charset'], 'latin1');
} catch (PDOException $e) {
printf("[032] %s\n", $e->getMessage());
}
try {
$dsn = MySQLPDOTest::getDSN(array('charset' => 'latin2'));
$db = new PDO($dsn, $user, $pass);
$stmt = $db->query('SELECT @@character_set_connection AS _charset');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
if ($tmp['_charset'] != 'latin2')
printf("[033] DSN = %s, character sets has not been set, @@character_set_connection reports '%s', expecting '%s'",
$dsn, $tmp['_charset'], 'latin2');
} catch (PDOException $e) {
printf("[034] %s\n", $e->getMessage());
}
}
}
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
(is_object($db)) ? $db->errorCode() : 'n/a',
(is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
}
print "done!";
--EXPECTF--
[002] invalid data source name, [n/a] n/a
[003] invalid data source name, [n/a] n/a
[004] invalid data source name, [n/a] n/a
[005] invalid data source name, [n/a] n/a
[006] invalid data source name, [n/a] n/a
[007] could not find driver, [n/a] n/a
[009] SQLSTATE[28000] [1045] Access denied for user 'dont%s'@'%s' (using password: YES), [n/a] n/a
[010] SQLSTATE[28000] [1045] Access denied for user 'dont%s'@'%s' (using password: YES), [n/a] n/a
[017] DSN=%s, SQLSTATE[%s] [%d] %s
Warning: assert(): Assertion failed in %s on line %d
mysql:%s
[033] DSN = mysql:%s, character sets has not been set, @@character_set_connection reports 'latin1', expecting 'latin2'done!

View file

@ -0,0 +1,56 @@
--TEST--
MySQL PDO->__construct() - URI
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
/* TODO - fix this limitation */
if (getenv('PDO_MYSQL_TEST_DSN') !== "mysql:dbname=phptest;unix_socket=/tmp/mysql.sock")
die("skip Fix test to run in other environments as well!");
?>
--INI--
pdo.dsn.mysql="mysql:dbname=phptest;socket=/tmp/mysql.sock"
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$found = false;
$values = ini_get_all();
foreach ($values as $name => $dsn)
if ('pdo.dsn.mysql' == $name) {
printf("pdo.dsn.mysql=%s\n", $dsn);
$found = true;
break;
}
if (!$found) {
$dsn = ini_get('pdo.dsn.mysql');
$found = ($dsn !== false);
}
if (!$found)
printf("pdo.dsn.mysql cannot be accessed through ini_get_all()/ini_get()\n");
if (MySQLPDOTest::getDSN() == $dsn) {
// we are lucky, we can run the test
try {
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
$db = new PDO('mysql', $user, $pass);
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
(is_object($db)) ? $db->errorCode() : 'n/a',
(is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
}
}
print "done!";
--EXPECTF--
pdo.dsn.mysql cannot be accessed through ini_get_all()/ini_get()
done!

View file

@ -0,0 +1,170 @@
--TEST--
MySQL PDO->__construct(), options
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
function set_option_and_check($offset, $option, $value, $option_desc) {
$dsn = MySQLPDOTest::getDSN();
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
try {
$db = new PDO($dsn, $user, $pass, array($option => $value));
if (!is_object($db) || ($value !== ($tmp = @$db->getAttribute($option))))
printf("[%03d] Execting '%s'/%s got '%s'/%s' for options '%s'\n",
$offset,
$value, gettype($value),
$tmp, gettype($tmp),
$option_desc);
} catch (PDOException $e) {
printf("[%03d] %s\n", $offset, $e->getMessage());
}
}
try {
$dsn = MySQLPDOTest::getDSN();
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
$valid_options = array(
/* pdo_dbh.c */
PDO::ATTR_PERSISTENT => 'PDO::ATTR_PERSISTENT',
PDO::ATTR_AUTOCOMMIT => 'PDO::ATTR_AUTOCOMMIT',
/* mysql_driver.c */
/* TODO Possible bug PDO::ATTR_TIMEOUT != MYSQLI_OPT_CONNECT_TIMEOUT*/
PDO::ATTR_TIMEOUT => 'PDO::ATTR_TIMEOUT',
PDO::ATTR_EMULATE_PREPARES => 'PDO::ATTR_EMULATE_PREPARES',
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => 'PDO::MYSQL_ATTR_USE_BUFFERED_QUERY',
PDO::MYSQL_ATTR_LOCAL_INFILE => 'PDO::MYSQL_ATTR_LOCAL_INFILE',
PDO::MYSQL_ATTR_DIRECT_QUERY => 'PDO::MYSQL_ATTR_DIRECT_QUERY',
);
$defaults = array(
PDO::ATTR_PERSISTENT => false,
PDO::ATTR_AUTOCOMMIT => 1,
/* TODO - why is this a valid option if getAttribute() does not support it?! */
PDO::ATTR_TIMEOUT => false,
PDO::ATTR_EMULATE_PREPARES => 1,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => 1,
/* TODO getAttribute() does not handle it */
PDO::MYSQL_ATTR_LOCAL_INFILE => false,
/* TODO getAttribute() does not handle it */
PDO::MYSQL_ATTR_DIRECT_QUERY => 1,
);
if (NULL !== ($db = @new PDO($dsn, $user, $pass, 'wrong type')))
printf("[001] Expecting NULL got %s/%s\n", gettype($db), $db);
if (!is_object($db = new PDO($dsn, $user, $pass, array())))
printf("[002] Expecting object got %s/%s¸\n", gettype($db), $db);
do {
$invalid = mt_rand(-1000, 1000);
} while (isset($valid_options[$invalid]));
if (is_object($db = new PDO($dsn, $user, $pass, array($invalid => true))))
printf("[003] [TODO][CHANGEREQUEST] Please, lets not ignore invalid options and bail out!\n");
$db = new PDO($dsn, $user, $pass);
foreach ($valid_options as $option => $name) {
/* TODO getAttribute() is pretty poor in supporting the options, suppress errors */
$tmp = @$db->getAttribute($option);
if ($tmp !== $defaults[$option])
printf("[003a] Expecting default value for '%s' of '%s'/%s, getAttribute() reports setting '%s'/%s\n",
$name, $defaults[$option], gettype($defaults[$option]),
$tmp, gettype($tmp));
}
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_AUTOCOMMIT => true));
if (!is_object($db) || !$db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[004] Autocommit should be on\n");
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_AUTOCOMMIT => false));
if (!is_object($db) || $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[005] Autocommit should be off\n");
/* TODO: no way to check ATTR_TIMEOUT settings */
if (!is_object($db = new PDO($dsn, $user, $pass, array(PDO::ATTR_TIMEOUT => 10))))
printf("[006] ATTR_TIMEOUT should be accepted\n");
if (!is_object($db = new PDO($dsn, $user, $pass, array(PDO::ATTR_TIMEOUT => PHP_INT_MAX))))
printf("[007] ATTR_TIMEOUT should be accepted\n");
if (!is_object($db = new PDO($dsn, $user, $pass, array(PDO::ATTR_TIMEOUT => -PHP_INT_MAX))))
printf("[008] ATTR_TIMEOUT should be accepted\n");
/* TODO: Its ugly that PDO::ATTR_EMULATE_PREPARES == PDO::MYSQL_ATTR_DIRECT_QUERY */
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_EMULATE_PREPARES => true));
if (!is_object($db))
printf("[009] ATTR_EMULATE_PREPARES should be accepted and on\n");
if (!$db->getAttribute(PDO::ATTR_EMULATE_PREPARES))
printf("[010] [TODO][CHANGEREQUEST] ATTR_EMULATE_PREPARES should be on\n");
if (!$db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[011] As PDO::MYSQL_ATTR_DIRECT_QUERY == PDO::ATTR_EMULATE_PREPARES
and PDO::ATTR_EMULATE_PREPARES overrules the other, PDO::MYSQL_ATTR_DIRECT_QUERY should be on\n");
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_EMULATE_PREPARES => false));
if (!is_object($db))
printf("[012] ATTR_EMULATE_PREPARES should be accepted and on\n");
if ($db->getAttribute(PDO::ATTR_EMULATE_PREPARES))
printf("[013] [TODO][CHANGEREQUEST] ATTR_EMULATE_PREPARES should be off\n");
if ($db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[014] As PDO::MYSQL_ATTR_DIRECT_QUERY == PDO::ATTR_EMULATE_PREPARES
and PDO::ATTR_EMULATE_PREPARES overrules the other, PDO::MYSQL_ATTR_DIRECT_QUERY should be off\n");
// PDO::ATTR_EMULATE_PREPARES overrules PDO::MYSQL_ATTR_DIRECT_QUERY
// TODO: is it clever that a generic setting overrules a specific setting?
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_EMULATE_PREPARES => true, PDO::MYSQL_ATTR_DIRECT_QUERY => false));
if (!$db->getAttribute(PDO::ATTR_EMULATE_PREPARES))
printf("[015] PDO::ATTR_EMULATE_PREPARES should be on\n");
if (!$db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[016] PDO::MYSQL_ATTR_DIRECT_QUERY should be on\n");
$db = new PDO($dsn, $user, $pass, array(PDO::ATTR_EMULATE_PREPARES => false, PDO::MYSQL_ATTR_DIRECT_QUERY => true));
if ($db->getAttribute(PDO::ATTR_EMULATE_PREPARES))
printf("[017] PDO::ATTR_EMULATE_PREPARES should be off\n");
if ($db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[018] PDO::MYSQL_ATTR_DIRECT_QUERY should be off\n");
set_option_and_check(19, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1, 'PDO::MYSQL_ATTR_USE_BUFFERED_QUERY');
set_option_and_check(20, PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 0, 'PDO::MYSQL_ATTR_USE_BUFFERED_QUERY');
set_option_and_check(21, PDO::MYSQL_ATTR_LOCAL_INFILE, true, 'PDO::MYSQL_ATTR_LOCAL_INFILE');
set_option_and_check(22, PDO::MYSQL_ATTR_LOCAL_INFILE, false, 'PDO::MYSQL_ATTR_LOCAL_INFILE');
set_option_and_check(33, PDO::MYSQL_ATTR_DIRECT_QUERY, 1, 'PDO::MYSQL_ATTR_DIRECT_QUERY');
set_option_and_check(34, PDO::MYSQL_ATTR_DIRECT_QUERY, 0, 'PDO::MYSQL_ATTR_DIRECT_QUERY');
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
(is_object($db)) ? $db->errorCode() : 'n/a',
(is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
}
print "done!";
--EXPECTF--
[003] [TODO][CHANGEREQUEST] Please, lets not ignore invalid options and bail out!
[003a] Expecting default value for 'PDO::ATTR_EMULATE_PREPARES' of '1'/integer, getAttribute() reports setting ''/boolean
Warning: PDO::getAttribute(): SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute in %s on line %d
[010] [TODO][CHANGEREQUEST] ATTR_EMULATE_PREPARES should be on
Warning: PDO::getAttribute(): SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute in %s on line %d
Warning: PDO::getAttribute(): SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute in %s on line %d
[015] PDO::ATTR_EMULATE_PREPARES should be on
[016] PDO::MYSQL_ATTR_DIRECT_QUERY should be on
Warning: PDO::getAttribute(): SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute in %s on line %d
[018] PDO::MYSQL_ATTR_DIRECT_QUERY should be off
[021] Execting '1'/boolean got ''/boolean' for options 'PDO::MYSQL_ATTR_LOCAL_INFILE'
done!

View file

@ -0,0 +1,88 @@
--TEST--
MySQL PDO->__construct(), libmysql only options
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
if (MySQLPDOTest::isPDOMySQLnd())
die("skip libmysql only options")
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
function set_option_and_check($offset, $option, $value, $option_desc, $ignore_diff = false) {
$dsn = MySQLPDOTest::getDSN();
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
try {
$db = new PDO($dsn, $user, $pass, array($option => $value));
if (!is_object($db) || (!$ignore_diff && ($value !== ($tmp = @$db->getAttribute($option)))))
printf("[%03d] Execting '%s'/%s got '%s'/%s' for options '%s'\n",
$offset,
$value, gettype($value),
$tmp, gettype($tmp),
$option_desc);
} catch (PDOException $e) {
printf("[%03d] %s\n", $offset, $e->getMessage());
}
}
try {
$dsn = MySQLPDOTest::getDSN();
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
$valid_options = array();
$valid_options[PDO::MYSQL_ATTR_MAX_BUFFER_SIZE] = 'PDO::MYSQL_ATTR_MAX_BUFFER_SIZE';
$valid_options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'PDO::MYSQL_ATTR_INIT_COMMAND';
$valid_options[PDO::MYSQL_ATTR_READ_DEFAULT_FILE] = 'PDO::MYSQL_ATTR_READ_DEFAULT_FILE';
$valid_options[PDO::MYSQL_ATTR_READ_DEFAULT_GROUP] = 'PDO::MYSQL_ATTR_READ_DEFAULT_GROUP';
$defaults[PDO::MYSQL_ATTR_MAX_BUFFER_SIZE] = 1048576;
/* TODO getAttribute() does not handle it */
$defaults[PDO::MYSQL_ATTR_INIT_COMMAND] = '';
$defaults[PDO::MYSQL_ATTR_READ_DEFAULT_FILE] = false;
$defaults[PDO::MYSQL_ATTR_READ_DEFAULT_GROUP] = false;
$db = new PDO($dsn, $user, $pass);
foreach ($valid_options as $option => $name) {
/* TODO getAttribute() is pretty poor in supporting the options, suppress errors */
$tmp = @$db->getAttribute($option);
if ($tmp !== $defaults[$option])
printf("[001] Expecting default value for '%s' of '%s'/%s, getAttribute() reports setting '%s'/%s\n",
$name, $defaults[$option], gettype($defaults[$option]),
$tmp, gettype($tmp));
}
set_option_and_check(23, PDO::MYSQL_ATTR_INIT_COMMAND, 'SET @a=1', 'PDO::MYSQL_ATTR_INIT_COMMAND');
set_option_and_check(24, PDO::MYSQL_ATTR_INIT_COMMAND, '', 'PDO::MYSQL_ATTR_INIT_COMMAND');
set_option_and_check(25, PDO::MYSQL_ATTR_INIT_COMMAND, 'INSERT INTO nonexistent(invalid) VALUES (1)', 'PDO::MYSQL_ATTR_INIT_COMMAND');
set_option_and_check(26, PDO::MYSQL_ATTR_READ_DEFAULT_FILE, true, 'PDO::MYSQL_ATTR_READ_DEFAULT_FILE');
set_option_and_check(27, PDO::MYSQL_ATTR_READ_DEFAULT_FILE, false, 'PDO::MYSQL_ATTR_READ_DEFAULT_FILE');
set_option_and_check(30, PDO::MYSQL_ATTR_MAX_BUFFER_SIZE, -1, 'PDO::MYSQL_ATTR_MAX_BUFFER_SIZE', true);
set_option_and_check(31, PDO::MYSQL_ATTR_MAX_BUFFER_SIZE, PHP_INT_MAX, 'PDO::MYSQL_ATTR_MAX_BUFFER_SIZE');
set_option_and_check(32, PDO::MYSQL_ATTR_MAX_BUFFER_SIZE, 1, 'PDO::MYSQL_ATTR_MAX_BUFFER_SIZE');
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
(is_object($db)) ? $db->errorCode() : 'n/a',
(is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
}
print "done!";
--EXPECTF--
[001] Expecting default value for 'PDO::MYSQL_ATTR_INIT_COMMAND' of ''/string, getAttribute() reports setting ''/boolean
[023] Execting 'SET @a=1'/string got ''/boolean' for options 'PDO::MYSQL_ATTR_INIT_COMMAND'
[024] SQLSTATE[42000] [1065] Query was empty
[025] SQLSTATE[42S02] [1146] Table '%snonexistent' doesn't exist
[026] Execting '1'/boolean got ''/boolean' for options 'PDO::MYSQL_ATTR_READ_DEFAULT_FILE'
done!

View file

@ -0,0 +1,75 @@
--TEST--
MySQL PDO->__construct() - URI
--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');
try {
if ($tmp = MySQLPDOTest::getTempDir()) {
$file = $tmp . DIRECTORY_SEPARATOR . 'pdomuri.tst';
$dsn = MySQLPDOTest::getDSN();
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
$uri = sprintf('uri:file:%s', $file);
if ($fp = @fopen($file, 'w')) {
// ok, great we can create a file with a DSN in it
fwrite($fp, $dsn);
fclose($fp);
clearstatcache();
assert(file_exists($file));
try {
$db = new PDO($uri, $user, $pass);
} catch (PDOException $e) {
printf("[002] URI=%s, DSN=%s, File=%s (%d bytes, '%s'), %s\n",
$uri, $dsn,
$file, filesize($file), file_get_contents($file),
$e->getMessage());
}
unlink($file);
}
if ($fp = @fopen($file, 'w')) {
fwrite($fp, sprintf('mysql:dbname=letshopeinvalid;%s%s',
chr(0), $dsn));
fclose($fp);
clearstatcache();
assert(file_exists($file));
try {
$db = new PDO($uri, $user, $pass);
} catch (PDOException $e) {
printf("[003] URI=%s, DSN=%s, File=%s (%d bytes, '%s'), chr(0) test, %s\n",
$uri, $dsn,
$file, filesize($file), file_get_contents($file),
$e->getMessage());
}
unlink($file);
}
}
/* TODO: safe mode */
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
(is_object($db)) ? $db->errorCode() : 'n/a',
(is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
}
print "done!";
--EXPECTF--
Warning: PDO::__construct(%s
[002] URI=uri:file:%spdomuri.tst, DSN=mysql%sdbname=%s, File=%spdomuri.tst (%d bytes, 'mysql%sdbname=%s'), invalid data source URI
Warning: PDO::__construct(%s
[003] URI=uri:file:%spdomuri.tst, DSN=mysql%sdbname=%s, File=%spdomuri.tst (%d bytes, 'mysql%sdbname=letshopeinvalid%s'), chr(0) test, invalid data source URI
done!

View file

@ -0,0 +1,93 @@
--TEST--
PDO::ATTR_AUTOCOMMIT
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
// autocommit should be on by default
if (1 !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
printf("[001] Expecting int/1 got %s\n", var_export($tmp, true));
// lets see if the server agrees to that
$row = $db->query('SELECT @@autocommit AS _autocommit')->fetch(PDO::FETCH_ASSOC);
if (!$row['_autocommit'])
printf("[002] Server autocommit mode should be on, got '%s'\n", var_export($row['_autocommit']));
// on -> off
if (!$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 0))
printf("[003] Cannot turn off autocommit\n");
$row = $db->query('SELECT @@autocommit AS _autocommit')->fetch(PDO::FETCH_ASSOC);
if ($row['_autocommit'])
printf("[004] Server autocommit mode should be off, got '%s'\n", var_export($row['_autocommit']));
// PDO thinks autocommit is off, but its manually turned on...
if (!$db->query('SET autocommit = 1'))
printf("[005] Cannot turn on server autocommit mode, %s\n", var_export($db->errorInfo(), true));
if (0 !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
printf("[006] Expecting int/0 got %s\n", var_export($tmp, true));
// off -> on
if (!$db->query('SET autocommit = 0'))
printf("[007] Cannot turn off server autocommit mode, %s\n", var_export($db->errorInfo(), true));
if (!$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 1))
printf("[008] Cannot turn on autocommit\n");
$row = $db->query('SELECT @@autocommit AS _autocommit')->fetch(PDO::FETCH_ASSOC);
if (!$row['_autocommit'])
printf("[009] Server autocommit mode should be on, got '%s'\n", var_export($row['_autocommit']));
if (1 !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
printf("[010] Expecting int/1 got %s\n", var_export($tmp, true));
if (MySQLPDOTest::detect_transactional_mysql_engine($db)) {
// nice, we have a transactional engine to play with
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
$num = $row['_num'];
$db->query('INSERT INTO test(id, label) VALUES (100, "z")');
$num++;
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
if ($row['_num'] != $num)
printf("[011] Insert has failed, test will fail\n");
// autocommit is on, no rollback possible
$db->query('ROLLBACK');
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
if ($row['_num'] != $num)
printf("[012] ROLLBACK should not have undone anything\n");
if (!$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 0))
printf("[013] Cannot turn off autocommit\n");
$db->query('DELETE FROM test WHERE id = 100');
$db->query('ROLLBACK');
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
if ($row['_num'] != $num)
printf("[014] ROLLBACK should have undone the DELETE\n");
$db->query('DELETE FROM test WHERE id = 100');
$db->query('COMMIT');
$num--;
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
if ($row['_num'] != $num)
printf("[015] DELETE should have been committed\n");
}
$db->exec(sprintf('DROP TABLE IF EXISTS test'));
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,219 @@
--TEST--
PDO::ATTR_CASE
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
$default = $db->getAttribute(PDO::ATTR_CASE);
$known = array(
PDO::CASE_LOWER => 'PDO::CASE_LOWER',
PDO::CASE_UPPER => 'PDO::CASE_UPPER',
PDO::CASE_NATURAL => 'PDO::CASE_NATURAL'
);
if (!isset($known[$default]))
printf("[001] getAttribute(PDO::ATTR_CASE) returns unknown value '%s'\n",
var_export($default, true));
else
var_dump($known[$default]);
// lets see what the default is...
if (!is_object($stmt = $db->query('SELECT id, id AS "ID_UPPER", label FROM test ORDER BY id ASC LIMIT 2')))
printf("[002] %s - %s\n",
var_export($db->errorInfo(), true), var_export($db->errorCode(), true));
var_dump($stmt->fetchAll(PDO::FETCH_BOTH));
if (true !== $db->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER))
printf("[003] Cannot set PDO::ATTR_CASE = PDO::CASE_LOWER, %s - %s\n",
var_export($db->errorInfo(), true), var_export($db->errorCode(), true));
if (($tmp = $db->getAttribute(PDO::ATTR_CASE)) !== PDO::CASE_LOWER)
printf("[004] getAttribute(PDO::ATTR_CASE) returns wrong value '%s'\n",
var_export($tmp, true));
if (true === $db->exec('ALTER TABLE test ADD MiXeD CHAR(1)'))
printf("[005] Cannot add column %s - %s\n",
var_export($db->errorInfo(), true), var_export($db->errorCode(), true));
if (false === $db->exec('ALTER TABLE test ADD MYUPPER CHAR(1)'))
printf("[006] Cannot add column %s - %s\n",
var_export($db->errorInfo(), true), var_export($db->errorCode(), true));
if (!is_object($stmt = $db->query('SELECT id, id AS "ID_UPPER", label, MiXeD, MYUPPER FROM test ORDER BY id ASC LIMIT 2')))
printf("[007] %s - %s\n",
var_export($db->errorInfo(), true), var_export($db->errorCode(), true));
var_dump($stmt->fetchAll(PDO::FETCH_BOTH));
if (true !== $db->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER))
printf("[008] Cannot set PDO::ATTR_CASE = PDO::CASE_UPPER %s - %s\n",
var_export($db->errorInfo(), true), var_export($db->errorCode(), true));
if (($tmp = $db->getAttribute(PDO::ATTR_CASE)) !== PDO::CASE_UPPER)
printf("[009] getAttribute(PDO::ATTR_CASE) returns wrong value '%s'\n",
var_export($tmp, true));
if (!is_object($stmt = $db->query('SELECT id, label, MiXeD, MYUPPER, MYUPPER AS "lower" FROM test ORDER BY id ASC LIMIT 1')))
printf("[010] %s - %s\n",
var_export($db->errorInfo(), true), var_export($db->errorCode(), true));
var_dump($stmt->fetchAll(PDO::FETCH_BOTH));
if (true !== $db->setAttribute(PDO::ATTR_CASE, PDO::CASE_NATURAL))
printf("[011] Cannot set PDO::ATTR_CASE = PDO::CASE_NATURAL %s - %s\n",
var_export($db->errorInfo(), true), var_export($db->errorCode(), true));
if (($tmp = $db->getAttribute(PDO::ATTR_CASE)) !== PDO::CASE_NATURAL)
printf("[012] getAttribute(PDO::ATTR_CASE) returns wrong value '%s'\n",
var_export($tmp, true));
if (!is_object($stmt = $db->query('SELECT id, label, MiXeD, MYUPPER, id AS "ID" FROM test ORDER BY id ASC LIMIT 1')))
printf("[013] %s - %s\n",
var_export($db->errorInfo(), true), var_export($db->errorCode(), true));
var_dump($stmt->fetchAll(PDO::FETCH_BOTH));
$db->exec(sprintf('DROP TABLE IF EXISTS test'));
print "done!";
--EXPECTF--
string(15) "PDO::CASE_LOWER"
array(2) {
[0]=>
array(6) {
["id"]=>
string(1) "1"
[0]=>
string(1) "1"
["id_upper"]=>
string(1) "1"
[1]=>
string(1) "1"
["label"]=>
string(1) "a"
[2]=>
string(1) "a"
}
[1]=>
array(6) {
["id"]=>
string(1) "2"
[0]=>
string(1) "2"
["id_upper"]=>
string(1) "2"
[1]=>
string(1) "2"
["label"]=>
string(1) "b"
[2]=>
string(1) "b"
}
}
array(2) {
[0]=>
array(10) {
["id"]=>
string(1) "1"
[0]=>
string(1) "1"
["id_upper"]=>
string(1) "1"
[1]=>
string(1) "1"
["label"]=>
string(1) "a"
[2]=>
string(1) "a"
["mixed"]=>
NULL
[3]=>
NULL
["myupper"]=>
NULL
[4]=>
NULL
}
[1]=>
array(10) {
["id"]=>
string(1) "2"
[0]=>
string(1) "2"
["id_upper"]=>
string(1) "2"
[1]=>
string(1) "2"
["label"]=>
string(1) "b"
[2]=>
string(1) "b"
["mixed"]=>
NULL
[3]=>
NULL
["myupper"]=>
NULL
[4]=>
NULL
}
}
array(1) {
[0]=>
array(10) {
["ID"]=>
string(1) "1"
[0]=>
string(1) "1"
["LABEL"]=>
string(1) "a"
[1]=>
string(1) "a"
["MIXED"]=>
NULL
[2]=>
NULL
["MYUPPER"]=>
NULL
[3]=>
NULL
["LOWER"]=>
NULL
[4]=>
NULL
}
}
array(1) {
[0]=>
array(10) {
["id"]=>
string(1) "1"
[0]=>
string(1) "1"
["label"]=>
string(1) "a"
[1]=>
string(1) "a"
["MiXeD"]=>
NULL
[2]=>
NULL
["MYUPPER"]=>
NULL
[3]=>
NULL
["ID"]=>
string(1) "1"
[4]=>
string(1) "1"
}
}
done!

View file

@ -0,0 +1,36 @@
--TEST--
PDO::ATTR_CLIENT_VERSION
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
assert(('' == $db->errorCode()) || ('00000' == $db->errorCode()));
$version = $db->getAttribute(PDO::ATTR_CLIENT_VERSION);
// No more constraints - mysqlnd and libmysql return different strings at least
// with mysqli. Return type check is already performed in the generic test.
// According to the manual we should get an int but as of today we do get a string...
if ('' == $version)
printf("[001] Client version must not be empty\n");
// Read-only
if (false !== $db->setAttribute(PDO::ATTR_CLIENT_VERSION, '1.0'))
printf("[002] Wonderful, I can change the client version!\n");
$new_version = $db->getAttribute(PDO::ATTR_CLIENT_VERSION);
if ($new_version !== $version)
printf("[003] Did we change it from '%s' to '%s'?\n", $version, $new_version);
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,36 @@
--TEST--
PDO::ATTR_CONNECTION_STATUS
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
$status = $db->getAttribute(PDO::ATTR_CONNECTION_STATUS);
if (ini_get('unicode.semantics')) {
if (!is_unicode($status))
printf("[001] Expecting unicode, got '%s'\n", var_export($status, true));
} else {
if (!is_string($status))
printf("[002] Expecting string, got '%s'\n", var_export($status, true));
}
if ('' == $status)
printf("[003] Connection status string must not be empty\n");
if (false !== $db->setAttribute(PDO::ATTR_CONNECTION_STATUS, 'my own connection status'))
printf("[004] Changing read only attribute\n");
$status2 = $db->getAttribute(PDO::ATTR_CONNECTION_STATUS);
if ($status !== $status2)
printf("[005] Connection status should not have changed\n");
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,30 @@
--TEST--
PDO::ATTR_DRIVER_NAME
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
assert(('' == $db->errorCode()) || ('00000' == $db->errorCode()));
$name = $db->getAttribute(PDO::ATTR_DRIVER_NAME);
var_dump($name);
if (false !== $db->setAttribute(PDO::ATTR_DRIVER_NAME, 'mydriver'))
printf("[001] Wonderful, I can create new PDO drivers!\n");
$new_name = $db->getAttribute(PDO::ATTR_DRIVER_NAME);
if ($name != $new_name)
printf("[002] Did we change it from '%s' to '%s'?\n", $name, $new_name);
print "done!";
--EXPECTF--
string(5) "mysql"
done!

View file

@ -0,0 +1,166 @@
--TEST--
PDO::ATTR_ERRMODE
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--INI--
error_reporting=E_ALL
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
$valid = array(PDO::ERRMODE_SILENT, PDO::ERRMODE_WARNING, PDO::ERRMODE_EXCEPTION);
do {
$invalid = mt_rand(-1000, 1000);
} while (in_array($invalid, $valid));
$tmp = array();
if (false != @$db->setAttribute(PDO::ATTR_ERRMODE, $tmp))
printf("[001] Maybe PDO could indicate that this is not a proper way of setting the ERRMODE...\n");
$tmp = new stdClass();
$ret = @$db->setAttribute(PDO::ATTR_ERRMODE, $tmp);
if (false != $ret)
printf("[002] Maybe PDO could indicate that this is not a proper way of setting the ERRMODE...%s\n",
var_export($ret, true));
$ret = @$db->setAttribute(PDO::ATTR_ERRMODE, 'pdo');
if (false != $ret)
printf("[003] Maybe PDO could indicate that this is not a proper way of setting the ERRMODE...%s\n",
var_export($ret, true));
if (false != @$db->setAttribute(PDO::ATTR_ERRMODE, $invalid))
printf("[004] Invalid ERRMODE should be rejected\n");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT);
// no message for any PDO call but...
$db->query('THIS IS NOT VALID SQL');
// ... still messages for everything else
$code = $db->errorCode();
$info = $db->errorInfo();
if ($code != '42000')
printf("[005] Expecting SQL code 42000 got '%s'\n", $code);
if ($code !== $info[0])
printf("[006] Code and info should be identical, got errorCode() = %s, errorInfo()[0] = %s\n",
$code, $info[0]);
if ('' == $info[1])
printf("[007] Driver specific error code not set\n");
if ('' == $info[2])
printf("[008] Driver specific error message not set\n");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$db->query('THIS IS NOT VALID SQL');
$code = $db->errorCode();
$info = $db->errorInfo();
if ($code != '42000')
printf("[009] Expecting SQL code 42000 got '%s'\n", $code);
if ($code !== $info[0])
printf("[010] Code and info should be identical, got errorCode() = %s, errorInfo()[0] = %s\n",
$code, $info[0]);
if ('' == $info[1])
printf("[011] Driver specific error code not set\n");
if ('' == $info[2])
printf("[012] Driver specific error message not set\n");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$line = __LINE__ + 1;
$db->query('THIS IS NOT VALID SQL');
} catch (PDOException $e) {
$code = $db->errorCode();
$info = $db->errorInfo();
if ($code != '42000')
printf("[013] Expecting SQL code 42000 got '%s'\n", $code);
if ($code !== $info[0])
printf("[014] Code and info should be identical, got errorCode() = %s, errorInfo()[0] = %s\n",
$code, $info[0]);
if ('' == $info[1])
printf("[015] Driver specific error code not set\n");
if ('' == $info[2])
printf("[016] Driver specific error message not set\n");
if ($e->getCode() !== $code)
printf("[017] Exception code '%s' differs from errorCode '%s'\n",
$e->getCode(), $code);
$msg = $e->getMessage();
foreach ($info as $k => $v) {
if (false === stristr($msg, (string)$v)) {
printf("[018] Cannot find all parts of the error info ('%s') in the exception message '%s'\n",
$v, $msg);
}
}
if ($e->getLine() !== $line)
printf("[019] Exception has been thrown in line %d, exception object reports line %d\n",
$line, $e->getLine());
if ($e->getFile() !== __FILE__)
printf("[020] Exception has been thrown in file '%s', exception object reports file '%s'\n",
__FILE__, $e->getFile());
}
function my_handler($e) {
global $db, $line;
$code = $db->errorCode();
$info = $db->errorInfo();
if ($code != '42000')
printf("[021] Expecting SQL code 42000 got '%s'\n", $code);
if ($code !== $info[0])
printf("[022] Code and info should be identical, got errorCode() = %s, errorInfo()[0] = %s\n",
$code, $info[0]);
if ('' == $info[1])
printf("[023] Driver specific error code not set\n");
if ('' == $info[2])
printf("[024] Driver specific error message not set\n");
if ($e->getCode() !== $code)
printf("[025] Exception code '%s' differs from errorCode '%s'\n",
$e->getCode(), $code);
$msg = $e->getMessage();
foreach ($info as $k => $v) {
if (false === stristr($msg, (string)$v)) {
printf("[026] Cannot find all parts of the error info ('%s') in the exception message '%s'\n",
$v, $msg);
}
}
if ($e->getLine() !== $line)
printf("[027] Exception has been thrown in line %d, exception object reports line %d\n",
$line, $e->getLine());
if ($e->getFile() !== __FILE__)
printf("[028] Exception has been thrown in file '%s', exception object reports file '%s'\n",
__FILE__, $e->getFile());
if (get_class($e) != 'PDOException')
printf("[029] Expecting PDO exception got exception of type '%s'\n", get_class($e));
print "\nend of execution";
}
set_exception_handler('my_handler');
$line = __LINE__ + 1;
$db->query('THIS IS NOT VALID SQL');
print "done!\n";
--EXPECTF--
[003] Maybe PDO could indicate that this is not a proper way of setting the ERRMODE...true
Warning: PDO::query(): SQLSTATE[42000]: Syntax error or access violation: %d You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%s' at line %d in %s on line %d
end of execution

View file

@ -0,0 +1,41 @@
--TEST--
PDO::ATTR_FETCH_TABLE_NAMES
--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();
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::ATTR_FETCH_TABLE_NAMES, 1);
$stmt = $db->query('SELECT label FROM test LIMIT 1');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt->closeCursor();
$db->setAttribute(PDO::ATTR_FETCH_TABLE_NAMES, 0);
$stmt = $db->query('SELECT label FROM test LIMIT 1');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt->closeCursor();
print "done!";
--EXPECTF--
array(1) {
[0]=>
array(1) {
["test.label"]=>
string(1) "a"
}
}
array(1) {
[0]=>
array(1) {
["label"]=>
string(1) "a"
}
}
done!

View file

@ -0,0 +1,51 @@
--TEST--
PDO::MYSQL_ATTR_INIT_COMMAND
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
if (MySQLPDOTest::isPDOMySQLnd())
die("skip PDO::MYSQL_ATTR_MAX_INIT_COMMAND not supported with mysqlnd");
?>
--INI--
error_reporting=E_ALL
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$dsn = MySQLPDOTest::getDSN();
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
$table = sprintf("test_%s", md5(mt_rand(0, PHP_INT_MAX)));
$db = new PDO($dsn, $user, $pass);
$db->exec(sprintf('DROP TABLE IF EXISTS %s', $table));
$create = sprintf('CREATE TABLE %s(id INT)', $table);
var_dump($create);
$db = new PDO($dsn, $user, $pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => $create));
var_dump($db->errorInfo());
$db->exec(sprintf('INSERT INTO %s(id) VALUES (1)', $table));
$stmt = $db->query(sprintf('SELECT id FROM %s', $table));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$db->exec(sprintf('DROP TABLE IF EXISTS %s', $table));
print "done!\n";
--EXPECTF--
string(58) "CREATE TABLE test_%s(id INT)"
array(1) {
[0]=>
string(5) "00000"
}
array(1) {
[0]=>
array(1) {
["id"]=>
string(1) "1"
}
}
done!

View file

@ -0,0 +1,70 @@
--TEST--
MySQL PDO->__construct(), PDO::MYSQL_ATTR_MAX_BUFFER_SIZE
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
if (MySQLPDOTest::isPDOMySQLnd())
die("skip PDO::MYSQL_ATTR_MAX_BUFFER_SIZE not supported with mysqlnd");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
function try_buffer_size($offset, $buffer_size) {
try {
$dsn = MySQLPDOTest::getDSN();
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
/* unsigned overflow possible ? */
$db = new PDO($dsn, $user, $pass,
array(
PDO::MYSQL_ATTR_MAX_BUFFER_SIZE => $buffer_size,
/* buffer is only relevant with native PS */
PDO::MYSQL_ATTR_DIRECT_QUERY => 0,
PDO::ATTR_EMULATE_PREPARES => 0,
));
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(id INT, val LONGBLOB) ENGINE = %s', PDO_MYSQL_TEST_ENGINE));
// 10 * (10 * 1024) = 10 * (10 * 1k) = 100k
$db->exec('INSERT INTO test(id, val) VALUES (1, REPEAT("01234567890", 10240))');
$stmt = $db->prepare('SELECT id, val FROM test');
$stmt->execute();
$id = $val = NULL;
$stmt->bindColumn(1, $id);
$stmt->bindColumn(2, $val);
while ($row = $stmt->fetch(PDO::FETCH_BOUND)) {
printf("[%03d] id = %d, val = %s... (length: %d)\n",
$offset, $id, substr($val, 0, 10), strlen($val));
}
$db->exec('DROP TABLE IF EXISTS test');
} catch (PDOException $e) {
printf("[%03d] %s, [%s] %s\n",
$offset,
$e->getMessage(),
(is_object($db)) ? $db->errorCode() : 'n/a',
(is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
}
}
try_buffer_size(1, -1);
try_buffer_size(2, 1000);
try_buffer_size(3, NULL);
try_buffer_size(4, 2000);
print "done!";
--EXPECTF--
[001] id = 1, val = 0123456789... (length: %d)
[002] id = 1, val = 0123456789... (length: 1000)
[003] id = 1, val = 0123456789... (length: %d)
[004] id = 1, val = 0123456789... (length: 2000)
done!

View file

@ -0,0 +1,120 @@
--TEST--
PDO::ATTR_ORACLE_NULLS
--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();
MySQLPDOTest::createTestTable($db);
$tmp = array();
if (false !== @$db->setAttribute(PDO::ATTR_ORACLE_NULLS, $tmp))
printf("[001] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...\n");
$tmp = new stdClass();
if (false !== @$db->setAttribute(PDO::ATTR_ORACLE_NULLS, $tmp));
printf("[002] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...\n");
if (false !== @$db->setAttribute(PDO::ATTR_ORACLE_NULLS, 'pdo'))
printf("[003] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...\n");
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, 1);
$stmt = $db->query('SELECT NULL AS z, "" AS a, " " AS b, TRIM(" ") as c, " d" AS d, "' . chr(0) . ' e" AS e');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, 0);
$stmt = $db->query('SELECT NULL AS z, "" AS a, " " AS b, TRIM(" ") as c, " d" AS d, "' . chr(0) . ' e" AS e');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$db->setAttribute(PDO::ATTR_ORACLE_NULLS, 1);
$stmt = $db->query('SELECT VERSION() as _version');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ((int)substr($row['_version'], 0, 1) >= 5)
$have_procedures = true;
else
$have_procedures = false;
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
if ($have_procedures && (false !== $db->exec('DROP PROCEDURE IF EXISTS p')) &&
(false !== $db->exec('CREATE PROCEDURE p() BEGIN SELECT NULL as z, "" AS a, " " AS b, TRIM(" ") as c, " d" AS d, " e" AS e; END;'))) {
// requires MySQL 5+
$stmt = $db->prepare('CALL p()');
$stmt->execute();
$expected = array(
array(
"z" => NULL,
"a" => NULL,
"b" => " ",
"c" => NULL,
"d" => " d",
"e" => " e",
),
);
do {
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($tmp != $expected) {
printf("[004] Expecting %s got %s\n",
var_export($expected, true), var_export($tmp, true));
}
} while ($stmt->nextRowset());
$stmt->execute();
do {
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($tmp != $expected) {
printf("[005] Expecting %s got %s\n",
var_export($expected, true), var_export($tmp, true));
}
} while ($stmt->nextRowset());
}
if ($have_procedures)
@$db->exec('DROP PROCEDURE IF EXISTS p');
print "done!";
--EXPECTF--
[002] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...
[003] Maybe PDO could indicate that this is not a proper way of setting ATTR_ORACLE_NULLS...
array(1) {
[0]=>
array(6) {
["z"]=>
NULL
["a"]=>
NULL
["b"]=>
string(1) " "
["c"]=>
NULL
["d"]=>
string(2) " d"
["e"]=>
string(3) "%se"
}
}
array(1) {
[0]=>
array(6) {
["z"]=>
NULL
["a"]=>
string(0) ""
["b"]=>
string(1) " "
["c"]=>
string(0) ""
["d"]=>
string(2) " d"
["e"]=>
string(3) "%se"
}
}
done!

View file

@ -0,0 +1,21 @@
--TEST--
PDO::ATTR_PREFETCH
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
var_dump($db->getAttribute(PDO::ATTR_PREFETCH));
var_dump($db->setAttribute(PDO::ATTR_PREFETCH, true));
print "done!";
--EXPECTF--
Warning: PDO::getAttribute(): SQLSTATE[IM001]: Driver does not support this function: driver does not support that attribute in %s on line %d
bool(false)
bool(false)
done!

View file

@ -0,0 +1,48 @@
--TEST--
PDO::ATTR_SERVER_INFO
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
assert(('' == $db->errorCode()) || ('00000' == $db->errorCode()));
$info = $db->getAttribute(PDO::ATTR_SERVER_INFO);
if ('' == $info)
printf("[001] Server info must not be empty\n");
// Read-only?
if (false !== $db->setAttribute(PDO::ATTR_SERVER_INFO, 'new uptime: 0s'))
printf("[002] Wonderful, I can change the client version!\n");
$new_info = $db->getAttribute(PDO::ATTR_SERVER_INFO);
if ($new_info !== $info)
printf("[003] Did we change it from '%s' to '%s'?\n", $info, $info);
// lets hope we always run this in the same second as we did run the server info request...
if (!$stmt = $db->query('SHOW STATUS LIKE "%uptime%"'))
printf("[004] Cannot run SHOW STATUS, [%s]\n", $db->errorCode());
else {
if (!$row = $stmt->fetch(PDO::FETCH_NUM))
printf("[005] Unable to fetch uptime, [%s]\n", $db->errorCode());
else
$uptime = $row[1];
$stmt->closeCursor();
}
if (!preg_match('/Uptime/i', $info))
printf("[006] Can't find uptime in server info '%s'\n", $info);
if (isset($uptime) && !preg_match(sprintf('/Uptime: %d/i', $uptime), $info))
printf("[007] SHOW STATUS and server info have reported a different uptime, please check. Server info: '%s', SHOW STATUS: '%s'\n", $info, $uptime);
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,64 @@
--TEST--
PDO::ATTR_SERVER_VERSION
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
assert(('' == $db->errorCode()) || ('00000' == $db->errorCode()));
$version = $db->getAttribute(PDO::ATTR_SERVER_VERSION);
if ('' == $version)
printf("[001] Server version must not be empty\n");
// Ideally the server version would be an integer - as documented but BC break!
// If its a version string it should be of the format \d+\.\d+\.\d+.*
if (is_string($version)) {
// Its not an int like documented but a string - maybe for BC reasons...
if (!preg_match('/(\d+)\.(\d+)\.(\d+)(.*)/', $version, $matches))
printf("[002] Client version string seems wrong, got '%s'\n", $version);
else {
// Difficult to define any meaningful constraints
// A possible better check would be calling mysqli_get_server_version() and
// comparing what we get. However, mysqli_get_server_version() needs a mysqli handle
// for which in turn one needs to parse the PDO test environment variables
// for connection parameter...
if ($matches[1] < 3)
printf("[003] Strange major version: '%s'. Should be more than 3\n", $matches[1]);
if ($matches[2] < 0)
printf("[004] Minor version should be at least 0, got '%s'\n", $matches[2]);
if ($matches[3] < 0)
printf("[005] Sub version should be at least 0, got '%s'\n", $matches[2]);
}
} else if (is_int($version)) {
// Lets accept also int if it follows the rules from the original MYSQL C API
$major = floor($version / 10000);
$minor = floor(($version - ($main * 10000)) / 100);
$sub = $version - ($main * 10000) - ($minor * 100);
if ($major < 3)
printf("[006] Strange major version: '%s'. Should be more than 3\n", $major);
if ($minor < 0)
printf("[007] Minor version should be at least 0, got '%s'\n", $minor);
if ($sub < 0)
printf("[008] Sub version should be at least 0, got '%s'\n", $sub);
}
// Read-only?
if (false !== $db->setAttribute(PDO::ATTR_CLIENT_VERSION, '1.0'))
printf("[009] Wonderful, I can change the client version!\n");
$new_version = $db->getAttribute(PDO::ATTR_SERVER_VERSION);
if ($new_version !== $version)
printf("[010] Did we change it from '%s' to '%s'?\n", $version, $new_version);
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,154 @@
--TEST--
PDO::ATTR_STATEMENT_CLASS
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
$default = $db->getAttribute(PDO::ATTR_STATEMENT_CLASS);
var_dump($default);
if (false !== ($tmp = @$db->setAttribute(PDO::ATTR_STATEMENT_CLASS)))
printf("[001] Expecting boolean/false got %s\n", var_export($tmp, true));
if (false !== ($tmp = @$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, 'foo')))
printf("[002] Expecting boolean/false got %s\n", var_export($tmp, true));
if (false !== ($tmp = @$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('classname'))))
printf("[003] Expecting boolean/false got %s\n", var_export($tmp, true));
// unknown class
if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('classname', array()))))
printf("[004] Expecting boolean/false got %s\n", var_export($tmp, true));
// class not derived from PDOStatement
class myclass {
function __construct() {
printf("myclass\n");
}
}
if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('myclass', array()))))
printf("[005] Expecting boolean/false got %s\n", var_export($tmp, true));
// public constructor not allowed
class mystatement extends PDOStatement {
public function __construct() {
printf("mystatement\n");
}
}
if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement', array()))))
printf("[006] Expecting boolean/false got %s\n", var_export($tmp, true));
// ... but a public destructor is allowed
class mystatement2 extends PDOStatement {
public function __destruct() {
printf("mystatement\n");
}
}
if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement2', array()))))
printf("[007] Expecting boolean/true got %s\n", var_export($tmp, true));
// private constructor
class mystatement3 extends PDOStatement {
private function __construct($msg) {
printf("mystatement3\n");
var_dump($msg);
}
}
if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement3', array('param1')))))
printf("[008] Expecting boolean/true got %s\n", var_export($tmp, true));
// private constructor
class mystatement4 extends PDOStatement {
private function __construct($msg) {
printf("%s\n", get_class($this));
var_dump($msg);
}
}
if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement4', array('param1')))))
printf("[008] Expecting boolean/true got %s\n", var_export($tmp, true));
var_dump($db->getAttribute(PDO::ATTR_STATEMENT_CLASS));
$stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 2');
class mystatement5 extends mystatement4 {
public function fetchAll($fetch_style = 1, $column_index = 1, $ctor_args = array()) {
return "no data :)";
}
}
if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement5', array('mystatement5')))))
printf("[009] Expecting boolean/true got %s\n", var_export($tmp, true));
$stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 2');
var_dump($stmt->fetchAll());
if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement'))))
printf("[010] Expecting boolean/true got %s\n", var_export($tmp, true));
$stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 1');
var_dump($stmt->fetchAll());
// Yes, this is a fatal error and I want it to fail.
abstract class mystatement6 extends mystatement5 {
}
if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement6', array('mystatement6')))))
printf("[011] Expecting boolean/true got %s\n", var_export($tmp, true));
$stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 1');
print "done!";
--EXPECTF--
array(1) {
[0]=>
string(12) "PDOStatement"
}
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); the classname must be a string specifying an existing class in %s on line %d
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: user-supplied statement class must be derived from PDOStatement in %s on line %d
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error: user-supplied statement class cannot have a public constructor in %s on line %d
Warning: PDO::setAttribute(): SQLSTATE[HY000]: General error in %s on line %d
array(2) {
[0]=>
string(12) "mystatement4"
[1]=>
array(1) {
[0]=>
string(6) "param1"
}
}
mystatement4
string(6) "param1"
mystatement5
string(12) "mystatement5"
string(10) "no data :)"
array(1) {
[0]=>
array(4) {
["id"]=>
string(1) "1"
[0]=>
string(1) "1"
["label"]=>
string(1) "a"
[1]=>
string(1) "a"
}
}
Fatal error: Cannot instantiate abstract class mystatement6 in %s on line %d

View file

@ -0,0 +1,201 @@
--TEST--
PDO->beginTransaction()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
die("skip Transactional engine not found");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[001] Autocommit should be on by default\n");
if (false == $db->beginTransaction())
printf("[002] Cannot start a transaction, [%s] [%s]\n",
$db->errorCode(), implode(' ', $db->errorInfo()));
if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[003] Autocommit should be on by default, beginTransaction() shall not impact it\n");
if (0 == $db->exec('DELETE FROM test'))
printf("[004] No rows deleted, can't be true.\n");
/* This is the PDO way to close a connection */
$db = null;
$db = MySQLPDOTest::factory();
/* 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')))
printf("[005] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($row);
if (!$db->beginTransaction())
printf("[006] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
if (1 !== $db->exec(sprintf('DELETE FROM test WHERE id = %d', $row['id'])))
printf("[007] DELETE should have indicated 1 deleted row, [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
if (!$db->commit())
printf("[008] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[009] Autocommit should be on after commit()\n");
if (!($stmt = $db->query(sprintf('SELECT id, label FROM test WHERE id = %d', $row['id']))))
printf("[010] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
var_dump($stmt->fetch(PDO::FETCH_ASSOC));
if (!$db->beginTransaction())
printf("[011] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
$db->exec(sprintf('INSERT INTO test(id, label) VALUES (%d, "z")', $row['id']));
if (!($stmt = $db->query(sprintf('SELECT id, label FROM test WHERE id = %d', $row['id']))))
printf("[012] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
$new_row1 = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($new_row1);
if (!$db->commit())
printf("[013] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
if (!($stmt = $db->query(sprintf('SELECT id, label FROM test WHERE id = %d', $row['id']))))
printf("[014] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
$new_row2 = $stmt->fetch(PDO::FETCH_ASSOC);
if ($new_row1 != $new_row2) {
printf("[015] Results must not differ!\n");
var_dump($new_row1);
var_dump($new_row2);
}
if (!$db->beginTransaction())
printf("[016] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
if (1 !== $db->exec(sprintf('DELETE FROM test WHERE id = %d', $row['id'])))
printf("[017] DELETE should have indicated 1 deleted row, [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
if (!$db->rollback())
printf("[018] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[019] Autocommit should be on after rollback\n");
if (!($stmt = $db->query(sprintf('SELECT id, label FROM test WHERE id = %d', $row['id']))))
printf("[020] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
$new_row2 = $stmt->fetch(PDO::FETCH_ASSOC);
if ($new_row1 != $new_row2) {
printf("[021] Results must not differ!\n");
var_dump($new_row1);
var_dump($new_row2);
}
// now, lets check the server variables
if (!($stmt = $db->query('SELECT @@autocommit as auto_commit')))
printf("[022] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
if ($tmp['auto_commit'] != 1)
printf("[023] MySQL Server should indicate autocommit mode, expecting 1, got '%s', [%d] %s\n",
$tmp['auto_commit'], $stmt->errorCode(), $stmt->errorInfo());
if (!$db->beginTransaction())
printf("[024] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
if (!($stmt = $db->query('SELECT @@autocommit as auto_commit')))
printf("[025] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
if ($tmp['auto_commit'] != 0)
printf("[026] Autocommit mode of the MySQL Server should be off, got '%s', [%d] %s\n",
$tmp['auto_commit'], $stmt->errorCode(), implode(' ', $stmt->errorInfo()));
$db->commit();
// Now we should be back to autocommit - we've issues a commit
if ($tmp['auto_commit'] != 1)
printf("[027] MySQL Server should indicate autocommit mode, expecting 1, got '%s', [%d] %s\n",
$tmp['auto_commit'], $stmt->errorCode(), $stmt->errorInfo());
// Turn off autocommit using a server variable
$db->exec('SET @@autocommit = 0');
if (1 === $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[028] I'm confused, how can autocommit be on? Didn't I say I want to manually control transactions?\n");
if (!$db->beginTransaction())
printf("[029] Cannot start a transaction, [%d] %s\n",
$db->errorCode(), implode(' ', $db->errorInfo()));
try {
if (false !== $db->beginTransaction()) {
printf("[030] No false and no exception - that's wrong.\n");
}
} catch (PDOException $e) {
assert($e->getMessage() != '');
}
// TODO: What about an engine that does not support transactions?
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, 'MyISAM');
if (false == $db->beginTransaction())
printf("[031] Cannot start a transaction, [%s] [%s]\n",
$db->errorCode(), implode(' ', $db->errorInfo()));
if (1 !== $db->getAttribute(PDO::ATTR_AUTOCOMMIT))
printf("[032] Autocommit should be on my default, beginTransaction() should not change that\n");
if (0 == $db->exec('DELETE FROM test'))
printf("[033] No rows deleted, can't be true.\n");
if (!$db->commit())
printf("[034] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
if (false == $db->beginTransaction())
printf("[035] Cannot start a transaction, [%s] [%s]\n",
$db->errorCode(), implode(' ', $db->errorInfo()));
if (0 == $db->exec('INSERT INTO test(id, label) VALUES (1, "a")'))
printf("[036] Cannot insert data, [%s] [%s]\n",
$db->errorCode(), implode(' ', $db->errorInfo()));
// Should cause a Server warning but no error
if (!$db->rollback())
printf("[037] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
var_dump($db->errorCode());
if (1 != $db->exec('DELETE FROM test'))
printf("[038] No rows deleted, can't be true.\n");
$db->exec(sprintf('DROP TABLE IF EXISTS test'));
print "done!";
--EXPECTF--
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
bool(false)
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "z"
}
[026] Autocommit mode of the MySQL Server should be off, got '1', [0] 00000
[028] I'm confused, how can autocommit be on? Didn't I say I want to manually control transactions?
string(5) "00000"
done!

View file

@ -0,0 +1,59 @@
--TEST--
MySQL PDO->exec(), BIT columns - remove after fix!
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
if (MySQLPDOTest::isPDOMySQLnd())
die("skip Known bug - mysqlnd handles BIT incorrectly!");
?>
--FILE--
<?php
/* TODO: remove this test after fix and enable the BIT test in pdo_mysql_types.phpt again */
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
function test_type(&$db, $offset, $sql_type, $value, $ret_value = NULL, $pattern = NULL) {
$db->exec('DROP TABLE IF EXISTS test');
$sql = sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, MySQLPDOTest::getTableEngine());
@$db->exec($sql);
if ($db->errorCode() != 0) {
// not all MySQL Server versions and/or engines might support the type
return true;
}
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (?, ?)');
$stmt->bindValue(1, $offset);
$stmt->bindValue(2, $value);
if (!$stmt->execute()) {
printf("[%03d + 1] INSERT failed, %s\n", $offset, var_export($stmt->errorInfo(), true));
return false;
}
$stmt = $db->query('SELECT id, label FROM test');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
var_dump($row);
var_dump($value);
return true;
}
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
test_type($db, 20, 'BIT(8)', 1);
echo "done!\n";
?>
--EXPECTF--
array(2) {
["id"]=>
string(2) "20"
["label"]=>
string(1) "1"
}
int(1)
done!

View file

@ -0,0 +1,78 @@
--TEST--
PDO MySQL specific class constants
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$expected = array(
'MYSQL_ATTR_USE_BUFFERED_QUERY' => true,
'MYSQL_ATTR_LOCAL_INFILE' => true,
'MYSQL_ATTR_DIRECT_QUERY' => true,
);
if (!MySQLPDOTest::isPDOMySQLnd()) {
$expected['MYSQL_ATTR_MAX_BUFFER_SIZE'] = true;
$expected['MYSQL_ATTR_INIT_COMMAND'] = true;
$expected['MYSQL_ATTR_READ_DEFAULT_FILE'] = true;
$expected['MYSQL_ATTR_READ_DEFAULT_GROUP'] = true;
}
/*
TODO
MYSQLI_OPT_CONNECT_TIMEOUT != PDO::ATTR_TIMEOUT (integer)
Sets the timeout value in seconds for communications with the database.
^ Potential BUG, PDO::ATTR_TIMEOUT is used in pdo_mysql_handle_factory
MYSQLI_SET_CHARSET_NAME -> DSN/charset=<charset_name>
^ Undocumented and pitfall for ext/mysqli users
Assorted mysqlnd settings missing
*/
$ref = new ReflectionClass('PDO');
$constants = $ref->getConstants();
$values = array();
foreach ($constants as $name => $value)
if (substr($name, 0, 11) == 'MYSQL_ATTR_') {
if (!isset($values[$value]))
$values[$value] = array($name);
else
$values[$value][] = $name;
if (isset($expected[$name])) {
unset($expected[$name]);
unset($constants[$name]);
}
} else {
unset($constants[$name]);
}
if (!empty($constants)) {
printf("[001] Dumping list of unexpected constants\n");
var_dump($constants);
}
if (!empty($expected)) {
printf("[002] Dumping list of missing constants\n");
var_dump($expected);
}
if (!empty($values)) {
foreach ($values as $value => $constants) {
if (count($constants) > 1) {
printf("[003] Several constants share the same value '%s'\n", $value);
var_dump($constants);
}
}
}
print "done!";
--EXPECT--
done!

View file

@ -0,0 +1,84 @@
--TEST--
MySQL PDO->commit()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
die("skip Transactional engine not found");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
try {
if (true !== ($tmp = $db->beginTransaction())) {
printf("[001] Expecting true, got %s/%s\n", gettype($tmp), $tmp);
}
// DDL will issue an implicit commit
$db->exec(sprintf('DROP TABLE IF EXISTS test_commit'));
$db->exec(sprintf('CREATE TABLE test_commit(id INT) ENGINE=%s', MySQLPDOTest::detect_transactional_mysql_engine($db)));
if (true !== ($tmp = $db->commit())) {
printf("[002] No commit allowed? [%s] %s\n",
$db->errorCode(), implode(' ', $db->errorInfo()));
}
// pdo_transaction_transitions should check this as well...
// ... just to be sure the most basic stuff really works we check it again...
if (1 !== ($tmp = $db->getAttribute(PDO::ATTR_AUTOCOMMIT)))
printf("[003] According to the manual we should be back to autocommit mode, got %s/%s\n",
gettype($tmp), var_export($tmp, true));
if (true !== ($tmp = $db->beginTransaction()))
printf("[004] Expecting true, got %s/%s\n", gettype($tmp), $tmp);
$db->exec('INSERT INTO test(id, label) VALUES (100, "z")');
if (true !== ($tmp = $db->commit()))
printf("[005] No commit allowed? [%s] %s\n",
$db->errorCode(), implode(' ', $db->errorInfo()));
// a weak test without unicode etc. - lets leave that to dedicated tests
$stmt = $db->query('SELECT id, label FROM test WHERE id = 100');
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!isset($rows[0]['label']) || ($rows[0]['label'] != 'z')) {
printf("[006] Record data is strange, dumping rows\n");
var_dump($rows);
}
// Ok, lets check MyISAM resp. any other non-transactional engine
// pdo_mysql_begin_transaction has more on this, quick check only
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, 'MyISAM');
if (true !== ($tmp = $db->beginTransaction()))
printf("[007] Expecting true, got %s/%s\n", gettype($tmp), $tmp);
$db->exec('INSERT INTO test(id, label) VALUES (100, "z")');
if (true !== ($tmp = $db->commit()))
printf("[008] No commit allowed? [%s] %s\n",
$db->errorCode(), implode(' ', $db->errorInfo()));
// a weak test without unicode etc. - lets leave that to dedicated tests
$stmt = $db->query('SELECT id, label FROM test WHERE id = 100');
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!isset($rows[0]['label']) || ($rows[0]['label'] != 'z')) {
printf("[009] Record data is strange, dumping rows\n");
var_dump($rows);
}
} catch (PDOException $e) {
printf("[002] %s, [%s] %s\n",
$e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec(sprintf('DROP TABLE IF EXISTS test_commit'));
print "done!";
--EXPECT--
done!

View file

@ -0,0 +1,81 @@
--TEST--
MySQL PDO->errorCode()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
function check_error($offset, &$obj, $expected = '00000') {
$code = $obj->errorCode();
if (($code != $expected) && (($expected != '00000') && ($code != ''))) {
printf("[%03d] Expecting error code '%s' got code '%s'\n",
$offset, $expected, $code);
}
}
try {
/*
If you create a PDOStatement object through PDO->prepare()
or PDO->query() and invoke an error on the statement handle,
PDO->errorCode() will not reflect that error. You must call
PDOStatement->errorCode() to return the error code for an
operation performed on a particular statement handle.
*/
$code = $db->errorCode();
check_error(2, $db);
$stmt = $db->query('SELECT id, label FROM test');
$stmt2 = &$stmt;
check_error(3, $db);
check_error(4, $stmt);
$db->exec('DROP TABLE IF EXISTS test');
@$stmt->execute();
check_error(4, $db);
check_error(5, $stmt, '42S02');
check_error(6, $stmt2, '42S02');
$db->exec('DROP TABLE IF EXISTS unknown');
@$stmt = $db->query('SELECT id, label FROM unknown');
check_error(7, $db, '42S02');
MySQLPDOTest::createTestTable($db);
$stmt = $db->query('SELECT id, label FROM test');
check_error(8, $db);
check_error(9, $stmt);
$db2 = &$db;
@$db->query('SELECT id, label FROM unknown');
check_error(10, $db, '42S02');
check_error(11, $db2, '42S02');
check_error(12, $stmt);
check_error(13, $stmt2);
// lets hope this is an invalid attribute code
$invalid_attr = -1 * PHP_INT_MAX + 3;
$tmp = @$db->getAttribute($invalid_attr);
check_error(14, $db, 'IM001');
check_error(15, $db2, 'IM001');
check_error(16, $stmt);
check_error(17, $stmt2);
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,173 @@
--TEST--
MySQL PDO->errorInfo()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
function check_error($offset, &$obj, $expected = '00000') {
$info = $obj->errorInfo();
if (count($info) != 3)
printf("[%03d] Info should have three fields, got %s\n",
$offset, var_export($info, true));
$code = $info[0];
if (($code != $expected) && (($expected != '00000') && ($code != ''))) {
printf("[%03d] Expecting error code '%s' got code '%s'\n",
$offset, $expected, $code);
}
if ($expected != '00000') {
if (!isset($info[1]) || $info[1] == '')
printf("[%03d] Driver-specific error code not set\n", $offset);
if (!isset($info[2]) || $info[2] == '')
printf("[%03d] Driver-specific error message.not set\n", $offset);
}
}
function pdo_mysql_errorinfo($db, $offset) {
try {
/*
If you create a PDOStatement object through PDO->prepare()
or PDO->query() and invoke an error on the statement handle,
PDO->errorCode() will not reflect that error. You must call
PDOStatement->errorCode() to return the error code for an
operation performed on a particular statement handle.
*/
$code = $db->errorCode();
check_error($offset + 2, $db);
$stmt = $db->query('SELECT id, label FROM test');
$stmt2 = &$stmt;
check_error($offset + 3, $db);
check_error($offset + 4, $stmt);
$db->exec('DROP TABLE IF EXISTS test');
@$stmt->execute();
check_error($offset + 5, $db);
check_error($offset + 6, $stmt, '42S02');
check_error($offset + 7, $stmt2, '42S02');
@$stmt = $db->query('SELECT id, label FROM unknown');
check_error($offset + 8, $db, '42S02');
MySQLPDOTest::createTestTable($db);
$stmt = $db->query('SELECT id, label FROM test');
check_error($offset + 9, $db);
check_error($offset + 10, $stmt);
$db2 = &$db;
$db->exec('DROP TABLE IF EXISTS unknown');
@$db->query('SELECT id, label FROM unknown');
check_error($offset + 11, $db, '42S02');
check_error($offset + 12, $db2, '42S02');
check_error($offset + 13, $stmt);
check_error($offset + 14, $stmt2);
// lets hope this is an invalid attribute code
$invalid_attr = -1 * PHP_INT_MAX + 3;
$tmp = @$db->getAttribute($invalid_attr);
check_error($offset + 15, $db, 'IM001');
check_error($offset + 16, $db2, 'IM001');
check_error($offset + 17, $stmt);
check_error($offset + 18, $stmt2);
} catch (PDOException $e) {
printf("[%03d] %s [%s] %s\n",
$offset + 19, $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
}
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
printf("Emulated Prepared Statements...\n");
pdo_mysql_errorinfo($db, 0);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
printf("Native Prepared Statements...\n");
pdo_mysql_errorinfo($db, 20);
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
--EXPECTF--
Emulated Prepared Statements...
[002] Info should have three fields, got array (
0 => '00000',
)
[003] Info should have three fields, got array (
0 => '00000',
)
[004] Info should have three fields, got array (
0 => '00000',
)
[005] Info should have three fields, got array (
0 => '00000',
)
[009] Info should have three fields, got array (
0 => '00000',
)
[010] Info should have three fields, got array (
0 => '00000',
)
[013] Info should have three fields, got array (
0 => '00000',
)
[014] Info should have three fields, got array (
0 => '00000',
)
[015] Info should have three fields, got array (
0 => 'IM001',
)
[015] Driver-specific error code not set
[015] Driver-specific error message.not set
[016] Info should have three fields, got array (
0 => 'IM001',
)
[016] Driver-specific error code not set
[016] Driver-specific error message.not set
[017] Info should have three fields, got array (
0 => '00000',
)
[018] Info should have three fields, got array (
0 => '00000',
)
Native Prepared Statements...
[022] Info should have three fields, got array (
0 => '00000',
)
[023] Info should have three fields, got array (
0 => '00000',
)
[024] Info should have three fields, got array (
0 => '00000',
)
[025] Info should have three fields, got array (
0 => '00000',
)
[030] Info should have three fields, got array (
0 => '00000',
)
[033] Info should have three fields, got array (
0 => '00000',
)
[034] Info should have three fields, got array (
0 => '00000',
)
[037] Info should have three fields, got array (
0 => '00000',
)
[038] Info should have three fields, got array (
0 => '00000',
)
done!

View file

@ -0,0 +1,179 @@
--TEST--
MySQL PDO->exec(), affected rows
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
?>
--FILE--
<?php
function exec_and_count($offset, &$db, $sql, $exp = NULL) {
try {
$ret = $db->exec($sql);
if (!is_null($exp) && ($ret !== $exp)) {
printf("[%03d] Expecting '%s'/%s got '%s'/%s when running '%s', [%s] %s\n",
$offset, $exp, gettype($exp), $ret, gettype($ret), $sql,
$db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
} catch (PDOException $e) {
printf("[%03d] '%s' has failed, [%s] %s\n",
$offset, $sql, $db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
return true;
}
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
/* affected rows related */
try {
exec_and_count(2, $db, 'DROP TABLE IF EXISTS test', 0);
exec_and_count(3, $db, sprintf('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE), 0);
exec_and_count(4, $db, 'INSERT INTO test(id, col1) VALUES (1, "a")', 1);
exec_and_count(5, $db, 'INSERT INTO test(id, col1) VALUES (2, "b"), (3, "c")', 2);
exec_and_count(6, $db, 'UPDATE test SET id = 4 WHERE id = 3', 1);
exec_and_count(7, $db, 'INSERT INTO test(id, col1) VALUES (1, "d") ON DUPLICATE KEY UPDATE id = 3', 2);
exec_and_count(8, $db, 'UPDATE test SET id = 5 WHERE id = 5', 0);
exec_and_count(9, $db, 'INSERT INTO test(id, col1) VALUES (5, "e") ON DUPLICATE KEY UPDATE id = 6', 1);
exec_and_count(10, $db, 'REPLACE INTO test(id, col1) VALUES (5, "f")', 2);
exec_and_count(11, $db, 'REPLACE INTO test(id, col1) VALUES (6, "g")', 1);
exec_and_count(12, $db, 'DELETE FROM test WHERE id > 2', 4);
exec_and_count(13, $db, 'DROP TABLE test', 0);
exec_and_count(14, $db, 'SET @myvar = 1', 0);
exec_and_count(15, $db, 'THIS IS NOT VALID SQL, I HOPE', false);
printf("[016] [%s] %s\n", $db->errorCode(), implode(' ', $db->errorInfo()));
exec_and_count(36, $db, sprintf('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE), 0);
exec_and_count(37, $db, 'INSERT INTO test(id, col1) VALUES (1, "a")', 1);
// Results may vary. Typically you will get 1. But the MySQL 5.1 manual states: Truncation operations do not return the number of deleted rows.
// Don't rely on any return value!
exec_and_count(38, $db, 'TRUNCATE TABLE test', NULL);
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
}
/* CREATE, DROP, CALL SP and SF */
if (MySQLPDOTest::getServerVersion($db) > 50000) {
// let's try to play with stored procedures
try {
$ignore_exception = true;
exec_and_count(18, $db, 'DROP PROCEDURE IF EXISTS p', 0);
exec_and_count(19, $db, 'CREATE PROCEDURE p(OUT ver_param VARCHAR(255)) BEGIN SELECT VERSION() INTO ver_param; END;', 0);
// we got this far without problems. If there's an issue from now on, its a failure
$ignore_exception = false;
exec_and_count(20, $db, 'CALL p(@version)', 0);
$stmt = $db->query('SELECT @version AS p_version');
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($tmp) > 1 || !isset($tmp[0]['p_version'])) {
printf("[022] Data seems wrong, dumping\n");
var_dump($tmp);
} else {
$p_version = $tmp[0]['p_version'];
}
$stmt = $db->query('SELECT VERSION() AS _version');
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($tmp) > 1 || !isset($tmp[0]['_version'])) {
printf("[023] Data seems wrong, dumping\n");
var_dump($tmp);
} else {
if ($p_version !== $tmp[0]['_version']) {
printf("[024] Found different version strings, SP returned '%s'/%s, SELECT returned '%s'/%s\n",
$p_version, gettype($p_version),
$tmp[0]['_version'], gettype($tmp[0]['_version']));
}
}
exec_and_count(25, $db, 'DROP PROCEDURE IF EXISTS p', 0);
} catch (PDOException $e) {
// ignore it, we might not have sufficient permissions
if (!$ignore_exception)
printf("[021] %s, [%s] %s\n",
$e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
}
// stored function
try {
$ignore_exception = true;
exec_and_count(27, $db, 'DROP FUNCTION IF EXISTS f', 0);
exec_and_count(28, $db, 'CREATE FUNCTION f( ver_param VARCHAR(255)) RETURNS VARCHAR(255) DETERMINISTIC RETURN ver_param;', 0);
// we got this far without problems. If there's an issue from now on, its a failure
$ignore_exception = false;
$stmt = $db->query('SELECT f(VERSION()) AS f_version');
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($tmp) > 1 || !isset($tmp[0]['f_version'])) {
printf("[029] Data seems wrong, dumping\n");
var_dump($tmp);
} else {
$f_version = $tmp[0]['f_version'];
}
$stmt = $db->query('SELECT VERSION() AS _version');
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($tmp) > 1 || !isset($tmp[0]['_version'])) {
printf("[030] Data seems wrong, dumping\n");
var_dump($tmp);
} else {
if ($f_version !== $tmp[0]['_version']) {
printf("[031] Found different version strings, SF returned '%s'/%s, SELECT returned '%s'/%s\n",
$f_version, gettype($f_version),
$tmp[0]['_version'], gettype($tmp[0]['_version']));
}
}
exec_and_count(32, $db, 'DROP FUNCTION IF EXISTS f', 0);
} catch (PDOException $e) {
// ignore it, we might not have sufficient permissions
if (!$ignore_exception)
printf("[026] %s, [%s] %s\n",
$e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
}
}
// multi query
try {
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$exp = 0;
$tmp = @$db->exec(sprintf('DROP TABLE IF EXISTS test; CREATE TABLE test(id INT) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
if ($exp !== $tmp)
printf("[034] Expecting %s/%s got %s/%s, [%s] %s\n",
$exp, gettype($exp),
$tmp, gettype($tmp),
$db->errorCode(), var_export($db->errorInfo(), true));
// this is interesting: if we get sort of affected rows, what will happen now?
$tmp = @$db->exec('INSERT INTO test(id) VALUES (1); INSERT INTO test(id) VALUES (2)');
printf("[035] With emulated PS it works but makes no sense given that exec() returns sort of affected rows...\n");
} catch (PDOException $e) {
printf("[033] %s, [%s] %s\n",
$e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
@$db->exec('DROP TABLE IF EXISTS test');
print "done!";
--EXPECTF--
Warning: PDO::exec(): SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'THIS IS NOT VALID SQL, I HOPE' at line 1 in %s on line %d
[016] [42000] 42000 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'THIS IS NOT VALID SQL, I HOPE' at line %d
[035] With emulated PS it works but makes no sense given that exec() returns sort of affected rows...
done!

View file

@ -0,0 +1,88 @@
--TEST--
MySQL PDO->exec(), affected rows
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
?>
--FILE--
<?php
function exec_and_count($offset, &$db, $sql, $exp, $suppress_warning = false) {
try {
if ($suppress_warning)
$ret = @$db->exec($sql);
else
$ret = $db->exec($sql);
if ($ret !== $exp) {
printf("[%03d] Expecting '%s'/%s got '%s'/%s when running '%s', [%s] %s\n",
$offset, $exp, gettype($exp), $ret, gettype($ret), $sql,
$db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
} catch (PDOException $e) {
printf("[%03d] '%s' has failed, [%s] %s\n",
$offset, $sql, $db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
return true;
}
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
/* affected rows related */
try {
@$db->exec('DROP DATABASE IF EXISTS pdo_exec_ddl');
@$db->exec('DROP DATABASE IF EXISTS pdo_exec_ddl2');
if (1 === @$db->exec('CREATE DATABASE pdo_exec_ddl')) {
// yippie - we can create databases etc.
exec_and_count(3, $db, 'ALTER DATABASE pdo_exec_ddl CHARACTER SET latin1', 1);
}
exec_and_count(4, $db, 'DROP TABLE IF EXISTS pdo_exec_ddl', 0);
exec_and_count(5, $db, 'DROP TABLE IF EXISTS pdo_exec_ddl2', 0);
if (0 === $db->exec('CREATE TABLE pdo_exec_ddl(id INT, col1 CHAR(2))')) {
exec_and_count(5, $db, 'CREATE INDEX idx1 ON pdo_exec_ddl(id)', 0);
exec_and_count(6, $db, 'DROP INDEX idx1 ON pdo_exec_ddl', 0);
exec_and_count(7, $db, 'ALTER TABLE pdo_exec_ddl DROP id', 0);
exec_and_count(8, $db, 'ALTER TABLE pdo_exec_ddl ADD id INT', 0);
exec_and_count(9, $db, 'ALTER TABLE pdo_exec_ddl ALTER id SET DEFAULT 1', 0);
exec_and_count(10, $db, 'RENAME TABLE pdo_exec_ddl TO pdo_exec_ddl2', 0);
}
/*
11.1.2. ALTER LOGFILE GROUP Syntax
11.1.3. ALTER SERVER Syntax
11.1.5. ALTER TABLESPACE Syntax
11.1.8. CREATE LOGFILE GROUP Syntax
11.1.9. CREATE SERVER Syntax
11.1.11. CREATE TABLESPACE Syntax
11.1.14. DROP LOGFILE GROUP Syntax
11.1.15. DROP SERVER Syntax
11.1.17. DROP TABLESPACE Syntax
*/
// clean up
@$db->exec('DROP TABLE IF EXISTS pdo_exec_ddl');
@$db->exec('DROP TABLE IF EXISTS pdo_exec_ddl2');
@$db->exec('DROP DATABASE IF EXISTS pdo_exec_ddl');
@$db->exec('DROP DATABASE IF EXISTS pdo_exec_ddl2');
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
}
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,102 @@
--TEST--
MySQL PDO->exec(), affected rows
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
// Run test only locally - not against remote hosts
$db = MySQLPDOTest::factory();
$stmt = $db->query('SELECT USER() as _user');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$tmp = explode('@', $row['_user']);
if (count($tmp) < 2)
die("skip Cannot detect if test is run against local or remote database server");
if (($tmp[1] !== 'localhost') && ($tmp[1] !== '127.0.0.1'))
die("skip Test cannot be run against remote database server");
?>
--FILE--
<?php
function exec_and_count($offset, &$db, $sql, $exp) {
try {
$ret = $db->exec($sql);
if ($ret !== $exp) {
printf("[%03d] Expecting '%s'/%s got '%s'/%s when running '%s', [%s] %s\n",
$offset, $exp, gettype($exp), $ret, gettype($ret), $sql,
$db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
} catch (PDOException $e) {
if (42000 == $db->errorCode()) {
// Error: 1148 SQLSTATE: 42000 (ER_NOT_ALLOWED_COMMAND)
// Load data infile not allowed
return false;
}
printf("[%03d] '%s' has failed, [%s] %s\n",
$offset, $sql, $db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
return true;
}
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
/* affected rows related */
try {
exec_and_count(2, $db, 'DROP TABLE IF EXISTS test', 0);
exec_and_count(3, $db, sprintf('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE), 0);
$stmt = $db->query('SHOW VARIABLES LIKE "secure_file_priv"');
if (($row = $stmt->fetch(PDO::FETCH_ASSOC)) && ($row['value'] != '')) {
$filename = $row['value'] . DIRECTORY_SEPARATOR . "pdo_mysql_exec_load_data.csv";
} else {
$filename = MySQLPDOTest::getTempDir() . DIRECTORY_SEPARATOR . "pdo_mysql_exec_load_data.csv";
}
$fp = fopen($filename, "w");
fwrite($fp, b"1;foo\n");
fwrite($fp, b"2;bar");
fclose($fp);
$sql = sprintf("LOAD DATA INFILE %s INTO TABLE test FIELDS TERMINATED BY ';' LINES TERMINATED BY '\n'", $db->quote($filename));
if (exec_and_count(4, $db, $sql, 2)) {
$stmt = $db->query('SELECT id, col1 FROM test ORDER BY id ASC');
$expected = array(array("id" => 1, "col1" => "foo"), array("id" => 2, "col1" => "bar"));
$ret = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($expected as $offset => $exp) {
foreach ($exp as $key => $value) {
if ($ret[$offset][$key] != $value) {
printf("Results seem wrong, check manually\n");
var_dump($ret);
var_dump($expected);
break 2;
}
}
}
}
unlink($filename);
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,59 @@
--TEST--
MySQL PDO->exec(), SELECT
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
?>
--FILE--
<?php
function exec_and_count($offset, &$db, $sql, $exp) {
try {
$ret = $db->exec($sql);
if ($ret !== $exp) {
printf("[%03d] Expecting '%s'/%s got '%s'/%s when running '%s', [%s] %s\n",
$offset, $exp, gettype($exp), $ret, gettype($ret), $sql,
$db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
} catch (PDOException $e) {
printf("[%03d] '%s' has failed, [%s] %s\n",
$offset, $sql, $db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
return true;
}
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
/* affected rows related */
try {
exec_and_count(2, $db, 'DROP TABLE IF EXISTS test', 0);
exec_and_count(3, $db, sprintf('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE), 0);
exec_and_count(4, $db, 'INSERT INTO test(id, col1) VALUES (1, "a")', 1);
// question is: will the result set be cleaned up, will it be possible to run more queries on the line?
// buffered or unbuffered does not matter!
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
exec_and_count(5, $db, 'SELECT id FROM test', 0);
exec_and_count(6, $db, 'INSERT INTO test(id, col1) VALUES (2, "b")', 1);
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
}
@$db->exec(sprintf('DROP TABLE IF EXISTS test'));
print "done!";
--EXPECTF--
Warning: PDO::exec(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
[006] Expecting '1'/integer got ''/boolean when running 'INSERT INTO test(id, col1) VALUES (2, "b")', [HY000] HY000 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.
done!

View file

@ -0,0 +1,88 @@
--TEST--
MySQL PDOStatement->fetch()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
function fetch($offset, &$db, $query, $expect = null) {
try {
$stmt = $db->query('SELECT 1');
$num = $stmt->fetch(PDO::FETCH_NUM);
$stmt = $db->query('SELECT 1');
$assoc = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt = $db->query('SELECT 1');
$both = $stmt->fetch(PDO::FETCH_BOTH);
$computed_both = array_merge($num, $assoc);
if ($computed_both != $both) {
printf("[%03d] Suspicious FETCH_BOTH result, dumping\n", $offset);
var_dump($computed_both);
var_dump($both);
}
if (!is_null($expect) && ($expect != $both)) {
printf("[%03d] Expected differes from returned data, dumping\n", $offset);
var_dump($expect);
var_dump($both);
}
} catch (PDOException $e) {
printf("[%03d] %s, [%s] %s\n",
$offset,
$e->getMessage(), $db->errroCode(), implode(' ', $db->errorInfo()));
}
}
try {
fetch(2, &$db, 'SELECT 1', array(0 => '1', '1' => '1'));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec(sprintf('DROP TABLE IF EXISTS test'));
print "done!";
--EXPECTF--
[002] Suspicious FETCH_BOTH result, dumping
array(2) {
[0]=>
string(1) "1"
[1]=>
string(1) "1"
}
array(2) {
[1]=>
string(1) "1"
[2]=>
string(1) "1"
}
[002] Expected differes from returned data, dumping
array(2) {
[0]=>
string(1) "1"
[1]=>
string(1) "1"
}
array(2) {
[1]=>
string(1) "1"
[2]=>
string(1) "1"
}
done!

View file

@ -0,0 +1,101 @@
--TEST--
MySQL PDO->getAttribute()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
die("skip Transactional engine not found");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
function find_invalid_int($valid_options) {
do {
$invalid = mt_rand(-10000, 10000);
} while (in_array($invalid, $valid_options));
return $invalid;
}
function set_and_get($offset, $db, $attribute, $value) {
$value_type = gettype($value);
try {
if (!$db->setAttribute($attribute, $value)) {
printf("[%03d] Cannot set attribute '%s' to value '%s'\n",
$offset, $attribute, var_export($tmp, true));
return false;
}
if (gettype($value) != $value_type) {
printf("[%03d] Call to PDO::setAttribute(int attribute, mixed value) has changed the type of value from %s to %s, test will not work properly\n",
$offset, $value_type, gettype($value));
return false;
}
$tmp = $db->getAttribute($attribute);
if ($tmp !== $value) {
printf("[%03d] Attribute '%s' was set to '%s'/%s but getAttribute() reports '%s'/%s\n",
$offset, $attribute, var_export($value, true), gettype($value), var_export($tmp, true), gettype($tmp));
return false;
}
} catch (PDOException $e) {
printf("[%03d] %s, [%s] %s\n",
$offset, $e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
return true;
}
set_and_get(1, $db, PDO::ATTR_AUTOCOMMIT, 1);
/*
set_and_get(2, $db, PDO::ATTR_AUTOCOMMIT, 0);
set_and_get(3, $db, PDO::ATTR_AUTOCOMMIT, -1);
$obj = new stdClass();
set_and_get(4, $db, PDO::ATTR_AUTOCOMMIT, $obj);
set_and_get(5, $db, PDO::MYSQL_ATTR_LOCAL_INFILE, 1);
set_and_get(6, $db, PDO::MYSQL_ATTR_LOCAL_INFILE, 0);
set_and_get(7, $db, PDO::MYSQL_ATTR_LOCAL_INFILE, -1);
$tmp = array();
set_and_get(8, $db, PDO::MYSQL_ATTR_LOCAL_INFILE, $tmp);
set_and_get(9, $db, PPDO::MYSQL_ATTR_INIT_COMMAND, '');
set_and_get(10, $db, PPDO::MYSQL_ATTR_INIT_COMMAND, 'SOME SQL');
set_and_get(11, $db, PPDO::MYSQL_ATTR_INIT_COMMAND, -1);
*/
/*
PDO::MYSQL_ATTR_READ_DEFAULT_FILE (integer)
Read options from the named option file instead of from my.cnf.
PDO::MYSQL_ATTR_READ_DEFAULT_GROUP (integer)
Read options from the named group from my.cnf or the file specified with MYSQL_READ_DEFAULT_FILE.
PDO::MYSQL_ATTR_MAX_BUFFER_SIZE (integer)
Maximum buffer size. Defaults to 1 MiB.
PDO::MYSQL_ATTR_DIRECT_QUERY (integer)
Perform direct queries, don't use prepared statements.
*/
/*
TODO - read only
PDO::ATTR_CONNECTION_STATUS
PDO::ATTR_SERVER_INFO
*/
$db->exec(sprintf('DROP TABLE IF EXISTS test'));
print "done!";
--EXPECTF--
[001] Call to PDO::setAttribute(int attribute, mixed value) has changed the type of value from integer to boolean, test will not work properly
done!

View file

@ -0,0 +1,58 @@
--TEST--
MySQL PDO class interface
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::getDriver();
if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
die("skip Transactional engine not found");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
$expected = array(
'__construct' => true,
'prepare' => true,
'beginTransaction' => true,
'commit' => true,
'rollBack' => true,
'setAttribute' => true,
'exec' => true,
'query' => true,
'lastInsertId' => true,
'errorCode' => true,
'errorInfo' => true,
'getAttribute' => true,
'quote' => true,
'__wakeup' => true,
'__sleep' => true,
'getAvailableDrivers' => true,
);
$classname = get_class($db);
$methods = get_class_methods($classname);
foreach ($methods as $k => $method) {
if (isset($expected[$method])) {
unset($expected[$method]);
unset($methods[$k]);
}
if ($method == $classname) {
unset($expected['__construct']);
unset($methods[$k]);
}
}
if (!empty($expected)) {
printf("Dumping missing class methods\n");
var_dump($expected);
}
if (!empty($methods)) {
printf("Found more methods than expected, dumping list\n");
var_dump($methods);
}
print "done!";
--EXPECT--
done!

View file

@ -0,0 +1,114 @@
--TEST--
MySQL PDO->lastInsertId()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
if ('0' !== ($tmp = $db->lastInsertId()))
printf("[001] No query has been run, lastInsertId() should return '0'/string got '%s'/%s\n",
var_export($tmp, true), gettype($tmp));
if ('0' !== ($tmp = $db->lastInsertId('sequence_name')))
printf("[002] MySQL does not support sequences, expecting '0'/string got '%s'/%s\n",
var_export($tmp, true), gettype($tmp));
$db->exec('DROP TABLE IF EXISTS test');
if ('0' !== ($tmp = $db->lastInsertId()))
printf("[003] Expecting '0'/string got '%s'/%s", var_export($tmp, true), gettype($tmp));
$db->exec(sprintf('CREATE TABLE test(id INT, col1 CHAR(10)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
if ('0' !== ($tmp = $db->lastInsertId()))
printf("[004] Expecting '0'/string got '%s'/%s", var_export($tmp, true), gettype($tmp));
$stmt = $db->query('SELECT id FROM test LIMIT 1');
if ('0' !== ($tmp = $db->lastInsertId()))
printf("[005] Expecting '0'/string got '%s'/%s", var_export($tmp, true), gettype($tmp));
// no auto increment column
$db->exec('INSERT INTO test(id, col1) VALUES (100, "a")');
if ('0' !== ($tmp = $db->lastInsertId()))
printf("[006] Expecting '0'/string got '%s'/%s", var_export($tmp, true), gettype($tmp));
$db->exec('ALTER TABLE test MODIFY id INT AUTO_INCREMENT PRIMARY KEY');
if ('0' !== ($tmp = $db->lastInsertId()))
printf("[006] Expecting '0'/string got '%s'/%s", var_export($tmp, true), gettype($tmp));
// duplicate key
@$db->exec('INSERT INTO test(id, col1) VALUES (100, "a")');
if ('0' !== ($tmp = $db->lastInsertId()))
printf("[007] Expecting '0'/string got '%s'/%s", var_export($tmp, true), gettype($tmp));
$db->exec('INSERT INTO test(id, col1) VALUES (101, "b")');
if ('101' !== ($tmp = $db->lastInsertId()))
printf("[008] Expecting '0'/string got '%s'/%s", var_export($tmp, true), gettype($tmp));
$db->exec('ALTER TABLE test MODIFY col1 CHAR(10) UNIQUE');
// replace = delete + insert -> new auto increment value
$db->exec('REPLACE INTO test(col1) VALUES ("b")');
$next_id = (int)$db->lastInsertId();
if ($next_id <= 101)
printf("[009] Expecting at least 102, got %d\n",$next_id);
$stmt = $db->query('SELECT LAST_INSERT_ID() as _last_id');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$last_id = $row['_last_id'];
if ($next_id != $last_id) {
printf("[010] LAST_INSERT_ID() = %d and lastInserId() = %d differ\n",
$last_id, $next_id);
}
$db->exec('INSERT INTO test(col1) VALUES ("c"), ("d"), ("e")');
$next_id = (int)$db->lastInsertId();
if ($next_id <= $last_id)
printf("[011] Expecting at least %d, got %d\n", $last_id + 1, $next_id);
// warnings are unhandy, lets go for exceptions for a second
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$ignore_exception = true;
$db->exec('LOCK TABLE test WRITE');
$ignore_exception = false;
if (MySQLPDOTest::getServerVersion($db) >= 50000) {
$stmt = $db->query('SELECT @@auto_increment_increment AS inc');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$inc = $row['inc'];
} else {
$inc = 1;
}
$stmt = $db->query('SELECT LAST_INSERT_ID() as _last_id');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$last_id = $row['_last_id'];
$db->exec('INSERT INTO test(col1) VALUES ("z")');
$next_id = (int)$db->lastInsertId();
if ($next_id < ($last_id + $inc))
printf("[012] Expecting at least %d, got %d\n", $last_id + $inc, $next_id);
} catch (PDOException $e) {
if (!$ignore_exception)
printf("[014] %s, [%s} %s\n", $e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
@$db->exec('UNLOCK TABLE test');
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec(sprintf('DROP TABLE IF EXISTS test'));
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,101 @@
--TEST--
MySQL PDO->__construct(), PDO::ATTR_PERSISTENT
--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');
try {
$dsn = MySQLPDOTest::getDSN();
$user = PDO_MYSQL_TEST_USER;
$pass = PDO_MYSQL_TEST_PASS;
$db1 = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$db2 = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$db1->exec('SET @pdo_persistent_connection=1');
$stmt = $db2->query('SELECT @pdo_persistent_connection as _pers');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
if ($tmp['_pers'] !== '1')
printf("[001] Both handles should use the same connection.");
$stmt = $db1->query('SELECT CONNECTION_ID() as _con1');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
$con1 = $tmp['_con1'];
$stmt = $db2->query('SELECT CONNECTION_ID() as _con2');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
$con2 = $tmp['_con2'];
if ($con1 !== $con2)
printf("[002] Both handles should report the same MySQL thread ID");
$db1 = NULL; /* should be equal to closing to my understanding */
$db1 = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$stmt = $db1->query('SELECT CONNECTION_ID() as _con1');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
$con1 = $tmp['_con1'];
if ($con1 !== $con2)
printf("[003] Both handles should report the same MySQL thread ID");
$affected = $db1->exec(sprintf('KILL %d', $con1));
// Server needs some think-time sometimes
sleep(1);
if ('00000' == $db1->errorCode()) {
// looks like KILL has worked ? Or not... TODO: why no warning with libmysql?!
@$db1->exec("SET @pdo_persistent_connection=2");
// but now I want to see some error...
if ('HY000' != $db1->errorCode())
printf("[004] Wrong error code %s\n", $db1->errorCode());
$tmp = implode(' ', $db1->errorInfo());
if (!strstr($tmp, '2006'))
printf("[005] Wrong error info %s\n", $tmp);
}
$db1 = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => false));
$stmt = $db1->query('SELECT CONNECTION_ID() as _con1');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
$con1 = $tmp['_con1'];
$db2 = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
$stmt = $db2->query('SELECT CONNECTION_ID() as _con2');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
$con2 = $tmp['_con2'];
if ($con1 == $con2)
printf("[006] Looks like the persistent and the non persistent connection are using the same link?!\n");
// lets go crazy and create a few pconnections...
$connections = array();
for ($i = 0; $i <= 20; $i++) {
$connections[$i] = new PDO($dsn, $user, $pass, array(PDO::ATTR_PERSISTENT => true));
}
do {
$i = mt_rand(0, 20);
if (isset($connections[$i]))
unset($connections[$i]);
} while (!empty($connections));
} catch (PDOException $e) {
printf("[001] %s, [%s] %s\n",
$e->getMessage(),
(is_object($db)) ? $db->errorCode() : 'n/a',
(is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
}
print "done!";
--XFAIL--
Expected to fail in debug mode as PDO doesn't properly clean persistent connections
--EXPECTF--
Warning: PDO::exec(): MySQL server has gone away in %s on line %d
Warning: PDO::exec(): Error while reading SET_OPTION's EOF packet. PID=%d in %s on line %d
done!

View file

@ -0,0 +1,34 @@
--TEST--
MySQL PDO phpinfo() output
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
ob_start();
phpinfo();
$tmp = ob_get_contents();
ob_end_clean();
/* PDO Driver for MySQL, client library version => 6.0.3-alpha */
$expected = sprintf('PDO Driver for MySQL, client library version => %s',
$db->getAttribute(PDO::ATTR_CLIENT_VERSION));
if (false === stristr($tmp, $expected)) {
// maybe its PDO_MYSQLND
$expected = sprintf('PDO Driver for MySQL, mysql native driver version => %s',
$db->getAttribute(PDO::ATTR_CLIENT_VERSION));
if (false === stristr($tmp, $expected))
printf("[001] Cannot find MySQL PDO driver line in phpinfo() output\n");
}
print "done!";
--EXPECT--
done!

View file

@ -0,0 +1,414 @@
--TEST--
MySQL PDO->prepare(), emulated PS
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
function prepex($offset, &$db, $query, $input_params = null, $error_info = null) {
try {
if (is_array($error_info) && isset($error_info['prepare']))
$stmt = @$db->prepare($query);
else
$stmt = $db->prepare($query);
if (is_array($error_info) && isset($error_info['prepare'])) {
$tmp = $db->errorInfo();
if (isset($error_info['prepare']['sqlstate']) &&
($error_info['prepare']['sqlstate'] !== $tmp[0])) {
printf("[%03d] prepare() - expecting SQLSTATE '%s' got '%s'\n",
$offset, $error_info['prepare']['sqlstate'], $tmp[0]);
return false;
}
if (isset($error_info['prepare']['mysql']) &&
($error_info['prepare']['mysql'] !== $tmp[1])) {
printf("[%03d] prepare() - expecting MySQL Code '%s' got '%s'\n",
$offset, $error_info['prepare']['mysql'], $tmp[0]);
return false;
}
return false;
}
if (is_null($input_params))
$input_params = array();
if (is_array($error_info) && isset($error_info['execute']))
$ret = @$stmt->execute($input_params);
else
$ret = $stmt->execute($input_params);
if (!is_bool($ret))
printf("[%03d] PDO::execute() should return a boolean value, got %s/%s\n",
var_export($ret, true), $ret);
if (is_array($error_info) && isset($error_info['execute'])) {
$tmp = $stmt->errorInfo();
if (isset($error_info['execute']['sqlstate']) &&
($error_info['execute']['sqlstate'] !== $tmp[0])) {
printf("[%03d] execute() - expecting SQLSTATE '%s' got '%s'\n",
$offset, $error_info['execute']['sqlstate'], $tmp[0]);
return false;
}
if (isset($error_info['execute']['mysql']) &&
($error_info['execute']['mysql'] !== $tmp[1])) {
printf("[%03d] execute() - expecting MySQL Code '%s' got '%s'\n",
$offset, $error_info['execute']['mysql'], $tmp[0]);
return false;
}
return false;
}
} catch (PDOException $e) {
printf("[%03d] %s, [%s} %s\n",
$offset, $e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
return $stmt;
}
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to switch to emulated prepared statements, test will fail\n");
// TODO - that's PDO - you can prepare empty statements!
prepex(3, $db, '',
array(), array('execute' => array('sqlstate' => '42000')));
// lets be fair and do the most simple SELECT first
$stmt = prepex(4, $db, 'SELECT 1 as "one"');
var_dump($stmt->fetch(PDO::FETCH_ASSOC));
prepex(5, $db, 'DROP TABLE IF EXISTS test');
prepex(6, $db, sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
prepex(7, $db, 'INSERT INTO test(id, label) VALUES(1, ":placeholder")');
$stmt = prepex(8, $db, 'SELECT label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
prepex(9, $db, 'DELETE FROM test');
prepex(10, $db, 'INSERT INTO test(id, label) VALUES(1, ":placeholder")',
array(':placeholder' => 'first row'));
$stmt = prepex(11, $db, 'SELECT label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
prepex(12, $db, 'DELETE FROM test');
prepex(13, $db, 'INSERT INTO test(id, label) VALUES(1, :placeholder)',
array(':placeholder' => 'first row'));
prepex(14, $db, 'INSERT INTO test(id, label) VALUES(2, :placeholder)',
array(':placeholder' => 'second row'));
$stmt = prepex(15, $db, 'SELECT label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// Is PDO fun?
prepex(16, $db, 'SELECT label FROM test WHERE :placeholder > 1',
array(':placeholder' => 'id'));
prepex(17, $db, 'SELECT :placeholder FROM test WHERE id > 1',
array(':placeholder' => 'id'));
prepex(18, $db, 'SELECT :placeholder FROM test WHERE :placeholder > :placeholder',
array(':placeholder' => 'test'));
for ($num_params = 2; $num_params < 100; $num_params++) {
$params = array(':placeholder' => 'a');
for ($i = 1; $i < $num_params; $i++) {
$params[str_repeat('a', $i)] = 'some data';
}
prepex(19, $db, 'SELECT id, label FROM test WHERE label > :placeholder',
$params, array('execute' => array('sqlstate' => 'HY093')));
}
prepex(20, $db, 'DELETE FROM test');
prepex(21, $db, 'INSERT INTO test(id, label) VALUES (1, :placeholder), (2, :placeholder)',
array(':placeholder' => 'row'));
$stmt = prepex(22, $db, 'SELECT id, label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt = prepex(23, $db, 'SELECT id, label FROM test WHERE :placeholder IS NOT NULL',
array(':placeholder' => 1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[024] '1' IS NOT NULL evaluates to true, expecting two rows, got %d rows\n", $tmp);
$stmt = prepex(25, $db, 'SELECT id, label FROM test WHERE :placeholder IS NULL',
array(':placeholder' => 1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0)
printf("[026] '1' IS NOT NULL evaluates to true, expecting zero rows, got %d rows\n", $tmp);
prepex(27, $db, 'DROP TABLE IF EXISTS test');
prepex(28, $db, 'CREATE TABLE test(id INT, label CHAR(255)) ENGINE=MyISAM');
if (is_object(prepex(29, $db, 'CREATE FULLTEXT INDEX idx1 ON test(label)'))) {
prepex(30, $db, 'INSERT INTO test(id, label) VALUES (1, :placeholder)',
array(':placeholder' => 'MySQL is the best database in the world!'));
prepex(31, $db, 'INSERT INTO test(id, label) VALUES (1, :placeholder)',
array(':placeholder' => 'If I have the freedom to choose, I would always go again for the MySQL Server'));
$stmt = prepex(32, $db, 'SELECT id, label FROM test WHERE MATCH label AGAINST (:placeholder)',
array(':placeholder' => 'mysql'));
/*
Lets ignore this
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[033] Expecting two rows, got %d rows\n", $tmp);
*/
}
prepex(34, $db, 'DELETE FROM test');
prepex(35, $db, 'INSERT INTO test(id, label) VALUES (1, :placeholder), (2, :placeholder)',
array(':placeholder' => 'row'));
/*
$stmt = prepex(36, $db, 'SELECT id, label FROM "test WHERE MATCH label AGAINST (:placeholder)',
array(':placeholder' => 'row'),
array('execute' => array('sqlstate' => '42000', 'mysql' => 1064)));
*/
$stmt = prepex(37, $db, 'SELECT id, label FROM \'test WHERE MATCH label AGAINST (:placeholder)',
array(':placeholder' => 'row'),
array('execute' => array('sqlstate' => '42000', 'mysql' => 1064)));
$stmt = prepex(38, $db, 'SELECT id, label AS "label" FROM test WHERE label = :placeholder',
array(':placeholder' => 'row'));
$sql = sprintf("SELECT id, label FROM test WHERE (label LIKE %s) AND (id = :placeholder)",
$db->quote('%ro%'));
$stmt = prepex(39, $db, $sql, array('placeholder' => -1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0)
printf("[040] Expecting zero rows, got %d rows\n", $tmp);
$sql = sprintf("SELECT id, label FROM test WHERE (id = :placeholder) OR (label LIKE %s)",
$db->quote('%ro%'));
$stmt = prepex(41, $db, $sql, array('placeholder' => 1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[042] Expecting two rows, got %d rows\n", $tmp);
$sql = "SELECT id, label FROM test WHERE id = :placeholder AND label = (SELECT label AS 'SELECT' FROM test WHERE id = :placeholder)";
$stmt = prepex(43, $db, $sql, array('placeholder' => 1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 1)
printf("[044] Expecting onw row, got %d rows\n", $tmp);
// and now, the same with anonymous placeholders...
prepex(45, $db, 'DROP TABLE IF EXISTS test');
prepex(46, $db, sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
prepex(47, $db, 'INSERT INTO test(id, label) VALUES(1, "?")');
$stmt = prepex(48, $db, 'SELECT label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
prepex(49, $db, 'DELETE FROM test');
prepex(50, $db, 'INSERT INTO test(id, label) VALUES(1, "?")',
array('first row'));
$stmt = prepex(51, $db, 'SELECT label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
prepex(52, $db, 'DELETE FROM test');
prepex(53, $db, 'INSERT INTO test(id, label) VALUES(1, ?)',
array('first row'));
prepex(54, $db, 'INSERT INTO test(id, label) VALUES(2, ?)',
array('second row'));
$stmt = prepex(55, $db, 'SELECT label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// Is PDO fun?
prepex(56, $db, 'SELECT label FROM test WHERE ? > 1',
array('id'));
prepex(57, $db, 'SELECT ? FROM test WHERE id > 1',
array('id'));
prepex(58, $db, 'SELECT ? FROM test WHERE ? > ?',
array('test'), array('execute' => array('sqlstate' => 'HY093')));
prepex(59, $db, 'SELECT ? FROM test WHERE ? > ?',
array('id', 'label', 'value'));
for ($num_params = 2; $num_params < 100; $num_params++) {
$params = array('a');
for ($i = 1; $i < $num_params; $i++) {
$params[] = 'some data';
}
prepex(60, $db, 'SELECT id, label FROM test WHERE label > ?',
$params, array('execute' => array('sqlstate' => 'HY093')));
}
prepex(61, $db, 'DELETE FROM test');
prepex(62, $db, 'INSERT INTO test(id, label) VALUES (1, ?), (2, ?)',
array('row', 'row'));
$stmt = prepex(63, $db, 'SELECT id, label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt = prepex(64, $db, 'SELECT id, label FROM test WHERE ? IS NOT NULL',
array(1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[065] '1' IS NOT NULL evaluates to true, expecting two rows, got %d rows\n", $tmp);
$stmt = prepex(66, $db, 'SELECT id, label FROM test WHERE ? IS NULL',
array(1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0)
printf("[067] '1' IS NOT NULL evaluates to true, expecting zero rows, got %d rows\n", $tmp);
prepex(68, $db, 'DROP TABLE IF EXISTS test');
prepex(69, $db, 'CREATE TABLE test(id INT, label CHAR(255)) ENGINE=MyISAM');
if (is_object(prepex(70, $db, 'CREATE FULLTEXT INDEX idx1 ON test(label)'))) {
prepex(71, $db, 'INSERT INTO test(id, label) VALUES (1, ?)',
array('MySQL is the best database in the world!'));
prepex(72, $db, 'INSERT INTO test(id, label) VALUES (1, ?)',
array('If I have the freedom to choose, I would always go again for the MySQL Server'));
$stmt = prepex(73, $db, 'SELECT id, label FROM test WHERE MATCH label AGAINST (?)',
array('mysql'));
/*
Lets ignore that
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[074] Expecting two rows, got %d rows\n", $tmp);
*/
}
prepex(74, $db, 'DELETE FROM test');
prepex(75, $db, 'INSERT INTO test(id, label) VALUES (1, ?), (2, ?)',
array('row', 'row'));
$stmt = prepex(76, $db, 'SELECT id, label FROM "test WHERE MATCH label AGAINST (?)',
array('row'),
array('execute' => array('sqlstate' => '42000', 'mysql' => 1064)));
/*
TODO enable after fix
$stmt = prepex(37, $db, 'SELECT id, label FROM \'test WHERE MATCH label AGAINST (:placeholder)',
array(':placeholder' => 'row'),
array('execute' => array('sqlstate' => '42000', 'mysql' => 1064)));
*/
$stmt = prepex(78, $db, 'SELECT id, label AS "label" FROM test WHERE label = ?',
array('row'));
$sql = sprintf("SELECT id, label FROM test WHERE (label LIKE %s) AND (id = ?)",
$db->quote('%ro%'));
$stmt = prepex(79, $db, $sql, array(-1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0)
printf("[080] Expecting zero rows, got %d rows\n", $tmp);
$sql = sprintf("SELECT id, label FROM test WHERE (id = ?) OR (label LIKE %s)",
$db->quote('%ro%'));
$stmt = prepex(81, $db, $sql, array(1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[082] Expecting two rows, got %d rows\n", $tmp);
$sql = "SELECT id, label FROM test WHERE id = ? AND label = (SELECT label AS 'SELECT' FROM test WHERE id = ?)";
$stmt = prepex(83, $db, $sql, array(1, 1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 1)
printf("[084] Expecting one row, got %d rows\n", $tmp);
$sql = "SELECT id, label FROM test WHERE id = :placeholder AND label = (SELECT label AS 'SELECT' FROM test WHERE id = ?)";
$stmt = prepex(85, $db, $sql, array(1, 1), array('execute' => array('sqlstate' => 'HY093')));
if (is_object($stmt) && count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0)
printf("[086] Expecting no rows, got %d rows\n", $tmp);
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--XFAIL--
PDO's PS parser has some problems with invalid SQL and crashes from time to time
(check with valgrind...)
--EXPECTF--
array(1) {
["one"]=>
string(1) "1"
}
array(1) {
[0]=>
array(1) {
["label"]=>
string(12) ":placeholder"
}
}
array(1) {
[0]=>
array(1) {
["label"]=>
string(12) ":placeholder"
}
}
array(2) {
[0]=>
array(1) {
["label"]=>
string(9) "first row"
}
[1]=>
array(1) {
["label"]=>
string(10) "second row"
}
}
array(2) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(3) "row"
}
[1]=>
array(2) {
["id"]=>
string(1) "2"
["label"]=>
string(3) "row"
}
}
array(1) {
[0]=>
array(1) {
["label"]=>
string(1) "?"
}
}
array(1) {
[0]=>
array(1) {
["label"]=>
string(1) "?"
}
}
array(2) {
[0]=>
array(1) {
["label"]=>
string(9) "first row"
}
[1]=>
array(1) {
["label"]=>
string(10) "second row"
}
}
array(2) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(3) "row"
}
[1]=>
array(2) {
["id"]=>
string(1) "2"
["label"]=>
string(3) "row"
}
}
done!

View file

@ -0,0 +1,78 @@
--TEST--
MySQL PDO->prepare(), emulated PS, anonymous placeholder
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to switch to emulated prepared statements, test will fail\n");
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES(1, "?")');
// you can bind as many values as you want no matter if they can be replaced or not
$stmt->execute(array('first row'));
if ('00000' !== $stmt->errorCode())
printf("[003] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
$stmt = $db->prepare('SELECT id, label FROM test');
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// now the same with native PS
printf("now the same with native PS\n");
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to switch off emulated prepared statements, test will fail\n");
$db->exec('DELETE FROM test');
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES(1, "?")');
// you can bind as many values as you want no matter if they can be replaced or not
$stmt->execute(array('first row'));
if ('00000' !== $stmt->errorCode())
printf("[005] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
$stmt = $db->prepare('SELECT id, label FROM test');
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "?"
}
}
now the same with native PS
[005] Execute has failed, 'HY093' array (
0 => 'HY093',
)
array(0) {
}
done!

View file

@ -0,0 +1,75 @@
--TEST--
MySQL PDO->prepare(), emulated PS, anonymous placeholder
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
// TODO: This test is MySQL version specific - for whatever reason
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
// native PS
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to switch off emulated prepared statements, test will fail\n");
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
$db->exec('INSERT INTO test(id, label) VALUES (1, "row1")');
// So, what will happen? More placeholder but values and
// placeholders in interesting places...
$stmt = $db->prepare('SELECT ? FROM test WHERE ? > ?');
$stmt->execute(array('test'));
if ('00000' !== $stmt->errorCode()) {
printf("[003] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
}
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// now the same with emulated PS
printf("now the same with emulated PS\n");
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to switch on emulated prepared statements, test will fail\n");
$stmt = $db->prepare('SELECT ? FROM test WHERE ? > ?');
$stmt->execute(array('test'));
if ('00000' !== $stmt->errorCode())
printf("[005] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec(sprintf('DROP TABLE IF EXISTS test'));
print "done!";
?>
--EXPECTF--
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number in %s on line %d
[003] Execute has failed, 'HY093' array (
0 => 'HY093',
)
array(0) {
}
now the same with emulated PS
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in %s on line %d
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number in %s on line 33
[005] Execute has failed, 'HY093' array (
0 => 'HY093',
)
array(0) {
}
done!

View file

@ -0,0 +1,48 @@
--TEST--
MySQL PDO->prepare(MATCH ... AGAINST (:placeholder)) - similar: http://bugs.php.net/bug.php?id=41876
--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();
try {
$db->exec('DROP TABLE IF EXISTS test');
$db->exec('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=MyISAM');
$db->exec('CREATE FULLTEXT INDEX idx1 ON test(label)');
$stmt = $db->prepare('SELECT id, label FROM test WHERE MATCH label AGAINST (:placeholder)');
$stmt->execute(array(':placeholder' => 'row'));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt = $db->prepare('SELECT id, label FROM test WHERE MATCH label AGAINST (:placeholder)');
$stmt->execute(array('placeholder' => 'row'));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt = $db->prepare('SELECT id, label FROM test WHERE MATCH label AGAINST (?)');
$stmt->execute(array('row'));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} catch (PDOException $e) {
printf("[001] %s, [%s} %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
--EXPECTF--
array(0) {
}
array(0) {
}
array(0) {
}
done!

View file

@ -0,0 +1,380 @@
--TEST--
MySQL PDO->prepare(), native PS
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
function prepex($offset, &$db, $query, $input_params = null, $error_info = null, $suppress_warning = false) {
try {
if ($suppress_warning || (is_array($error_info) && isset($error_info['prepare'])))
$stmt = @$db->prepare($query);
else
$stmt = $db->prepare($query);
if (is_array($error_info) && isset($error_info['prepare'])) {
$tmp = $db->errorInfo();
if (isset($error_info['prepare']['sqlstate']) &&
($error_info['prepare']['sqlstate'] !== $tmp[0])) {
printf("[%03d] prepare() - expecting SQLSTATE '%s' got '%s'\n",
$offset, $error_info['prepare']['sqlstate'], $tmp[0]);
return false;
}
if (isset($error_info['prepare']['mysql']) &&
($error_info['prepare']['mysql'] !== $tmp[1])) {
printf("[%03d] prepare() - expecting MySQL Code '%s' got '%s'\n",
$offset, $error_info['prepare']['mysql'], $tmp[0]);
return false;
}
return false;
}
if (!is_object($stmt))
return false;
if (is_null($input_params))
$input_params = array();
// 5.0.18, 5.1.14 @ 15
// printf("[%03d]\n", $offset);
if ($suppress_warning || (is_array($error_info) && isset($error_info['execute'])))
$ret = @$stmt->execute($input_params);
else
$ret = $stmt->execute($input_params);
if (!is_bool($ret))
printf("[%03d] PDO::execute() should return a boolean value, got %s/%s\n",
var_export($ret, true), $ret);
$tmp = $stmt->errorInfo();
if (isset($tmp[1]) && ($tmp[1] == 2030)) {
// Trying to hack around MySQL Server version dependent features
// 2030 This command is not supported in the prepared statement protocol yet
return false;
}
if (is_array($error_info) && isset($error_info['execute'])) {
if (isset($error_info['execute']['sqlstate']) &&
($error_info['execute']['sqlstate'] !== $tmp[0])) {
printf("[%03d] execute() - expecting SQLSTATE '%s' got '%s'\n",
$offset, $error_info['execute']['sqlstate'], $tmp[0]);
return false;
}
if (isset($error_info['execute']['mysql']) &&
($error_info['execute']['mysql'] !== $tmp[1])) {
printf("[%03d] execute() - expecting MySQL Code '%s' got '%s'\n",
$offset, $error_info['execute']['mysql'], $tmp[0]);
return false;
}
return false;
}
} catch (PDOException $e) {
printf("[%03d] %s, [%s} %s\n",
$offset, $e->getMessage(),
$db->errorCode(), implode(' ', $db->errorInfo()));
return false;
}
return $stmt;
}
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn off emulated prepared statements\n");
// TODO - that's PDO - you can prepare empty statements!
prepex(3, $db, '',
array(), array('prepare' => array('sqlstate' => '42000')));
// lets be fair and do the most simple SELECT first
$stmt = prepex(4, $db, 'SELECT 1 as "one"');
if (MySQLPDOTest::isPDOMySQLnd())
// native types - int
$expected = array('one' => 1);
else
// always strings, like STRINGIFY flag
$expected = array('one' => '1');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if ($row !== $expected) {
printf("[004a] Expecting %s got %s\n", var_export($expected, true), vat_export($row, true));
}
prepex(5, $db, 'DROP TABLE IF EXISTS test');
prepex(6, $db, sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
prepex(7, $db, 'INSERT INTO test(id, label) VALUES(1, ":placeholder")');
$stmt = prepex(8, $db, 'SELECT label FROM test ORDER BY id ASC');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
prepex(9, $db, 'DELETE FROM test');
prepex(10, $db, 'INSERT INTO test(id, label) VALUES(1, :placeholder)',
array(':placeholder' => 'first row'));
prepex(11, $db, 'INSERT INTO test(id, label) VALUES(2, :placeholder)',
array(':placeholder' => 'second row'));
$stmt = prepex(12, $db, 'SELECT label FROM test ORDER BY id ASC');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// Is PDO fun?
$stmt = prepex(13, $db, 'SELECT label FROM test WHERE :placeholder > 1',
array(':placeholder' => 'id'));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
for ($num_params = 2; $num_params < 100; $num_params++) {
$params = array(':placeholder' => 'a');
for ($i = 1; $i < $num_params; $i++) {
$params[str_repeat('a', $i)] = 'some data';
}
prepex(16, $db, 'SELECT id, label FROM test WHERE label > :placeholder',
$params, array('execute' => array('sqlstate' => 'HY093')));
}
$stmt = prepex(16, $db, 'SELECT id, label FROM test WHERE :placeholder IS NOT NULL',
array(':placeholder' => 1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[017] '1' IS NOT NULL evaluates to true, expecting two rows, got %d rows\n", $tmp);
$stmt = prepex(18, $db, 'SELECT id, label FROM test WHERE :placeholder IS NULL',
array(':placeholder' => 1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0)
printf("[019] '1' IS NOT NULL evaluates to true, expecting zero rows, got %d rows\n", $tmp);
prepex(20, $db, 'DROP TABLE IF EXISTS test');
prepex(21, $db, 'CREATE TABLE test(id INT, label CHAR(255)) ENGINE=MyISAM');
// Not every MySQL Server version supports this
if (is_object(prepex(22, $db, 'CREATE FULLTEXT INDEX idx1 ON test(label)', null, null, true))) {
prepex(23, $db, 'INSERT INTO test(id, label) VALUES (1, :placeholder)',
array(':placeholder' => 'MySQL is the best database in the world!'));
prepex(24, $db, 'INSERT INTO test(id, label) VALUES (2, :placeholder)',
array(':placeholder' => 'If I have the freedom to choose, I would always go again for the MySQL Server'));
$stmt = prepex(25, $db, 'SELECT id, label FROM test WHERE MATCH label AGAINST (:placeholder)',
array(':placeholder' => 'mysql'), null, true);
if (is_object($stmt)) {
/*
Lets ignore this
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[033] Expecting two rows, got %d rows\n", $tmp);
*/
$stmt = prepex(26, $db, 'SELECT id, label FROM test ORDER BY id ASC');
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[027] Expecting two rows, got %d rows\n", $tmp);
if ($tmp[0]['label'] !== 'MySQL is the best database in the world!') {
printf("[028] INSERT seems to have failed, dumping data, check manually\n");
var_dump($tmp);
}
}
}
$db->exec('DELETE FROM test');
$db->exec('INSERT INTO test(id, label) VALUES (1, "row1")');
$db->exec('INSERT INTO test(id, label) VALUES (2, "row2")');
$sql = sprintf("SELECT id, label FROM test WHERE (label LIKE %s) AND (id = :placeholder)",
$db->quote('%ro%'));
$stmt = prepex(29, $db, $sql, array('placeholder' => -1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0)
printf("[030] Expecting zero rows, got %d rows\n", $tmp);
$sql = sprintf("SELECT id, label FROM test WHERE (id = :placeholder) OR (label LIKE %s)",
$db->quote('%go%'));
$stmt = prepex(31, $db, $sql, array('placeholder' => 1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 1)
printf("[032] Expecting one row, got %d rows\n", $tmp);
// and now, the same with anonymous placeholders...
prepex(33, $db, 'DROP TABLE IF EXISTS test');
prepex(34, $db, sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
prepex(35, $db, 'INSERT INTO test(id, label) VALUES(1, "?")');
$stmt = prepex(36, $db, 'SELECT label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
prepex(37, $db, 'DELETE FROM test');
prepex(38, $db, 'INSERT INTO test(id, label) VALUES(1, ?)',
array('first row'));
prepex(39, $db, 'INSERT INTO test(id, label) VALUES(2, ?)',
array('second row'));
$stmt = prepex(40, $db, 'SELECT label FROM test');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// Is PDO fun?
prepex(40, $db, 'SELECT label FROM test WHERE ? > 1',
array('id'));
prepex(41, $db, 'SELECT ? FROM test WHERE id > 1',
array('id'));
prepex(42, $db, 'SELECT ? FROM test WHERE ? > ?',
array('id', 'label', 'value'));
for ($num_params = 2; $num_params < 100; $num_params++) {
$params = array('a');
for ($i = 1; $i < $num_params; $i++) {
$params[] = 'some data';
}
prepex(43, $db, 'SELECT id, label FROM test WHERE label > ?',
$params, array('execute' => array('sqlstate' => 'HY093')));
}
prepex(44, $db, 'DELETE FROM test');
prepex(45, $db, 'INSERT INTO test(id, label) VALUES (1, ?), (2, ?)',
array('row', 'row'));
$stmt = prepex(46, $db, 'SELECT id, label FROM test');
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
$exp = array(
0 => array(
"id" => "1",
"label" => "row"
),
1 => array(
"id" => "2",
"label" => "row"
),
);
if (MySQLPDOTest::isPDOMySQLnd()) {
// mysqlnd returns native types
$exp[0]['id'] = 1;
$exp[1]['id'] = 2;
}
if ($tmp !== $exp) {
printf("[064] Results seem wrong. Please check dumps manually.\n");
var_dump($exp);
var_dump($tmp);
}
$stmt = prepex(47, $db, 'SELECT id, label FROM test WHERE ? IS NOT NULL',
array(1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[048] '1' IS NOT NULL evaluates to true, expecting two rows, got %d rows\n", $tmp);
$stmt = prepex(49, $db, 'SELECT id, label FROM test WHERE ? IS NULL',
array(1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0)
printf("[050] '1' IS NOT NULL evaluates to true, expecting zero rows, got %d rows\n", $tmp);
prepex(51, $db, 'DROP TABLE IF EXISTS test');
prepex(52, $db, 'CREATE TABLE test(id INT, label CHAR(255)) ENGINE=MyISAM');
if (is_object(prepex(53, $db, 'CREATE FULLTEXT INDEX idx1 ON test(label)', null, null, true))) {
prepex(54, $db, 'INSERT INTO test(id, label) VALUES (1, ?)',
array('MySQL is the best database in the world!'));
prepex(55, $db, 'INSERT INTO test(id, label) VALUES (1, ?)',
array('If I have the freedom to choose, I would always go again for the MySQL Server'));
$stmt = prepex(56, $db, 'SELECT id, label FROM test WHERE MATCH label AGAINST (?)',
array('mysql'), null, true);
/*
Lets ignore that
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[074] Expecting two rows, got %d rows\n", $tmp);
*/
}
prepex(57, $db, 'DELETE FROM test');
prepex(58, $db, 'INSERT INTO test(id, label) VALUES (1, ?), (2, ?)',
array('row1', 'row2'));
/*
TODO enable after fix
$stmt = prepex(37, $db, 'SELECT id, label FROM \'test WHERE MATCH label AGAINST (:placeholder)',
array(':placeholder' => 'row'),
array('execute' => array('sqlstate' => '42000', 'mysql' => 1064)));
*/
$stmt = prepex(59, $db, 'SELECT id, label AS "label" FROM test WHERE label = ?',
array('row1'));
$tmp = $stmt->fetchAll(PDO::FETCH_ASSOC);
$exp = array(
0 => array("id" => "1", "label" => "row1")
);
if (MySQLPDOTest::isPDOMySQLnd()) {
// mysqlnd returns native types
$exp[0]['id'] = 1;
}
if ($tmp !== $exp) {
printf("[065] Results seem wrong. Please check dumps manually.\n");
var_dump($exp);
var_dump($tmp);
}
$sql = sprintf("SELECT id, label FROM test WHERE (label LIKE %s) AND (id = ?)",
$db->quote('%ro%'));
$stmt = prepex(60, $db, $sql, array(-1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 0)
printf("[061] Expecting zero rows, got %d rows\n", $tmp);
$sql = sprintf("SELECT id, label FROM test WHERE (id = ?) OR (label LIKE %s)",
$db->quote('%ro%'));
$stmt = prepex(61, $db, $sql, array(1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 2)
printf("[062] Expecting two rows, got %d rows\n", $tmp);
$sql = "SELECT id, label FROM test WHERE id = ? AND label = (SELECT label AS 'SELECT' FROM test WHERE id = ?)";
$stmt = prepex(63, $db, $sql, array(1, 1));
if (count(($tmp = $stmt->fetchAll(PDO::FETCH_ASSOC))) != 1)
printf("[064] Expecting one row, got %d rows\n", $tmp);
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
array(1) {
[0]=>
array(1) {
["label"]=>
string(12) ":placeholder"
}
}
array(2) {
[0]=>
array(1) {
["label"]=>
string(9) "first row"
}
[1]=>
array(1) {
["label"]=>
string(10) "second row"
}
}
array(0) {
}
array(1) {
[0]=>
array(1) {
["label"]=>
string(1) "?"
}
}
array(2) {
[0]=>
array(1) {
["label"]=>
string(9) "first row"
}
[1]=>
array(1) {
["label"]=>
string(10) "second row"
}
}
done!

View file

@ -0,0 +1,91 @@
--TEST--
MySQL PDO->prepare(), native PS, clear line after error
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
// We need to run the emulated version first. Native version will cause a fatal error
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn on emulated prepared statements\n");
// INSERT a single row
$db->exec('INSERT INTO test(id, label) VALUES (1, "row1")');
$stmt = $db->prepare('SELECT unknown_column FROM test WHERE id > :placeholder ORDER BY id ASC');
$stmt->execute(array(':placeholder' => 0));
if ('00000' !== $stmt->errorCode())
printf("[003] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > :placeholder ORDER BY id ASC');
$stmt->execute(array(':placeholder' => 0));
if ('00000' !== $stmt->errorCode())
printf("[004] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// Native PS
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[005] Unable to turn off emulated prepared statements\n");
$stmt = $db->prepare('SELECT unknown_column FROM test WHERE id > :placeholder ORDER BY id ASC');
$stmt->execute(array(':placeholder' => 0));
if ('00000' !== $stmt->errorCode())
printf("[006] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > :placeholder ORDER BY id ASC');
$stmt->execute(array(':placeholder' => 0));
if ('00000' !== $stmt->errorCode())
printf("[007] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Warning: PDOStatement::execute(): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'unknown_column' in 'field list' in %s on line %d
[003] Execute has failed, '42S22' array (
0 => '42S22',
1 => 1054,
2 => 'Unknown column \'unknown_column\' in \'field list\'',
)
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(4) "row1"
}
}
Warning: PDO::prepare(): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'unknown_column' in 'field list' in %s on line %d
Fatal error: Call to a member function execute() on a non-object in %s on line %d

View file

@ -0,0 +1,44 @@
--TEST--
MySQL PDO->prepare(), native PS, named placeholder
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn off emulated prepared statements\n");
$stmt = $db->prepare("SELECT :param FROM test ORDER BY id ASC LIMIT 1");
$stmt->execute(array(':param' => 'id'));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$db->prepare('SELECT :placeholder FROM test WHERE :placeholder > :placeholder');
$stmt->execute(array(':placeholder' => 'test'));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
array(1) {
[0]=>
array(1) {
["?"]=>
string(2) "id"
}
}
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: parameter was not defined in %s on line %d
array(0) {
}
done!

View file

@ -0,0 +1,136 @@
--TEST--
MySQL PDO->prepare(), native PS, named placeholder II
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(id INT, label1 CHAR(255), label2 CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn off emulated prepared statements\n");
printf("Native...\n");
// INSERT a single row
$stmt = $db->prepare('INSERT INTO test(id, label1, label2) VALUES (1, :placeholder, :placeholder)');
$stmt->execute(array(':placeholder' => 'row1'));
if ('00000' !== $stmt->errorCode())
printf("[003] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
// Ok, what has happened: anything inserted into the DB?
$stmt = $db->prepare('SELECT id, label1, label2 FROM test WHERE id = 1');
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// Now the same with emulated PS.
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to turn on emulated prepared statements\n");
printf("Emulated...\n");
$stmt = $db->prepare('INSERT INTO test(id, label1, label2) VALUES(2, :placeholder, :placeholder)');
// No replacement shall be made
$stmt->execute(array(':placeholder' => 'row2'));
if ('00000' !== $stmt->errorCode())
printf("[005] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
// Now, what do we have in the DB?
$stmt = $db->prepare('SELECT id, label1, label2 FROM test WHERE id = 2');
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
//
// Another variation of the theme
//
$db->exec('DELETE FROM test');
$db->exec('INSERT INTO test (id, label1, label2) VALUES (1, "row1", "row2")');
$sql = "SELECT id, label1 FROM test WHERE id = :placeholder AND label1 = (SELECT label1 AS 'SELECT' FROM test WHERE id = :placeholder)";
// emulated...
$stmt = $db->prepare($sql);
$stmt->execute(array(':placeholder' => 1));
if ('00000' !== $stmt->errorCode())
printf("[006] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// native...
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[007] Unable to turn off emulated prepared statements\n");
printf("Native...\n");
$stmt = $db->prepare($sql);
$stmt->execute(array(':placeholder' => 1));
if ('00000' !== $stmt->errorCode())
printf("[008] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Native...
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number in %s on line %d
[003] Execute has failed, 'HY093' array (
0 => 'HY093',
)
array(0) {
}
Emulated...
array(1) {
[0]=>
array(3) {
["id"]=>
string(1) "2"
["label1"]=>
string(4) "row2"
["label2"]=>
string(4) "row2"
}
}
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label1"]=>
string(4) "row1"
}
}
Native...
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number in %s on line %d
[008] Execute has failed, 'HY093' array (
0 => 'HY093',
)
array(0) {
}
done!

View file

@ -0,0 +1,35 @@
--TEST--
MySQL PDO->prepare(), native PS, mixed, wired style
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn off emulated prepared statements\n");
$stmt = $db->query('DELETE FROM test');
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (1, ?), (2, ?)');
$stmt->execute(array('a', 'b'));
$stmt = $db->prepare("SELECT id, label FROM test WHERE id = :placeholder AND label = (SELECT label AS 'SELECT' FROM test WHERE id = ?)");
$stmt->execute(array(1, 1));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Warning: PDO::prepare(): SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters in %s on line %d
Warning: PDO::prepare(): SQLSTATE[HY093]: Invalid parameter number in %s on line %d
Fatal error: Call to a member function execute() on a non-object in %s on line %d

View file

@ -0,0 +1,85 @@
--TEST--
MySQL PDO->prepare(), native PS, named placeholder
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn off emulated prepared statements\n");
// INSERT a single row
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (100, ":placeholder")');
// Yes, there is no placeholder to bind to and named placeholder
// do not work with MySQL native PS, but lets see what happens!
// The ':placeholder' is a string constant in the INSERT statement.
// I would expect to get an error message, but this is not what happens.
$stmt->execute(array(':placeholder' => 'row1'));
if ('00000' !== $stmt->errorCode())
printf("[003] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
// Ok, what has happened: anything inserted into the DB?
$stmt = $db->prepare('SELECT id, label FROM test');
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// Now the same with emulated PS.
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to turn on emulated prepared statements\n");
// Note that the "named placeholder" is enclosed by double quotes.
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES(101, ":placeholder")');
// No replacement shall be made
$stmt->execute(array(':placeholder' => 'row1'));
// Again, I'd like to see an error message
if ('00000' !== $stmt->errorCode())
printf("[005] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
// Now, what do we have in the DB?
$stmt = $db->prepare('SELECT id, label FROM test ORDER BY id');
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
[003] Execute has failed, 'HY093' array (
0 => 'HY093',
)
array(0) {
}
array(1) {
[0]=>
array(2) {
["id"]=>
string(3) "101"
["label"]=>
string(12) ":placeholder"
}
}
done!

View file

@ -0,0 +1,85 @@
--TEST--
MySQL PDO->prepare(),native PS, anonymous placeholder
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to switch on emulated prepared statements, test will fail\n");
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(id INT, label CHAR(255)) ENGINE=%s', PDO_MYSQL_TEST_ENGINE));
$db->exec('INSERT INTO test(id, label) VALUES (1, "row1")');
$stmt = $db->prepare('SELECT ?, id, label FROM test WHERE ? = ? ORDER BY id ASC');
$stmt->execute(array('id', 'label', 'label'));
if ('00000' !== $stmt->errorCode())
printf("[003] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
// now the same with native PS
printf("now the same with native PS\n");
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to switch off emulated prepared statements, test will fail\n");
$stmt = $db->prepare('SELECT ?, id, label FROM test WHERE ? = ? ORDER BY id ASC');
$stmt->execute(array('id', 'label', 'label'));
if ('00000' !== $stmt->errorCode())
printf("[005] Execute has failed, %s %s\n",
var_export($stmt->errorCode(), true),
var_export($stmt->errorInfo(), true));
$tmp = $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) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(4) "row1"
}
}
now the same with native PS
array(1) {
[0]=>
array(3) {
["?"]=>
string(2) "id"
["id"]=>
int(1)
["label"]=>
string(4) "row1"
}
}
done!

View file

@ -0,0 +1,90 @@
--TEST--
PDO::rollBack()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
if (false == MySQLPDOTest::detect_transactional_mysql_engine($db))
die("skip Transactional engine not found");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db, MySQLPDOTest::detect_transactional_mysql_engine($db));
$db->beginTransaction();
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
$num = $row['_num'];
$db->query('INSERT INTO test(id, label) VALUES (100, "z")');
$num++;
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
if ($row['_num'] != $num)
printf("[001] INSERT has failed, test will fail\n");
$db->rollBack();
$num--;
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
if ($row['_num'] != $num)
printf("[002] ROLLBACK has failed\n");
$db->beginTransaction();
$db->query('INSERT INTO test(id, label) VALUES (100, "z")');
$db->query('DROP TABLE IF EXISTS test2');
$db->query('CREATE TABLE test2(id INT)');
$num++;
$db->rollBack();
$row = $db->query('SELECT COUNT(*) AS _num FROM test')->fetch(PDO::FETCH_ASSOC);
if ($row['_num'] != $num)
printf("[002] ROLLBACK should have no effect because of the implicit COMMIT
triggered by DROP/CREATE TABLE\n");
$db->query('DROP TABLE IF EXISTS test2');
$db->query('CREATE TABLE test2(id INT) ENGINE=MyISAM');
$db->beginTransaction();
$db->query('INSERT INTO test2(id) VALUES (1)');
$db->rollBack();
$row = $db->query('SELECT COUNT(*) AS _num FROM test2')->fetch(PDO::FETCH_ASSOC);
if ($row['_num'] != 1)
printf("[003] ROLLBACK should have no effect\n");
$db->query('DROP TABLE IF EXISTS test2');
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);
$db->beginTransaction();
$db->query('DELETE FROM test');
$db->rollBack();
var_dump($db->getAttribute(PDO::ATTR_AUTOCOMMIT));
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 0);
$db->beginTransaction();
$db->query('DELETE FROM test');
$db->rollBack();
var_dump($db->getAttribute(PDO::ATTR_AUTOCOMMIT));
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 1);
$db->beginTransaction();
$db->query('DELETE FROM test');
$db->commit();
var_dump($db->getAttribute(PDO::ATTR_AUTOCOMMIT));
$db->setAttribute(PDO::ATTR_AUTOCOMMIT, 0);
$db->beginTransaction();
$db->query('DELETE FROM test');
$db->commit();
var_dump($db->getAttribute(PDO::ATTR_AUTOCOMMIT));
$db->exec('DROP TABLE IF EXISTS test');
$db->exec('DROP TABLE IF EXISTS test2');
print "done!";
--EXPECTF--
int(1)
int(0)
int(1)
int(0)
done!

View file

@ -0,0 +1,110 @@
--TEST--
MySQL PDOStatement->bindColumn()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn on emulated prepared statements\n");
$stmt = $db->prepare('SELECT id, label FROM test ORDER BY id ASC LIMIT 2');
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[003] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[004] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$data = array();
while ($stmt->fetch(PDO::FETCH_BOUND)) {
printf("id = %s (%s) / label = %s (%s)\n",
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
$data[] = array('id' => $id, 'label' => $label);
}
$stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 2');
$index = 0;
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if ($row['id'] != $data[$index]['id']) {
printf("[005] Fetch bound and fetch assoc differ - column 'id', bound: %s/%s, assoc: %s/%s\n",
var_export($data[$index]['id'], true), gettype($data[$index]['id']),
var_export($row['id'], true), gettype($row['id']));
}
if ($row['label'] != $data[$index]['label']) {
printf("[006] Fetch bound and fetch assoc differ - column 'label', bound: %s/%s, assoc: %s/%s\n",
var_export($data[$index]['label'], true), gettype($data[$index]['label']),
var_export($row['label'], true), gettype($row['label']));
}
$index++;
}
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[007] Unable to turn off emulated prepared statements\n");
$stmt = $db->prepare('SELECT id, label FROM test ORDER BY id ASC LIMIT 2, 2');
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[008] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[009] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$data = array();
while ($stmt->fetch(PDO::FETCH_BOUND)) {
printf("id = %s (%s) / label = %s (%s)\n",
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
$data[] = array('id' => $id, 'label' => $label);
}
$stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 2, 2');
$index = 0;
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if ($row['id'] != $data[$index]['id']) {
printf("[010] Fetch bound and fetch assoc differ - column 'id', bound: %s/%s, assoc: %s/%s\n",
var_export($data[$index]['id'], true), gettype($data[$index]['id']),
var_export($row['id'], true), gettype($row['id']));
}
if ($row['label'] != $data[$index]['label']) {
printf("[011] Fetch bound and fetch assoc differ - column 'label', bound: %s/%s, assoc: %s/%s\n",
var_export($data[$index]['label'], true), gettype($data[$index]['label']),
var_export($row['label'], true), gettype($row['label']));
}
$index++;
}
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
id = 1 (integer) / label = 'a' (string)
id = 2 (integer) / label = 'b' (string)
id = 3 (integer) / label = 'c' (string)
id = 4 (integer) / label = 'd' (string)
done!

View file

@ -0,0 +1,155 @@
--TEST--
MySQL PDOStatement->bindParam()
--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();
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
MySQLPDOTest::createTestTable($db);
function pdo_mysql_stmt_bindparam($db, $offset) {
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? ORDER BY id ASC LIMIT 2');
$in = 0;
if (!$stmt->bindParam(1, $in))
printf("[%03d + 1] Cannot bind parameter, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[%03d + 2] Cannot bind integer column, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[%03d + 3] Cannot bind string column, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
printf("Same again...\n");
$stmt->execute();
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
// NULL values
printf("NULL...\n");
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (100, ?)');
$label = null;
if (!$stmt->bindParam(1, $label))
printf("[%03d + 4] Cannot bind parameter, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->execute())
printf("[%03d + 5] Cannot execute statement, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
/* NOTE: you cannot use PDO::query() with unbuffered, native PS - see extra test */
$stmt = $db->prepare('SELECT id, NULL AS _label FROM test WHERE label IS NULL');
$stmt->execute();
$id = $label = 'bogus';
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[%03d + 6] Cannot bind NULL column, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[%03d + 3] Cannot bind string column, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
}
try {
printf("Emulated PS...\n");
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn on emulated prepared statements\n");
printf("Buffered...\n");
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
pdo_mysql_stmt_bindparam($db, 3);
printf("Unbuffered...\n");
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
pdo_mysql_stmt_bindparam($db, 4);
printf("Native PS...\n");
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to turn off emulated prepared statements\n");
printf("Buffered...\n");
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
pdo_mysql_stmt_bindparam($db, 5);
printf("Unbuffered...\n");
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
pdo_mysql_stmt_bindparam($db, 6);
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Emulated PS...
Buffered...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Same again...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
NULL...
in = 0 -> id = 100 (integer) / label = NULL (NULL)
Unbuffered...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Same again...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
NULL...
in = 0 -> id = 100 (integer) / label = NULL (NULL)
Native PS...
Buffered...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Same again...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
NULL...
in = 0 -> id = 100 (integer) / label = NULL (NULL)
Unbuffered...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Same again...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
NULL...
in = 0 -> id = 100 (integer) / label = NULL (NULL)
done!

View file

@ -0,0 +1,169 @@
--TEST--
MySQL PDOStatement->bindParam() - SQL column types
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
function pdo_mysql_stmt_bindparam_types_do($db, $offset, $native, $sql_type, $value) {
if ($native)
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
else
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
$db->exec('DROP TABLE IF EXISTS test');
$sql = sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, MySQLPDOTest::getTableEngine());
if ((!$stmt = @$db->prepare($sql)) || (!@$stmt->execute()))
// Server might not support column type - skip it
return true;
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (1, ?)');
if (!$stmt->bindParam(1, $value)) {
printf("[%03d/%s + 1] %s\n", $offset, ($native) ? 'native' : 'emulated',
var_export($stmt->errorInfo(), true));
return false;
}
if (!$stmt->execute()) {
printf("[%03d/%s + 2] %s\n", $offset, ($native) ? 'native' : 'emulated',
var_export($stmt->errorInfo(), true));
return false;
}
$stmt = $db->query('SELECT id, label FROM test');
$id = $label = null;
if (!$stmt->bindColumn(1, $id)) {
printf("[%03d/%s + 3] %s\n", $offset, ($native) ? 'native' : 'emulated',
var_export($stmt->errorInfo(), true));
return false;
}
if (!$stmt->bindColumn(2, $label)) {
printf("[%03d/%s + 4] %s\n", $offset, ($native) ? 'native' : 'emulated',
var_export($stmt->errorInfo(), true));
return false;
}
if (!$stmt->fetch(PDO::FETCH_BOUND)) {
printf("[%03d/%s + 5] %s\n", $offset, ($native) ? 'native' : 'emulated',
var_export($stmt->errorInfo(), true));
return false;
}
$stmt->closeCursor();
if ($label != $value) {
printf("[%03d/%s + 6] Got %s expecting %s - plase check manually\n",
$offset, ($native) ? 'native' : 'emulated',
var_export($label, true), var_export($value, true));
// fall through
}
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (empty($row)) {
printf("[%03d/%s + 7] %s\n", $offset, ($native) ? 'native' : 'emulated',
var_export($stmt->errorInfo(), true));
return false;
}
if ($row['label'] != $value) {
printf("[%03d/%s + 8] Got %s expecting %s - plase check manually\n",
$offset, ($native) ? 'native' : 'emulated',
var_export($row['label'], true), var_export($value, true));
return false;
}
if ($row['label'] != $label) {
printf("[%03d/%s + 9] Got %s from FETCH_ASSOC and %s from FETCH_BOUND- plase check manually\n",
$offset, ($native) ? 'native' : 'emulated',
var_export($row['label'], true), var_export($value, true));
return false;
}
$db->exec('DROP TABLE IF EXISTS test');
return true;
}
function pdo_mysql_stmt_bindparam_types($db, $offset, $sql_type, $value) {
pdo_mysql_stmt_bindparam_types_do($db, $offset, true, $sql_type, $value);
pdo_mysql_stmt_bindparam_types_do($db, $offset, false, $sql_type, $value);
}
try {
// pdo_mysql_stmt_bindparam_types($db, 2, 'BIT(8)', 1);
pdo_mysql_stmt_bindparam_types($db, 3, 'TINYINT', -127);
pdo_mysql_stmt_bindparam_types($db, 4, 'TINYINT UNSIGNED', 255);
pdo_mysql_stmt_bindparam_types($db, 5, 'BOOLEAN', 1);
pdo_mysql_stmt_bindparam_types($db, 6, 'SMALLINT', -32768);
pdo_mysql_stmt_bindparam_types($db, 7, 'SMALLINT UNSIGNED', 65535);
pdo_mysql_stmt_bindparam_types($db, 8, 'MEDIUMINT', -8388608);
pdo_mysql_stmt_bindparam_types($db, 9, 'MEDIUMINT UNSIGNED', 16777215);
pdo_mysql_stmt_bindparam_types($db, 10, 'INT', -2147483648);
pdo_mysql_stmt_bindparam_types($db, 11, 'INT UNSIGNED', 4294967295);
pdo_mysql_stmt_bindparam_types($db, 12, 'BIGINT', -1000);
pdo_mysql_stmt_bindparam_types($db, 13, 'BIGINT UNSIGNED', 1000);
pdo_mysql_stmt_bindparam_types($db, 14, 'REAL', -1000);
pdo_mysql_stmt_bindparam_types($db, 15, 'REAL UNSIGNED', 1000);
pdo_mysql_stmt_bindparam_types($db, 16, 'REAL ZEROFILL', '0000000000000000000000');
pdo_mysql_stmt_bindparam_types($db, 17, 'REAL UNSIGNED ZEROFILL', '0000000000000000000010');
pdo_mysql_stmt_bindparam_types($db, 18, 'DOUBLE', -1000);
pdo_mysql_stmt_bindparam_types($db, 19, 'DOUBLE UNSIGNED', 1000);
pdo_mysql_stmt_bindparam_types($db, 20, 'DOUBLE ZEROFILL', '000000000000');
pdo_mysql_stmt_bindparam_types($db, 21, 'DOUBLE ZEROFILL UNSIGNED', '000000001000');
pdo_mysql_stmt_bindparam_types($db, 22, 'FLOAT', -1000);
pdo_mysql_stmt_bindparam_types($db, 23, 'FLOAT UNSIGNED', 1000);
pdo_mysql_stmt_bindparam_types($db, 24, 'FLOAT ZEROFILL', '000000000000');
pdo_mysql_stmt_bindparam_types($db, 25, 'FLOAT ZEROFILL UNSIGNED', '000000001000');
pdo_mysql_stmt_bindparam_types($db, 26, 'DECIMAL', -1000);
pdo_mysql_stmt_bindparam_types($db, 27, 'DECIMAL UNSIGNED', 1000);
pdo_mysql_stmt_bindparam_types($db, 28, 'DECIMAL ZEROFILL', '000000000000');
pdo_mysql_stmt_bindparam_types($db, 29, 'DECIMAL ZEROFILL UNSIGNED', '000000001000');
pdo_mysql_stmt_bindparam_types($db, 30, 'NUMERIC', -1000);
pdo_mysql_stmt_bindparam_types($db, 31, 'NUMERIC UNSIGNED', 1000);
pdo_mysql_stmt_bindparam_types($db, 32, 'NUMERIC ZEROFILL', '000000000000');
pdo_mysql_stmt_bindparam_types($db, 33, 'NUMERIC ZEROFILL UNSIGNED', '000000001000');
pdo_mysql_stmt_bindparam_types($db, 34, 'DATE', '2008-04-23');
pdo_mysql_stmt_bindparam_types($db, 35, 'TIME', '16:43:12');
pdo_mysql_stmt_bindparam_types($db, 36, 'TIMESTAMP', '2008-04-23 16:44:53');
pdo_mysql_stmt_bindparam_types($db, 37, 'DATETIME', '2008-04-23 16:44:53');
pdo_mysql_stmt_bindparam_types($db, 38, 'YEAR', '2008');
pdo_mysql_stmt_bindparam_types($db, 39, 'CHAR(1)', 'a');
pdo_mysql_stmt_bindparam_types($db, 40, 'CHAR(255)', 'abc');
pdo_mysql_stmt_bindparam_types($db, 41, 'VARCHAR(255)', str_repeat('a', 255));
pdo_mysql_stmt_bindparam_types($db, 42, 'BINARY(255)', str_repeat('a', 255));
pdo_mysql_stmt_bindparam_types($db, 43, 'VARBINARY(255)', str_repeat('a', 255));
pdo_mysql_stmt_bindparam_types($db, 44, 'TINYBLOB', str_repeat('a', 255));
pdo_mysql_stmt_bindparam_types($db, 45, 'BLOB', str_repeat('b', 300));
pdo_mysql_stmt_bindparam_types($db, 46, 'MEDIUMBLOB', str_repeat('b', 300));
pdo_mysql_stmt_bindparam_types($db, 47, 'LONGBLOB', str_repeat('b', 300));
pdo_mysql_stmt_bindparam_types($db, 48, 'TINYTEXT', str_repeat('c', 255));
pdo_mysql_stmt_bindparam_types($db, 49, 'TINYTEXT BINARY', str_repeat('c', 255));
pdo_mysql_stmt_bindparam_types($db, 50, 'TEXT', str_repeat('d', 300));
pdo_mysql_stmt_bindparam_types($db, 51, 'TEXT BINARY', str_repeat('d', 300));
pdo_mysql_stmt_bindparam_types($db, 52, 'MEDIUMTEXT', str_repeat('d', 300));
pdo_mysql_stmt_bindparam_types($db, 53, 'MEDIUMTEXT BINARY', str_repeat('d', 300));
pdo_mysql_stmt_bindparam_types($db, 54, 'LONGTEXT', str_repeat('d', 300));
pdo_mysql_stmt_bindparam_types($db, 55, 'LONGTEXT BINARY', str_repeat('d', 300));
pdo_mysql_stmt_bindparam_types($db, 56, "ENUM('yes', 'no') DEFAULT 'yes'", "no");
pdo_mysql_stmt_bindparam_types($db, 57, "SET('yes', 'no') DEFAULT 'yes'", "no");
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
done!

View file

@ -0,0 +1,332 @@
--TEST--
MySQL PDOStatement->bindValue()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
printf("Testing native PS...\n");
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn off emulated prepared statements\n");
printf("Binding variable...\n");
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? ORDER BY id ASC LIMIT 2');
$in = 0;
if (!$stmt->bindValue(1, $in))
printf("[003] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[004] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[005] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
printf("Binding value and not variable...\n");
if (!$stmt->bindValue(1, 0))
printf("[006] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[007] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[008] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
printf("Binding variable which references another variable...\n");
$in = 0;
$in_ref = &$in;
if (!$stmt->bindValue(1, $in_ref))
printf("[009] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[010] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[011] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
printf("Binding a variable and a value...\n");
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? AND id <= ? ORDER BY id ASC LIMIT 2');
$in = 0;
if (!$stmt->bindValue(1, $in))
printf("[012] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindValue(2, 2))
printf("[013] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[014] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[015] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
printf("Binding a variable to two placeholders and changing the variable value in between the binds...\n");
// variable value change shall have no impact
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? AND id <= ? ORDER BY id ASC LIMIT 2');
$in = 0;
if (!$stmt->bindValue(1, $in))
printf("[016] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$in = 2;
if (!$stmt->bindValue(2, $in))
printf("[017] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[018] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[019] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
printf("Testing emulated PS...\n");
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn on emulated prepared statements\n");
printf("Binding variable...\n");
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? ORDER BY id ASC LIMIT 2');
$in = 0;
if (!$stmt->bindValue(1, $in))
printf("[003] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[004] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[005] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
printf("Binding value and not variable...\n");
if (!$stmt->bindValue(1, 0))
printf("[006] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[007] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[008] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
printf("Binding variable which references another variable...\n");
$in = 0;
$in_ref = &$in;
if (!$stmt->bindValue(1, $in_ref))
printf("[009] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[010] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[011] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
printf("Binding a variable and a value...\n");
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? AND id <= ? ORDER BY id ASC LIMIT 2');
$in = 0;
if (!$stmt->bindValue(1, $in))
printf("[012] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindValue(2, 2))
printf("[013] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[014] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[015] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
printf("Binding a variable to two placeholders and changing the variable value in between the binds...\n");
// variable value change shall have no impact
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? AND id <= ? ORDER BY id ASC LIMIT 2');
$in = 0;
if (!$stmt->bindValue(1, $in))
printf("[016] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$in = 2;
if (!$stmt->bindValue(2, $in))
printf("[017] Cannot bind value, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[018] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[019] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Testing native PS...
Binding variable...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Binding value and not variable...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Binding variable which references another variable...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Binding a variable and a value...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Binding a variable to two placeholders and changing the variable value in between the binds...
in = 2 -> id = 1 (integer) / label = 'a' (string)
in = 2 -> id = 2 (integer) / label = 'b' (string)
Testing emulated PS...
Binding variable...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Binding value and not variable...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Binding variable which references another variable...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Binding a variable and a value...
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Binding a variable to two placeholders and changing the variable value in between the binds...
in = 2 -> id = 1 (integer) / label = 'a' (string)
in = 2 -> id = 2 (integer) / label = 'b' (string)
done!

View file

@ -0,0 +1,143 @@
--TEST--
MySQL PDOStatement - inserting BLOB from stream
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$tmp = MySQLPDOTest::getTempDir();
if (!$tmp)
die("skip Can't create temporary file");
$file = $tmp . DIRECTORY_SEPARATOR . 'pdoblob.tst';
$fp = fopen($file, 'w');
if (!$fp)
die("skip Can't create temporary file");
if (4 != fwrite($fp, 'test')) {
die("skip Can't create temporary file");
}
fclose($fp);
clearstatcache();
if (!file_exists($file))
die("skip Can't create temporary file");
unlink($file);
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
function blob_from_stream($offset, $db, $file, $blob) {
@unlink($file);
clearstatcache();
if (file_exists($file)) {
printf("[%03d + 1] Cannot remove old test file\n", $offset);
return false;
}
$fp = fopen($file, 'w');
if (!$fp || !fwrite($fp, $blob)) {
printf("[%03d + 2] Cannot create test file '%s'\n", $offset, $file);
return false;
}
fclose($fp);
clearstatcache();
if (!file_exists($file)) {
printf("[%03d + 3] Failed to create test file '%s'\n", $offset, $file);
return false;
}
$db->exec('DROP TABLE IF EXISTS test');
$sql = sprintf('CREATE TABLE test(id INT, label BLOB) ENGINE=%s', PDO_MYSQL_TEST_ENGINE);
$db->exec($sql);
if (!$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (?, ?)')) {
printf("[%03d + 4] %s\n", $offset, var_export($db->errorInfo(), true));
return false;
}
$fp = fopen($file, 'r');
if (!$fp) {
printf("[%03d + 5] Cannot create test file '%s'\n", $offset, $file);
return false;
}
$id = 1;
$stmt->bindParam(1, $id);
if (true !== ($tmp = $stmt->bindParam(2, $fp, PDO::PARAM_LOB))) {
printf("[%03d + 6] Expecting true, got %s. %s\n",
$offset,
var_export($tmp, true),
var_export($db->errorInfo(), true));
return false;
}
if (true !== $stmt->execute()) {
printf("[%03d + 7] Failed to INSERT data, %s\n", $offset, var_export($stmt->errorInfo(), true));
return false;
}
$stmt2 = $db->query('SELECT id, label FROM test WHERE id = 1');
$row = $stmt2->fetch(PDO::FETCH_ASSOC);
if ($row['label'] != $blob) {
printf("[%03d + 8] INSERT and/or SELECT has failed, dumping data.\n", $offset);
var_dump($row);
var_dump($blob);
return false;
}
// Lets test the chr(0) handling in case the streaming has failed:
// is the bug about chr(0) or the streaming...
$db->exec('DELETE FROM test');
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (?, ?)');
$stmt->bindParam(1, $id);
$stmt->bindParam(2, $blob);
if (true !== $stmt->execute())
printf("[%03d + 9] %s\n", $offset, var_export($stmt->errorInfo(), true));
$stmt2 = $db->query('SELECT id, label FROM test WHERE id = 1');
$row = $stmt2->fetch(PDO::FETCH_ASSOC);
if ($row['label'] != $blob) {
printf("[%03d + 10] INSERT and/or SELECT has failed, dumping data.\n", $offset);
var_dump($row);
var_dump($blob);
return false;
}
return true;
}
$db = MySQLPDOTest::factory();
$blob = 'I am a mighty BLOB!' . chr(0) . "I am a binary thingie!";
$tmp = MySQLPDOTest::getTempDir();
$file = $tmp . DIRECTORY_SEPARATOR . 'pdoblob.tst';
try {
printf("Emulated PS...\n");
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
blob_from_stream(10, $db, $file, $blob);
printf("Native PS...\n");
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
blob_from_stream(30, $db, $file, $blob);
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
@unlink($file);
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Emulated PS...
Native PS...
done!

View file

@ -0,0 +1,91 @@
--TEST--
MySQL Prepared Statements and BLOBs
--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();
$blobs = array(
'TINYBLOB' => 255,
'TINYTEXT' => 255,
'BLOB' => 32767,
'TEXT' => 32767,
'MEDIUMBLOB' => 100000,
'MEDIUMTEXT' => 100000,
'LONGBLOB' => 100000,
'LONGTEXT' => 100000,
);
function test_blob($db, $offset, $sql_type, $test_len) {
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, PDO_MYSQL_TEST_ENGINE));
$value = str_repeat('a', $test_len);
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (?, ?)');
$stmt->bindValue(1, 1);
$stmt->bindValue(2, $value);
if (!$stmt->execute()) {
printf("[%03d + 1] %d %s\n",
$offset, $stmt->errorCode(), var_export($stmt->errorInfo(), true));
return false;
}
$stmt = $db->query('SELECT id, label FROM test');
$id = $label = NULL;
$stmt->bindColumn(1, $id, PDO::PARAM_INT);
$stmt->bindColumn(2, $label, PDO::PARAM_LOB);
if (!$stmt->fetch(PDO::FETCH_BOUND)) {
printf("[%03d + 2] %d %s\n",
$offset, $stmt->errorCode(), var_export($stmt->errorInfo(), true));
return false;
}
if ($label !== $value) {
printf("[%03d + 3] Returned value seems to be wrong (%d vs. %d charachters). Check manually\n",
$offset, strlen($label), strlen($value));
return false;
}
if (1 != $id) {
printf("[%03d + 3] Returned id column value seems wrong, expecting 1 got %s.\n",
$offset, var_export($id, true));
return false;
}
$stmt = $db->query('SELECT id, label FROM test');
$ret = $stmt->fetch(PDO::FETCH_ASSOC);
if ($ret['label'] !== $value) {
printf("[%03d + 3] Returned value seems to be wrong (%d vs. %d charachters). Check manually\n",
$offset, strlen($ret['label']), strlen($value));
return false;
}
if (1 != $ret['id']) {
printf("[%03d + 3] Returned id column value seems wrong, expecting 1 got %s.\n",
$offset, var_export($ret['id'], true));
return false;
}
return true;
}
$offset = 0;
foreach ($blobs as $sql_type => $test_len) {
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
test_blob($db, ++$offset, $sql_type, $test_len);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
test_blob($db, ++$offset, $sql_type, $test_len);
}
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,172 @@
--TEST--
MySQL PDOStatement->closeCursor()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
/* TODO the results look wrong, why do we get 2014 with buffered AND unbuffered queries */
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
function pdo_mysql_stmt_closecursor($db) {
// This one should fail. I let it fail to prove that closeCursor() makes a difference.
// If no error messages gets printed do not know if proper usage of closeCursor() makes any
// difference or not. That's why we need to cause an error here.
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
// query() shall fail!
$stmt2 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
$stmt1->closeCursor();
// This is proper usage of closeCursor(). It shall prevent any further error messages.
if (MySQLPDOTest::isPDOMySQLnd()) {
$stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
} else {
// see pdo_mysql_stmt_unbuffered_2050.phpt for an explanation
unset($stmt1);
$stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
}
// fetch only the first rows and let closeCursor() clean up
$row1 = $stmt1->fetch(PDO::FETCH_ASSOC);
$stmt1->closeCursor();
$stmt2 = $db->prepare('UPDATE test SET label = ? WHERE id = ?');
$stmt2->bindValue(1, "z");
$stmt2->bindValue(2, $row1['id']);
$stmt2->execute();
$stmt2->closeCursor();
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
// check if changing the fetch mode from unbuffered to buffered will
// cause any harm to a statement created prior to the change
$stmt1->execute();
$row2 = $stmt1->fetch(PDO::FETCH_ASSOC);
$stmt1->closeCursor();
if (!isset($row2['label']) || ('z' !== $row2['label']))
printf("Expecting array(id => 1, label => z) got %s\n", var_export($row2, true));
unset($stmt1);
$stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
// should work
$stmt2 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
$stmt1->closeCursor();
$stmt1 = $db->query('SELECT id, label FROM test ORDER BY id ASC');
// fetch only the first rows and let closeCursor() clean up
$row3 = $stmt1->fetch(PDO::FETCH_ASSOC);
$stmt1->closeCursor();
assert($row3 == $row2);
$stmt2 = $db->prepare('UPDATE test SET label = ? WHERE id = ?');
$stmt2->bindValue(1, "a");
$stmt2->bindValue(2, $row1['id']);
$stmt2->execute();
$stmt2->closeCursor();
$stmt1->execute();
$row4 = $stmt1->fetch(PDO::FETCH_ASSOC);
$stmt1->closeCursor();
assert($row4 == $row1);
$offset = 0;
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? ORDER BY id ASC LIMIT 2');
$in = 0;
if (!$stmt->bindParam(1, $in))
printf("[%03d + 1] Cannot bind parameter, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[%03d + 2] Cannot bind integer column, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[%03d + 3] Cannot bind string column, %s %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
$stmt->closeCursor();
$stmt->execute();
}
try {
printf("Testing emulated PS...\n");
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn on emulated prepared statements\n");
printf("Buffered...\n");
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
MySQLPDOTest::createTestTable($db);
pdo_mysql_stmt_closecursor($db);
printf("Unbuffered...\n");
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
MySQLPDOTest::createTestTable($db);
pdo_mysql_stmt_closecursor($db);
printf("Testing native PS...\n");
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn off emulated prepared statements\n");
printf("Buffered...\n");
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
pdo_mysql_stmt_closecursor($db);
printf("Unbuffered...\n");
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
pdo_mysql_stmt_closecursor($db);
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Testing emulated PS...
Buffered...
Warning: PDO::query(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Unbuffered...
Warning: PDO::query(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Testing native PS...
Buffered...
Warning: PDO::query(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
Unbuffered...
Warning: PDO::query(): SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute. in %s on line %d
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
done!

View file

@ -0,0 +1,69 @@
--TEST--
MySQL PDOStatement->closeCursor()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn off emulated prepared statements\n");
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
MySQLPDOTest::createTestTable($db);
$stmt = $db->prepare('SELECT id, label FROM test WHERE id > ? ORDER BY id ASC LIMIT 2');
$in = 0;
if (!$stmt->bindParam(1, $in))
printf("[003] Cannot bind parameter, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
$stmt->execute();
$id = $label = null;
if (!$stmt->bindColumn(1, $id, PDO::PARAM_INT))
printf("[004] Cannot bind integer column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
if (!$stmt->bindColumn(2, $label, PDO::PARAM_STR))
printf("[005] Cannot bind string column, %s %s\n",
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
$stmt->closeCursor();
$stmt->execute();
while ($stmt->fetch(PDO::FETCH_BOUND))
printf("in = %d -> id = %s (%s) / label = %s (%s)\n",
$in,
var_export($id, true), gettype($id),
var_export($label, true), gettype($label));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
in = 0 -> id = 1 (integer) / label = 'a' (string)
in = 0 -> id = 2 (integer) / label = 'b' (string)
done!

View file

@ -0,0 +1,65 @@
--TEST--
MySQL PDOStatement->columnCount()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
// The only purpose of this is to check if emulated and native PS
// return the same. If it works for one, it should work for all.
// Internal data structures should be the same in both cases.
printf("Testing emulated PS...\n");
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn on emulated prepared statements\n");
$stmt = $db->prepare('SELECT id, label, "?" as foo FROM test');
$stmt->execute();
var_dump($stmt->columnCount());
$stmt = $db->query('SELECT * FROM test');
var_dump($stmt->columnCount());
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
printf("Testing native PS...\n");
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to turn off emulated prepared statements\n");
$stmt = $db->prepare('SELECT id, label, "?" as foo, "TODO - Stored Procedure" as bar FROM test');
$stmt->execute();
var_dump($stmt->columnCount());
$stmt = $db->query('SELECT * FROM test');
var_dump($stmt->columnCount());
} catch (PDOException $e) {
printf("[003] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Testing emulated PS...
int(3)
int(2)
Testing native PS...
int(4)
int(2)
done!

View file

@ -0,0 +1,61 @@
--TEST--
MySQL PDOStatement->errorCode();
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
$db->exec('DROP TABLE IF EXISTS ihopeitdoesnotexist');
printf("Testing emulated PS...\n");
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn on emulated prepared statements\n");
$stmt = $db->prepare('SELECT id FROM ihopeitdoesnotexist ORDER BY id ASC');
$stmt->execute();
var_dump($stmt->errorCode());
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
printf("Testing native PS...\n");
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to turn off emulated prepared statements\n");
$stmt = $db->prepare('SELECT id FROM ihopeitdoesnotexist ORDER BY id ASC');
$stmt->execute();
var_dump($stmt->errorCode());
} catch (PDOException $e) {
printf("[003] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
print "done!";
?>
--EXPECTF--
Testing emulated PS...
Warning: PDOStatement::execute(): SQLSTATE[42S02]: Base table or view not found: 1146 Table '%s.ihopeitdoesnotexist' doesn't exist in %s on line %d
string(5) "42S02"
Testing native PS...
Warning: PDO::prepare(): SQLSTATE[42S02]: Base table or view not found: 1146 Table '%s.ihopeitdoesnotexist' doesn't exist in %s on line %d
Fatal error: Call to a member function execute() on a non-object in %s on line %d

View file

@ -0,0 +1,119 @@
--TEST--
MySQL PDOStatement->errorInfo();
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
printf("Testing emulated PS...\n");
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn on emulated prepared statements\n");
$stmt = $db->prepare('SELECT id FROM ihopeitdoesnotexist ORDER BY id ASC');
var_dump($stmt->errorInfo());
$stmt->execute();
var_dump($stmt->errorInfo());
MySQLPDOTest::createTestTable($db);
$stmt = $db->prepare('SELECT label FROM test ORDER BY id ASC LIMIT 1');
$db->exec('DROP TABLE test');
var_dump($stmt->execute());
var_dump($stmt->errorInfo());
var_dump($db->errorInfo());
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorInfo(), implode(' ', $db->errorInfo()));
}
printf("Testing native PS...\n");
try {
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to turn off emulated prepared statements\n");
$stmt = $db->prepare('SELECT id FROM ihopeitdoesnotexist ORDER BY id ASC');
var_dump($stmt);
MySQLPDOTest::createTestTable($db);
$stmt = $db->prepare('SELECT label FROM test ORDER BY id ASC LIMIT 1');
var_dump($stmt->errorInfo());
$db->exec('DROP TABLE test');
$stmt->execute();
var_dump($stmt->errorInfo());
var_dump($db->errorInfo());
} catch (PDOException $e) {
printf("[003] %s [%s] %s\n",
$e->getMessage(), $db->errorInfo(), implode(' ', $db->errorInfo()));
}
print "done!";
?>
--EXPECTF--
Testing emulated PS...
array(1) {
[0]=>
string(0) ""
}
Warning: PDOStatement::execute(): SQLSTATE[42S02]: Base table or view not found: 1146 Table '%s.ihopeitdoesnotexist' doesn't exist in %s on line %d
array(3) {
[0]=>
string(5) "42S02"
[1]=>
int(1146)
[2]=>
string(%d) "Table '%s.ihopeitdoesnotexist' doesn't exist"
}
Warning: PDOStatement::execute(): SQLSTATE[42S02]: Base table or view not found: 1146 Table '%s.test' doesn't exist in %s on line %d
bool(false)
array(3) {
[0]=>
string(5) "42S02"
[1]=>
int(1146)
[2]=>
string(%d) "Table '%s.test' doesn't exist"
}
array(1) {
[0]=>
string(5) "00000"
}
Testing native PS...
Warning: PDO::prepare(): SQLSTATE[42S02]: Base table or view not found: 1146 Table '%s.ihopeitdoesnotexist' doesn't exist in %s on line %d
bool(false)
array(1) {
[0]=>
string(0) ""
}
Warning: PDOStatement::execute(): SQLSTATE[42S02]: Base table or view not found: 1146 Table '%s.test' doesn't exist in %s on line %d
array(3) {
[0]=>
string(5) "42S02"
[1]=>
int(1146)
[2]=>
string(%d) "Table '%s.test' doesn't exist"
}
array(3) {
[0]=>
string(5) "00000"
[1]=>
int(1146)
[2]=>
string(%d) "Table '%s.ihopeitdoesnotexist' doesn't exist"
}
done!

View file

@ -0,0 +1,187 @@
--TEST--
MySQL PDOStatement->execute()/fetch(), Non-SELECT
--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();
MySQLPDOTest::createTestTable($db);
try {
// Emulated PS first
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 1);
if (1 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn on emulated prepared statements\n");
if (!is_object($stmt = $db->query('DESCRIBE test id')))
printf("[003] Emulated PS, DESCRIBE failed, %s\n", var_export($db->errorInfo(), true));
$describe = array();
$valid = false;
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$describe[] = $row;
foreach ($row as $column => $value)
if (isset($row['field']) && ($row['field'] == 'id'))
$valid = true;
}
if (empty($describe))
printf("[004] Emulated PS, DESCRIBE returned no results\n");
else if (!$valid)
printf("[005] Emulated PS, DESCRIBE, returned data seems wrong, dumping %s\n",
var_export($describe, true));
if (!is_object($stmt = $db->query('SHOW ENGINES')))
printf("[006] Emulated PS, SHOW failed, %s\n", var_export($db->errorInfo(), true));
$show = array();
$valid = false;
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$show[] = $row;
foreach ($row as $column => $value)
// MyISAM engine should be part of _every_ MySQL today
if ($value == 'MyISAM')
$valid = true;
}
if (empty($show))
printf("[007] Emulated PS, SHOW returned no results\n");
else if (!$valid)
printf("[008] Emulated PS, SHOW data seems wrong, dumping %s\n",
var_export($show, true));
if (!is_object($stmt = $db->query("EXPLAIN SELECT id FROM test")))
printf("[009] Emulated PS, EXPLAIN returned no results\n");
$explain = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
$explain[] = $row;
if (empty($explain))
printf("[010] Emulated PS, EXPLAIN returned no results\n");
// And now native PS
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[011] Unable to turn off emulated prepared statements\n");
$native_support = 'no';
if ($db->exec('PREPARE mystmt FROM "DESCRIBE test id"')) {
$native_support = 'yes';
$db->exec('DEALLOCATE PREPARE mystmt');
}
if (!is_object($stmt = $db->query('DESCRIBE test id')))
printf("[012] Native PS (native support: %s), DESCRIBE failed, %s\n",
$native_support,
var_export($db->errorInfo(), true));
$describe_native = array();
$valid = false;
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$describe_native[] = $row;
foreach ($row as $column => $value)
if (isset($row['field']) && ($row['field'] == 'id'))
$valid = true;
}
if (empty($describe_native))
printf("[013] Native PS (native support: %s), DESCRIBE returned no results\n",
$native_support);
else if (!$valid)
printf("[014] Native PS (native support: %s), DESCRIBE, returned data seems wrong, dumping %s\n",
$native_support,
var_export($describe_native, true));
if ($describe != $describe_native)
printf("[015] Emulated and native PS (native support: %s) results of DESCRIBE differ: %s vs. %s\n",
$native_support,
var_export($describe, true),
var_export($describe_native, true));
$native_support = 'no';
if ($db->exec('PREPARE mystmt FROM "SHOW ENGINES"')) {
$native_support = 'yes';
$db->exec('DEALLOCATE PREPARE mystmt');
}
if (!is_object($stmt = $db->query('SHOW ENGINES')))
printf("[016] Native PS (native support: %s), SHOW failed, %s\n",
$native_support,
var_export($db->errorInfo(), true));
$show_native = array();
$valid = false;
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$show_native[] = $row;
foreach ($row as $column => $value)
// MyISAM engine should be part of _every_ MySQL today
if ($value == 'MyISAM')
$valid = true;
}
if (empty($show_native))
printf("[017] Native PS (native support: %s), SHOW returned no results\n",
$native_support);
else if (!$valid)
printf("[018] Native PS (native support: %s), SHOW data seems wrong, dumping %s\n",
var_export($show_native, true));
if ($show != $show_native)
printf("Native PS (native support: %s) and emulated PS returned different data for SHOW: %s vs. %s\n",
$native_support,
var_export($show, true),
var_export($show_native, true));
$native_support = 'no';
if ($db->exec('PREPARE mystmt FROM "EXPLAIN SELECT id FROM test"')) {
$native_support = 'yes';
$db->exec('DEALLOCATE PREPARE mystmt');
}
if (!is_object($stmt = $db->query("EXPLAIN SELECT id FROM test")))
printf("[012] Native PS (native support: %s), EXPLAIN failed, %s\n",
$native_support,
var_export($db->errorInfo(), true));
$explain_native = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC))
$explain_native[] = $row;
if (empty($explain_native))
printf("[013] Native PS (native support: %s), EXPLAIN returned no results\n",
$native_support);
if ($explain != $explain_native)
printf("Native PS (native support: %s) and emulated PS returned different data for EXPLAIN: %s vs. %s\n",
$native_support,
var_export($explain, true),
var_export($explain_native, true));
$stmt->execute();
$explain_native = $stmt->fetchAll(PDO::FETCH_ASSOC);
if ($explain != $explain_native)
printf("Native PS (native support: %s) and emulated PS returned different data for EXPLAIN: %s vs. %s\n",
$native_support,
var_export($explain, true),
var_export($explain_native, true));
$stmt->execute();
$stmt->execute();
// libmysql needs this - otherwise we get a 2015 error
if (!MYSQLPDOTest::isPDOMySQLnd())
$stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!\n";
?>
--EXPECTF--
done!

View file

@ -0,0 +1,151 @@
--TEST--
MySQL PDOStatement->fetch(), PDO::FETCH_SERIALIZE
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
if (version_compare(PHP_VERSION, '5.1.0', '<'))
die("skip Needs 5.1.0 and Interface Serializable");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
class myclass implements Serializable {
private static $instance = null;
protected $myprotected = 'a protected propery';
// Good old magic stuff
private function __construct($caller = NULL) {
printf("%s(%s)\n", __METHOD__, $caller);
}
public function __destruct() {
// printf("%s()\n", __METHOD__);
}
public function __sleep() {
printf("%s()\n", __METHOD__);
}
public function __wakeup() {
printf("%s()\n", __METHOD__);
}
public function __call($method, $params) {
printf("%s(%s, %s)\n", __METHOD__, $method, var_export($params, true));
}
public function __set($prop, $value) {
printf("%s(%s, %s)\n", __METHOD__, $prop, var_export($value, true));
$this->{$prop} = $value;
}
public function __get($prop) {
printf("%s(%s)\n", __METHOD__, $prop);
return NULL;
}
// Singleton
public static function singleton($caller) {
printf("%s(%s)\n", __METHOD__, $caller);
if (!self::$instance) {
$c = __CLASS__;
self::$instance = new $c($caller);
}
return self::$instance;
}
// Serializable
public function serialize() {
printf("%s()\n", __METHOD__);
return 'Data from serialize';
}
public function unserialize($data) {
printf("%s(%s)\n", __METHOD__, var_export($data, true));
}
}
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[002] Unable to turn off emulated prepared statements\n");
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(id INT, myobj BLOB) ENGINE=%s',
MySQLPDOTest::getTableEngine()));
printf("Creating an object, serializing it and writing it to DB...\n");
$id = 1;
$obj = myclass::singleton('Creating object');
$myobj = serialize($obj);
$stmt = $db->prepare('INSERT INTO test(id, myobj) VALUES (?, ?)');
$stmt->bindValue(1, $id);
$stmt->bindValue(2, $myobj);
$stmt->execute();
printf("\nUnserializing the previously serialized object...\n");
var_dump(unserialize($myobj));
printf("\nUsing PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE to fetch the object from DB and unserialize it...\n");
$stmt = $db->prepare('SELECT myobj FROM test');
$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE, 'myclass', array('PDO shall not call __construct()'));
$stmt->execute();
var_dump($stmt->fetch());
printf("\nUsing PDO::FETCH_CLASS to fetch the object from DB and unserialize it...\n");
$stmt = $db->prepare('SELECT myobj FROM test');
$stmt->setFetchMode(PDO::FETCH_CLASS, 'myclass', array('PDO shall call __construct()'));
$stmt->execute();
var_dump($stmt->fetch());
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!\n";
?>
--EXPECTF--
Creating an object, serializing it and writing it to DB...
myclass::singleton(Creating object)
myclass::__construct(Creating object)
myclass::serialize()
Unserializing the previously serialized object...
myclass::unserialize('Data from serialize')
object(myclass)#4 (1) {
["myprotected":protected]=>
string(19) "a protected propery"
}
Using PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE to fetch the object from DB and unserialize it...
myclass::__set(myobj, 'C:7:"myclass":19:{Data from serialize}')
myclass::__construct(PDO shall not call __construct())
object(myclass)#%d (2) {
["myprotected":protected]=>
string(19) "a protected propery"
["myobj"]=>
string(38) "C:7:"myclass":19:{Data from serialize}"
}
Using PDO::FETCH_CLASS to fetch the object from DB and unserialize it...
myclass::__set(myobj, 'C:7:"myclass":19:{Data from serialize}')
myclass::__construct(PDO shall call __construct())
object(myclass)#%d (2) {
["myprotected":protected]=>
string(19) "a protected propery"
["myobj"]=>
string(38) "C:7:"myclass":19:{Data from serialize}"
}
done!

View file

@ -0,0 +1,98 @@
--TEST--
MySQL PDOStatement->fetch(), PDO::FETCH_SERIALIZE
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
if (version_compare(PHP_VERSION, '5.1.0', '<'))
die("skip Needs 5.1.0 and Interface Serializable");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
class myclass implements Serializable {
public function __construct($caller = null) {
printf("%s(%s) - note that it must not be called when unserializing\n", __METHOD__, var_export($caller, true));
}
public function __set($prop, $value) {
printf("%s(%s, %s)\n", __METHOD__, var_export($prop, true), var_export($value, true));
$this->{$prop} = $value;
}
public function serialize() {
printf("%s()\n", __METHOD__);
return 'Value from serialize()';
}
public function unserialize($data) {
printf("%s(%s)\n", __METHOD__, var_export($data, true));
}
}
printf("Lets see what the Serializeable interface makes our object behave like...\n");
$obj = new myclass('Called by script');
$tmp = unserialize(serialize($obj));
var_dump($tmp);
printf("\nAnd now magic PDO using fetchAll(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE)...\n");
$db->exec('DROP TABLE IF EXISTS test');
$db->exec(sprintf('CREATE TABLE test(myobj BLOB) ENGINE=%s', MySQLPDOTest::getTableEngine()));
$db->exec('INSERT INTO test(myobj) VALUES ("Data fetched from DB to be given to unserialize()")');
$stmt = $db->prepare('SELECT myobj FROM test');
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE, 'myclass', array('Called by PDO'));
var_dump($rows[0]);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE, 'myclass');
var_dump($rows[0]);
printf("\nAnd now PDO using setFetchMode(PDO::FETCH:CLASS|PDO::FETCH_SERIALIZE) + fetch()...\n");
$stmt = $db->prepare('SELECT myobj FROM test');
$stmt->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE, 'myclass', array('Called by PDO'));
$stmt->execute();
var_dump($stmt->fetch());
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!\n";
?>
--EXPECTF--
Lets see what the Serializeable interface makes our object behave like...
myclass::__construct('Called by script') - note that it must not be called when unserializing
myclass::serialize()
myclass::unserialize('Value from serialize()')
object(myclass)#%d (0) {
}
And now magic PDO using fetchAll(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE)...
myclass::unserialize('Data fetched from DB to be given to unserialize()')
myclass::__construct('Called by PDO') - note that it must not be called when unserializing
object(myclass)#%d (0) {
}
myclass::unserialize('Data fetched from DB to be given to unserialize()')
myclass::__construct(NULL) - note that it must not be called when unserializing
object(myclass)#%d (0) {
}
And now PDO using setFetchMode(PDO::FETCH:CLASS|PDO::FETCH_SERIALIZE) + fetch()...
myclass::__set('myobj', 'Data fetched from DB to be given to unserialize()')
myclass::__construct('Called by PDO') - note that it must not be called when unserializing
object(myclass)#%d (1) {
["myobj"]=>
string(49) "Data fetched from DB to be given to unserialize()"
}
done!

View file

@ -0,0 +1,95 @@
--TEST--
MySQL PDO: PDOStatement->fetchObject()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
try {
// default settings
$query = "SELECT id, '', NULL, \"\" FROM test ORDER BY id ASC LIMIT 3";
$stmt = $db->prepare($query);
class myclass {
private $set_calls = 0;
protected static $static_set_calls = 0;
// NOTE: PDO does not care about protected
protected $grp;
// NOTE: PDO does not care about private and calls __construct() after __set()
private function __construct($param1, $param2) {
printf("myclass::__construct(%s, %s): %d / %d\n",
$param1, $param2,
self::$static_set_calls, $this->set_calls);
}
// NOTE: PDO will call __set() prior to calling __construct()
public function __set($prop, $value) {
$this->not_a_magic_one();
printf("myclass::__set(%s, -%s-) %d\n",
$prop, var_export($value, true), $this->set_calls, self::$static_set_calls);
$this->{$prop} = $value;
}
// NOTE: PDO can call regular methods prior to calling __construct()
public function not_a_magic_one() {
$this->set_calls++;
self::$static_set_calls++;
}
}
$stmt->execute();
$rowno = 0;
$rows[] = array();
while (is_object($rows[] = $stmt->fetchObject('myclass', array($rowno++, $rowno))))
;
var_dump($rows[$rowno - 1]);
} catch (PDOException $e) {
// we should never get here, we use warnings, but never trust a system...
printf("[001] %s, [%s} %s\n",
$e->getMessage(), $db->errorInfo(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
myclass::__set(id, -'1'-) 1
myclass::__set(, -''-) 2
myclass::__set(null, -NULL-) 3
myclass::__set(, -''-) 4
myclass::__construct(0, 1): 4 / 4
myclass::__set(id, -'2'-) 1
myclass::__set(, -''-) 2
myclass::__set(null, -NULL-) 3
myclass::__set(, -''-) 4
myclass::__construct(1, 2): 8 / 4
myclass::__set(id, -'3'-) 1
myclass::__set(, -''-) 2
myclass::__set(null, -NULL-) 3
myclass::__set(, -''-) 4
myclass::__construct(2, 3): 12 / 4
object(myclass)#%d (4) {
["set_calls":"myclass":private]=>
int(4)
["grp":protected]=>
NULL
["id"]=>
string(1) "3"
["null"]=>
NULL
}
done!

View file

@ -0,0 +1,309 @@
--TEST--
MySQL: PDOStatement->getColumnMeta()
--SKIPIF--
<?php # vim:ft=php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
// Too many differences among MySQL version - run only with a recent one
$db = MySQLPDOTest::factory();
$stmt = $db->query('SELECT VERSION() as _version');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$version = ((int)substr($row['_version'], 0, 1) * 10) + (int)substr($row['_version'], 2, 1);
if ($version < 51)
die("skip Test needs MySQL 5.1+");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
MySQLPDOTest::createTestTable($db);
try {
$stmt = $db->prepare('SELECT id FROM test ORDER BY id ASC');
// execute() has not been called yet
// NOTE: no warning
if (false !== ($tmp = $stmt->getColumnMeta(0)))
printf("[002] Expecting false got %s\n", var_export($tmp, true));
$stmt->execute();
// Warning: PDOStatement::getColumnMeta() expects exactly 1 parameter, 0 given in
if (false !== ($tmp = @$stmt->getColumnMeta()))
printf("[003] Expecting false got %s\n", var_export($tmp, true));
// invalid offset
if (false !== ($tmp = @$stmt->getColumnMeta(-1)))
printf("[004] Expecting false got %s\n", var_export($tmp, true));
// Warning: PDOStatement::getColumnMeta() expects parameter 1 to be long, array given in
if (false !== ($tmp = @$stmt->getColumnMeta(array())))
printf("[005] Expecting false got %s\n", var_export($tmp, true));
// Warning: PDOStatement::getColumnMeta() expects exactly 1 parameter, 2 given in
if (false !== ($tmp = @$stmt->getColumnMeta(1, 1)))
printf("[006] Expecting false got %s\n", var_export($tmp, true));
$emulated = $stmt->getColumnMeta(0);
printf("Testing native PS...\n");
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[007] Unable to turn off emulated prepared statements\n");
$stmt = $db->prepare('SELECT id FROM test ORDER BY id ASC');
$stmt->execute();
$native = $stmt->getColumnMeta(0);
if (count($native) == 0) {
printf("[008] Meta data seems wrong, %s / %s\n",
var_export($native, true), var_export($emulated, true));
}
// invalid offset
if (false !== ($tmp = $stmt->getColumnMeta(1)))
printf("[009] Expecting false because of invalid offset got %s\n", var_export($tmp, true));
function test_meta(&$db, $offset, $sql_type, $value, $native_type, $pdo_type) {
$db->exec('DROP TABLE IF EXISTS test');
$sql = sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, MySQLPDOTest::getTableEngine());
if (!($stmt = @$db->prepare($sql)) || (!@$stmt->execute())) {
// Some engines and/or MySQL server versions might not support the data type
return true;
}
if (!$db->exec(sprintf('INSERT INTO test(id, label) VALUES (1, "%s")', $value))) {
printf("[%03d] + 1] Insert failed, %d - %s\n", $offset,
$db->errorCode(), var_export($db->errorInfo(), true));
return false;
}
$stmt = $db->prepare('SELECT id, label FROM test');
$stmt->execute();
$meta = $stmt->getColumnMeta(1);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
if (empty($meta)) {
printf("[%03d + 2] getColumnMeta() failed, %d - %s\n", $offset,
$stmt->errorCode(), var_export($stmt->errorInfo(), true));
return false;
}
$elements = array('flags', 'table', 'name', 'len', 'precision', 'pdo_type');
foreach ($elements as $k => $element)
if (!isset($meta[$element])) {
printf("[%03d + 3] Element %s missing, %s\n", $offset,
$element, var_export($meta, true));
return false;
}
if (($meta['table'] != 'test') || ($meta['name'] != 'label')) {
printf("[%03d + 4] Table or field name is wrong, %s\n", $offset,
var_export($meta, true));
return false;
}
if (!is_null($native_type)) {
if (!isset($meta['native_type'])) {
printf("[%03d + 5] Element native_type missing, %s\n", $offset,
var_export($meta, true));
return false;
}
if (!is_array($native_type))
$native_type = array($native_type);
$found = false;
foreach ($native_type as $k => $type) {
if ($meta['native_type'] == $type) {
$found = true;
break;
}
}
if (!$found) {
printf("[%03d + 6] Expecting native type %s, %s\n", $offset,
var_export($native_type, true), var_export($meta, true));
return false;
}
}
if (!is_null($pdo_type) && ($meta['pdo_type'] != $pdo_type)) {
printf("[%03d + 6] Expecting PDO type %s got %s (%s)\n", $offset,
$pdo_type, var_export($meta, true), var_export($meta['native_type']));
return false;
}
return true;
}
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
$is_mysqlnd = MySQLPDOTest::isPDOMySQLnd();
test_meta($db, 20, 'BIT(8)', 1, NULL, ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 30, 'TINYINT', -127, NULL, ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 40, 'TINYINT UNSIGNED', 255, NULL, ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 50, 'BOOLEAN', 1, NULL, ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 60, 'SMALLINT', -32768, 'SHORT', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 70, 'SMALLINT UNSIGNED', 65535, 'SHORT', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 80, 'MEDIUMINT', -8388608, 'INT24', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 90, 'MEDIUMINT UNSIGNED', 16777215, 'INT24', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 100, 'INT', -2147483648, 'LONG', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 110, 'INT UNSIGNED', 4294967295, 'LONG', ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 120, 'BIGINT', -9223372036854775808, 'LONGLONG', ($is_mysqlnd) ? ((PHP_INT_SIZE == 4) ? PDO::PARAM_STR : PDO::PARAM_INT) : PDO::PARAM_STR);
test_meta($db, 130, 'BIGINT UNSIGNED', 18446744073709551615, 'LONGLONG', ($is_mysqlnd) ? ((PHP_INT_SIZE == 4) ? PDO::PARAM_STR : PDO::PARAM_INT) : PDO::PARAM_STR);
test_meta($db, 130, 'REAL', -1.01, 'DOUBLE', PDO::PARAM_STR);
test_meta($db, 140, 'REAL UNSIGNED', 1.01, 'DOUBLE', PDO::PARAM_STR);
test_meta($db, 150, 'REAL ZEROFILL', -1.01, 'DOUBLE', PDO::PARAM_STR);
test_meta($db, 160, 'REAL UNSIGNED ZEROFILL', 1.01, 'DOUBLE', PDO::PARAM_STR);
test_meta($db, 170, 'DOUBLE', -1.01, 'DOUBLE', PDO::PARAM_STR);
test_meta($db, 180, 'DOUBLE UNSIGNED', 1.01, 'DOUBLE', PDO::PARAM_STR);
test_meta($db, 190, 'DOUBLE ZEROFILL', -1.01, 'DOUBLE', PDO::PARAM_STR);
test_meta($db, 200, 'DOUBLE UNSIGNED ZEROFILL', 1.01, 'DOUBLE', PDO::PARAM_STR);
test_meta($db, 210, 'FLOAT', -1.01, 'FLOAT', PDO::PARAM_STR);
test_meta($db, 220, 'FLOAT UNSIGNED', 1.01, 'FLOAT', PDO::PARAM_STR);
test_meta($db, 230, 'FLOAT ZEROFILL', -1.01, 'FLOAT', PDO::PARAM_STR);
test_meta($db, 240, 'FLOAT UNSIGNED ZEROFILL', 1.01, 'FLOAT', PDO::PARAM_STR);
test_meta($db, 250, 'DECIMAL', -1.01, array('DECIMAL', 'NEWDECIMAL'), PDO::PARAM_STR);
test_meta($db, 260, 'DECIMAL UNSIGNED', 1.01, array('DECIMAL', 'NEWDECIMAL'), PDO::PARAM_STR);
test_meta($db, 270, 'DECIMAL ZEROFILL', -1.01, array('DECIMAL', 'NEWDECIMAL'), PDO::PARAM_STR);
test_meta($db, 280, 'DECIMAL UNSIGNED ZEROFILL', 1.01, array('DECIMAL', 'NEWDECIMAL'), PDO::PARAM_STR);
test_meta($db, 290, 'NUMERIC', -1.01, array('DECIMAL', 'NEWDECIMAL'), PDO::PARAM_STR);
test_meta($db, 300, 'NUMERIC UNSIGNED', 1.01, array('DECIMAL', 'NEWDECIMAL'), PDO::PARAM_STR);
test_meta($db, 310, 'NUMERIC ZEROFILL', -1.01, array('DECIMAL', 'NEWDECIMAL'), PDO::PARAM_STR);
test_meta($db, 320, 'NUMERIC UNSIGNED ZEROFILL', 1.01, array('DECIMAL', 'NEWDECIMAL'), PDO::PARAM_STR);
test_meta($db, 330, 'DATE', '2008-04-23', array('DATE', 'NEWDATE'), PDO::PARAM_STR);
test_meta($db, 340, 'TIME', '14:37:00', 'TIME', PDO::PARAM_STR);
test_meta($db, 350, 'TIMESTAMP', time(), 'TIMESTAMP', PDO::PARAM_STR);
test_meta($db, 360, 'DATETIME', '2008-03-23 14:38:00', 'DATETIME', PDO::PARAM_STR);
test_meta($db, 370, 'YEAR', '2008', NULL, ($is_mysqlnd) ? PDO::PARAM_INT : PDO::PARAM_STR);
test_meta($db, 380, 'CHAR(1)', 'a', 'STRING', PDO::PARAM_STR);
test_meta($db, 390, 'CHAR(10)', '0123456789', 'STRING', PDO::PARAM_STR);
test_meta($db, 400, 'CHAR(255)', str_repeat('z', 255), 'STRING', PDO::PARAM_STR);
test_meta($db, 410, 'VARCHAR(1)', 'a', 'VAR_STRING', PDO::PARAM_STR);
test_meta($db, 420, 'VARCHAR(10)', '0123456789', 'VAR_STRING', PDO::PARAM_STR);
test_meta($db, 430, 'VARCHAR(255)', str_repeat('z', 255), 'VAR_STRING', PDO::PARAM_STR);
test_meta($db, 440, 'BINARY(1)', str_repeat('a', 1), 'STRING', PDO::PARAM_STR);
test_meta($db, 450, 'BINARY(255)', str_repeat('b', 255), 'STRING', PDO::PARAM_STR);
test_meta($db, 460, 'VARBINARY(1)', str_repeat('a', 1), 'VAR_STRING', PDO::PARAM_STR);
test_meta($db, 470, 'VARBINARY(255)', str_repeat('b', 255), 'VAR_STRING', PDO::PARAM_STR);
test_meta($db, 480, 'TINYBLOB', str_repeat('b', 255), 'BLOB', PDO::PARAM_STR);
test_meta($db, 490, 'BLOB', str_repeat('b', 256), 'BLOB', PDO::PARAM_STR);
test_meta($db, 500, 'MEDIUMBLOB', str_repeat('b', 256), 'BLOB', PDO::PARAM_STR);
test_meta($db, 510, 'LONGBLOB', str_repeat('b', 256), 'BLOB', PDO::PARAM_STR);
test_meta($db, 520, 'TINYTEXT', str_repeat('b', 255), 'BLOB', PDO::PARAM_STR);
test_meta($db, 530, 'TINYTEXT BINARY', str_repeat('b', 255), 'BLOB', PDO::PARAM_STR);
test_meta($db, 560, 'TEXT', str_repeat('b', 256), 'BLOB', PDO::PARAM_STR);
test_meta($db, 570, 'TEXT BINARY', str_repeat('b', 256), 'BLOB', PDO::PARAM_STR);
test_meta($db, 580, 'MEDIUMTEXT', str_repeat('b', 256), 'BLOB', PDO::PARAM_STR);
test_meta($db, 590, 'MEDIUMTEXT BINARY', str_repeat('b', 256), 'BLOB', PDO::PARAM_STR);
test_meta($db, 600, 'LONGTEXT', str_repeat('b', 256), 'BLOB', PDO::PARAM_STR);
test_meta($db, 610, 'LONGTEXT BINARY', str_repeat('b', 256), 'BLOB', PDO::PARAM_STR);
test_meta($db, 620, "ENUM('yes', 'no') DEFAULT 'yes'", 'no', NULL, PDO::PARAM_STR);
test_meta($db, 630, "SET('yes', 'no') DEFAULT 'yes'", 'no', NULL, PDO::PARAM_STR);
/*
| spatial_type
*/
// unique key
$db->exec('DROP TABLE IF EXISTS test');
$sql = sprintf('CREATE TABLE test(id INT, label INT UNIQUE) ENGINE = %s', MySQLPDOTest::getTableEngine());
if (($stmt = @$db->prepare($sql)) && @$stmt->execute()) {
$db->exec('INSERT INTO test(id, label) VALUES (1, 2)');
$stmt = $db->query('SELECT id, label FROM test');
$meta = $stmt->getColumnMeta(1);
if (!isset($meta['flags'])) {
printf("[1000] No flags contained in metadata %s\n", var_export($meta, true));
} else {
$flags = $meta['flags'];
$found = false;
foreach ($flags as $k => $flag) {
if ($flag == 'unique_key')
$found = true;
}
if (!$found)
printf("[1001] Flags seem wrong %s\n", var_export($meta, true));
}
}
// primary key
$db->exec('DROP TABLE IF EXISTS test');
$sql = sprintf('CREATE TABLE test(id INT PRIMARY KEY NOT NULL AUTO_INCREMENT) ENGINE = %s', MySQLPDOTest::getTableEngine());
if (($stmt = @$db->prepare($sql)) && @$stmt->execute()) {
$db->exec('INSERT INTO test(id) VALUES (1)');
$stmt = $db->query('SELECT id FROM test');
$meta = $stmt->getColumnMeta(0);
if (!isset($meta['flags'])) {
printf("[1002] No flags contained in metadata %s\n", var_export($meta, true));
} else {
$flags = $meta['flags'];
$found = false;
foreach ($flags as $k => $flag) {
if ($flag == 'primary_key')
$found = true;
}
if (!$found)
printf("[1003] Flags seem wrong %s\n", var_export($meta, true));
}
}
// multiple key
$db->exec('DROP TABLE IF EXISTS test');
$sql = sprintf('CREATE TABLE test(id INT, label1 INT, label2 INT, INDEX idx1(label1, label2)) ENGINE = %s', MySQLPDOTest::getTableEngine());
if (($stmt = @$db->prepare($sql)) && @$stmt->execute()) {
$db->exec('INSERT INTO test(id, label1, label2) VALUES (1, 2, 3)');
$stmt = $db->query('SELECT id, label1, label2 FROM test');
$meta = $stmt->getColumnMeta(1);
if (!isset($meta['flags'])) {
printf("[1004] No flags contained in metadata %s\n", var_export($meta, true));
} else {
$flags = $meta['flags'];
$found = false;
foreach ($flags as $k => $flag) {
if ($flag == 'multiple_key')
$found = true;
}
if (!$found)
printf("[1005] Flags seem wrong %s\n", var_export($meta, true));
}
}
$stmt = $db->query('SELECT NULL AS col1');
$meta = $stmt->getColumnMeta(0);
if ('NULL' !== $meta['native_type'])
printf("[1006] Expecting NULL got %s\n", $meta['native_type']);
} catch (PDOException $e) {
// we should never get here, we use warnings, but never trust a system...
printf("[001] %s, [%s} %s\n",
$e->getMessage(), $db->errorInfo(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Testing native PS...
done!

View file

@ -0,0 +1,90 @@
--TEST--
PDOStatements and multi query
--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');
function mysql_stmt_multiquery_wrong_usage($db) {
$stmt = $db->query('SELECT label FROM test ORDER BY id ASC LIMIT 1; SELECT label FROM test ORDER BY id ASC LIMIT 1');
var_dump($stmt->errorInfo());
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
var_dump($stmt->errorInfo());
}
function mysql_stmt_multiquery_proper_usage($db) {
$stmt = $db->query('SELECT label FROM test ORDER BY id ASC LIMIT 1; SELECT label FROM test ORDER BY id ASC LIMIT 1');
do {
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} while ($stmt->nextRowset());
}
try {
printf("Emulated Prepared Statements...\n");
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
mysql_stmt_multiquery_wrong_usage($db);
mysql_stmt_multiquery_proper_usage($db);
printf("Native Prepared Statements...\n");
$db = MySQLPDOTest::factory();
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
mysql_stmt_multiquery_wrong_usage($db);
mysql_stmt_multiquery_proper_usage($db);
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Emulated Prepared Statements...
array(1) {
[0]=>
string(5) "00000"
}
array(1) {
[0]=>
array(1) {
["label"]=>
string(1) "a"
}
}
array(1) {
[0]=>
string(5) "00000"
}
array(1) {
[0]=>
array(1) {
["label"]=>
string(1) "a"
}
}
array(1) {
[0]=>
array(1) {
["label"]=>
string(1) "a"
}
}
Native Prepared Statements...
Warning: PDO::query(): SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; SELECT label FROM test ORDER BY id ASC LIMIT 1' at line %d in %s on line %d
Fatal error: Call to a member function errorInfo() on a non-object in %s on line %d

View file

@ -0,0 +1,309 @@
--TEST--
MySQL PDOStatement->nextRowSet()
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
$row = $db->query('SELECT VERSION() as _version')->fetch(PDO::FETCH_ASSOC);
$matches = array();
if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
die(sprintf("skip Cannot determine MySQL Server version\n"));
$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
if ($version < 50000)
die(sprintf("skip Need MySQL Server 5.0.0+, found %d.%02d.%02d (%d)\n",
$matches[0], $matches[1], $matches[2], $version));
if (!MySQLPDOTest::isPDOMySQLnd())
die("skip This will not work with libmysql");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
MySQLPDOTest::createTestTable($db);
$stmt = $db->query('SELECT id FROM test');
if (false !== ($tmp = $stmt->nextRowSet()))
printf("[002] Expecting false got %s\n", var_export($tmp, true));
// TODO: should give a warning, but its PDO, let's ignore the missing warning for now
if (false !== ($tmp = $stmt->nextRowSet(1)))
printf("[003] Expecting false got %s\n", var_export($tmp, true));
function test_proc1($db) {
$stmt = $db->query('SELECT @VERSION as _version');
$tmp = $stmt->fetch(PDO::FETCH_ASSOC);
assert($tmp['_version'] === NULL);
while ($stmt->fetch()) ;
$db->exec('DROP PROCEDURE IF EXISTS p');
$db->exec('CREATE PROCEDURE p(OUT ver_param VARCHAR(25)) BEGIN SELECT VERSION() INTO ver_param; END;');
$db->exec('CALL p(@VERSION)');
$stmt = $db->query('SELECT @VERSION as _version');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
var_dump($stmt->nextRowSet());
}
function test_proc2($db) {
$db->exec('DROP PROCEDURE IF EXISTS p');
$db->exec('CREATE PROCEDURE p() BEGIN SELECT id FROM test ORDER BY id ASC LIMIT 3; SELECT id, label FROM test WHERE id < 4 ORDER BY id DESC LIMIT 3; END;');
$stmt = $db->query('CALL p()');
do {
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} while ($stmt->nextRowSet());
var_dump($stmt->nextRowSet());
}
try {
// Emulated PS
printf("Emulated PS...\n");
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
test_proc1($db);
test_proc2($db);
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 0);
test_proc1($db);
test_proc2($db);
// Native PS
printf("Native PS...\n");
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
test_proc1($db);
test_proc2($db);
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 0);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
test_proc1($db);
test_proc2($db);
@$db->exec('DROP PROCEDURE IF EXISTS p');
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Emulated PS...
array(1) {
[0]=>
array(1) {
["_version"]=>
string(%d) "%s"
}
}
bool(false)
array(3) {
[0]=>
array(1) {
["id"]=>
string(1) "1"
}
[1]=>
array(1) {
["id"]=>
string(1) "2"
}
[2]=>
array(1) {
["id"]=>
string(1) "3"
}
}
array(3) {
[0]=>
array(2) {
["id"]=>
string(1) "3"
["label"]=>
string(1) "c"
}
[1]=>
array(2) {
["id"]=>
string(1) "2"
["label"]=>
string(1) "b"
}
[2]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
bool(false)
array(1) {
[0]=>
array(1) {
["_version"]=>
string(%d) "%s"
}
}
bool(false)
array(3) {
[0]=>
array(1) {
["id"]=>
string(1) "1"
}
[1]=>
array(1) {
["id"]=>
string(1) "2"
}
[2]=>
array(1) {
["id"]=>
string(1) "3"
}
}
array(3) {
[0]=>
array(2) {
["id"]=>
string(1) "3"
["label"]=>
string(1) "c"
}
[1]=>
array(2) {
["id"]=>
string(1) "2"
["label"]=>
string(1) "b"
}
[2]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
bool(false)
Native PS...
array(1) {
[0]=>
array(1) {
["_version"]=>
string(%d) "%s"
}
}
bool(false)
array(3) {
[0]=>
array(1) {
["id"]=>
string(1) "1"
}
[1]=>
array(1) {
["id"]=>
string(1) "2"
}
[2]=>
array(1) {
["id"]=>
string(1) "3"
}
}
array(3) {
[0]=>
array(2) {
["id"]=>
string(1) "3"
["label"]=>
string(1) "c"
}
[1]=>
array(2) {
["id"]=>
string(1) "2"
["label"]=>
string(1) "b"
}
[2]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
bool(false)
array(1) {
[0]=>
array(1) {
["_version"]=>
string(%d) "%s"
}
}
bool(false)
array(3) {
[0]=>
array(1) {
["id"]=>
string(1) "1"
}
[1]=>
array(1) {
["id"]=>
string(1) "2"
}
[2]=>
array(1) {
["id"]=>
string(1) "3"
}
}
array(3) {
[0]=>
array(2) {
["id"]=>
string(1) "3"
["label"]=>
string(1) "c"
}
[1]=>
array(2) {
["id"]=>
string(1) "2"
["label"]=>
string(1) "b"
}
[2]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
bool(false)
done!

View file

@ -0,0 +1,32 @@
--TEST--
MySQL PDOStatement->rowCount() @ SELECT
--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();
MySQLPDOTest::createTestTable($db);
try {
if (0 !== ($tmp = $db->query('SELECT id FROM test WHERE 1 = 0')->rowCount()))
printf("[002] Expecting 0 got %s", var_export($tmp, true));
if (1 !== ($tmp = $db->query('SELECT id FROM test WHERE id = 1')->rowCount()))
printf("[003] Expecting 1 got %s", var_export($tmp, true));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
done!

View file

@ -0,0 +1,180 @@
--TEST--
MySQL PDO:query() vs. PDO::prepare() and MySQL error 2050
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
if (MYSQLPDOTest::isPDOMySQLnd())
die("skip libmysql only test");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
try {
printf("Native PS...\n");
$db->setAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY, 0);
if (0 != $db->getAttribute(PDO::MYSQL_ATTR_DIRECT_QUERY))
printf("[004] Unable to turn off emulated prepared statements\n");
printf("Buffered...\n");
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
$stmt = $db->query('SELECT id, label FROM test WHERE id = 1');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt = $db->query('SELECT id, label FROM test WHERE id = 1');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
printf("Unbuffered...\n");
MySQLPDOTest::createTestTable($db);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $db->query('SELECT id, label FROM test WHERE id = 1');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
/*
NOTE - this will cause an error and it OK
When using unbuffered prepared statements MySQL expects you to
fetch all data from the row before sending new data to the server.
PDO::query() will prepare and execute a statement in one step.
After the execution of PDO::query(), MySQL expects you to fetch
the results from the line before sending new commands. However,
PHP/PDO will send a CLOSE message as part of the PDO::query() call.
The following happens:
$stmt = PDO::query(<some query>)
mysql_stmt_prepare()
mysql_stmt_execute()
$stmt->fetchAll()
mysql_stmt_fetch()
And now the right side of the expression will be executed first:
$stmt = PDO::query(<some query>)
PDO::query(<some query>)
mysql_stmt_prepare
mysql_stmt_execute
PHP continues at the left side of the expression:
$stmt = PDO::query(<some query>)
What happens is that $stmt gets overwritten. The reference counter of the
zval representing the current value of $stmt. PDO gets a callback that
it has to free the resources associated with the zval representing the
current value of stmt:
mysql_stmt_close
---> ERROR
---> execute() has been send on the line, you are supposed to fetch
---> you must not try to send a CLOSE after execute()
---> Error: 2050 (CR_FETCH_CANCELED)
---> Message: Row retrieval was canceled by mysql_stmt_close() call
---> MySQL does its best to recover the line and cancels the retrieval
PHP proceeds and assigns the new statement object/zval obtained from
PDO to $stmt.
Solutions:
- use mysqlnd
- use prepare() + execute() instead of query()
- as there is no explicit close() in PDO, try unset($stmt) before the new assignment
- fix PDO::query() [not the driver, fix PDO itself]
*/
$stmt = $db->query('SELECT id, label FROM test WHERE id = 1');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt = $db->prepare('SELECT id, label FROM test WHERE id = 1');
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
$stmt = $db->prepare('SELECT id, label FROM test WHERE id = 1');
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
unset($stmt);
$stmt = $db->query('SELECT id, label FROM test WHERE id = 1');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
unset($stmt);
$stmt = $db->query('SELECT id, label FROM test WHERE id = 1');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!";
?>
--EXPECTF--
Native PS...
Buffered...
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
Unbuffered...
Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: 2050 in %s on line %d
array(0) {
}
Warning: PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: 2050 in %s on line %d
array(0) {
}
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
array(1) {
[0]=>
array(2) {
["id"]=>
string(1) "1"
["label"]=>
string(1) "a"
}
}
done!

View file

@ -0,0 +1,122 @@
--TEST--
MySQL Prepared Statements and different column counts
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
$db = MySQLPDOTest::factory();
$row = $db->query('SELECT VERSION() as _version')->fetch(PDO::FETCH_ASSOC);
$matches = array();
if (!preg_match('/^(\d+)\.(\d+)\.(\d+)/ismU', $row['_version'], $matches))
die(sprintf("skip Cannot determine MySQL Server version\n"));
$version = $matches[0] * 10000 + $matches[1] * 100 + $matches[2];
if ($version < 50000)
die(sprintf("skip Need MySQL Server 5.0.0+, found %d.%02d.%02d (%d)\n",
$matches[0], $matches[1], $matches[2], $version));
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
$db = MySQLPDOTest::factory();
function check_result($offset, $stmt, $columns) {
do {
$row = $stmt->fetch(PDO::FETCH_ASSOC);
} while ($stmt->nextRowSet());
if (!isset($row['one']) || ($row['one'] != 1)) {
printf("[%03d + 1] Expecting array('one' => 1), got %s\n", $offset, var_export($row, true));
return false;
}
if (($columns == 2) &&
(!isset($row['two']) || ($row['two'] != 2))) {
printf("[%03d + 2] Expecting array('one' => 1, 'two' => 2), got %s\n", $offset, var_export($row, true));
return false;
} else if (($columns == 1) && isset($row['two'])) {
printf("[%03d + 3] Expecting one array element got two\n", $offset);
return false;
}
return true;
}
try {
// What will happen if a PS returns a differen number of result set column upon each execution?
// Lets try with a SP accepting parameters...
$db->exec('DROP PROCEDURE IF EXISTS p');
$db->exec('CREATE PROCEDURE p(IN cols INT) BEGIN IF cols < 2 THEN SELECT cols AS "one"; ELSE SELECT 1 AS "one", cols AS "two"; END IF; END;');
// Emulates PS first
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$stmt = $db->prepare('CALL p(?)');
$columns = null;
$stmt->bindParam(1, $columns);
for ($i = 0; $i < 5; $i++) {
$columns = ($i % 2) + 1;
$stmt->execute();
check_result($i, $stmt, $columns);
}
if (MySQLPDOTest::isPDOMySQLnd()) {
// Native PS
// Libmysql cannot handle such a stored procedure. You will see leaks with libmysql
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
$stmt = $db->prepare('CALL p(?)');
$stmt->bindParam(1, $columns);
for ($i = 5; $i < 10; $i++) {
$columns = ($i % 2) + 1;
$stmt->execute();
check_result($i, $stmt, $columns);
}
}
// And now without parameters... - this gives a different control flow inside PDO
$db->exec('DROP PROCEDURE IF EXISTS p');
$db->exec('CREATE PROCEDURE p() BEGIN DECLARE cols INT; SELECT @numcols INTO cols; IF cols < 2 THEN SET @numcols = 2; SELECT cols AS "one"; ELSE SET @numcols = 1; SELECT 1 AS "one", cols AS "two"; END IF; END;');
// Emulates PS first
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
$db->exec('SET @numcols = 1');
$stmt = $db->prepare('CALL p()');
$stmt->execute();
check_result(11, $stmt, 1);
$stmt->execute();
check_result(12, $stmt, 2);
$db->exec('SET @numcols = 1');
$stmt->execute();
check_result(13, $stmt, 1);
if (MySQLPDOTest::isPDOMySQLnd()) {
// Native PS
// Libmysql cannot handle such a stored procedure. You will see leaks with libmysql
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 0);
$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
$db->exec('SET @numcols = 1');
$stmt = $db->prepare('CALL p()');
$stmt->execute();
check_result(14, $stmt, 1);
$stmt->execute();
check_result(15, $stmt, 2);
$db->exec('SET @numcols = 1');
$stmt->execute();
check_result(16, $stmt, 1);
}
} catch (PDOException $e) {
printf("[99] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
print "done!";
--EXPECTF--
done!

View file

@ -0,0 +1,101 @@
--TEST--
MySQL PDOStatement->execute()/fetch(), Non-SELECT
--SKIPIF--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'skipif.inc');
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
MySQLPDOTest::skip();
if (version_compare(PHP_VERSION, '5.0.0', '<'))
die("skip Requires PHP 5.0+");
?>
--FILE--
<?php
require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
// No silly strict mode warnings, please!
error_reporting(E_ALL^E_STRICT);
ini_set('display_errors', false);
try {
class MyPDO extends PDO {
public function __construct() {
$this->protocol();
return call_user_func_array(array($this, 'parent::__construct'), func_get_args());
}
public function exec() {
$this->protocol();
return call_user_func_array(array($this, 'parent::exec'), func_get_args());
}
public function query() {
$this->protocol();
return call_user_func_array(array($this, 'parent::query'), func_get_args());
}
public function __call($method, $args) {
print "__call()";
// $this->protocol();
}
private function protocol() {
$stack = debug_backtrace();
if (!isset($stack[1]))
return;
printf("%s(", $stack[1]['function']);
$args = '';
foreach ($stack[1]['args'] as $k => $v)
$args .= sprintf("%s, ", var_export($v, true));
if ($args != '')
printf("%s", substr($args, 0, -2));
printf(")\n");
}
}
$db = new MyPDO(PDO_MYSQL_TEST_DSN, PDO_MYSQL_TEST_USER, PDO_MYSQL_TEST_PASS);
$db->exec('DROP TABLE IF EXISTS test');
$db->exec('CREATE TABLE test(id INT)');
$db->exec('INSERT INTO test(id) VALUES (1), (2)');
$stmt = $db->query('SELECT * FROM test ORDER BY id ASC');
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));
var_dump($stmt->fetch());
$db->intercept_call();
} catch (PDOException $e) {
printf("[001] %s [%s] %s\n",
$e->getMessage(), $db->errorCode(), implode(' ', $db->errorInfo()));
}
$db->exec('DROP TABLE IF EXISTS test');
print "done!\n";
?>
--XFAIL--
PDO doesn't like __call()
--EXPECTF--
__construct('%s', '%s', '%s')
exec('DROP TABLE IF EXISTS test')
exec('CREATE TABLE test(id INT)')
exec('INSERT INTO test(id) VALUES (1), (2)')
query('SELECT * FROM test ORDER BY id ASC')
array(2) {
[0]=>
array(1) {
["id"]=>
string(1) "1"
}
[1]=>
array(1) {
["id"]=>
string(1) "2"
}
}
bool(false)
__call('intercept_call', array (
))
exec('DROP TABLE IF EXISTS test')
done!

View file

@ -0,0 +1,174 @@
--TEST--
MySQL PDO->exec(), native types wo ZEROFILL
--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');
function test_type(&$db, $offset, $sql_type, $value, $ret_value = NULL, $pattern = NULL) {
$db->exec('DROP TABLE IF EXISTS test');
$sql = sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, MySQLPDOTest::getTableEngine());
@$db->exec($sql);
if ($db->errorCode() != 0) {
// not all MySQL Server versions and/or engines might support the type
return true;
}
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (?, ?)');
$stmt->bindValue(1, $offset);
$stmt->bindValue(2, $value);
if (!$stmt->execute()) {
printf("[%03d + 1] INSERT failed, %s\n", $offset, var_export($stmt->errorInfo(), true));
return false;
}
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
$stmt = $db->query('SELECT id, label FROM test');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->closeCursor();
if (!isset($row['id']) || !isset($row['label'])) {
printf("[%03d + 2] Fetched result seems wrong, dumping result: %s\n", $offset, var_export($row, true));
return false;
}
if ($row['id'] != $offset) {
printf("[%03d + 3] Expecting %s got %s\n", $offset, $row['id']);
return false;
}
if (!is_null($pattern)) {
if (!preg_match($pattern, $row['label'])) {
printf("[%03d + 5] Value seems wrong, accepting pattern %s got %s, check manually\n",
$offset, $pattern, var_export($row['label'], true));
return false;
}
} else {
$exp = $value;
if (!is_null($ret_value)) {
// we expect a different return value than our input value
// typically the difference is only the type
$exp = $ret_value;
}
if ($row['label'] !== $exp) {
printf("[%03d + 4] %s - input = %s/%s, output = %s/%s\n", $offset,
$sql_type, var_export($exp, true), gettype($exp),
var_export($row['label'], true), gettype($row['label']));
return false;
}
}
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
$stmt = $db->query('SELECT id, label FROM test');
$row_string = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->closeCursor();
if (is_null($pattern) && ($row['label'] != $row_string['label'])) {
printf("%s - STRINGIGY = %s, NATIVE = %s\n", $sql_type, var_export($row_string['label'], true), var_export($row['label'], true));
return false;
} else if (!is_null($pattern) && !preg_match($pattern, $row_string['label'])) {
printf("%s - STRINGIGY = %s, NATIVE = %s, pattern '%s'\n", $sql_type, var_export($row_string['label'], true), var_export($row['label'], true), $pattern);
return false;
}
return true;
}
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
/*
test_type($db, 20, 'BIT(8)', 1);
*/
$is_mysqlnd = MySQLPDOTest::isPDOMySQLnd();
test_type($db, 30, 'TINYINT', -127, ($is_mysqlnd) ? -127: '-127');
test_type($db, 40, 'TINYINT UNSIGNED', 255, ($is_mysqlnd) ? 255 : '255');
test_type($db, 50, 'BOOLEAN', 1, ($is_mysqlnd) ? 1 : '1');
test_type($db, 60, 'SMALLINT', -32768, ($is_mysqlnd) ? -32768 : '-32768');
test_type($db, 70, 'SMALLINT UNSIGNED', 65535, ($is_mysqlnd) ? 65535 : '65535');
test_type($db, 80, 'MEDIUMINT', -8388608, ($is_mysqlnd) ? -8388608 : '-8388608');
test_type($db, 90, 'MEDIUMINT UNSIGNED', 16777215, ($is_mysqlnd) ? 16777215 : '16777215');
test_type($db, 100, 'INT', -2147483648, ($is_mysqlnd) ? -2147483648 : '-2147483648');
test_type($db, 110, 'INT UNSIGNED', 4294967295, ($is_mysqlnd) ? 4294967295 : '4294967295');
// no chance to return int with the current PDO version - we are forced to return strings
test_type($db, 120, 'BIGINT', 1, ($is_mysqlnd) ? 1 : '1');
// to avoid trouble with numeric ranges, lets pass the numbers as a string
test_type($db, 130, 'BIGINT', '-9223372036854775808', NULL, '/^\-9[\.]*22/');
test_type($db, 140, 'BIGINT UNSIGNED', '18446744073709551615', NULL, '/^1[\.]*844/');
test_type($db, 150, 'REAL', -1.01, ($is_mysqlnd) ? -1.01 : '-1.01');
test_type($db, 160, 'REAL UNSIGNED', 1.01, ($is_mysqlnd) ? 1.01 : '1.01');
test_type($db, 170, 'DOUBLE', -1.01, ($is_mysqlnd) ? -1.01 : '-1.01');
test_type($db, 180, 'DOUBLE UNSIGNED', 1.01, ($is_mysqlnd) ? 1.01 : '1.01');
test_type($db, 210, 'FLOAT', -1.01, NULL, '/^\-1.0\d+/');
test_type($db, 220, 'FLOAT UNSIGNED', 1.01, NULL, '/^1.0\d+/');
test_type($db, 250, 'DECIMAL', -1.01, '-1');
test_type($db, 260, 'DECIMAL UNSIGNED', 1.01, '1');
test_type($db, 290, 'NUMERIC', -1.01, '-1');
test_type($db, 300, 'NUMERIC UNSIGNED', 1.01, '1');
test_type($db, 330, 'DATE', '2008-04-23');
test_type($db, 340, 'TIME', '14:37:00');
test_type($db, 350, 'TIMESTAMP', '2008-05-06 21:09:00');
test_type($db, 360, 'DATETIME', '2008-03-23 14:38:00');
test_type($db, 370, 'YEAR', 2008, ($is_mysqlnd) ? 2008 : '2008');
test_type($db, 380, 'CHAR(1)', 'a');
test_type($db, 390, 'CHAR(10)', '0123456789');
test_type($db, 400, 'CHAR(255)', str_repeat('z', 255));
test_type($db, 410, 'VARCHAR(1)', 'a');
test_type($db, 420, 'VARCHAR(10)', '0123456789');
test_type($db, 430, 'VARCHAR(255)', str_repeat('z', 255));
test_type($db, 440, 'BINARY(1)', str_repeat('a', 1));
test_type($db, 450, 'BINARY(255)', str_repeat('b', 255));
test_type($db, 460, 'VARBINARY(1)', str_repeat('a', 1));
test_type($db, 470, 'VARBINARY(255)', str_repeat('b', 255));
test_type($db, 480, 'TINYBLOB', str_repeat('b', 255));
test_type($db, 490, 'BLOB', str_repeat('b', 256));
test_type($db, 500, 'MEDIUMBLOB', str_repeat('b', 256));
test_type($db, 510, 'LONGBLOB', str_repeat('b', 256));
test_type($db, 520, 'TINYTEXT', str_repeat('b', 255));
test_type($db, 530, 'TINYTEXT BINARY', str_repeat('b', 255));
test_type($db, 560, 'TEXT', str_repeat('b', 256));
test_type($db, 570, 'TEXT BINARY', str_repeat('b', 256));
test_type($db, 580, 'MEDIUMTEXT', str_repeat('b', 256));
test_type($db, 590, 'MEDIUMTEXT BINARY', str_repeat('b', 256));
test_type($db, 600, 'LONGTEXT', str_repeat('b', 256));
test_type($db, 610, 'LONGTEXT BINARY', str_repeat('b', 256));
test_type($db, 620, "ENUM('yes', 'no') DEFAULT 'yes'", 'no');
test_type($db, 630, "SET('yes', 'no') DEFAULT 'yes'", 'no');
test_type($db, 640, 'DECIMAL(3,2)', -1.01, '-1.01');
echo "done!\n";
?>
--EXPECTF--
done!

View file

@ -0,0 +1,117 @@
--TEST--
MySQL PDO->exec(), native types - ZEROFILL
--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');
function test_type(&$db, $offset, $sql_type, $value, $ret_value = NULL, $pattern = NULL) {
$db->exec('DROP TABLE IF EXISTS test');
$sql = sprintf('CREATE TABLE test(id INT, label %s) ENGINE=%s', $sql_type, MySQLPDOTest::getTableEngine());
@$db->exec($sql);
if ($db->errorCode() != 0) {
// not all MySQL Server versions and/or engines might support the type
return true;
}
$stmt = $db->prepare('INSERT INTO test(id, label) VALUES (?, ?)');
$stmt->bindValue(1, $offset);
$stmt->bindValue(2, $value);
try {
if (!$stmt->execute()) {
printf("[%03d + 1] INSERT failed, %s\n", $offset, var_export($stmt->errorInfo(), true));
return false;
}
} catch (PDOException $e) {
// This might be a SQL warning on signed values inserted in unsigned columns
// Zerofill implies unsigned but the test plays with signed = negative values as well!
return true;
}
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
$stmt = $db->query('SELECT id, label FROM test');
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->closeCursor();
if (!isset($row['id']) || !isset($row['label'])) {
printf("[%03d + 2] Fetched result seems wrong, dumping result: %s\n", $offset, var_export($row, true));
return false;
}
if ($row['id'] != $offset) {
printf("[%03d + 3] Expecting %s got %s\n", $offset, $row['id']);
return false;
}
if (!is_null($pattern)) {
if (!preg_match($pattern, $row['label'])) {
printf("[%03d + 5] Value seems wrong, accepting pattern %s got %s, check manually\n",
$offset, $pattern, var_export($row['label'], true));
return false;
}
} else {
$exp = $value;
if (!is_null($ret_value)) {
// we expect a different return value than our input value
// typically the difference is only the type
$exp = $ret_value;
}
if ($row['label'] !== $exp) {
printf("[%03d + 4] %s - input = %s/%s, output = %s/%s\n", $offset,
$sql_type, var_export($exp, true), gettype($exp),
var_export($row['label'], true), gettype($row['label']));
return false;
}
}
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
$stmt = $db->query('SELECT id, label FROM test');
$row_string = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->closeCursor();
if ($row['label'] != $row_string['label']) {
printf("%s - STRINGIGY = %s, NATIVE = %s\n", $sql_type, var_export($row_string['label'], true), var_export($row['label'], true));
return false;
}
return true;
}
$db = MySQLPDOTest::factory();
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
test_type($db, 100, 'REAL ZEROFILL', -1.01, NULL, '/^[0]*0$/');
test_type($db, 110, 'REAL ZEROFILL', 1.01, NULL, '/^[0]*1\.01$/');
test_type($db, 120, 'REAL UNSIGNED ZEROFILL', 1.01, NULL, '/^[0]*1\.01$/');
test_type($db, 130, 'DOUBLE ZEROFILL', -1.01, NULL, '/^[0]*0$/');
test_type($db, 140, 'DOUBLE ZEROFILL', 1.01, NULL, '/^[0]*1\.01$/');
test_type($db, 150, 'DOUBLE UNSIGNED ZEROFILL', 1.01, NULL, '/^[0]*1\.01$/');
test_type($db, 160, 'FLOAT ZEROFILL', -1.01, NULL, '/^[0]*0$/');
test_type($db, 170, 'FLOAT ZEROFILL', 1, NULL, '/^[0]*1$/');
test_type($db, 180, 'FLOAT UNSIGNED ZEROFILL', -1, NULL, '/^[0]*0$/');
test_type($db, 190, 'DECIMAL ZEROFILL', -1.01, NULL, '/^[0]*0$/');
test_type($db, 200, 'DECIMAL ZEROFILL', 1.01, NULL, '/^[0]*1$/');
test_type($db, 210, 'DECIMAL UNSIGNED ZEROFILL', 1.01, NULL, '/^[0]*1$/');
test_type($db, 220, 'NUMERIC ZEROFILL', -1, NULL, '/^[0]*0$/');
test_type($db, 230, 'NUMERIC ZEROFILL', 1, NULL, '/^[0]*1$/');
test_type($db, 240, 'NUMERIC UNSIGNED ZEROFILL', 1.01, NULL, '/^[0]*1$/');
echo "done!\n";
?>
--EXPECTF--
done!

View file

@ -0,0 +1,30 @@
--TEST--
PDO MySQL PECL Bug #5200 (Describe table gives unexpected result mysql and type enum)
--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__) . '/../../../ext/pdo/tests/pdo_test.inc';
$db = PDOTest::test_factory(dirname(__FILE__). '/common.phpt');
$db->exec("CREATE TABLE test (bar INT NOT NULL, phase enum('please_select', 'I', 'II', 'IIa', 'IIb', 'III', 'IV'))");
foreach ($db->query('DESCRIBE test phase')->fetchAll(PDO::FETCH_ASSOC) as $row) {
print_r($row);
}
--EXPECT--
Array
(
[field] => phase
[type] => enum('please_select','I','II','IIa','IIb','III','IV')
[null] => YES
[key] =>
[default] =>
[extra] =>
)

Some files were not shown because too many files have changed in this diff Show more