Skip to content

Commit

Permalink
feat: 🎸 Support Oracle (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
mpyw authored Nov 27, 2021
1 parent ba698b9 commit 807a2b1
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 43 deletions.
104 changes: 63 additions & 41 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,58 +6,80 @@ jobs:
build:
runs-on: ubuntu-latest

services:
mysql:
image: mysql:8.0
ports:
- '3306:3306'
env:
MYSQL_DATABASE: testing
MYSQL_USER: testing
MYSQL_PASSWORD: testing
MYSQL_ROOT_PASSWORD: testing
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=30s
--health-retries=5
postgres:
image: postgres:13.3
ports:
- '5432:5432'
env:
POSTGRES_DB: testing
POSTGRES_USER: testing
POSTGRES_PASSWORD: testing
options: >-
--health-cmd=pg_isready
--health-interval=10s
--health-timeout=30s
--health-retries=5
sqlsrv:
image: mcr.microsoft.com/mssql/server:2019-latest
ports:
- '1433:1433'
env:
ACCEPT_EULA: Y
SA_PASSWORD: Password!
options: >-
--name sqlsrv
--health-cmd "echo quit | /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -l 1 -U sa -P Password!"
strategy:
matrix:
php: [7.1, 7.2, 7.3, 7.4, '8.0', 8.1]
db: [mysql, pgsql, sqlite, sqlsrv, 'odbc:sqlsrv', 'dblib:sqlsrv']
db: [mysql, pgsql, sqlite, sqlsrv, 'odbc:sqlsrv', 'dblib:sqlsrv', oci]

steps:
- uses: actions/checkout@v2

- name: Cache Docker Registry
uses: actions/cache@v2
with:
path: /tmp/docker-registry
key: ${{ matrix.db }}-${{ github.ref }}-${{ github.sha }}
restore-keys: |
${{ matrix.db }}-${{ github.ref }}-${{ github.sha }}
${{ matrix.db }}-${{ github.ref }}
${{ matrix.db }}-refs/head/master
- name: Boot-up Local Docker Registry
run: docker run -d -p 5000:5000 --restart=always --name registry -v /tmp/docker-registry:/var/lib/registry registry:2

- name: Wait for Docker Registry
run: npx wait-on tcp:5000

- name: Boot-up MySQL Container
if: matrix.db == 'mysql'
run: |
if [[ -z "$(docker images -q localhost:5000/mysql:latest)" ]]; then
docker pull mysql:8.0
docker tag mysql:8.0 localhost:5000/mysql:latest
docker push localhost:5000/mysql:latest
fi
docker-compose up -d mysql
sh -c 'docker-compose logs -f mysql | { sed "/\[Entrypoint\]: MySQL init process done\. Ready for start up\./ q" && kill $$ ;}' >/dev/null 2>&1 || true
- name: Boot-up Postgres Container
if: matrix.db == 'pgsql'
run: |
if [[ -z "$(docker images -q localhost:5000/postgres:latest)" ]]; then
docker pull postgres:13.3
docker tag postgres:13.3 localhost:5000/postgres:latest
docker push localhost:5000/postgres:latest
fi
docker-compose up -d postgres
sh -c 'docker-compose logs -f postgres | { sed "/PostgreSQL init process complete; ready for start up\./ q" && kill $$ ;}' >/dev/null 2>&1 || true
- name: Boot-up SQLServer Container
if: matrix.db == 'sqlsrv' || matrix.db == 'odbc:sqlsrv' || matrix.db == 'dblib:sqlsrv'
run: |
if [[ -z "$(docker images -q localhost:5000/sqlsrv)" ]]; then
docker pull mcr.microsoft.com/mssql/server
docker tag mcr.microsoft.com/mssql/server localhost:5000/sqlsrv
docker push localhost:5000/sqlsrv
fi
docker-compose up -d sqlsrv
sh -c 'docker-compose logs -f sqlsrv | { sed "/Recovery is complete\./ q" && kill $$ ;}' >/dev/null 2>&1 || true
- name: Boot-up Oracle Container
if: matrix.db == 'oci'
run: |
if [[ -z "$(docker images -q localhost:5000/oracle:latest)" ]]; then
docker pull quay.io/maksymbilenko/oracle-12c:latest
docker tag quay.io/maksymbilenko/oracle-12c:latest localhost:5000/oracle:latest
docker push localhost:5000/oracle:latest
fi
docker-compose up -d oracle
sh -c 'docker-compose logs -f oracle | { sed "/Database ready to use\./ q" && kill $$ ;}' >/dev/null 2>&1 || true
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: xdebug
extensions: ${{ matrix.db == 'oci' && 'pdo_oci' || '' }}

- name: Set up MySQL
if: matrix.db == 'mysql'
Expand All @@ -73,7 +95,7 @@ jobs:
- name: Set up SQLServer
if: matrix.db == 'sqlsrv' || matrix.db == 'odbc:sqlsrv' || matrix.db == 'dblib:sqlsrv'
run: |
docker exec sqlsrv \
docker-compose exec -T sqlsrv \
/opt/mssql-tools/bin/sqlcmd \
-S 127.0.0.1 \
-U sa \
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ composer require mpyw/unique-violation-detector
|:---|:---|
| PHP | <code>^7.1 &#124;&#124; ^8.0</code> |

## Supported PDO Drivers

| Database | Driver | Auto-Discoverable |
|:---|:---|:---:|
| MySQL | `pdo_mysql` ||
| PostgreSQL | `pdo_pgsql` ||
| SQLite | `pdo_sqlite` ||
| SQLServer | `pdo_sqlsrv` ||
| SQLServer | `pdo_odbc` | |
| SQLServer | `pdo_dblib` | |
| Oracle | `pdo_oci` ||

## Usage

```php
Expand Down
49 changes: 49 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
version: '3.8'

services:

mysql:
image: localhost:5000/mysql:latest
ports:
- '3306:3306'
environment:
MYSQL_DATABASE: testing
MYSQL_USER: testing
MYSQL_PASSWORD: testing
MYSQL_ROOT_PASSWORD: testing
healthcheck:
test: [CMD, mysqladmin, ping]
interval: 10s
timeout: 30s
retries: 5

postgres:
image: localhost:5000/postgres:latest
ports:
- '5432:5432'
environment:
POSTGRES_DB: testing
POSTGRES_USER: testing
POSTGRES_PASSWORD: testing
healthcheck:
test: [CMD, pg_isready]
interval: 10s
timeout: 30s
retries: 5

sqlsrv:
image: localhost:5000/sqlsrv:latest
ports:
- '1433:1433'
environment:
ACCEPT_EULA: Y
SA_PASSWORD: Password!
healthcheck:
test: [CMD-SHELL, 'echo quit | /opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -l 1 -U sa -P Password!']

oracle:
image: localhost:5000/oracle:latest
ports:
- '1521:1521'
environment:
WEB_CONSOLE: 'false'
2 changes: 2 additions & 0 deletions src/DetectorDiscoverer.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public function discover(PDO $pdo): UniqueViolationDetector
return new SQLiteDetector();
case 'sqlsrv':
return new SQLServerDetector();
case 'oci':
return new OracleDetector();
default:
throw new DiscoveryFailedException('Failed to automatically discover a detector.');
}
Expand Down
16 changes: 16 additions & 0 deletions src/OracleDetector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace Mpyw\UniqueViolationDetector;

use PDOException;

class OracleDetector implements UniqueViolationDetector
{
public function uniqueConstraintViolated(PDOException $e): bool
{
// SQLSTATE[HY000]: OCIStmtExecute: ORA-00001: unique constraint (...) violated
return $e->getCode() === 'HY000' && ($e->errorInfo[1] ?? 0) === 1;
}
}
15 changes: 13 additions & 2 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,15 @@ public function setUp(): void
if ($this->driver === 'sqlite') {
$this->pdo->exec('PRAGMA foreign_keys=true');
} else {
$this->pdo->exec('DROP TABLE IF EXISTS posts');
$this->pdo->exec('DROP TABLE IF EXISTS users');
// Oracle doesn't support IF EXISTS
try {
$this->pdo->exec('DROP TABLE posts');
} catch (PDOException $_) {
}
try {
$this->pdo->exec('DROP TABLE users');
} catch (PDOException $_) {
}
}
} catch (PDOException $e) {
if ($e->getMessage() === 'could not find driver') {
Expand Down Expand Up @@ -89,6 +96,10 @@ private static function initPdo(string $driver): PDO
return new PDO('dblib:host=127.0.0.1:1433;dbname=testing', 'sa', 'Password!', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
case 'oci':
return new PDO('oci:dbname=//localhost:1521/xe', 'system', 'oracle', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
]);
default:
throw new RuntimeException('Unsupported Driver.');
}
Expand Down

0 comments on commit 807a2b1

Please sign in to comment.