Skip to content

Commit 48658f0

Browse files
committed
fix(OCI8): revert per-component user isolation, run Oracle sequentially instead
OCI8 config uses DSN (not hostname/port/database), so per-component user creation via oci_connect failed silently. Oracle Free containers also restrict CREATE USER in PDB context. Instead, exclude OCI8 from per-component DB isolation and run Oracle components sequentially (--max-jobs 1, --repeat 2) to avoid ORA-00955 table name collisions.
1 parent eff8e83 commit 48658f0

2 files changed

Lines changed: 46 additions & 77 deletions

File tree

.github/workflows/test-random-execution.yml

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -212,14 +212,19 @@ jobs:
212212
args+=("--component" "${{ inputs.component }}")
213213
fi
214214
215-
# Add --max-jobs flag if specified (empty means auto-detect)
216-
if [[ -n "${{ inputs.max-jobs }}" ]]; then
217-
args+=("--max-jobs" "${{ inputs.max-jobs }}")
215+
# OCI8 connects to a single shared schema via DSN, so components
216+
# cannot be isolated with per-component databases like MySQLi/Postgre/SQLSRV.
217+
# Run Oracle sequentially to avoid table name collisions (ORA-00955).
218+
if [[ "${{ matrix.db-platform }}" == "Oracle" ]]; then
219+
args+=("--max-jobs" "1")
220+
args+=("--repeat" "${{ inputs.repeat || '2' }}")
221+
else
222+
if [[ -n "${{ inputs.max-jobs }}" ]]; then
223+
args+=("--max-jobs" "${{ inputs.max-jobs }}")
224+
fi
225+
args+=("--repeat" "${{ inputs.repeat || '10' }}")
218226
fi
219227
220-
# Add --repeat flag (always, default is 10)
221-
args+=("--repeat" "${{ inputs.repeat || '10' }}")
222-
223228
# Add --timeout flag (always, default is 300)
224229
args+=("--timeout" "${{ inputs.timeout || '300' }}")
225230

tests/_support/Config/Registrar.php

Lines changed: 35 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public static function Database(): array
147147

148148
$dbParams = self::$dbConfig[$group] ?? [];
149149

150-
if (! empty($dbParams) && $group !== 'SQLite3') {
150+
if (! empty($dbParams) && ! in_array($group, ['SQLite3', 'OCI8'], true)) {
151151
$componentName = '';
152152

153153
foreach ($_SERVER['argv'] ?? [] as $arg) {
@@ -161,79 +161,43 @@ public static function Database(): array
161161
}
162162

163163
if ($componentName !== '') {
164-
if ($group === 'OCI8') {
165-
$hostname = $dbParams['hostname'] ?? '127.0.0.1';
166-
$port = $dbParams['port'] ?? 1521;
167-
$database = $dbParams['database'] ?? 'FREEPDB1';
168-
$username = $dbParams['username'] ?? 'ORACLE';
169-
$password = $dbParams['password'] ?? 'ORACLE';
170-
171-
$compUser = strtoupper('t_' . substr(preg_replace('/[^a-zA-Z0-9]/', '', $componentName), 0, 20));
172-
$tns = '//' . $hostname . ':' . $port . '/' . $database;
173-
174-
try {
175-
$conn = @oci_connect($username, $password, $tns);
176-
if ($conn !== false) {
177-
$stmt = @oci_parse($conn, 'SELECT USERNAME FROM ALL_USERS WHERE USERNAME = :usr');
178-
@oci_bind_by_name($stmt, ':usr', $compUser);
179-
@oci_execute($stmt);
180-
181-
if (@oci_fetch_array($stmt, OCI_ASSOC) === false) {
182-
$stmt2 = @oci_parse($conn, 'CREATE USER ' . $compUser . ' IDENTIFIED BY ' . $compUser);
183-
@oci_execute($stmt2);
184-
$stmt3 = @oci_parse($conn, 'GRANT CONNECT, RESOURCE, DBA TO ' . $compUser);
185-
@oci_execute($stmt3);
186-
$stmt4 = @oci_parse($conn, 'GRANT UNLIMITED TABLESPACE TO ' . $compUser);
187-
@oci_execute($stmt4);
188-
}
189-
190-
@oci_close($conn);
191-
192-
$dbParams['username'] = $compUser;
193-
$dbParams['password'] = $compUser;
164+
$dbParams['database'] = 'test_' . strtolower($componentName);
165+
166+
try {
167+
if ($group === 'MySQLi') {
168+
$conn = new mysqli(
169+
$dbParams['hostname'],
170+
$dbParams['username'],
171+
$dbParams['password'],
172+
'',
173+
(int) $dbParams['port'],
174+
);
175+
if (! $conn->connect_error) {
176+
$conn->query('CREATE DATABASE IF NOT EXISTS ' . $conn->real_escape_string($dbParams['database']));
177+
$conn->close();
194178
}
195-
} catch (Throwable) {
196-
// Ignore error and fall back to default user
197-
}
198-
} else {
199-
$dbParams['database'] = 'test_' . strtolower($componentName);
200-
201-
try {
202-
if ($group === 'MySQLi') {
203-
$conn = new mysqli(
204-
$dbParams['hostname'],
205-
$dbParams['username'],
206-
$dbParams['password'],
207-
'',
208-
(int) $dbParams['port'],
209-
);
210-
if (! $conn->connect_error) {
211-
$conn->query('CREATE DATABASE IF NOT EXISTS ' . $conn->real_escape_string($dbParams['database']));
212-
$conn->close();
213-
}
214-
} elseif ($group === 'Postgre') {
215-
$dsn = 'pgsql:host=' . $dbParams['hostname'] . ';port=' . $dbParams['port'] . ';user=' . $dbParams['username'] . ';password=' . $dbParams['password'];
216-
$pdo = new PDO($dsn);
217-
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
218-
$stmt = $pdo->prepare('SELECT 1 FROM pg_database WHERE datname = ?');
219-
$stmt->execute([$dbParams['database']]);
220-
if (! $stmt->fetchColumn()) {
221-
$dbName = str_replace('"', '""', $dbParams['database']);
222-
$pdo->exec('CREATE DATABASE "' . $dbName . '"');
223-
}
224-
} elseif ($group === 'SQLSRV') {
225-
$dsn = 'sqlsrv:Server=' . $dbParams['hostname'] . ',' . $dbParams['port'] . ';Encrypt=False;TrustServerCertificate=True';
226-
$pdo = new PDO($dsn, $dbParams['username'], $dbParams['password']);
227-
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
228-
$stmt = $pdo->prepare('SELECT 1 FROM sys.databases WHERE name = ?');
229-
$stmt->execute([$dbParams['database']]);
230-
if (! $stmt->fetchColumn()) {
231-
$pdo->exec('CREATE DATABASE [' . str_replace(']', ']]', $dbParams['database']) . '] COLLATE Latin1_General_100_CS_AS_SC_UTF8');
232-
}
179+
} elseif ($group === 'Postgre') {
180+
$dsn = 'pgsql:host=' . $dbParams['hostname'] . ';port=' . $dbParams['port'] . ';user=' . $dbParams['username'] . ';password=' . $dbParams['password'];
181+
$pdo = new PDO($dsn);
182+
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
183+
$stmt = $pdo->prepare('SELECT 1 FROM pg_database WHERE datname = ?');
184+
$stmt->execute([$dbParams['database']]);
185+
if (! $stmt->fetchColumn()) {
186+
$dbName = str_replace('"', '""', $dbParams['database']);
187+
$pdo->exec('CREATE DATABASE "' . $dbName . '"');
188+
}
189+
} elseif ($group === 'SQLSRV') {
190+
$dsn = 'sqlsrv:Server=' . $dbParams['hostname'] . ',' . $dbParams['port'] . ';Encrypt=False;TrustServerCertificate=True';
191+
$pdo = new PDO($dsn, $dbParams['username'], $dbParams['password']);
192+
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
193+
$stmt = $pdo->prepare('SELECT 1 FROM sys.databases WHERE name = ?');
194+
$stmt->execute([$dbParams['database']]);
195+
if (! $stmt->fetchColumn()) {
196+
$pdo->exec('CREATE DATABASE [' . str_replace(']', ']]', $dbParams['database']) . '] COLLATE Latin1_General_100_CS_AS_SC_UTF8');
233197
}
234-
} catch (Throwable) {
235-
// Ignore any error and let the connection fail naturally
236198
}
199+
} catch (Throwable) {
200+
// Ignore any error and let the connection fail naturally
237201
}
238202
}
239203
}

0 commit comments

Comments
 (0)