No rule in the scanner matches a NUL byte, so what re2c does with one
is undefined. Before 5ccc56b1e4 it happened to skip one character. Now
it returns a zero-length text token and pdo_parse_params() loops
forever, or reads an uninitialized YYMARKER if the NUL is the first
byte. Add a default rule so a NUL is skipped as one character of text
again.
Close GH-24496
PostgreSQL sends int2/int4/int8 values in text format in canonical
decimal form: an optional minus sign followed by digits without leading
zeros. That is exactly what ZEND_HANDLE_NUMERIC_STR() accepts for
numeric array keys, including the range check. Use it instead of
calling strtoll() through ZEND_ATOL() for every value, and keep
ZEND_ATOL() as fallback for anything else.
fetchAll(PDO::FETCH_ASSOC) of 1M rows with 4 integer columns:
-11% instructions, -9% cycles.
Close GH-24385
* PHP-8.6:
pdo_pgsql_request_shutdown() leaves statements of freed PDO objects prepared.
ext/pdo_pgsql: persistent connection reset drops prepared statements and plans.
ext/pdo: persistent_shutdown run while the connection is still shared.
The scanner that finds placeholders in queries excluded e/E from plain
text, because they can start an E'...' string. So every e/E in a query
(SELECT, WHERE, created_at, ...) ended a text token and became a
one-character token of its own. Allow e/E inside text as long as the
text doesn't end with one, so E'...' strings are still recognized.
Also let re2c generate bitmaps (-b) for the character classes instead
of a switch on every input character.
The scanner runs in PDO::prepare() and, with emulated prepares, again in
PDOStatement::execute(). Instructions for 200k calls of prepare():
emulated native
SELECT, 11 cols -24% -16%
INSERT, 8 params -15% -7%
For a whole emulated query (prepare, execute, fetch one row) against a
local server, PHP executes 7-9% fewer instructions.
Co-authored-by: Gina Peter Banyard <girgias@php.net>
Close GH-24353
The destructor of a statement created with
[PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL] tried to close the cursor even
when it did not exist. The attempted close causes an error on the server
that the destructor discards, so it cannot be observed by the user, but
inside a transaction it leaves subsequent statements failing for a reason
nobody can see.
is_prepared was overloaded to also mean "cursor declared" and was never
reset, so the cursor state now has its own flag. A close that fails no
longer aborts the caller's transaction.
Close GH-23490
Headers required by the generated code (zend_attributes.h, zend_constants.h, zend_enum.h) are collected during generation and emitted as includes at the top of the arginfo file, with the same preprocessor conditions and PHP version guards as the code that needs them.
Removes the manual zend_attributes.h and zend_enum.h includes from sources that only needed them for the arginfo file they include.
Generalizes the lazy fetch added in GH-15287 by letting a statement choose
how many rows it fetches per chunk, trading memory for speed. ext/pgsql
already exposed this as pg_set_chunked_rows_size(); ext/pdo_pgsql had no
way to reach it.
ATTR_PREFETCH and ATTR_CHUNK_SIZE replace each other: setting one on the
connection clears the other, a statement given either does not inherit the
connection's value, and a chunk size of 1 or more wins when both are set on
the same statement. A chunk size cannot be combined with a statement-level
PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL, which throws a ValueError; a
connection-level chunk size is simply disabled by a scrollable statement.
Requires libpq 17 or later.
Close GH-23210
A statement prepared with PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL and lazy
fetching (PDO::ATTR_PREFETCH => 0) failed at execute() with
SQLSTATE[HY000]: General error: 7 and no message. Either option alone
worked.
A cursor does not stream its result, but S->is_unbuffered stayed set, so
execute() called PQgetResult() with nothing in flight. Clear the flag when
the statement has a cursor.
Close GH-23471
With PDO::ATTR_PREFETCH => 0 a statement streams its result set, and the
cleanup reads the rest of it by calling PQgetResult() until it returns
NULL. That never happens while the connection is copying: PQgetResult()
hands out a fresh COPY result every time. A COPY run through a lazy fetch
has therefore spun at 100% CPU since 8.5.0, as soon as another lazy fetch
takes the connection over. The copy has to be ended first: a copy in with
PQputCopyEnd(), a copy out by draining PQgetCopyData().
The drain was skipped as well, because is_running_unbuffered was cleared
first, both in the cleanup's own abort path and in pgsql_stmt_fetch()
before it calls the cleanup. With PDO::ATTR_EMULATE_PREPARES or
Pdo\Pgsql::ATTR_DISABLE_PREPARES the connection then stayed busy and the
next lazy fetch failed with "another command is already in progress".
The connection's pointer to the statement streaming on it was only cleared
while closing a server-side prepared statement, which those two modes do
not create, so destroying one left the pointer dangling for the next lazy
fetch to read. And a statement whose stream was taken over kept its row
counters after its result had been freed, so fetch() returned a row of
NULLs rather than false.
Close GH-23065
Prevents unavailable optional test services from slowing the suite through repeated connection timeouts. PDO and SNMP availability probes cache the first failure for the duration of one test run, so later SKIPIF checks return immediately.
Only failures are cached; successful probes and test connections are unchanged. PDOs one second timeout applies only to the default availability probe. The caches are private, run-scoped and removed afterwards. A service becoming available mid run is detected on the next test-suite run.
pgsqlCopyFromArray() feeds each row through try_convert_to_string(). A
non-stringable row throws a TypeError, but both the array and iterator
branches then called pdo_pgsql_error() and recorded a fabricated
PGRES_FATAL_ERROR, leaving PDO::errorInfo() reporting "HY000" for what is
a client-side type error. Return through the pending exception instead of
overwriting the driver error state.
Closes GH-22384
The current function `CHECK_HEADER_ADD_INCLUDE()` automatically defines
`HAVE_<HEADER_NAME_H>` preprocessor macros, which makes it difficult to
sync with other build systems. Specially, if some `HAVE_` macro is used
in the code and this function defines this macro but Autotools doesn't.
The new `CHECK_HEADER()` function behaves similar except it doesn't
define the `HAVE_<HEADER_NAME_H>` preprocessor macro.
This removes the following unused compile definitions:
HAVE_ARGON2_H
HAVE_AVIF_H
HAVE_BZLIB_H
HAVE_CAPSTONE_CAPSTONE_H
HAVE_CURL_EASY_H
HAVE_DB_H
HAVE_DECODE_H
HAVE_DEPOT_H
HAVE_EDITLINE_READLINE_H
HAVE_ENCHANT_H
HAVE_ENCODE_H
HAVE_FFI_H
HAVE_FIREBIRD_INTERFACE_H
HAVE_FT2BUILD_H
HAVE_GD_H
HAVE_GLIB_H
HAVE_GMP_H
HAVE_HTTPD_H
HAVE_IBASE_H
HAVE_IR_IR_H
HAVE_KECCAKHASH_H
HAVE_LBER_H
HAVE_LDAP_H
HAVE_LIBEXSLT_EXSLT_H
HAVE_LIBINTL_H
HAVE_LIBPQ_FE_H
HAVE_LIBTIDY_TIDY_H
HAVE_LIBXML_PARSER_H
HAVE_LIBXML_TREE_H
HAVE_LIBXML_XMLWRITER_H
HAVE_LIBXSLT_XSLT_H
HAVE_LMDB_H
HAVE_MBSTRING_H
HAVE_MYSQL_H
HAVE_ONIGURUMA_H
HAVE_OPENSSL_SSL_H
HAVE_PNG_H
HAVE_SNMP_H
HAVE_SODIUM_H
HAVE_SQLITE3_H
HAVE_SQLITE3EXT_H
HAVE_SYBFRONT_H
HAVE_TIDY_H
HAVE_TIDY_TIDY_H
HAVE_TIDYBUFFIO_H
HAVE_TIMELIB_CONFIG_H
HAVE_UNICODE_USPOOF_H
HAVE_UNICODE_UTF_H
HAVE_XPM_H
HAVE_ZIP_H
HAVE_ZIPCONF_H
HAVE_ZLIB_H
The following compile definitions are defined explicitly:
- HAVE_ICONV_H
- HAVE_MSCOREE_H
- HAVE_SQL_H
- HAVE_SQLEXT_H
Additionally, the `SETUP_OPENSSL()` function doesn't accept the 6th
argument anymore.
* PHP-8.5:
Update NEWS with info about security issues
Fix GHSA-www2-q4fc-65wf
Fix GHSA-h96m-rvf9-jgm2
Fix GHSA-8xr5-qppj-gvwj: PDO quoting result null deref
Fix GH-20584: Information Leak of Memory
* PHP-8.4:
Update NEWS with info about security issues
Fix GHSA-www2-q4fc-65wf
Fix GHSA-h96m-rvf9-jgm2
Fix GHSA-8xr5-qppj-gvwj: PDO quoting result null deref
Fix GH-20584: Information Leak of Memory
* PHP-8.3:
Update NEWS with info about security issues
Fix GHSA-www2-q4fc-65wf
Fix GHSA-h96m-rvf9-jgm2
Fix GHSA-8xr5-qppj-gvwj: PDO quoting result null deref
Fix GH-20584: Information Leak of Memory
* PHP-8.2:
Update NEWS with info about security issues
Fix GHSA-www2-q4fc-65wf
Fix GHSA-h96m-rvf9-jgm2
Fix GHSA-8xr5-qppj-gvwj: PDO quoting result null deref
Fix GH-20584: Information Leak of Memory
* PHP-8.1:
Update NEWS with info about security issues
Fix GHSA-www2-q4fc-65wf
Fix GHSA-h96m-rvf9-jgm2
Fix GHSA-8xr5-qppj-gvwj: PDO quoting result null deref
Fix GH-20584: Information Leak of Memory
* Reduce code bloat in arginfo by using specialised string releases
Comparing this patch to master (c7da728574),
with a plain configure command without any options:
```
text data bss dec hex filename
20683738 1592400 137712 22413850 156021a sapi/cli/php
20688522 1592400 137712 22418634 15614ca sapi/cli/php_old
```
We see a minor reduction of 0.023% in code size.
* Also use true for the other initialization line
* Also use specialized code for consts
As stated in the UPGRADING, using the passthrough ("single-row") mode of libpq (introduced in #15287)
forbids passing a new query while the current one's results have not been entirely consumed.
… But I didn't notice that ext/pdo_pgsql internally used new queries to fetch metadata (example use case:
a call to getColumnMeta() while fetch()ing row by row will interleave the getColumnMeta()-triggered
internal query to the database, with the results fetching for the user-called query).
This PR makes those internal calls return NULL for non-essential metadata, instead of letting libpq abort the user-called query.
It moreover includes a small tweak to table oid-to-name translation, with a 1-slot cache.
This may by chance allow the internal call to return something instead of NULL,
but it will nonetheless avoid 30 server calls to get the table name of 30 columns of the same table.
optimize calls to foreach(columns of the same table) getColumnMeta()
- each call queried the DB to know the name associated with the table's OID:
cache the result between two calls
- make pdo_pgsql_translate_oid_to_table higher-level,
with the last parameter being the handle instead of the raw connection;
thus the statement is cleaner, letting the handle do all memory handling on the table oid-to-name translation cache
(which by the way is a driver feature more than a statement one)
close GH-16249