Skip to content

Commit b1ef76e

Browse files
authored
Merge pull request #224 from moufmouf/oracle_fix
Fixing Oracle unit tests
2 parents 45c7cd2 + dd68fea commit b1ef76e

22 files changed

+397
-162
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 44 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ jobs:
350350
- name: "Running PHPBench on current branch"
351351
run: "./phpbench.dist.sh run --tag=current_pr --store"
352352

353+
- name: "Reverting any change (that could have been triggered by composer install)"
354+
run: "git checkout -- ."
355+
353356
- name: "Switching to master branch"
354357
run: "git checkout master"
355358

@@ -362,55 +365,44 @@ jobs:
362365
- name: "Generating comparison"
363366
run: "./phpbench.dist.sh report --uuid=tag:current_pr --uuid=tag:master --report='{extends: compare, compare: tag}'"
364367

365-
# phpunit-oci8:
366-
# name: "PHPUnit on OCI8"
367-
# runs-on: "ubuntu-latest"
368-
#
369-
# strategy:
370-
# matrix:
371-
# php-version:
372-
# - "7.4"
373-
#
374-
# services:
375-
# oracle:
376-
# image: "wnameless/oracle-xe-11g-r2"
377-
# ports:
378-
# - "1521:1521"
379-
#
380-
# steps:
381-
# - name: "Checkout"
382-
# uses: "actions/checkout@v2"
383-
#
384-
# - name: "Install PHP"
385-
# uses: "shivammathur/setup-php@v2"
386-
# with:
387-
# php-version: "${{ matrix.php-version }}"
388-
# extensions: "oci8"
389-
# coverage: "pcov"
390-
#
391-
# - name: "Cache dependencies installed with composer"
392-
# uses: "actions/cache@v1"
393-
# with:
394-
# path: "~/.composer/cache"
395-
# key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
396-
# restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
397-
#
398-
# - name: "Setup Oracle user"
399-
# run: |
400-
# docker exec $(docker ps -aqf "ancestor=wnameless/oracle-xe-11g-r2") bash -c "export PS1=1 && source /etc/bash.bashrc && source /root/.bashrc && sqlplus -L -S sys/oracle AS SYSDBA <<<SQL \
401-
# create user tdbm_admin identified by tdbm quota unlimited on USERS default tablespace USERS; \
402-
# GRANT CONNECT,RESOURCE TO tdbm_admin; \
403-
# GRANT dba TO tdbm_admin WITH ADMIN OPTION; \
404-
# grant create session, create procedure, create type, create table, create sequence, create view to tdbm_admin; \
405-
# grant select any dictionary to tdbm_admin; \
406-
# exit \
407-
# SQL"
408-
#
409-
# - name: "Install dependencies with composer"
410-
# run: "composer install --no-interaction --no-progress --no-suggest"
411-
#
412-
# - name: "Run PHPUnit"
413-
# run: "vendor/bin/phpunit -c phpunit.oracle.xml --coverage-clover=coverage.xml"
414-
#
415-
# - name: "Upload Code Coverage"
416-
# uses: "codecov/codecov-action@v1"
368+
phpunit-oci8:
369+
name: "PHPUnit on OCI8"
370+
runs-on: "ubuntu-latest"
371+
372+
strategy:
373+
matrix:
374+
php-version:
375+
- "7.4"
376+
377+
services:
378+
oracle:
379+
image: "wnameless/oracle-xe-11g-r2"
380+
ports:
381+
- "1521:1521"
382+
383+
steps:
384+
- name: "Checkout"
385+
uses: "actions/checkout@v2"
386+
387+
- name: "Install PHP"
388+
uses: "shivammathur/setup-php@v2"
389+
with:
390+
php-version: "${{ matrix.php-version }}"
391+
extensions: "oci8"
392+
coverage: "pcov"
393+
394+
- name: "Cache dependencies installed with composer"
395+
uses: "actions/cache@v1"
396+
with:
397+
path: "~/.composer/cache"
398+
key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
399+
restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
400+
401+
- name: "Install dependencies with composer"
402+
run: "composer install --no-interaction --no-progress --no-suggest"
403+
404+
- name: "Run PHPUnit"
405+
run: "vendor/bin/phpunit -c phpunit.oracle.xml --coverage-clover=coverage.xml"
406+
407+
- name: "Upload Code Coverage"
408+
uses: "codecov/codecov-action@v1"

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"doctrine/annotations": "^1.10",
3636
"zendframework/zend-code": "^3.4",
3737
"psr/container": "^1",
38-
"brain-diminished/schema-version-control": "^1.0.2",
38+
"brain-diminished/schema-version-control": "dev-master",
3939
"ext-PDO": "*",
4040
"ext-json": "*",
4141
"ext-hash": "*",

couscous.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ menu:
101101
migrating:
102102
text: Migrating
103103
relativeUrl: doc/migrating.html
104+
compatibility:
105+
text: Databases compatibility
106+
relativeUrl: doc/compatibility.html
104107
internals:
105108
text: TDBM internals
106109
relativeUrl: doc/internals.html

doc/compatibility.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: Compatibility
3+
subTitle: Compatibility with databases
4+
currentMenu: compatibility
5+
---
6+
7+
TDBM uses *Doctrine DBAL* under the hood to access your database.
8+
*Doctrine DBAL* provides a solid abstraction layer allowing TDBM to be compatible with many databases out of the box.
9+
10+
TDBM is tested with these databases:
11+
12+
- MySQL (5.7 and 8.0)
13+
- MariaDB (10.x)
14+
- PostgreSQL (tested on v12, but v9, v10 and v11 should be compatible)
15+
- Oracle (11g)
16+
17+
TDBM is **not** compatible with Sqlite (because the database does not support foreign keys properly)
18+
19+
20+
# Known vendor issues
21+
22+
## Oracle 11g
23+
24+
### JSON columns are not supported
25+
26+
Oracle 11g does not have a notion of JSON column and DBAL casts those columns in CLOB.
27+
But CLOB columns have an issue (they cannot be part of a DISTINCT query) that is used by TDBM.
28+
As a result, any request on a table containing a JSON column will fail.
29+
30+
### BLOB columns are not supported
31+
32+
Due to a limitation in the way OCI8 driver works, the Oracle database cannot accept *streams*
33+
in BLOB columns (it only accepts strings). But TDBM is exclusively using *streams* for BLOB
34+
columns. As a result, TDBM does not support any kind of BLOB column in Oracle.

phpstan.neon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ parameters:
1111
- "#expects TheCodingMachine\\\\TDBM\\\\AbstractTDBMObject, object given.#"
1212
- "#should return array<TheCodingMachine\\\\TDBM\\\\AbstractTDBMObject> but returns array<int, object>#"
1313
#- "#expects array<string>, array<int, int|string> given.#"
14-
- "/Parameter #. \\$types of method Doctrine\\\\DBAL\\\\Connection::.*() expects array<int|string>, array<int, Doctrine\\\\DBAL\\\\Types\\\\Type> given./"
14+
- "/Parameter #. \\$types of method Doctrine\\\\DBAL\\\\Connection::.*() expects array<int\\|string>, array<int, Doctrine\\\\DBAL\\\\Types\\\\Type> given./"
1515
- '#Method TheCodingMachine\\TDBM\\NativeWeakrefObjectStorage::get\(\) should return TheCodingMachine\\TDBM\\DbRow\|null but returns object\|null.#'
1616
- '#Method TheCodingMachine\\TDBM\\QueryFactory\\AbstractQueryFactory::.* should return string but returns string\|null.#'
1717
-

phpunit.oracle.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
<php>
2020
<!-- "Real" test database -->
2121
<var name="db_host" value="localhost" />
22-
<var name="db_admin_username" value="tdbm_admin" />
22+
<var name="db_admin_username" value="system" />
2323
<var name="db_username" value="tdbm" />
24-
<var name="db_password" value="tdbm" />
24+
<var name="db_password" value="oracle" />
2525
<var name="db_name" value="tdbm" />
2626
<var name="db_port" value="1521"/>
2727
<var name="db_driver" value="oci8"/>

src/QueryFactory/AbstractQueryFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ protected function getColumnsList(string $mainTable, array $additionalTablesFetc
141141
}
142142
} elseif ($orderByColumn['type'] === 'expr') {
143143
$sortColumnName = 'sort_column_'.$sortColumn;
144-
$columnsList[] = $orderByColumn['expr'].' as '.$sortColumnName;
144+
$columnsList[] = $orderByColumn['expr'].' as '.$connection->quoteIdentifier($sortColumnName);
145145
$columnDescList[$sortColumnName] = [
146146
'tableGroup' => null,
147147
];

src/QueryFactory/FindObjectsFromRawSqlQueryFactory.php

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use TheCodingMachine\TDBM\TDBMService;
1010
use PHPSQLParser\PHPSQLCreator;
1111
use PHPSQLParser\PHPSQLParser;
12+
use function array_merge;
1213

1314
/**
1415
* This class is in charge of formatting the SQL passed to findObjectsFromRawSql method.
@@ -224,7 +225,7 @@ private function formatSelect(array $baseSelect): array
224225
],
225226
'alias' => [
226227
'as' => true,
227-
'name' => $alias,
228+
'name' => $connection->quoteIdentifier($alias),
228229
]
229230
];
230231
$formattedSelect[] = $astColumn;
@@ -352,20 +353,98 @@ private function generateGroupedSqlCount(array $parsedSql): array
352353
{
353354
$group = $parsedSql['GROUP'];
354355
unset($parsedSql['GROUP']);
355-
$parsedSql['SELECT'] = [[
356-
'expr_type' => 'aggregate_function',
357-
'alias' => [
358-
'as' => true,
359-
'name' => 'cnt',
360-
],
361-
'base_expr' => 'COUNT',
362-
'sub_tree' => array_merge([[
356+
357+
// Count(DISTINCT ...) on multiple columns is only valid in MySQL (unsupported on Pgsql or Oracle). For those, we need to do a subquery.
358+
if (count($group) === 1 || $this->tdbmService->getConnection()->getDatabasePlatform() instanceof MySqlPlatform) {
359+
$parsedSql['SELECT'] = [[
360+
'expr_type' => 'aggregate_function',
361+
'alias' => [
362+
'as' => true,
363+
'name' => 'cnt',
364+
],
365+
'base_expr' => 'COUNT',
366+
'sub_tree' => array_merge([[
367+
'expr_type' => 'reserved',
368+
'base_expr' => 'DISTINCT',
369+
'delim' => ','
370+
]], $group),
371+
'delim' => false,
372+
]];
373+
} else {
374+
$innerColumns = [[
363375
'expr_type' => 'reserved',
364376
'base_expr' => 'DISTINCT',
365-
'delim' => ','
366-
]], $group),
367-
'delim' => false,
368-
]];
377+
'delim' => ' '
378+
]];
379+
foreach ($group as $item) {
380+
$item['delim'] = ',';
381+
$innerColumns[] = $item;
382+
}
383+
$innerColumns[count($innerColumns)-1]['delim'] = false;
384+
$parsedSql['SELECT'] = $innerColumns;
385+
386+
$parsedSql = [
387+
'SELECT' =>
388+
[
389+
0 =>
390+
[
391+
'expr_type' => 'aggregate_function',
392+
'alias' =>
393+
[
394+
'as' => true,
395+
'name' => 'cnt',
396+
'base_expr' => 'AS cnt',
397+
'no_quotes' =>
398+
[
399+
'delim' => false,
400+
'parts' =>
401+
[
402+
0 => 'cnt',
403+
],
404+
],
405+
],
406+
'base_expr' => 'COUNT',
407+
'sub_tree' =>
408+
[
409+
0 =>
410+
[
411+
'expr_type' => 'colref',
412+
'base_expr' => '*',
413+
'sub_tree' => false,
414+
],
415+
],
416+
'delim' => false,
417+
],
418+
],
419+
'FROM' =>
420+
[
421+
0 =>
422+
[
423+
'expr_type' => 'subquery',
424+
'alias' =>
425+
[
426+
'as' => false,
427+
'name' => 'subquery',
428+
'no_quotes' =>
429+
[
430+
'delim' => false,
431+
'parts' =>
432+
[
433+
0 => 'subquery',
434+
],
435+
],
436+
'base_expr' => 'subquery',
437+
],
438+
'hints' => false,
439+
'join_type' => 'JOIN',
440+
'ref_type' => false,
441+
'ref_clause' => false,
442+
//'base_expr' => 'SELECT id FROM country',
443+
'sub_tree' => $parsedSql
444+
],
445+
],
446+
];
447+
}
369448
return $parsedSql;
370449
}
371450

src/SchemaLockFileDumper.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Doctrine\DBAL\Schema\Schema;
1111
use Doctrine\DBAL\Schema\Table;
1212
use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer;
13+
use TheCodingMachine\TDBM\Utils\ColumnsReorderer;
1314
use TheCodingMachine\TDBM\Utils\ImmutableCaster;
1415
use function array_map;
1516
use function array_values;
@@ -92,6 +93,7 @@ public function getSchema(bool $ignoreCache = false): Schema
9293
} else {
9394
$this->schema = $this->schemaVersionControlService->loadSchemaFile();
9495
ImmutableCaster::castSchemaToImmutable($this->schema);
96+
ColumnsReorderer::reorderTableColumns($this->schema);
9597
$this->cache->save($cacheKey, $this->schema);
9698
}
9799
}

src/Utils/BeanDescriptor.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1349,7 +1349,7 @@ private function generateFindByDaoCodeForIndex(Index $index, string $beanNamespa
13491349
}
13501350
} elseif ($element instanceof ObjectBeanPropertyDescriptor) {
13511351
$foreignKey = $element->getForeignKey();
1352-
$columns = SafeFunctions::arrayCombine($foreignKey->getLocalColumns(), $foreignKey->getForeignColumns());
1352+
$columns = SafeFunctions::arrayCombine($foreignKey->getUnquotedLocalColumns(), $foreignKey->getUnquotedForeignColumns());
13531353
++$count;
13541354
$foreignTable = $this->schema->getTable($foreignKey->getForeignTableName());
13551355
foreach ($columns as $localColumn => $foreignColumn) {

0 commit comments

Comments
 (0)