Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Add Oracle driver #2487

Merged
merged 184 commits into from
Jan 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
184 commits
Select commit Hold shift + click to select a range
d02d8e4
feat: copy MySQLi to OCI8.
ytetsuro Dec 31, 2019
325614c
fix: namespace MySQLi to OCI8.
ytetsuro Dec 31, 2019
1e412ca
feat: add build DNS process.
ytetsuro Dec 31, 2019
96350b8
style: fix style.
ytetsuro Dec 31, 2019
b5e0286
feat: add get forgen key data method.
ytetsuro Dec 31, 2019
c6dcfda
feat: add close method.
ytetsuro Dec 31, 2019
c4362a9
feat: add reconnect method.
ytetsuro Dec 31, 2019
8444672
feat: add setDatabase method.
ytetsuro Dec 31, 2019
2ec92fe
feat: add get version method.
ytetsuro Dec 31, 2019
4ea5d58
feat: add exec method.
ytetsuro Dec 31, 2019
f1c68a1
feat: add get affected rows method.
ytetsuro Dec 31, 2019
359817f
feat: remove escape method.
ytetsuro Dec 31, 2019
bdd528c
feat: add get table list method.
ytetsuro Dec 31, 2019
e43a5f2
feat: add column list method.
ytetsuro Dec 31, 2019
31a9f12
feat: add get field list method.
ytetsuro Dec 31, 2019
1534314
feat: add get index list method.
ytetsuro Dec 31, 2019
19d1a18
feat: add disable foreign key method.
ytetsuro Dec 31, 2019
31f24bf
feat: add enable foreign key method.
ytetsuro Dec 31, 2019
82cf9dd
feat: add get cursor method.
ytetsuro Dec 31, 2019
6c4ef9b
feat: add call stored procedure method.
ytetsuro Dec 31, 2019
f7880e5
feat: add bind parameter method.
ytetsuro Dec 31, 2019
1de6967
feat: add error method.
ytetsuro Dec 31, 2019
194e683
feat: add insert_id method.
ytetsuro Dec 31, 2019
eed3529
feat: add transaction start method.
ytetsuro Dec 31, 2019
f940c36
feat: add transaction commit method.
ytetsuro Dec 31, 2019
e7600eb
feat: add transaction rollback method.
ytetsuro Dec 31, 2019
917e7ec
feat: add necessary property.
ytetsuro Dec 31, 2019
44bd4ca
feat: add insert batch method.
ytetsuro Dec 31, 2019
626e53d
feat: add truncate method.
ytetsuro Dec 31, 2019
945d03d
feat: add delete method.
ytetsuro Dec 31, 2019
836928e
feat: add delete method.
ytetsuro Dec 31, 2019
d6b5223
feat: add limit method.
ytetsuro Dec 31, 2019
10b6d80
feat: add reset select method.
ytetsuro Dec 31, 2019
26277b8
remove: unncessary method and property.
ytetsuro Dec 31, 2019
08fc170
feat: add necessary properties.
ytetsuro Dec 31, 2019
02c86e0
style: fix doc comment style.
ytetsuro Dec 31, 2019
e181418
feat: add alter table method.
ytetsuro Dec 31, 2019
0ce7e2e
feat: add auto increment method.
ytetsuro Dec 31, 2019
9b0a9d8
feat: add processColumn method.
ytetsuro Dec 31, 2019
0538af6
feat: merge column type method.
ytetsuro Dec 31, 2019
3f8d252
feat: add drop table method.
ytetsuro Dec 31, 2019
53e4421
feat: add forgen key method.
ytetsuro Dec 31, 2019
4236bae
feat: add prepear method.
ytetsuro Dec 31, 2019
d2fc77e
feat: add bind process.
ytetsuro Dec 31, 2019
08153a5
feat: add get result method.
ytetsuro Dec 31, 2019
0c7fc2f
feat: add parameterize method.
ytetsuro Dec 31, 2019
6dea7b1
feat: add get field count method.
ytetsuro Dec 31, 2019
e9bd2ca
feat: add get fieldNames method.
ytetsuro Dec 31, 2019
739c74e
feat: add get field data method.
ytetsuro Dec 31, 2019
dfdb6e0
feat: add free result method.
ytetsuro Dec 31, 2019
da3674b
feat: add data Seek method.
ytetsuro Dec 31, 2019
0e37935
feat: fetchAssoc method.
ytetsuro Dec 31, 2019
3c42fd2
feat: add fetchObject method.
ytetsuro Dec 31, 2019
9fe2661
feat: define property.
ytetsuro Dec 31, 2019
82a22dc
test: add test for oci listDatabase method.
ytetsuro Dec 31, 2019
e07cee0
test: add databaseExists test for oci8.
ytetsuro Dec 31, 2019
b26946e
fix: skip not support oci8 test.
ytetsuro Dec 31, 2019
0a684f4
style: fix style.
ytetsuro Jan 3, 2020
1e33e52
test: add test for get foreign key method.
ytetsuro Jan 3, 2020
65ff057
test: add test for add field method.
ytetsuro Jan 3, 2020
14fd82c
fix: remove comment.
ytetsuro Jan 14, 2020
01d92b8
fix: remove as keyword.
ytetsuro Jan 14, 2020
6f19c1b
feat: insertBatch for auto increment.
ytetsuro Jan 14, 2020
4a26bd5
feat: add replace command.
ytetsuro Jan 14, 2020
5b9167f
fix: update method for limit.
ytetsuro Jan 14, 2020
5798e8e
feat: add insertId method, @todo: has a strange design.
ytetsuro Jan 14, 2020
ea52a9e
feat: add nullable flag.
ytetsuro Jan 14, 2020
3a83365
fix: remove dbPrefix.
ytetsuro Jan 14, 2020
cd5db61
style: fix code style.
ytetsuro Jan 14, 2020
5315ada
fix: ORA-01451
ytetsuro Jan 14, 2020
74db15b
fix: Fix to be able to update identity.
ytetsuro Jan 14, 2020
b6a96fa
feat: Specified default length.
ytetsuro Jan 14, 2020
d9ebce1
style: fix code style.
ytetsuro Jan 14, 2020
cad4a7e
fix: Fixed typing errors.
ytetsuro Jan 14, 2020
17b2e1f
fix: dbname to upper.
ytetsuro Jan 14, 2020
2576896
test: skip to not support oci.
ytetsuro Jan 14, 2020
60b55e4
test: fix column type.
ytetsuro Jan 14, 2020
850b598
test: add getIndexData.
ytetsuro Jan 14, 2020
96e2fcb
test: add escape.
ytetsuro Jan 14, 2020
8a41297
test: add last insert id.
ytetsuro Jan 14, 2020
cc75e37
test: add test case for not escape.
ytetsuro Jan 14, 2020
940222f
test: add test case for sub query.
ytetsuro Jan 14, 2020
fc3f80f
feat: add test case for dataSeek.
ytetsuro Jan 14, 2020
2e7df63
docs: add note.
ytetsuro Jan 16, 2020
3c27a6f
fix: too many connection.
ytetsuro Jan 29, 2020
e70071b
fix: the random value retrieval is now not affected by DB prefix.
ytetsuro Sep 8, 2021
623bf34
fix: due to supported ignoreOffset.
ytetsuro Sep 8, 2021
029a8fb
fix: Not throw execute error when DBDebug is false.
ytetsuro Sep 8, 2021
a547c29
fix: fixed happen error when multiple column in bulk drop.
ytetsuro Sep 8, 2021
ef9ffc0
feat: Fixed to store missing types in oracle.
ytetsuro Sep 8, 2021
429cc0b
feat: Use check constraint to reproduce the enum.
ytetsuro Sep 8, 2021
555a9b2
fix: Aligned the API with the changed interface.
ytetsuro Sep 8, 2021
7949505
fix: Date types are now added according to the Oracle format.
ytetsuro Sep 8, 2021
9865743
fix: syntax error.
ytetsuro Sep 8, 2021
d6f0cd2
fix: Due to table name to long.
ytetsuro Sep 8, 2021
a6c53c7
fix: Fixed to fit the problem that the structure of seeder has changed.
ytetsuro Sep 8, 2021
bcde669
test: add OCI8 case for RANDOM.
ytetsuro Sep 8, 2021
9098891
fix: Since it is treated as uppercase unless explicitly specified.
ytetsuro Sep 8, 2021
b9ce6ea
feat: Due to name of the tablespace is not defined in the property wh…
ytetsuro Sep 8, 2021
6e97504
style: php -d memory_limit=-1 ./vendor/bin/php-cs-fixer fix system/Da…
ytetsuro Sep 8, 2021
a77ad8d
style: php -d memory_limit=-1 ./vendor/bin/phpstan analyse
ytetsuro Sep 9, 2021
5fc81d8
fix: BOOLEAN is now cast to NUMBER.
ytetsuro Sep 9, 2021
f2924f6
fix: support CompositeForeignKey.
ytetsuro Sep 9, 2021
205d869
style: php -d memory_limit=-1 ./vendor/bin/php-cs-fixer fix
ytetsuro Sep 9, 2021
5a6cc7c
fix: Changed foreach for object to be performed on the return value o…
ytetsuro Sep 9, 2021
9be4e2f
refactor: vendor/bin/rector
ytetsuro Sep 15, 2021
2e5ffef
fix: user_id -> users_id
ytetsuro Sep 16, 2021
a69f281
style: vendor/bin/php-cs-fixer fix
ytetsuro Sep 16, 2021
4a919fc
docs: fix link path.
ytetsuro Sep 16, 2021
202f3ec
fix: remove unnecessary escape. i can’t imagine set key is not column.
ytetsuro Sep 23, 2021
61ad650
fix: fix fail bulk insert when table has auto increment column.
ytetsuro Sep 23, 2021
6a6472a
test: add escape for lower case column name.
ytetsuro Sep 23, 2021
6109a72
fix: fixed groupBy column not matching select column.
ytetsuro Sep 23, 2021
015840a
test: Added skip test for create database.
ytetsuro Sep 23, 2021
4622e3c
fix: Changed the database property to be immutable.
ytetsuro Sep 25, 2021
99c20e4
style: vendor/bin/php-cs-fixer fix --verbose --ansi --using-cache=no …
ytetsuro Sep 25, 2021
a37b852
chore: Add phpunit workflow for oci8.
ytetsuro Sep 25, 2021
523333a
docs: MySQLi -> OCI8
ytetsuro Sep 25, 2021
751243b
docs: i writed that oci8 is supported.
ytetsuro Sep 25, 2021
e3a2a69
test: Fixed to use escaped column names based on whether they are ANS…
ytetsuro Sep 28, 2021
97cb609
test: fixed using variables for column names.
ytetsuro Sep 29, 2021
5408d8b
test: The process of generating select by character concatenation is …
ytetsuro Oct 3, 2021
e9260fe
feat: Fixed the problem that 1 is always returned when the type is no…
ytetsuro Oct 14, 2021
31a6540
docs: fix typo Postgres -> OCI8
ytetsuro Oct 14, 2021
d7c2693
fix: access level for DBDriver property
ytetsuro Oct 14, 2021
cb29df0
style: composer cs-fix
ytetsuro Oct 14, 2021
1a84ca0
docs: add @used-by for OCI8
ytetsuro Oct 19, 2021
8a0fca9
docs: remove unnecessary @property annotation for OCI8
ytetsuro Oct 19, 2021
275f729
docs: The query method explicitly states that insertId cannot be obta…
ytetsuro Oct 19, 2021
0e9d056
fix: The scope of the access modifier has been changed to protected.
ytetsuro Oct 19, 2021
e7cb7c9
docs: add @used-by for commitMode
ytetsuro Oct 19, 2021
70a1fca
docs: remove unnecessary comment.
ytetsuro Oct 19, 2021
51686fc
style: fix indent.
ytetsuro Oct 19, 2021
45c4ffb
style: It seems that the reference operator needs to cover the result.
ytetsuro Oct 19, 2021
0295774
style: using sprintf for create query.
ytetsuro Oct 19, 2021
c3ce98f
style: Fixed ternary operator style as noted.
ytetsuro Oct 19, 2021
b8f0b5e
style: importd stdClass.
ytetsuro Oct 19, 2021
7b2a9c0
style: Changed to start conditions from literals.
ytetsuro Oct 19, 2021
c57778c
style: Removed unnecessary parentheses.
ytetsuro Oct 19, 2021
9fb0685
style: remove empty line.
ytetsuro Oct 19, 2021
68cff03
style: fix indent
ytetsuro Oct 19, 2021
2169360
style: Removed unnecessary parentheses.
ytetsuro Oct 19, 2021
a6a8c40
style: Removed unnecessary parentheses.
ytetsuro Oct 19, 2021
2b0b3ad
style: Removed unnecessary parentheses.
ytetsuro Oct 19, 2021
5e610f9
docs: fixme -> todo
ytetsuro Oct 19, 2021
0f2dc49
style: dual -> DUAL
ytetsuro Oct 19, 2021
310d724
refactor: latestInsertedTableName -> lastInsertedTableName
ytetsuro Oct 20, 2021
61fbf49
fix: Fixed a code that should have been specified as an argument, but…
ytetsuro Oct 20, 2021
b3a5ae7
style: cs-fixer error.
ytetsuro Oct 20, 2021
e653cdc
style: fix for rector.
ytetsuro Oct 20, 2021
1d8f6cc
docs: I made sure to start with zero bindings.
ytetsuro Oct 20, 2021
c63db89
style: I stopped using yoda notation.
ytetsuro Oct 21, 2021
a776475
style: remove comment.
ytetsuro Oct 21, 2021
d072269
test: Add a test for lastInsertId.
ytetsuro Oct 24, 2021
6c074e6
feat: To know the last insertID for OCI8.
ytetsuro Oct 24, 2021
6cfb0be
feat: Added getting the last insertID.
ytetsuro Oct 24, 2021
fd8057a
feat: Added the ability to get the last insertID even when executing …
ytetsuro Oct 24, 2021
2745e6a
docs: remove unneeded note.
ytetsuro Oct 24, 2021
1cee894
test: add setUp for skipTest when using OCI8 driver
ytetsuro Oct 24, 2021
7644cdd
test: add return type for setUp method.
ytetsuro Oct 27, 2021
2d18992
feat: add dropIndexStr for OCI8.
ytetsuro Nov 28, 2021
e78d8c3
feat: add test case.
ytetsuro Nov 28, 2021
40fce31
style: compover cs-fix
ytetsuro Nov 28, 2021
7e2424f
test: import need module.
ytetsuro Nov 28, 2021
3f700c6
chore: add stored procedure in github actions for oracle database.
ytetsuro Dec 18, 2021
9c170aa
feat: add call storedProcedure test.
ytetsuro Dec 18, 2021
c4f2e69
style: composer cs-fix
ytetsuro Dec 19, 2021
190f76d
feat: Removed semicolon from ALTER TABLE to make it distinguish betwe…
ytetsuro Dec 29, 2021
fb62ab2
chore: Defined the stored procedure needed for the test.
ytetsuro Dec 29, 2021
8638ac2
chore: composer update --ansi --no-interaction && vendor/bin/rector p…
ytetsuro Jan 15, 2022
0cb021a
docs: add oci8 description in changelog.
ytetsuro Jan 15, 2022
50547e8
docs: Added a document to the query method about the presence of semi…
ytetsuro Jan 15, 2022
a46d0bb
chore: vendor/bin/php-cs-fixer fix --verbose --ansi
ytetsuro Jan 15, 2022
7f09031
docs: Fixed the incomprehensible changelog.
ytetsuro Jan 15, 2022
870bd27
docs: add backquote.
ytetsuro Jan 15, 2022
b01f918
refactor: Removed unnecessary processes.
ytetsuro Jan 16, 2022
5feae18
docs: fix phpdoc for storedProcedure
ytetsuro Jan 23, 2022
5c1cda1
test: add call stored procedure test for cursor.
ytetsuro Jan 23, 2022
c1bbee8
feat: add getDriverFunctionPrefix for oci8
ytetsuro Jan 23, 2022
fb1fb00
docs: remove unnecessary notes in Oracle for random sort.
ytetsuro Jan 23, 2022
af2654b
docs: fix return type for storedProcedure method.
ytetsuro Jan 23, 2022
76c1029
chore: composer cs-fix && ./vendor/bin/rector process system/Database…
ytetsuro Jan 23, 2022
119b59a
fix: Fixed to problem PLSQL will be treated as SQL when the first wor…
ytetsuro Jan 24, 2022
c7d1620
style: composer cs-fix
ytetsuro Jan 24, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions .github/workflows/test-phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
fail-fast: false
matrix:
php-versions: ['7.4', '8.0', '8.1']
db-platforms: ['MySQLi', 'Postgre', 'SQLite3', 'SQLSRV']
db-platforms: ['MySQLi', 'Postgre', 'SQLite3', 'SQLSRV', 'OCI8']
mysql-versions: ['5.7']
include:
- php-versions: '7.4'
Expand Down Expand Up @@ -68,6 +68,14 @@ jobs:
- 1433:1433
options: --health-cmd="/opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U sa -P 1Secure*Password1 -Q 'SELECT @@VERSION'" --health-interval=10s --health-timeout=5s --health-retries=3

oracle:
image: quillbuilduser/oracle-18-xe
env:
ORACLE_ALLOW_REMOTE: true
ports:
- 1521:1521
options: --health-cmd="/opt/oracle/product/18c/dbhomeXE/bin/sqlplus -s sys/Oracle18@oracledbxe/XE as sysdba <<< 'SELECT 1 FROM DUAL'" --health-interval=10s --health-timeout=5s --health-retries=3

redis:
image: redis
ports:
Expand All @@ -84,6 +92,28 @@ jobs:
if: matrix.db-platforms == 'SQLSRV'
run: sqlcmd -S 127.0.0.1 -U sa -P 1Secure*Password1 -Q "CREATE DATABASE test"

- name: Install Oracle InstantClient
if: matrix.db-platforms == 'OCI8'
run: |
sudo apt-get install wget libaio1 alien
sudo wget https://download.oracle.com/otn_software/linux/instantclient/185000/oracle-instantclient18.5-basic-18.5.0.0.0-3.x86_64.rpm
sudo wget https://download.oracle.com/otn_software/linux/instantclient/185000/oracle-instantclient18.5-devel-18.5.0.0.0-3.x86_64.rpm
sudo wget https://download.oracle.com/otn_software/linux/instantclient/185000/oracle-instantclient18.5-sqlplus-18.5.0.0.0-3.x86_64.rpm
sudo alien oracle-instantclient18.5-basic-18.5.0.0.0-3.x86_64.rpm
sudo alien oracle-instantclient18.5-devel-18.5.0.0.0-3.x86_64.rpm
sudo alien oracle-instantclient18.5-sqlplus-18.5.0.0.0-3.x86_64.rpm
sudo dpkg -i oracle-instantclient18.5-basic_18.5.0.0.0-4_amd64.deb oracle-instantclient18.5-devel_18.5.0.0.0-4_amd64.deb oracle-instantclient18.5-sqlplus_18.5.0.0.0-4_amd64.deb
echo "LD_LIBRARY_PATH=/lib/oracle/18.5/client64/lib/" >> $GITHUB_ENV
echo "NLS_LANG=AMERICAN_AMERICA.UTF8" >> $GITHUB_ENV
echo "C_INCLUDE_PATH=/usr/include/oracle/18.5/client64" >> $GITHUB_ENV
echo 'NLS_DATE_FORMAT=YYYY-MM-DD HH24:MI:SS' >> $GITHUB_ENV
echo 'NLS_TIMESTAMP_FORMAT=YYYY-MM-DD HH24:MI:SS' >> $GITHUB_ENV
echo 'NLS_TIMESTAMP_TZ_FORMAT=YYYY-MM-DD HH24:MI:SS' >> $GITHUB_ENV

- name: Create database for Oracle Database
if: matrix.db-platforms == 'OCI8'
run: echo -e "ALTER SESSION SET CONTAINER = XEPDB1;\nCREATE BIGFILE TABLESPACE \"TEST\" DATAFILE '/opt/oracle/product/18c/dbhomeXE/dbs/TEST' SIZE 10M AUTOEXTEND ON MAXSIZE UNLIMITED SEGMENT SPACE MANAGEMENT AUTO EXTENT MANAGEMENT LOCAL AUTOALLOCATE;\nCREATE USER \"ORACLE\" IDENTIFIED BY \"ORACLE\" DEFAULT TABLESPACE \"TEST\" TEMPORARY TABLESPACE TEMP QUOTA UNLIMITED ON \"TEST\";\nGRANT CONNECT,RESOURCE TO \"ORACLE\";\nexit;" | /lib/oracle/18.5/client64/bin/sqlplus -s sys/Oracle18@localhost:1521/XE as sysdba

- name: Checkout
uses: actions/checkout@v2

Expand All @@ -92,7 +122,7 @@ jobs:
with:
php-version: ${{ matrix.php-versions }}
tools: composer, pecl
extensions: imagick, sqlsrv, gd, sqlite3, redis, memcached, pgsql
extensions: imagick, sqlsrv, gd, sqlite3, redis, memcached, oci8, pgsql
coverage: xdebug
env:
update: true
Expand Down
231 changes: 231 additions & 0 deletions system/Database/OCI8/Builder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
<?php

/**
* This file is part of CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace CodeIgniter\Database\OCI8;

use CodeIgniter\Database\BaseBuilder;
use CodeIgniter\Database\Exceptions\DatabaseException;

/**
* Builder for OCI8
*/
class Builder extends BaseBuilder
{
/**
* Identifier escape character
*
* @var string
*/
protected $escapeChar = '"';

/**
* ORDER BY random keyword
*
* @var array
*/
protected $randomKeyword = [
'"DBMS_RANDOM"."RANDOM"',
];

/**
* COUNT string
*
* @used-by CI_DB_driver::count_all()
* @used-by BaseBuilder::count_all_results()
*
* @var string
*/
protected $countString = 'SELECT COUNT(1) ';

/**
* Limit used flag
*
* If we use LIMIT, we'll add a field that will
* throw off num_fields later.
*
* @var bool
*/
protected $limitUsed = false;

/**
* A reference to the database connection.
*
* @var Connection
*/
protected $db;

/**
* Generates a platform-specific insert string from the supplied data.
*/
protected function _insertBatch(string $table, array $keys, array $values): string
{
$insertKeys = implode(', ', $keys);
$hasPrimaryKey = in_array('PRIMARY', array_column($this->db->getIndexData($table), 'type'), true);

// ORA-00001 measures
if ($hasPrimaryKey) {
$sql = 'INSERT INTO ' . $table . ' (' . $insertKeys . ") \n SELECT * FROM (\n";
$selectQueryValues = [];

foreach ($values as $value) {
$selectValues = implode(',', array_map(static fn ($value, $key) => $value . ' as ' . $key, explode(',', substr(substr($value, 1), 0, -1)), $keys));
$selectQueryValues[] = 'SELECT ' . $selectValues . ' FROM DUAL';
}

return $sql . implode("\n UNION ALL \n", $selectQueryValues) . "\n)";
}

$sql = "INSERT ALL\n";

foreach ($values as $value) {
$sql .= ' INTO ' . $table . ' (' . $insertKeys . ') VALUES ' . $value . "\n";
}

return $sql . 'SELECT * FROM DUAL';
}

/**
* Generates a platform-specific replace string from the supplied data
*/
protected function _replace(string $table, array $keys, array $values): string
{
$fieldNames = array_map(static fn ($columnName) => trim($columnName, '"'), $keys);

$uniqueIndexes = array_filter($this->db->getIndexData($table), static function ($index) use ($fieldNames) {
$hasAllFields = count(array_intersect($index->fields, $fieldNames)) === count($index->fields);

return ($index->type === 'PRIMARY') && $hasAllFields;
});
$replaceableFields = array_filter($keys, static function ($columnName) use ($uniqueIndexes) {
foreach ($uniqueIndexes as $index) {
if (in_array(trim($columnName, '"'), $index->fields, true)) {
return false;
}
}

return true;
});

$sql = 'MERGE INTO ' . $table . "\n USING (SELECT ";

$sql .= implode(', ', array_map(static fn ($columnName, $value) => $value . ' ' . $columnName, $keys, $values));

$sql .= ' FROM DUAL) "_replace" ON ( ';

$onList = [];
$onList[] = '1 != 1';

foreach ($uniqueIndexes as $index) {
$onList[] = '(' . implode(' AND ', array_map(static fn ($columnName) => $table . '."' . $columnName . '" = "_replace"."' . $columnName . '"', $index->fields)) . ')';
}

$sql .= implode(' OR ', $onList) . ') WHEN MATCHED THEN UPDATE SET ';

$sql .= implode(', ', array_map(static fn ($columnName) => $columnName . ' = "_replace".' . $columnName, $replaceableFields));

$sql .= ' WHEN NOT MATCHED THEN INSERT (' . implode(', ', $replaceableFields) . ') VALUES ';
$sql .= ' (' . implode(', ', array_map(static fn ($columnName) => '"_replace".' . $columnName, $replaceableFields)) . ')';

return $sql;
}

/**
* Generates a platform-specific truncate string from the supplied data
*
* If the database does not support the truncate() command,
* then this method maps to 'DELETE FROM table'
*/
protected function _truncate(string $table): string
{
return 'TRUNCATE TABLE ' . $table;
}

/**
* Compiles a delete string and runs the query
*
* @param mixed $where
*
* @throws DatabaseException
*
* @return mixed
*/
public function delete($where = '', ?int $limit = null, bool $resetData = true)
{
if (! empty($limit)) {
$this->QBLimit = $limit;
}

return parent::delete($where, null, $resetData);
}

/**
* Generates a platform-specific delete string from the supplied data
*/
protected function _delete(string $table): string
{
if ($this->QBLimit) {
$this->where('rownum <= ', $this->QBLimit, false);
$this->QBLimit = false;
}

return parent::_delete($table);
}

/**
* Generates a platform-specific update string from the supplied data
*/
protected function _update(string $table, array $values): string
{
$valStr = [];

foreach ($values as $key => $val) {
$valStr[] = $key . ' = ' . $val;
}

if ($this->QBLimit) {
$this->where('rownum <= ', $this->QBLimit, false);
}

return 'UPDATE ' . $this->compileIgnore('update') . $table . ' SET ' . implode(', ', $valStr)
. $this->compileWhereHaving('QBWhere')
. $this->compileOrderBy();
}

/**
* Generates a platform-specific LIMIT clause.
*/
protected function _limit(string $sql, bool $offsetIgnore = false): string
{
$offset = (int) ($offsetIgnore === false ? $this->QBOffset : 0);
if (version_compare($this->db->getVersion(), '12.1', '>=')) {
// OFFSET-FETCH can be used only with the ORDER BY clause
if (empty($this->QBOrderBy)) {
$sql .= ' ORDER BY 1';
}

return $sql . ' OFFSET ' . $offset . ' ROWS FETCH NEXT ' . $this->QBLimit . ' ROWS ONLY';
}

$this->limitUsed = true;
$limitTemplateQuery = 'SELECT * FROM (SELECT INNER_QUERY.*, ROWNUM RNUM FROM (%s) INNER_QUERY WHERE ROWNUM < %d)' . ($offset ? ' WHERE RNUM >= %d' : '');

return sprintf($limitTemplateQuery, $sql, $offset + $this->QBLimit + 1, $offset);
}

/**
* Resets the query builder values. Called by the get() function
*/
protected function resetSelect()
{
$this->limitUsed = false;
parent::resetSelect();
}
}
Loading