Conversation
PHP_RINIT_FUNCTION() called OCIEnvCreate() on every request in every process
that had the extension enabled, even when no Oracle connection was ever
opened. Initializing the Oracle client library is not free and, on Windows,
has process-wide side effects: any child process spawned afterwards crashes
with an access violation (0xC0000005) at exit if it loads sqlsrv or
pdo_sqlsrv. That makes merely enabling pdo_oci break unrelated tooling --
every Composer script fails, because Composer spawns children.
oci8 does not have this problem because it initializes the client only when a
connection is actually opened. This restores that parity: pdo_oci_Env is used
only from pdo_oci_handle_factory(), so creating it there is enough.
This does not fix the underlying access violation, which reproduces with oci8
alone once a real connection has been made. It removes the case where a
process pays the cost and the side effects without ever using Oracle.
Deferring the call out of MINIT is preserved -- connections are still opened
during a request, so NLS_LANG is available under php-fpm.
Tested on Windows 11 x64 with PHP 8.5.8 NTS VS17 x64 and an Oracle Database
21c Express Edition client, against a DLL built by this repository's CI
(php/php-windows-builder, artifact php_pdo_oci-8.5-nts-vs17-x86_64).
The reproduction is a parent script that spawns a child with a php.ini
enabling only sqlsrv:
$d = array(0 => array("pipe","r"), 1 => array("pipe","w"), 2 => array("pipe","w"));
$p = proc_open('php -c child.ini -r "echo 7;"', $d, $pipes);
fclose($pipes[0]); stream_get_contents($pipes[1]);
fclose($pipes[1]); fclose($pipes[2]);
echo proc_close($p), "\n";
The child prints 7 correctly either way; only its exit code differs.
before after
child spawned, no Oracle connection -1073741819 0
composer check (3 runs) -1073741819 0
composer test -1073741819 0
child spawned after a real connection -1073741819 -1073741819
The last row is the underlying conflict this commit does not address; it
behaves identically with oci8 once oci_new_connect() has run.
PDO_OCI itself is unaffected: connecting with
oci:dbname=//localhost:1521/XEPDB1;charset=AL32UTF8 and running
SELECT 1 FROM DUAL works before and after.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
vrana
added a commit
to vrana/adminer
that referenced
this pull request
Sep 8, 2026
Both projects pass without a single extension specific branch. On Windows this needs php/pecl-database-pdo_oci#42, without it a PHP process with pdo_oci loaded makes the children it spawns crash if they load sqlsrv, which breaks every Composer script: php/pecl-database-pdo_oci#42 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PHP_RINIT_FUNCTION() called OCIEnvCreate() on every request in every process that had the extension enabled, even when no Oracle connection was ever opened. Initializing the Oracle client library is not free and, on Windows, has process-wide side effects: any child process spawned afterwards crashes with an access violation (0xC0000005) at exit if it loads sqlsrv or pdo_sqlsrv. That makes merely enabling pdo_oci break unrelated tooling -- every Composer script fails, because Composer spawns children.
oci8 does not have this problem because it initializes the client only when a connection is actually opened. This restores that parity: pdo_oci_Env is used only from pdo_oci_handle_factory(), so creating it there is enough.
This does not fix the underlying access violation, which reproduces with oci8 alone once a real connection has been made. It removes the case where a process pays the cost and the side effects without ever using Oracle.
Deferring the call out of MINIT is preserved -- connections are still opened during a request, so NLS_LANG is available under php-fpm.
Tested on Windows 11 x64 with PHP 8.5.8 NTS VS17 x64 and an Oracle Database 21c Express Edition client, against a DLL built by this repository's CI (php/php-windows-builder, artifact php_pdo_oci-8.5-nts-vs17-x86_64).
The reproduction is a parent script that spawns a child with a php.ini enabling only sqlsrv:
The child prints 7 correctly either way; only its exit code differs.
The last row is the underlying conflict this commit does not address; it behaves identically with oci8 once oci_new_connect() has run.
PDO_OCI itself is unaffected: connecting with
oci:dbname=//localhost:1521/XEPDB1;charset=AL32UTF8 and running SELECT 1 FROM DUAL works before and after.