Browse files

MFH: 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.
  • Loading branch information...
1 parent c6c238c commit be0793d2e7892a394c3d7105e157ede37d692400 @johannes johannes committed Jul 21, 2008
Showing with 10,616 additions and 505 deletions.
  1. +6 −0 NEWS
  2. +18 −1 ext/pdo/pdo_stmt.c
  3. +7 −2 ext/pdo/php_pdo_driver.h
  4. +2 −0 ext/pdo/tests/bug_34630.phpt
  5. +7 −6 ext/pdo/tests/bug_39656.phpt
  6. +3 −0 ext/pdo/tests/bug_43130.phpt
  7. +10 −1 ext/pdo/tests/bug_43663.phpt
  8. +7 −3 ext/pdo/tests/bug_44159.phpt
  9. +0 −1 ext/pdo/tests/pdo.inc
  10. +6 −4 ext/pdo/tests/pdo_017.phpt
  11. +1 −1 ext/pdo/tests/pdo_025.phpt
  12. +8 −18 ext/pdo/tests/pdo_test.inc
  13. +3 −3 ext/pdo_mysql/CREDITS
  14. +120 −114 ext/pdo_mysql/config.m4
  15. +10 −4 ext/pdo_mysql/config.w32
  16. +246 −71 ext/pdo_mysql/mysql_driver.c
  17. +495 −200 ext/pdo_mysql/mysql_statement.c
  18. +177 −39 ext/pdo_mysql/pdo_mysql.c
  19. +6 −5 ext/pdo_mysql/php_pdo_mysql.h
  20. +86 −20 ext/pdo_mysql/php_pdo_mysql_int.h
  21. +16 −0 ext/pdo_mysql/tests/README
  22. +9 −2 ext/pdo_mysql/tests/bug_33689.phpt
  23. +96 −0 ext/pdo_mysql/tests/bug_39858.phpt
  24. +44 −0 ext/pdo_mysql/tests/bug_41125.phpt
  25. +64 −0 ext/pdo_mysql/tests/bug_41997.phpt
  26. +80 −0 ext/pdo_mysql/tests/bug_42499.phpt
  27. +20 −0 ext/pdo_mysql/tests/bug_43371.phpt
  28. +104 −0 ext/pdo_mysql/tests/bug_44454.phpt
  29. +92 −0 ext/pdo_mysql/tests/bug_44707.phpt
  30. +50 −0 ext/pdo_mysql/tests/bug_45120.phpt
  31. +62 −0 ext/pdo_mysql/tests/bug_pecl_12925.phpt
  32. +87 −0 ext/pdo_mysql/tests/bug_pecl_7976.phpt
  33. +43 −10 ext/pdo_mysql/tests/config.inc
  34. +162 −0 ext/pdo_mysql/tests/mysql_pdo_test.inc
  35. +303 −0 ext/pdo_mysql/tests/pdo_mysql___construct.phpt
  36. +56 −0 ext/pdo_mysql/tests/pdo_mysql___construct_ini.phpt
  37. +170 −0 ext/pdo_mysql/tests/pdo_mysql___construct_options.phpt
  38. +88 −0 ext/pdo_mysql/tests/pdo_mysql___construct_options_libmysql.phpt
  39. +75 −0 ext/pdo_mysql/tests/pdo_mysql___construct_uri.phpt
  40. +93 −0 ext/pdo_mysql/tests/pdo_mysql_attr_autocommit.phpt
  41. +219 −0 ext/pdo_mysql/tests/pdo_mysql_attr_case.phpt
  42. +36 −0 ext/pdo_mysql/tests/pdo_mysql_attr_client_version.phpt
  43. +36 −0 ext/pdo_mysql/tests/pdo_mysql_attr_connection_status.phpt
  44. +30 −0 ext/pdo_mysql/tests/pdo_mysql_attr_driver_name.phpt
  45. +166 −0 ext/pdo_mysql/tests/pdo_mysql_attr_errmode.phpt
  46. +41 −0 ext/pdo_mysql/tests/pdo_mysql_attr_fetch_table_names.phpt
  47. +51 −0 ext/pdo_mysql/tests/pdo_mysql_attr_init_command.phpt
  48. +70 −0 ext/pdo_mysql/tests/pdo_mysql_attr_max_buffer_size.phpt
  49. +120 −0 ext/pdo_mysql/tests/pdo_mysql_attr_oracle_nulls.phpt
  50. +21 −0 ext/pdo_mysql/tests/pdo_mysql_attr_prefetch.phpt
  51. +48 −0 ext/pdo_mysql/tests/pdo_mysql_attr_server_info.phpt
  52. +64 −0 ext/pdo_mysql/tests/pdo_mysql_attr_server_version.phpt
  53. +154 −0 ext/pdo_mysql/tests/pdo_mysql_attr_statement_class.phpt
  54. +201 −0 ext/pdo_mysql/tests/pdo_mysql_begintransaction.phpt
  55. +59 −0 ext/pdo_mysql/tests/pdo_mysql_bit.phpt
  56. +78 −0 ext/pdo_mysql/tests/pdo_mysql_class_constants.phpt
  57. +84 −0 ext/pdo_mysql/tests/pdo_mysql_commit.phpt
  58. +81 −0 ext/pdo_mysql/tests/pdo_mysql_errorcode.phpt
  59. +173 −0 ext/pdo_mysql/tests/pdo_mysql_errorinfo.phpt
  60. +179 −0 ext/pdo_mysql/tests/pdo_mysql_exec.phpt
  61. +88 −0 ext/pdo_mysql/tests/pdo_mysql_exec_ddl.phpt
  62. +102 −0 ext/pdo_mysql/tests/pdo_mysql_exec_load_data.phpt
  63. +59 −0 ext/pdo_mysql/tests/pdo_mysql_exec_select.phpt
  64. +88 −0 ext/pdo_mysql/tests/pdo_mysql_fetch_both.phpt
  65. +101 −0 ext/pdo_mysql/tests/pdo_mysql_get_attribute.phpt
  66. +58 −0 ext/pdo_mysql/tests/pdo_mysql_interface.phpt
  67. +114 −0 ext/pdo_mysql/tests/pdo_mysql_last_insert_id.phpt
  68. +101 −0 ext/pdo_mysql/tests/pdo_mysql_pconnect.phpt
  69. +34 −0 ext/pdo_mysql/tests/pdo_mysql_phpinfo.phpt
  70. +414 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_emulated.phpt
  71. +78 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_emulated_anonymous.phpt
  72. +75 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_emulated_placeholder_everywhere.phpt
  73. +48 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_match_against.phpt
  74. +380 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_native.phpt
  75. +91 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_native_clear_error.phpt
  76. +44 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_native_column.phpt
  77. +136 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_native_dup_named_placeholder.phpt
  78. +35 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_native_mixed_style.phpt
  79. +85 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_native_named_placeholder.phpt
  80. +85 −0 ext/pdo_mysql/tests/pdo_mysql_prepare_native_placeholder_everywhere.phpt
  81. +90 −0 ext/pdo_mysql/tests/pdo_mysql_rollback.phpt
  82. +110 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_bindcolumn.phpt
  83. +155 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_bindparam.phpt
  84. +169 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_bindparam_types.phpt
  85. +332 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_bindvalue.phpt
  86. +143 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_blobfromsteam.phpt
  87. +91 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_blobs.phpt
  88. +172 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_closecursor.phpt
  89. +69 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_closecursor_empty.phpt
  90. +65 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_columncount.phpt
  91. +61 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_errorcode.phpt
  92. +119 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_errorinfo.phpt
  93. +187 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_fetch_non_select.phpt
  94. +151 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_fetch_serialize.phpt
  95. +98 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_fetch_serialize_simple.phpt
  96. +95 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_fetchobject.phpt
  97. +309 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_getcolumnmeta.phpt
  98. +90 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_multiquery.phpt
  99. +309 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_nextrowset.phpt
  100. +32 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_rowcount.phpt
  101. +180 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_unbuffered_2050.phpt
  102. +122 −0 ext/pdo_mysql/tests/pdo_mysql_stmt_variable_columncount.phpt
  103. +101 −0 ext/pdo_mysql/tests/pdo_mysql_subclass.phpt
  104. +174 −0 ext/pdo_mysql/tests/pdo_mysql_types.phpt
  105. +117 −0 ext/pdo_mysql/tests/pdo_mysql_types_zerofill.phpt
  106. +7 −0 ext/pdo_mysql/tests/skipif.inc
  107. +9 −0 ext/pdo_mysql/tests/table.inc
View
6 NEWS
@@ -206,7 +206,9 @@ PHP NEWS
- Fixed an issue where exec() on Windows would eat the first and last double quotes.
(Scott)
+- Fixed PECL bug #12794 (PDOStatement->nextRowset() doesn�t work). (Johannes)
- Fixed PECL bug #12431 (OCI8 ping functionality is broken). (Oracle Corp.)
+- Fixed PECL bug #12401 (Add support for ATTR_FETCH_TABLE_NAMES). (Johannes)
- Fixed bug #45571 (ReflectionClass::export() shows superclasses' private static
methods). (robin_fernandes at uk dot ibm dot com)
@@ -266,6 +268,8 @@ PHP NEWS
- Fixed bug #42637 (SoapFault : Only http and https are allowed). (Bill Moran)
- Fixed bug #42548 (mysqli PROCEDURE calls can't return result sets). (hartmut)
- Fixed bug #42509 (gmp leaks memory when gmp_init() not used). (Stas)
+- Fixed bug #42499 (PDO_MYSQL: multi-statement execution via PDO::exec() makes
+ connection unusable). (Johannes)
- Fixed bug #42443 (PDO SQLite driver binds integers and booleans as strings).
(Scott)
- Fixed bug #42284 (duplicate of #39700). (Lars W)
@@ -274,6 +278,8 @@ PHP NEWS
DateTimeZone). (Derick)
- Fixed bug #42069 (parse_ini_file() allows using some non-alpha numeric
characters). (Jani)
+- Fixed bug #41997 (pdo_mysql: stored procedure call returning single rowset
+ blocks future queries). (Johannes)
- Fixed bug #41599 (setTime() fails after modify() is used). (Derick)
- Fixed bug #41522 (PDO firebird driver returns null if it fails to connect).
(Lars W)
View
19 ext/pdo/pdo_stmt.c
@@ -545,6 +545,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);
@@ -1883,7 +1897,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
9 ext/pdo/php_pdo_driver.h
@@ -44,7 +44,7 @@ PDO_API char *php_pdo_int64_to_str(pdo_int64_t i64 TSRMLS_DC);
# define FALSE 0
#endif
-#define PDO_DRIVER_API 20060511
+#define PDO_DRIVER_API 20080721
enum pdo_param_type {
PDO_PARAM_NULL,
@@ -67,7 +67,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
2 ext/pdo/tests/bug_34630.phpt
@@ -45,6 +45,8 @@ $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
var_dump($db->query("SELECT * from test")->fetchAll(PDO::FETCH_ASSOC));
?>
+--XFAIL--
+This bug might be still open on aix5.2-ppc64 and hpux11.23-ia64
--EXPECT--
array(1) {
[0]=>
View
13 ext/pdo/tests/bug_39656.phpt
@@ -1,7 +1,7 @@
--TEST--
PDO Common: Bug #39656 (Crash when calling fetch() on a PDO statment object after closeCursor())
--SKIPIF--
-<?php
+<?php
if (!extension_loaded('pdo')) die('skip');
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
@@ -15,13 +15,13 @@ if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.dirname(__FILE_
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
-@$db->exec("DROP TABLE testtable");
+@$db->exec("DROP TABLE test");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
-$db->exec("CREATE TABLE testtable (id INTEGER NOT NULL PRIMARY KEY, usr VARCHAR( 256 ) NOT NULL)");
-$db->exec("INSERT INTO testtable (id, usr) VALUES (1, 'user')");
+$db->exec("CREATE TABLE test (id INTEGER NOT NULL PRIMARY KEY, usr VARCHAR( 256 ) NOT NULL)");
+$db->exec("INSERT INTO test (id, usr) VALUES (1, 'user')");
-$stmt = $db->prepare("SELECT * FROM testtable WHERE id = ?");
+$stmt = $db->prepare("SELECT * FROM test WHERE id = ?");
$stmt->bindValue(1, 1, PDO::PARAM_INT );
$stmt->execute();
$row = $stmt->fetch();
@@ -32,9 +32,10 @@ $stmt->closeCursor();
$row = $stmt->fetch(); // this line will crash CLI
var_dump( $row );
+@$db->exec("DROP TABLE test");
echo "Done\n";
?>
---EXPECT--
+--EXPECT--
array(4) {
["id"]=>
string(1) "1"
View
3 ext/pdo/tests/bug_43130.phpt
@@ -16,6 +16,9 @@ if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.dirname(__FILE_
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
+if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql')
+ $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, 1);
+
$db->exec("CREATE TABLE test (a varchar(100), b varchar(100), c varchar(100))");
for ($i = 0; $i < 5; $i++) {
View
11 ext/pdo/tests/bug_43663.phpt
@@ -2,7 +2,12 @@
PDO Common: Bug #43663 (__call on classes derived from PDO)
--SKIPIF--
<?php # vim:ft=php
-if (!extension_loaded('pdo_sqlite')) die('skip no pdo_sqlite');
+if (!extension_loaded('pdo')) die('skip');
+if (!extension_loaded('pdo_sqlite')) die('skip');
+$dir = getenv('REDIR_TEST_DIR');
+if (false == $dir) die('skip no driver');
+require_once $dir . 'pdo_test.inc';
+PDOTest::skip();
?>
--FILE--
<?php
@@ -14,6 +19,10 @@ class test extends PDO{
echo "Called foo in ".__CLASS__."\n";
}
}
+
+if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.dirname(__FILE__) . '/../../pdo/tests/');
+require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
+
$a = new test('sqlite::memory:');
$a->foo();
$a->bar();
View
10 ext/pdo/tests/bug_44159.phpt
@@ -1,12 +1,16 @@
--TEST--
Bug #44159 (Crash: $pdo->setAttribute(PDO::STATEMENT_ATTR_CLASS, NULL))
--SKIPIF--
-<?php
-if (!extension_loaded('pdo_sqlite')) die('skip no pdo_sqlite');
+<?php # vim:ft=php
+if (!extension_loaded('pdo')) die('skip PDO not available');
+try {
+ $pdo = new PDO("sqlite:/tmp/foo.db");
+} catch (Exception $e) {
+ die("skip PDP_SQLITE not available");
+}
?>
--FILE--
<?php
-
$pdo = new PDO("sqlite:/tmp/foo.db");
$attrs = array(PDO::ATTR_STATEMENT_CLASS, PDO::ATTR_STRINGIFY_FETCHES, PDO::NULL_TO_STRING);
View
1 ext/pdo/tests/pdo.inc
@@ -7,5 +7,4 @@ function set_sql($name, $query)
$GLOBALS['SQL'][$name] = $query;
}
}
-
?>
View
10 ext/pdo/tests/pdo_017.phpt
@@ -16,7 +16,8 @@ try {
}
if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') {
- if (false === PDOTest::detect_transactional_mysql_engine($db)) {
+ require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+ if (false === MySQLPDOTest::detect_transactional_mysql_engine($db)) {
die('skip your mysql configuration does not support working transactions');
}
}
@@ -28,14 +29,15 @@ require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') {
- $suf = ' Type=' . PDOTest::detect_transactional_mysql_engine($db);
+ require_once(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+ $suf = ' ENGINE=' . MySQLPDOTest::detect_transactional_mysql_engine($db);
} else {
$suf = '';
}
$db->exec('CREATE TABLE test(id INT NOT NULL PRIMARY KEY, val VARCHAR(10))'.$suf);
-$db->exec("INSERT INTO test VALUES(1, 'A')");
-$db->exec("INSERT INTO test VALUES(2, 'B')");
+$db->exec("INSERT INTO test VALUES(1, 'A')");
+$db->exec("INSERT INTO test VALUES(2, 'B')");
$db->exec("INSERT INTO test VALUES(3, 'C')");
$delete = $db->prepare('DELETE FROM test');
View
2 ext/pdo/tests/pdo_025.phpt
@@ -110,4 +110,4 @@ object(Test)#%d (3) {
}
===FAIL===
-Fatal error: Cannot access protected property Fail::$id in %spdo_025.php on line %d
+Fatal error: Cannot access protected property Fail::$id in %spdo_025.php on line %d%a
View
26 ext/pdo/tests/pdo_test.inc
@@ -19,7 +19,7 @@ if (getenv('PDOTEST_DSN') === false) {
class PDOTest {
// create an instance of the PDO driver, based on
// the current environment
- static function factory($classname = 'PDO') {
+ static function factory($classname = 'PDO', $drop_test_tables = true) {
$dsn = getenv('PDOTEST_DSN');
$user = getenv('PDOTEST_USER');
$pass = getenv('PDOTEST_PASS');
@@ -32,7 +32,7 @@ class PDOTest {
if ($user === false) $user = NULL;
if ($pass === false) $pass = NULL;
-
+
$db = new $classname($dsn, $user, $pass, $attr);
if (!$db) {
@@ -46,10 +46,12 @@ class PDOTest {
'test2',
'classtypes'
);
- foreach ($test_tables as $table) {
- $db->exec("DROP TABLE $table");
+ if ($drop_test_tables) {
+ foreach ($test_tables as $table) {
+ $db->exec("DROP TABLE $table");
+ }
}
-
+
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$db->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
$db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, true);
@@ -64,15 +66,6 @@ class PDOTest {
}
}
- 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 test_factory($file) {
$data = file_get_contents($file);
$data = preg_replace('/^.*--REDIRECTTEST--/s', '', $data);
@@ -83,7 +76,4 @@ class PDOTest {
return self::factory();
}
}
-
-
-
-?>
+?>
View
6 ext/pdo_mysql/CREDITS
@@ -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
234 ext/pdo_mysql/config.m4
@@ -2,139 +2,142 @@ 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=$PDO_MYSQL_DIR/$1
- break 2
- fi
- done
-])
-
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])
-
- 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;
+ PHP_MYSQLND_ENABLED=yes
+
+ 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
- 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])
+ 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_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
+ 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
- PDO_MYSQL_LIB_DIR=$PDO_MYSQL_DIR/$PHP_LIBDIR
+ 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 -r "$PDO_MYSQL_LIB_DIR"; then
- AC_MSG_RESULT([libs under $PDO_MYSQL_LIB_DIR; seems promising])
+ 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([can not find it])
- AC_MSG_ERROR([Unable to find your mysql installation])
- fi
+ 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
- PHP_ADD_LIBRARY_WITH_PATH($PDO_MYSQL_LIBNAME, $PDO_MYSQL_LIB_DIR, PDO_MYSQL_SHARED_LIBADD)
- PHP_ADD_INCLUDE($PDO_MYSQL_INC_DIR)
- PDO_MYSQL_INCLUDE=-I$PDO_MYSQL_INC_DIR
- 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
- if test "$PHP_MYSQL_SOCK" != "no" && test "$PHP_MYSQL_SOCK" != "yes"; then
- AC_DEFINE_UNQUOTED(PDO_MYSQL_UNIX_ADDR, "$PHP_MYSQL_SOCK", [ ])
- else
AC_DEFINE_UNQUOTED(PDO_MYSQL_UNIX_ADDR, "$PDO_MYSQL_SOCKET", [ ])
- 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
+ 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
- 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
+ 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],
[
@@ -153,16 +156,19 @@ if test "$PHP_PDO_MYSQL" != "no"; then
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)
+ if test "$PHP_MYSQL" = "mysqlnd"; then
+ PHP_ADD_EXTENSION_DEP(pdo_mysql, mysqlnd)
+ fi
])
PDO_MYSQL_MODULE_TYPE=external
- PHP_SUBST(PDO_MYSQL_SHARED_LIBADD)
PHP_SUBST_OLD(PDO_MYSQL_MODULE_TYPE)
fi
-fi
dnl vim: se ts=2 sw=2 et:
View
14 ext/pdo_mysql/config.w32
@@ -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
317 ext/pdo_mysql/mysql_driver.c
@@ -14,6 +14,7 @@
+----------------------------------------------------------------------+
| Author: George Schlossnagle <george@omniti.com> |
| Wez Furlong <wez@php.net> |
+ | Johannes Schlueter <johannes@mysql.com> |
+----------------------------------------------------------------------+
*/
@@ -30,25 +31,38 @@
#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;
pdo_error_type *pdo_err;
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,7 @@ int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int lin
einfo = &H->einfo;
}
-#if HAVE_MYSQL_STMT_PREPARE
+#if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
if (S && S->stmt) {
einfo->errcode = mysql_stmt_errno(S->stmt);
}
@@ -77,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.",
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
@@ -106,20 +126,23 @@ int _pdo_mysql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int lin
#endif
if (!dbh->methods) {
+ 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);
}
-/* 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;
@@ -132,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);
@@ -151,21 +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;
@@ -174,7 +206,7 @@ static int mysql_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len,
goto end;
}
-#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;
@@ -189,15 +221,15 @@ 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))) {
pdo_mysql_error(dbh);
if (nsql) {
efree(nsql);
}
- return 0;
+ PDO_DBG_RETURN(0);
}
if (mysql_stmt_prepare(S->stmt, sql, sql_len)) {
@@ -213,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);
@@ -222,115 +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;
-
- 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:
- case PDO_ATTR_EMULATE_PREPARES:
- ((pdo_mysql_db_handle *)dbh->driver_data)->emulate_prepare = Z_BVAL_P(val);
- return 1;
- default:
- return 0;
+ /* 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);
+ 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);
@@ -343,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;
@@ -387,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,
@@ -422,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;
@@ -436,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
@@ -447,46 +584,68 @@ 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;
+
+#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, 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 ((PG(open_basedir) && PG(open_basedir)[0] != '\0') || PG(safe_mode)) {
+#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;
}
@@ -503,7 +662,7 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
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)) {
@@ -533,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;
@@ -543,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;
}
@@ -569,7 +744,7 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
dbh->methods = &mysql_methods;
- return ret;
+ PDO_DBG_RETURN(ret);
}
/* }}} */
View
695 ext/pdo_mysql/mysql_statement.c
@@ -14,6 +14,7 @@
+----------------------------------------------------------------------+
| Author: George Schlossnagle <george@omniti.com> |
| Wez Furlong <wez@php.net> |
+ | Johannes Schlueter <johannes@mysql.com> |
+----------------------------------------------------------------------+
*/
@@ -31,11 +32,24 @@
#include "php_pdo_mysql.h"
#include "php_pdo_mysql_int.h"
+#ifdef PDO_USE_MYSQLND
+# define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_mysqlnd(stmt TSRMLS_CC)
+# define pdo_free_bound_result(res) zval_dtor(res.zv)
+# define pdo_mysql_stmt_close(stmt) mysqlnd_stmt_close(stmt, 0)
+#else
+# define pdo_mysql_stmt_execute_prepared(stmt) pdo_mysql_stmt_execute_prepared_libmysql(stmt TSRMLS_CC)
+# define pdo_free_bound_result(res) efree(res.buffer)
+# define pdo_mysql_stmt_close(stmt) mysql_stmt_close(stmt)
+#endif
+
-static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
+
+static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
{
pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+ PDO_DBG_ENTER("pdo_mysql_stmt_dtor");
+ PDO_DBG_INF_FMT("stmt=%p", S->stmt);
if (S->result) {
/* free the resource */
mysql_free_result(S->result);
@@ -45,29 +59,42 @@ static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
pefree(S->einfo.errmsg, stmt->dbh->is_persistent);
S->einfo.errmsg = NULL;
}
-#if HAVE_MYSQL_STMT_PREPARE
+#if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
if (S->stmt) {
- mysql_stmt_close(S->stmt);
+ pdo_mysql_stmt_close(S->stmt);
S->stmt = NULL;
}
+#endif /* HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND */
+
+#ifndef PDO_USE_MYSQLND
if (S->params) {
efree(S->params);
+ }
+ if (S->in_null) {
efree(S->in_null);
+ }
+ if (S->in_length) {
efree(S->in_length);
}
+
+#endif /* PDO_USE_MYSQLND */
+
+#ifdef HAVE_MYSQL_STMT_PREPARE
if (S->bound_result)
{
int i;
for (i = 0; i < stmt->column_count; i++) {
- efree(S->bound_result[i].buffer);
+ pdo_free_bound_result(S->bound_result[i]);
}
efree(S->bound_result);
efree(S->out_null);
efree(S->out_length);
}
-#endif
-#if HAVE_MYSQL_NEXT_RESULT
+#endif /* HAVE_MYSQL_STMT_PREPARE */
+
+
+#if HAVE_MYSQL_NEXT_RESULT || PDO_USE_MYSQLND
if (S->H->server) {
while (mysql_more_results(S->H->server)) {
MYSQL_RES *res;
@@ -80,132 +107,199 @@ static int pdo_mysql_stmt_dtor(pdo_stmt_t *stmt TSRMLS_DC)
mysql_free_result(res);
}
}
+ }
+#endif /* HAVE_MYSQL_NEXT_RESULT || PDO_USE_MYSQLND */
+#if PDO_USE_MYSQLND
+ if (!S->stmt && S->current_data) {
+ free(S->current_data);
}
-#endif
+#endif /* PDO_USE_MYSQLND */
+
efree(S);
- return 1;
+ PDO_DBG_RETURN(1);
}
+/* }}} */
-static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
+static void pdo_mysql_stmt_set_row_count(pdo_stmt_t *stmt) /* {{{ */
{
- pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
- pdo_mysql_db_handle *H = S->H;
my_ulonglong row_count;
-#if HAVE_MYSQL_STMT_PREPARE
- int i;
+ pdo_mysql_stmt *S = stmt->driver_data;
+ row_count = mysql_stmt_affected_rows(S->stmt);
+ if (row_count != (my_ulonglong)-1) {
+ stmt->row_count = row_count;
+ }
+}
+/* }}} */
- if (S->stmt) {
- /* (re)bind the parameters */
- if (mysql_stmt_bind_param(S->stmt, S->params)) {
- pdo_mysql_error_stmt(stmt);
- return 0;
- }
+#ifdef HAVE_MYSQL_STMT_PREPARE
+static int pdo_mysql_stmt_execute_prepared_libmysql(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
+{
+ pdo_mysql_stmt *S = stmt->driver_data;
+ pdo_mysql_db_handle *H = S->H;
- if (mysql_stmt_execute(S->stmt)) {
- pdo_mysql_error_stmt(stmt);
- return 0;
+ PDO_DBG_ENTER("pdo_mysql_stmt_execute_prepared_libmysql");
+
+ /* (re)bind the parameters */
+ if (mysql_stmt_bind_param(S->stmt, S->params) || mysql_stmt_execute(S->stmt)) {
+ if (S->params) {
+ efree(S->params);
+ S->params = 0;
}
+ pdo_mysql_error_stmt(stmt);
+ if (mysql_stmt_errno(S->stmt) == 2057) {
+ /* CR_NEW_STMT_METADATA makes the statement unusable */
+ S->stmt = NULL;
+ }
+ PDO_DBG_RETURN(0);
+ }
- if (!S->result) {
- /* figure out the result set format, if any */
- S->result = mysql_stmt_result_metadata(S->stmt);
- if (S->result) {
- int calc_max_length = H->buffered && S->max_length == 1;
+ if (!S->result) {
+ int i;
+
+ /* figure out the result set format, if any */
+ S->result = mysql_stmt_result_metadata(S->stmt);
+ if (S->result) {
+ int calc_max_length = H->buffered && S->max_length == 1;
+ S->fields = mysql_fetch_fields(S->result);
+ if (S->bound_result) {
+ int i;
+ for (i = 0; i < stmt->column_count; i++) {
+ efree(S->bound_result[i].buffer);
+ }
+ efree(S->bound_result);
+ efree(S->out_null);
+ efree(S->out_length);
+ }
- S->fields = mysql_fetch_fields(S->result);
-
- if (S->bound_result) {
- int i;
- for (i = 0; i < stmt->column_count; i++) {
- efree(S->bound_result[i].buffer);
- }
- efree(S->bound_result);
- efree(S->out_null);
- efree(S->out_length);
+ stmt->column_count = (int)mysql_num_fields(S->result);
+ S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
+ S->out_null = ecalloc(stmt->column_count, sizeof(my_bool));
+ S->out_length = ecalloc(stmt->column_count, sizeof(unsigned long));
+
+ /* summon memory to hold the row */
+ for (i = 0; i < stmt->column_count; i++) {
+ if (calc_max_length && S->fields[i].type == FIELD_TYPE_BLOB) {
+ my_bool on = 1;
+ mysql_stmt_attr_set(S->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &on);
+ calc_max_length = 0;
+ }
+ switch (S->fields[i].type) {
+ case FIELD_TYPE_INT24:
+ S->bound_result[i].buffer_length = MAX_MEDIUMINT_WIDTH + 1;
+ break;
+ case FIELD_TYPE_LONG:
+ S->bound_result[i].buffer_length = MAX_INT_WIDTH + 1;
+ break;
+ case FIELD_TYPE_LONGLONG:
+ S->bound_result[i].buffer_length = MAX_BIGINT_WIDTH + 1;
+ break;
+ case FIELD_TYPE_TINY:
+ S->bound_result[i].buffer_length = MAX_TINYINT_WIDTH + 1;
+ break;
+ case FIELD_TYPE_SHORT:
+ S->bound_result[i].buffer_length = MAX_SMALLINT_WIDTH + 1;
+ break;
+ default:
+ S->bound_result[i].buffer_length =
+ S->fields[i].max_length? S->fields[i].max_length:
+ S->fields[i].length;
+ /* work-around for longtext and alike */
+ if (S->bound_result[i].buffer_length > H->max_buffer_size) {
+ S->bound_result[i].buffer_length = H->max_buffer_size;
+ }
}
- stmt->column_count = (int)mysql_num_fields(S->result);
- S->bound_result = ecalloc(stmt->column_count, sizeof(MYSQL_BIND));
- S->out_null = ecalloc(stmt->column_count, sizeof(my_bool));
- S->out_length = ecalloc(stmt->column_count, sizeof(unsigned long));
-
- /* summon memory to hold the row */
- for (i = 0; i < stmt->column_count; i++) {
- if (calc_max_length && S->fields[i].type == FIELD_TYPE_BLOB) {
- my_bool on = 1;
- mysql_stmt_attr_set(S->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &on);
- calc_max_length = 0;
- }
- switch (S->fields[i].type) {
- case FIELD_TYPE_INT24:
- S->bound_result[i].buffer_length = MAX_MEDIUMINT_WIDTH;
- break;
- case FIELD_TYPE_LONG:
- S->bound_result[i].buffer_length = MAX_INT_WIDTH;
- break;
- case FIELD_TYPE_LONGLONG:
- S->bound_result[i].buffer_length = MAX_BIGINT_WIDTH;
- break;
- case FIELD_TYPE_TINY:
- S->bound_result[i].buffer_length = MAX_TINYINT_WIDTH;
- break;
- case FIELD_TYPE_SHORT:
- S->bound_result[i].buffer_length = MAX_SMALLINT_WIDTH;
- break;
- default:
- S->bound_result[i].buffer_length =
- S->fields[i].max_length? S->fields[i].max_length:
- S->fields[i].length;
- /* work-around for longtext and alike */
- if (S->bound_result[i].buffer_length > H->max_buffer_size) {
- S->bound_result[i].buffer_length = H->max_buffer_size;
- }
- }
-#if 0
- printf("%d: max_length=%d length=%d buffer_length=%d type=%d\n",
- i,
- S->fields[i].max_length,
- S->fields[i].length,
- S->bound_result[i].buffer_length,
- S->fields[i].type
- );
-#endif
-
- /* there are cases where the length reported by mysql is too short.
- * eg: when describing a table that contains an enum column. Since
- * we have no way of knowing the true length either, we'll bump up
- * our buffer size to a reasonable size, just in case */
- if (S->fields[i].max_length == 0 && S->bound_result[i].buffer_length < 128 && MYSQL_TYPE_VAR_STRING) {
- S->bound_result[i].buffer_length = 128;
- }
+ /* there are cases where the length reported by mysql is too short.
+ * eg: when describing a table that contains an enum column. Since
+ * we have no way of knowing the true length either, we'll bump up
+ * our buffer size to a reasonable size, just in case */
+ if (S->fields[i].max_length == 0 && S->bound_result[i].buffer_length < 128 && MYSQL_TYPE_VAR_STRING) {
+ S->bound_result[i].buffer_length = 128;
+ }
- S->out_length[i] = 0;
+ S->out_length[i] = 0;
- S->bound_result[i].buffer = emalloc(S->bound_result[i].buffer_length);
- S->bound_result[i].is_null = &S->out_null[i];
- S->bound_result[i].length = &S->out_length[i];
- S->bound_result[i].buffer_type = MYSQL_TYPE_STRING;
- }
+ S->bound_result[i].buffer = emalloc(S->bound_result[i].buffer_length);
+ S->bound_result[i].is_null = &S->out_null[i];
+ S->bound_result[i].length = &S->out_length[i];
+ S->bound_result[i].buffer_type = MYSQL_TYPE_STRING;
+ }
- if (mysql_stmt_bind_result(S->stmt, S->bound_result)) {
- pdo_mysql_error_stmt(stmt);
- return 0;
- }
+ if (mysql_stmt_bind_result(S->stmt, S->bound_result)) {
+ pdo_mysql_error_stmt(stmt);
+ PDO_DBG_RETURN(0);
+ }
- /* if buffered, pre-fetch all the data */
- if (H->buffered) {
- mysql_stmt_store_result(S->stmt);
- }
+ /* if buffered, pre-fetch all the data */
+ if (H->buffered) {
+ mysql_stmt_store_result(S->stmt);
}
}
+ }
+
+ pdo_mysql_stmt_set_row_count(stmt);
+ PDO_DBG_RETURN(1);
+}
+/* }}} */
+#endif
- row_count = mysql_stmt_affected_rows(S->stmt);
- if (row_count != (my_ulonglong)-1) {
- stmt->row_count = row_count;
+#ifdef PDO_USE_MYSQLND
+static int pdo_mysql_stmt_execute_prepared_mysqlnd(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
+{
+ pdo_mysql_stmt *S = stmt->driver_data;
+ pdo_mysql_db_handle *H = S->H;
+ unsigned int i;
+
+ PDO_DBG_ENTER("pdo_mysql_stmt_execute_prepared_mysqlnd");
+
+ if (mysql_stmt_execute(S->stmt)) {
+ pdo_mysql_error_stmt(stmt);
+ PDO_DBG_RETURN(0);
+ }
+
+ if (S->result) {
+ /* TODO: add a test to check if we really have zvals here... */
+ mysql_free_result(S->result);
+ S->result = NULL;
+ }
+
+ /* for SHOW/DESCRIBE and others the column/field count is not available before execute */
+ stmt->column_count = S->stmt->field_count;
+ for (i = 0; i < stmt->column_count; i++) {
+ mysqlnd_stmt_bind_one_result(S->stmt, i);
+ }
+
+ S->result = mysqlnd_stmt_result_metadata(S->stmt);
+ if (S->result) {
+ S->fields = mysql_fetch_fields(S->result);
+ /* if buffered, pre-fetch all the data */
+ if (H->buffered) {
+ if (mysql_stmt_store_result(S->stmt)) {
+ PDO_DBG_RETURN(0);
+ }
}
- return 1;
}
+
+ pdo_mysql_stmt_set_row_count(stmt);
+ PDO_DBG_RETURN(1);
+}
+/* }}} */
#endif
+
+static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
+{
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+ pdo_mysql_db_handle *H = S->H;
+ my_ulonglong row_count;
+ PDO_DBG_ENTER("pdo_mysql_stmt_execute");
+ PDO_DBG_INF_FMT("stmt=%p", S->stmt);
+
+#if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
+ if (S->stmt) {
+ PDO_DBG_RETURN(pdo_mysql_stmt_execute_prepared(stmt));
+ }
+#endif
+
/* ensure that we free any previous unfetched results */
if (S->result) {
mysql_free_result(S->result);
@@ -214,7 +308,7 @@ static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
if (mysql_real_query(H->server, stmt->active_query_string, stmt->active_query_stringlen) != 0) {
pdo_mysql_error_stmt(stmt);
- return 0;
+ PDO_DBG_RETURN(0);
}
row_count = mysql_affected_rows(H->server);
@@ -228,34 +322,88 @@ static int pdo_mysql_stmt_execute(pdo_stmt_t *stmt TSRMLS_DC)
}
if (NULL == S->result) {
pdo_mysql_error_stmt(stmt);
- return 0;
+ PDO_DBG_RETURN(0);
}
stmt->row_count = mysql_num_rows(S->result);
+ stmt->column_count = (int) mysql_num_fields(S->result);
+ S->fields = mysql_fetch_fields(S->result);
- if (!stmt->executed) {
- stmt->column_count = (int) mysql_num_fields(S->result);
- S->fields = mysql_fetch_fields(S->result);
- }
} else {
/* this was a DML or DDL query (INSERT, UPDATE, DELETE, ... */
stmt->row_count = row_count;
}
- return 1;
+ PDO_DBG_RETURN(1);
}
+/* {{{ */
-static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
+static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
{
-#if HAVE_MYSQL_NEXT_RESULT
+#if HAVE_MYSQL_NEXT_RESULT || PDO_USE_MYSQLND
pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
pdo_mysql_db_handle *H = S->H;
my_ulonglong row_count;
int ret;
+ PDO_DBG_ENTER("pdo_mysql_stmt_next_rowset");
+ PDO_DBG_INF_FMT("stmt=%p", S->stmt);
- /* ensure that we free any previous unfetched results */
+#if PDO_USE_MYSQLND
+ if (!H->emulate_prepare) {
+ if (!mysqlnd_stmt_more_results(S->stmt)) {
+ PDO_DBG_RETURN(0);
+ }
+ if (mysqlnd_stmt_next_result(S->stmt)) {
+ PDO_DBG_RETURN(0);
+ }
+
+ if (!mysqlnd_stmt_more_results(S->stmt)) {
+ /*
+ MySQL gives us n + 1 result sets for
+ CALL proc() and n result sets returned by the proc itself.
+ Result set n + 1 is about the procedure call itself.
+ As the PDO emulation does not return it, we skip it as well
+ */
+ PDO_DBG_RETURN(0);
+ }
+
+ /* TODO - this code is stolen from execute() - see above */
+ if (S->result) {
+ mysql_free_result(S->result);
+ S->result = NULL;
+ }
+ {
+ /* for SHOW/DESCRIBE and others the column/field count is not available before execute */
+ unsigned int i;
+
+ stmt->column_count = S->stmt->field_count;
+ for (i = 0; i < stmt->column_count; i++) {
+ mysqlnd_stmt_bind_one_result(S->stmt, i);
+ }
+ }
+
+ S->result = mysqlnd_stmt_result_metadata(S->stmt);
+ if (S->result) {
+ S->fields = mysql_fetch_fields(S->result);
+
+ /* if buffered, pre-fetch all the data */
+ if (H->buffered) {
+ if (mysql_stmt_store_result(S->stmt))
+ PDO_DBG_RETURN(1);
+ }
+ }
+ row_count = mysql_stmt_affected_rows(S->stmt);
+ if (row_count != (my_ulonglong)-1) {
+ stmt->row_count = row_count;
+ }
+ PDO_DBG_RETURN(1);
+ }
+#endif
+
+/* ensure that we free any previous unfetched results */
#if HAVE_MYSQL_STMT_PREPARE
if (S->stmt) {
+ stmt->column_count = (int)mysql_num_fields(S->result);
mysql_stmt_free_result(S->stmt);
}
#endif
@@ -268,10 +416,10 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
if (ret > 0) {
pdo_mysql_error_stmt(stmt);
- return 0;
+ PDO_DBG_RETURN(0);
} else if (ret < 0) {
/* No more results */
- return 0;
+ PDO_DBG_RETURN(0);
} else {
if (!H->buffered) {
S->result = mysql_use_result(H->server);
@@ -280,65 +428,103 @@ static int pdo_mysql_stmt_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
S->result = mysql_store_result(H->server);
if ((my_ulonglong)-1 == (row_count = mysql_affected_rows(H->server))) {
pdo_mysql_error_stmt(stmt);
- return 0;
+ PDO_DBG_RETURN(0);
}
}
if (NULL == S->result) {
- return 0;
+ PDO_DBG_RETURN(0);
}
stmt->row_count = row_count;
stmt->column_count = (int) mysql_num_fields(S->result);
S->fields = mysql_fetch_fields(S->result);
- return 1;
+ PDO_DBG_RETURN(1);
}
#else
strcpy(stmt->error_code, "HYC00");
- return 0;
-#endif
+ PDO_DBG_RETURN(0);
+#endif /* HAVE_MYSQL_STMT_PREPARE */
}
+/* }}} */
+
+
+static const char * const pdo_param_event_names[] =
+{
+ "PDO_PARAM_EVT_ALLOC",
+ "PDO_PARAM_EVT_FREE",
+ "PDO_PARAM_EVT_EXEC_PRE",
+ "PDO_PARAM_EVT_EXEC_POST",
+ "PDO_PARAM_EVT_FETCH_PRE",
+ "PDO_PARAM_EVT_FETCH_POST",
+ "PDO_PARAM_EVT_NORMALIZE",
+};
static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *param,
- enum pdo_param_event event_type TSRMLS_DC)
+ enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
{
-#if HAVE_MYSQL_STMT_PREPARE
- pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
- MYSQL_BIND *b;
+#ifndef PDO_USE_MYSQLND
+ PDO_MYSQL_PARAM_BIND *b;
+#endif
+#if HAVE_MYSQL_STMT_PREPARE || PDO_USE_MYSQLND
+ pdo_mysql_stmt *S = (pdo_mysql_stmt*)stmt->driver_data;
+ PDO_DBG_ENTER("pdo_mysql_stmt_param_hook");
+ PDO_DBG_INF_FMT("stmt=%p", S->stmt);
+ PDO_DBG_INF_FMT("event = %s", pdo_param_event_names[event_type]);
if (S->stmt && param->is_param) {
switch (event_type) {
case PDO_PARAM_EVT_ALLOC:
/* sanity check parameter number range */
if (param->paramno < 0 || param->paramno >= S->num_params) {
strcpy(stmt->error_code, "HY093");
- return 0;
+ PDO_DBG_RETURN(0);
}
+ S->params_given++;
+
+#ifndef PDO_USE_MYSQLND
b = &S->params[param->paramno];
param->driver_data = b;
b->is_null = &S->in_null[param->paramno];
b->length = &S->in_length[param->paramno];
- return 1;
+ /* recall how many parameters have been provided */
+#endif
+ PDO_DBG_RETURN(1);
case PDO_PARAM_EVT_EXEC_PRE:
- b = (MYSQL_BIND*)param->driver_data;
+ if (S->params_given < S->num_params) {
+ /* too few parameter bound */
+ PDO_DBG_ERR("too few parameters bound");
+ strcpy(stmt->error_code, "HY093");
+ PDO_DBG_RETURN(0);
+ }
- *b->is_null = 0;
- if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
+#if PDO_USE_MYSQLND
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
Z_TYPE_P(param->parameter) == IS_NULL) {
- *b->is_null = 1;
- b->buffer_type = MYSQL_TYPE_STRING;
- b->buffer = NULL;
- b->buffer_length = 0;
- *b->length = 0;
- return 1;
+ mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_NULL);
+ PDO_DBG_RETURN(1);
}
+#else
+ b = (PDO_MYSQL_PARAM_BIND*)param->driver_data;
+ *b->is_null = 0;
+ if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_NULL ||
+ Z_TYPE_P(param->parameter) == IS_NULL) {
+ *b->is_null = 1;
+ b->buffer_type = MYSQL_TYPE_STRING;
+ b->buffer = NULL;
+ b->buffer_length = 0;
+ *b->length = 0;
+ PDO_DBG_RETURN(1);
+ }
+#endif /* PDO_USE_MYSQLND */
switch (PDO_PARAM_TYPE(param->param_type)) {
case PDO_PARAM_STMT:
- return 0;
+ PDO_DBG_RETURN(0);
case PDO_PARAM_LOB:
+ PDO_DBG_INF("PDO_PARAM_LOB");
if (Z_TYPE_P(param->parameter) == IS_RESOURCE) {
php_stream *stm;
php_stream_from_zval_no_verify(stm, &param->parameter);
@@ -357,150 +543,239 @@ static int pdo_mysql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_da
default:
;
}
-
+
+#if PDO_USE_MYSQLND
+ /* Is it really correct to check the zval's type? - But well, that's what the old code below does, too */
+ PDO_DBG_INF_FMT("param->parameter->type=%d", Z_TYPE_P(param->parameter));
+ switch (Z_TYPE_P(param->parameter)) {
+ case IS_STRING:
+ mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_VAR_STRING);
+ break;
+ case IS_LONG:
+#if SIZEOF_LONG==8
+ mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_LONGLONG);
+#elif SIZEOF_LONG==4
+ mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_LONG);
+#endif /* SIZEOF_LONG */
+ break;
+ case IS_DOUBLE:
+ mysqlnd_stmt_bind_one_param(S->stmt, param->paramno, param->parameter, MYSQL_TYPE_DOUBLE);
+ break;
+ default:
+ PDO_DBG_RETURN(0);
+ }
+
+ PDO_DBG_RETURN(1);
+#else
+ PDO_DBG_INF_FMT("param->parameter->type=%d", Z_TYPE_P(param->parameter));
switch (Z_TYPE_P(param->parameter)) {
case IS_STRING:
b->buffer_type = MYSQL_TYPE_STRING;
b->buffer = Z_STRVAL_P(param->parameter);
b->buffer_length = Z_STRLEN_P(param->parameter);
*b->length = Z_STRLEN_P(param->parameter);
- return 1;
+ PDO_DBG_RETURN(1);
case IS_LONG:
b->buffer_type = MYSQL_TYPE_LONG;