Commit graph

449 commits

Author SHA1 Message Date
Nikita Popov
caa710037e Rewrite PDO result binding
Instead of requiring the type to be determined in advance by the
describer function and then requiring get_col to return a buffer
of appropriate type, allow get_col to return an arbitrary zval.
See UPGRADING.INTERNALS for a more detailed description of the
change.

This makes the result fetching simpler, more efficient and more
flexible. The general possibility already existed via the special
PDO_PARAM_ZVAL type, but the usage was very inconvenient and/or
inefficient. Now it's possible to easily implement behavior like
"return int if it fits, otherwise string" and to avoid any kind
of complex management of temporary buffers.

This also fixes bug #40913 (our second highest voted bug of all
time, for some reason). PARAM_LOB result bindings will now
consistently return a stream resource, independently of the used
database driver.

I've tried my best to update all PDO drivers for this change, but
some of the changes may be broken, as I cannot test or even build
some of these drivers (in particular PDO dblib and PDO oci).
Fixes are appreciated -- a working CI setup would be even more
appreciated ;)
2020-12-22 15:56:34 +01:00
Nikita Popov
7a5cc7aa67 Add basic libmysqlclient CI job
This tests that mysqli and pdo_mysql build against libmysqlclient,
and that tests pass for pdo_mysql. mysqli has too many test failures.

This is not an officially supported configuration.
2020-12-18 12:52:54 +01:00
Nikita Popov
b88a493aaa PDO MySQL: Make test libmysql compatible 2020-12-18 11:28:15 +01:00
Nikita Popov
c18b1aea28 PDO MySQL: Use native types for results
Previously, PDO MySQL only fetched data as native int/float if
native prepared statements were used. This patch updates PDO to
have the same behavior for emulated prepared statements, and thus
removes the largest remaining discrepancy between these two modes.

Note that PDO already has a ATTR_STRINGIFY_FETCHES option to control
whether native types are desired or not. The previous output can
be restored by enabling this option.

Most of the tests make use of that option, because this allows the
tests to work under libmysqlclient as well, which currently always
returns string results (independently of whether native or emulated
PS are used).
2020-12-17 10:54:34 +01:00
Nikita Popov
cfe2b36a6d Fix ATTR_ORACLE_NULLS with PARAM_ZVAL
PARAM_ZVAL with a STR result should be treated the same way as
PARAM_STR in this regard.
2020-12-15 17:12:46 +01:00
Christoph M. Becker
15d9c42070 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Drop pdo_mysql_prepare_load_data.phpt
2020-12-14 18:27:53 +01:00
Christoph M. Becker
10c9d615de Drop pdo_mysql_prepare_load_data.phpt
Like the test title and some comments in this test describe, this test
was supposed to have `::prepare()` failing because `LOAD DATA INFILE`
would not be supported as prepared statement, and then the test checks
whether follow-up queries would succeed.  However, `LOAD DATA INFILE`
is supported for prepared statements at least on Windows with mysqlnd,
so the test does no longer test what it is supposed to do.  Therefore,
we drop it.

Closes GH-6509.
2020-12-14 18:26:12 +01:00
Nikita Popov
ccb7f1c7d8 Fixed bug #79132
Following cmb's suggestion and replacing the counter with a check
against the bound_params HT, which ensures that both cannot go
out of sync.
2020-12-11 16:35:03 +01:00
Nikita Popov
7a89157f8c PDO MySQL: Fix nextRowset() on libmysqlclient with native PS
The logic after next_result should match the one after execute.
This was the case for mysqlnd but not libmysqlclient, which used
the non-PS logic.
2020-12-11 14:48:44 +01:00
Nikita Popov
81f012a164 PDO MySQL: Don't skip two LOCAL_INFILE tests with libmysqlclient 2020-12-11 14:48:43 +01:00
Nikita Popov
e4e88bd7e3 PDO MySQL: Unskip bug_41125.phpt
This test was always skipped (leftover debug statement?)

Contrary to the comments in the test and the test expectation,
this actually works fine.
2020-12-11 13:04:20 +01:00
Nikita Popov
ad8eb116d8 Fixed bug #67004
Repeated execute() with native PS failed to release the previous
result set on libmysqlclient.

Move freeing the result set into a common location.
2020-12-11 12:52:59 +01:00
Nikita Popov
4e51059d52 PDO MySQL: Fix libmysql option test
The fact that getAttribute() fails for various libmysqlclient-only
options is a known issue, and the test was taking that into account.
However, the change of the default error mode broke the handling.
We need to handle the exceptions now.
2020-12-11 12:20:02 +01:00
Dharman
54a63d91b8 Fix test cases for MariaDB
And remove unnecessary try-catch.

Closes GH-6505.
2020-12-11 09:53:20 +01:00
Nikita Popov
9e3ba775b7 Fixed bug #72368
Generate a param count mismatch error even if the query contains
no placeholders.

Additionally we shouldn't HANDLE errors from pdo_parse_params,
which are always reported via raise_impl_error. Doing so results
in duplicate error messages.
2020-12-10 16:53:08 +01:00
Nikita Popov
15b51a215a Fixed bug #79131
When a driver reports an error during EVT_ALLOC (and some over EVTs),
make sure we handle it as usual, i.e. warn or throw.

This requires some adjustments in PDO PgSQL to stop manually doing
this through an impl error.

Unfortunately the PDO PgSQL error messages regress because of this,
as they now include a completely arbitrary error code. There doesn't
seem to be an ability to skip it right now.
2020-12-10 15:53:23 +01:00
Nikita Popov
288581fade Fixed bug #79872 by improving error message
The actual behavior here is correct, but the previous error
message was misleading, as neither fetchAll() nor buffered queries
would help in this situation. Instead it is necessary to consume
all rowsets, which can be done by either unsetting the statement
or calling closeCursor().
2020-12-10 11:46:29 +01:00
Nikita Popov
d63aedd173 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fixed bug #76815
2020-12-10 11:24:19 +01:00
Nikita Popov
e450621f5e Fixed bug #76815
When we receive an error while reading a result set, we should
assume that no more result sets are available. libmysqlclient
implements the same behavior.
2020-12-10 11:23:41 +01:00
Nikita Popov
9b678bc4d5 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fixed bug #71145
2020-12-10 10:31:36 +01:00
Nikita Popov
4922049213 Fixed bug #71145
Consume any additional result sets when running INIT_COMMAND.
2020-12-10 10:28:10 +01:00
Nikita Popov
f3d5877845 Backport fix for bug #70066
Given the number of duplicates this bug report had, it seems
worthwhile to fix this on PHP-7.4 as well.

Cherry-pick of 106e7e4bca.
2020-12-10 09:58:47 +01:00
Nikita Popov
106e7e4bca Fixed bug #70066
If we fall back to emulated prepared statements, destroy S->stmt,
so the code doesn't get confused about which mode we're in.
2020-12-09 17:24:30 +01:00
Nikita Popov
fcfa7fd06b Fixed bug #66878
Keep track of whether we have fully consumed all result sets,
either using nextRowset() calls or closeCursor() and skip the
attempt to consume remaining results sets during destruction in
that case.

Especiall if closeCursor() has been used, we really shouldn't
have this sort of cross-statement inference.
2020-12-09 16:38:22 +01:00
Nikita Popov
186b766368 PDO MySQL: Make sure nextRowset() works with partially consumed result
This was already working in all cases apart from native prepared
statements with unbuffered queries. In that case invoking
stmt_free_result() addresses the issue.
2020-12-09 14:46:49 +01:00
Nikita Popov
23193e89e4 PDO MySQL: Handle error during closeCursor() 2020-12-09 14:04:30 +01:00
Nikita Popov
71b5f1446e Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fixed bug #78154
2020-12-09 12:47:34 +01:00
Nikita Popov
44b234a9bc Fixed bug #78154
Handle errors during next_result in exec.
2020-12-09 12:46:47 +01:00
Nikita Popov
18517e7a63 Fix stmt_free_result implementation and usage
Two bugs both affecting the bug_pecl_7976.phpt test ("works with
mysqlnd" haha):

 * We should not change the connection state in stmt_free_result.
   This makes mysql_stmt_free_result usable under mysqlnd and
   not just libmysqlclient.
 * If we call mysql_stmt_free_result, we still need to consume
   any outstanding result sets.
2020-12-09 11:13:48 +01:00
Nikita Popov
311a77d08e Handle changing column count in mysqlnd result binding
If the count changes from prepare to execute and result_bind is
alreadly allocated, reallocate it there.

This is something of a hack. It would be cleaner to require that
result bindings are registered only after execute, when the final
result set fields are known. But mysqli at least directly exposes
this to the user, so we have no guarantee.
2020-12-09 10:30:23 +01:00
Nikita Popov
2df09b9b64 PDO MySQL: Normalize handling of empty stored procedure result set
MySQL always returns a trailing empty result set for stored
procedure calls, which is used to convey status information.
The PDO MySQL implementation is presently confused about what to
do with it: If mysqlnd is used and native prepared statements are
used, this result set is skipped. In all other cases it is not
skipped. We also have quite a few XFAILed tests relating to this.

This patch normalizes (for PHP-8.0 only) the behavior towards
always retaining the empty result set. This is simply how MySQL
stored procedures work (some expletives omitted here) and we can't
distinguish this "useless" result set from an empty result of a
multi query. Multi queries are not a concern for native prepared
statements, as PDO does not allow them in that case, but they are
a concern for emulated prepared statements.

Closes GH-6497.
2020-12-08 17:01:56 +01:00
Nikita Popov
bfa69d27bc Handle column count change in PDO MySQL
This has been fixed for PDO SQlite by GH-4313, however the same
issue also applied to PDO MySQL.

Move the column count setting function into the main PDO layer
(and export it) and then use it in both PDO SQLite and PDO MySQL.
2020-12-08 16:41:35 +01:00
Nikita Popov
713ef8511b Enable XFAILed test
This one had a rather scary XFAIL message, but seems to work just
fine...
2020-12-08 16:03:50 +01:00
Nikita Popov
bd72e4aa44 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fixed bug #63185
2020-12-08 11:35:57 +01:00
Nikita Popov
bd093ad861 Fixed bug #63185 2020-12-08 11:30:54 +01:00
Nikita Popov
9dc42b4114 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fixed bug #80458
2020-12-04 17:00:51 +01:00
Dharman
a83cc03c13 Fixed bug #80458
If there is no result set (e.g. for upsert queries), still allow
fetching to occur without error, i.e. treat it the same way as
an empty result set.

This normalizes behavior between native and emulated prepared
statements and addresses a regression in PHP 7.4.13.
2020-12-04 16:59:47 +01:00
Nikita Popov
f4a600be04 Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fix #80312: change default engine from MyISAM to InnoDB in tests
2020-11-17 13:16:17 +01:00
Darek Slusarczyk
79a606bd95 Fix #80312: change default engine from MyISAM to InnoDB in tests
Change mysqli and pdo_mysql tests configuration to use by default
InnoDB instead of MyISAM.

Closes GH-6405.
2020-11-17 13:15:15 +01:00
Dharman
cf38a6f51f Fix tests for MariaDB
Closes GH-6390.
2020-11-02 09:58:46 +01:00
Nikita Popov
39be0df2ed Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fixed bug #66528
2020-10-28 12:18:17 +01:00
Nikita Popov
68dcaa29d8 Fixed bug #66528
Report errors in commit, rollback and autocommit handlers.
2020-10-28 12:18:02 +01:00
Nikita Popov
793bf12f8c Merge branch 'PHP-7.4' into PHP-8.0
* PHP-7.4:
  Fix bug #79375
2020-10-28 11:04:32 +01:00
Dharman
b03776adb5 Fix bug #79375
Make sure deadlock errors are properly propagated and reports in
a number of places in mysqli and PDO MySQL.

This also fixes a memory and a segfault that can occur under these
conditions.
2020-10-28 11:01:47 +01:00
Nikita Popov
7b9519a792 Fix inconsistency in PDO transaction state
This addresses an issue introduced by #4996 and reported in
https://bugs.php.net/bug.php?id=80260.

Now that PDO::inTransaction() reports the real transaction state
of the connection, there may be a mismatch with PDOs internal
transaction state (in_tcx). This is compounded by the fact that
MySQL performs implicit commits for DDL queries.

This patch fixes the issue by making beginTransaction/commit/rollBack
work on the real transaction state provided by the driver as well
(or falling back to in_tcx if the driver does not support it).

This does mean that writing something like

    $pdo->beginTransaction();
    $pdo->exec('CREATE DATABASE ...');
    $pdo->rollBack(); // <- illegal

will now result in an error, because the CREATE DATABASE already
committed the transaction. I believe this behavior is both correct
and desired -- otherwise, there is no indication that the code did
not behave correctly and the rollBack() was effectively ignored.
However, this is also a BC break.

Closes GH-6355.
2020-10-26 17:01:18 +01:00
Nikita Popov
0f3698173e Update PDO parameter names
Followup to previous changes:
 * Use camel case, as PDO uses a camel case OO API.
 * Use &$var instead of &$bind_var or &$param.
 * Use $column instead of $index. We have cases (both inside PDO
   and in other DB exts) where columns can also be represented as
   strings, so $column is the safer generic name.

Closes GH-6272.
2020-10-05 15:51:36 +02:00
Larry Garfield
ea03cbebbc Update PDO parameters for named arguments.
Closes GH-6220
2020-09-28 23:02:05 +01:00
George Peter Banyard
7553c696c3 Another pass making some failure states unconditional erros in PDO
Also make internal function return type more accurate to inform usage
2020-09-28 19:35:31 +01:00
George Peter Banyard
a5cf82802d Make various failure conditions in PDO unconditional errors
This includes TypeErrors, ValueErrors, Error for uninitialized objects
and invalid user classes/callable instanciation

Closes GH-6212
2020-09-28 18:51:36 +01:00
George Peter Banyard
9fab1b90ab Drop ZPP check in PDO MySQLi test
This test is marked as XFAIL so it doesn't get looked at.

It checks that the method is called without arguments which is a ZPP concern
2020-09-28 18:51:35 +01:00