Skip to content

Commit 8641cde

Browse files
authored
Merge pull request #6689 from sclubricants/insertUpsertUpdateFromQuery
insertBatch updateBatch upsertBatch deleteBatch from query
2 parents 64f7ecc + 2154e87 commit 8641cde

File tree

16 files changed

+653
-40
lines changed

16 files changed

+653
-40
lines changed

system/Database/BaseBuilder.php

Lines changed: 132 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ class BaseBuilder
169169
* tableIdentity?: string,
170170
* updateFields?: array,
171171
* constraints?: array,
172-
* fromQuery?: string,
172+
* setQueryAsData?: string,
173173
* sql?: string,
174174
* alias?: string
175175
* }
@@ -1925,6 +1925,22 @@ public function upsert($set = null, ?bool $escape = null)
19251925
*/
19261926
public function upsertBatch($set = null, ?bool $escape = null, int $batchSize = 100)
19271927
{
1928+
if (isset($this->QBOptions['setQueryAsData'])) {
1929+
$sql = $this->_upsertBatch($this->QBFrom[0], $this->QBKeys, []);
1930+
1931+
if ($sql === '') {
1932+
return false; // @codeCoverageIgnore
1933+
}
1934+
1935+
if ($this->testMode === false) {
1936+
$this->db->query($sql, null, false);
1937+
}
1938+
1939+
$this->resetWrite();
1940+
1941+
return $this->testMode ? $sql : $this->db->affectedRows();
1942+
}
1943+
19281944
if ($set !== null) {
19291945
$this->setData($set, $escape);
19301946
}
@@ -1965,8 +1981,8 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
19651981
$this->QBOptions['sql'] = $sql;
19661982
}
19671983

1968-
if (isset($this->QBOptions['fromQuery'])) {
1969-
$data = $this->QBOptions['fromQuery'];
1984+
if (isset($this->QBOptions['setQueryAsData'])) {
1985+
$data = $this->QBOptions['setQueryAsData'];
19701986
} else {
19711987
$data = 'VALUES ' . implode(', ', $this->formatValues($values)) . "\n";
19721988
}
@@ -2067,6 +2083,60 @@ public function onConstraint($set)
20672083
return $this;
20682084
}
20692085

2086+
/**
2087+
* Sets data source as a query for insertBatch()/updateBatch()/upsertBatch()/deleteBatch()
2088+
*
2089+
* @param BaseBuilder|RawSql $query
2090+
* @param array|string|null $columns an array or comma delimited string of columns
2091+
*/
2092+
public function setQueryAsData($query, ?string $alias = null, $columns = null): BaseBuilder
2093+
{
2094+
if (is_string($query)) {
2095+
throw new InvalidArgumentException('$query parameter must be BaseBuilder or RawSql class.');
2096+
}
2097+
2098+
if ($query instanceof BaseBuilder) {
2099+
$query = $query->getCompiledSelect();
2100+
} elseif ($query instanceof RawSql) {
2101+
$query = $query->__toString();
2102+
}
2103+
2104+
if (is_string($query)) {
2105+
if ($columns !== null && is_string($columns)) {
2106+
$columns = explode(',', $columns);
2107+
$columns = array_map(static fn ($key) => trim($key), $columns);
2108+
}
2109+
2110+
$columns = (array) $columns;
2111+
2112+
if ($columns === []) {
2113+
$columns = $this->fieldsFromQuery($query);
2114+
}
2115+
2116+
if ($alias !== null) {
2117+
$this->setAlias($alias);
2118+
}
2119+
2120+
foreach ($columns as $key => $value) {
2121+
$columns[$key] = $this->db->escapeChar . $value . $this->db->escapeChar;
2122+
}
2123+
2124+
$this->QBOptions['setQueryAsData'] = $query;
2125+
$this->QBKeys = $columns;
2126+
$this->QBSet = [];
2127+
}
2128+
2129+
return $this;
2130+
}
2131+
2132+
/**
2133+
* Gets column names from a select query
2134+
*/
2135+
protected function fieldsFromQuery(string $sql): array
2136+
{
2137+
return $this->db->query('SELECT * FROM (' . $sql . ') _u_ LIMIT 1')->getFieldNames();
2138+
}
2139+
20702140
/**
20712141
* Converts value array of array to array of strings
20722142
*/
@@ -2084,6 +2154,22 @@ protected function formatValues(array $values): array
20842154
*/
20852155
public function insertBatch($set = null, ?bool $escape = null, int $batchSize = 100)
20862156
{
2157+
if (isset($this->QBOptions['setQueryAsData'])) {
2158+
$sql = $this->_insertBatch($this->QBFrom[0], $this->QBKeys, []);
2159+
2160+
if ($sql === '') {
2161+
return false; // @codeCoverageIgnore
2162+
}
2163+
2164+
if ($this->testMode === false) {
2165+
$this->db->query($sql, null, false);
2166+
}
2167+
2168+
$this->resetWrite();
2169+
2170+
return $this->testMode ? $sql : $this->db->affectedRows();
2171+
}
2172+
20872173
if ($set !== null && $set !== []) {
20882174
$this->setData($set, $escape);
20892175
}
@@ -2114,8 +2200,8 @@ protected function _insertBatch(string $table, array $keys, array $values): stri
21142200
$this->QBOptions['sql'] = $sql;
21152201
}
21162202

2117-
if (isset($this->QBOptions['fromQuery'])) {
2118-
$data = $this->QBOptions['fromQuery'];
2203+
if (isset($this->QBOptions['setQueryAsData'])) {
2204+
$data = $this->QBOptions['setQueryAsData'];
21192205
} else {
21202206
$data = 'VALUES ' . implode(', ', $this->formatValues($values));
21212207
}
@@ -2427,9 +2513,9 @@ protected function validateUpdate(): bool
24272513
}
24282514

24292515
/**
2430-
* Sets data and calls batchExecute to run queryies
2516+
* Sets data and calls batchExecute to run queries
24312517
*
2432-
* @param array|object|null $set a dataset or select query
2518+
* @param array|object|null $set a dataset
24332519
* @param array|RawSql|string|null $constraints
24342520
*
24352521
* @return false|int|string[] Number of rows affected or FALSE on failure, SQL array when testMode
@@ -2438,6 +2524,22 @@ public function updateBatch($set = null, $constraints = null, int $batchSize = 1
24382524
{
24392525
$this->onConstraint($constraints);
24402526

2527+
if (isset($this->QBOptions['setQueryAsData'])) {
2528+
$sql = $this->_updateBatch($this->QBFrom[0], $this->QBKeys, []);
2529+
2530+
if ($sql === '') {
2531+
return false; // @codeCoverageIgnore
2532+
}
2533+
2534+
if ($this->testMode === false) {
2535+
$this->db->query($sql, null, false);
2536+
}
2537+
2538+
$this->resetWrite();
2539+
2540+
return $this->testMode ? $sql : $this->db->affectedRows();
2541+
}
2542+
24412543
if ($set !== null && $set !== []) {
24422544
$this->setData($set, true);
24432545
}
@@ -2521,8 +2623,8 @@ protected function _updateBatch(string $table, array $keys, array $values): stri
25212623
$this->QBOptions['sql'] = $sql;
25222624
}
25232625

2524-
if (isset($this->QBOptions['fromQuery'])) {
2525-
$data = $this->QBOptions['fromQuery'];
2626+
if (isset($this->QBOptions['setQueryAsData'])) {
2627+
$data = $this->QBOptions['setQueryAsData'];
25262628
} else {
25272629
$data = implode(
25282630
" UNION ALL\n",
@@ -2677,7 +2779,7 @@ public function delete($where = '', ?int $limit = null, bool $resetData = true)
26772779
/**
26782780
* Sets data and calls batchExecute to run queries
26792781
*
2680-
* @param array|object|null $set a dataset or select query
2782+
* @param array|object|null $set a dataset
26812783
* @param array|RawSql|null $constraints
26822784
*
26832785
* @return false|int|string[] Number of rows affected or FALSE on failure, SQL array when testMode
@@ -2686,6 +2788,22 @@ public function deleteBatch($set = null, $constraints = null, int $batchSize = 1
26862788
{
26872789
$this->onConstraint($constraints);
26882790

2791+
if (isset($this->QBOptions['setQueryAsData'])) {
2792+
$sql = $this->_deleteBatch($this->QBFrom[0], $this->QBKeys, []);
2793+
2794+
if ($sql === '') {
2795+
return false; // @codeCoverageIgnore
2796+
}
2797+
2798+
if ($this->testMode === false) {
2799+
$this->db->query($sql, null, false);
2800+
}
2801+
2802+
$this->resetWrite();
2803+
2804+
return $this->testMode ? $sql : $this->db->affectedRows();
2805+
}
2806+
26892807
if ($set !== null && $set !== []) {
26902808
$this->setData($set, true);
26912809
}
@@ -2757,8 +2875,8 @@ protected function _deleteBatch(string $table, array $keys, array $values): stri
27572875
$this->QBOptions['sql'] = trim($sql);
27582876
}
27592877

2760-
if (isset($this->QBOptions['fromQuery'])) {
2761-
$data = $this->QBOptions['fromQuery'];
2878+
if (isset($this->QBOptions['setQueryAsData'])) {
2879+
$data = $this->QBOptions['setQueryAsData'];
27622880
} else {
27632881
$data = implode(
27642882
" UNION ALL\n",
@@ -3156,7 +3274,7 @@ protected function isLiteral(string $str): bool
31563274
*
31573275
* @return $this
31583276
*/
3159-
public function resetQuery()
3277+
public function resetQueryAsData()
31603278
{
31613279
$this->resetSelect();
31623280
$this->resetWrite();
@@ -3311,7 +3429,7 @@ protected function setBind(string $key, $value = null, bool $escape = true): str
33113429
*/
33123430
protected function cleanClone()
33133431
{
3314-
return (clone $this)->from([], true)->resetQuery();
3432+
return (clone $this)->from([], true)->resetQueryAsData();
33153433
}
33163434

33173435
/**

system/Database/MySQLi/Builder.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,8 @@ protected function _updateBatch(string $table, array $keys, array $values): stri
124124
$this->QBOptions['sql'] = $sql;
125125
}
126126

127-
if (isset($this->QBOptions['fromQuery'])) {
128-
$data = $this->QBOptions['fromQuery'];
127+
if (isset($this->QBOptions['setQueryAsData'])) {
128+
$data = $this->QBOptions['setQueryAsData'];
129129
} else {
130130
$data = implode(
131131
" UNION ALL\n",

system/Database/OCI8/Builder.php

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,8 @@ protected function _insertBatch(string $table, array $keys, array $values): stri
8181
$this->QBOptions['sql'] = $sql;
8282
}
8383

84-
if (isset($this->QBOptions['fromQuery'])) {
85-
$data = $this->QBOptions['fromQuery'];
84+
if (isset($this->QBOptions['setQueryAsData'])) {
85+
$data = $this->QBOptions['setQueryAsData'];
8686
} else {
8787
$data = implode(
8888
" FROM DUAL UNION ALL\n",
@@ -307,8 +307,8 @@ protected function _updateBatch(string $table, array $keys, array $values): stri
307307
$this->QBOptions['sql'] = $sql;
308308
}
309309

310-
if (isset($this->QBOptions['fromQuery'])) {
311-
$data = $this->QBOptions['fromQuery'];
310+
if (isset($this->QBOptions['setQueryAsData'])) {
311+
$data = $this->QBOptions['setQueryAsData'];
312312
} else {
313313
$data = implode(
314314
" UNION ALL\n",
@@ -416,8 +416,8 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
416416
$this->QBOptions['sql'] = $sql;
417417
}
418418

419-
if (isset($this->QBOptions['fromQuery'])) {
420-
$data = $this->QBOptions['fromQuery'];
419+
if (isset($this->QBOptions['setQueryAsData'])) {
420+
$data = $this->QBOptions['setQueryAsData'];
421421
} else {
422422
$data = implode(
423423
" FROM DUAL UNION ALL\n",
@@ -495,8 +495,8 @@ protected function _deleteBatch(string $table, array $keys, array $values): stri
495495
$this->QBOptions['sql'] = $sql;
496496
}
497497

498-
if (isset($this->QBOptions['fromQuery'])) {
499-
$data = $this->QBOptions['fromQuery'];
498+
if (isset($this->QBOptions['setQueryAsData'])) {
499+
$data = $this->QBOptions['setQueryAsData'];
500500
} else {
501501
$data = implode(
502502
" FROM DUAL UNION ALL\n",
@@ -513,4 +513,12 @@ protected function _deleteBatch(string $table, array $keys, array $values): stri
513513

514514
return str_replace('{:_table_:}', $data, $sql);
515515
}
516+
517+
/**
518+
* Gets column names from a select query
519+
*/
520+
protected function fieldsFromQuery(string $sql): array
521+
{
522+
return $this->db->query('SELECT * FROM (' . $sql . ') "_u_" WHERE ROWNUM = 1')->getFieldNames();
523+
}
516524
}

system/Database/Postgre/Builder.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,8 @@ protected function _insertBatch(string $table, array $keys, array $values): stri
209209
$this->QBOptions['sql'] = $sql;
210210
}
211211

212-
if (isset($this->QBOptions['fromQuery'])) {
213-
$data = $this->QBOptions['fromQuery'];
212+
if (isset($this->QBOptions['setQueryAsData'])) {
213+
$data = $this->QBOptions['setQueryAsData'];
214214
} else {
215215
$data = 'VALUES ' . implode(', ', $this->formatValues($values));
216216
}
@@ -400,8 +400,8 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
400400
$this->QBOptions['sql'] = $sql;
401401
}
402402

403-
if (isset($this->QBOptions['fromQuery'])) {
404-
$data = $this->QBOptions['fromQuery'];
403+
if (isset($this->QBOptions['setQueryAsData'])) {
404+
$data = $this->QBOptions['setQueryAsData'];
405405
} else {
406406
$data = 'VALUES ' . implode(', ', $this->formatValues($values)) . "\n";
407407
}
@@ -469,8 +469,8 @@ protected function _deleteBatch(string $table, array $keys, array $values): stri
469469
$this->QBOptions['sql'] = $sql;
470470
}
471471

472-
if (isset($this->QBOptions['fromQuery'])) {
473-
$data = $this->QBOptions['fromQuery'];
472+
if (isset($this->QBOptions['setQueryAsData'])) {
473+
$data = $this->QBOptions['setQueryAsData'];
474474
} else {
475475
$data = implode(
476476
" UNION ALL\n",

system/Database/SQLSRV/Builder.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,8 @@ protected function _insertBatch(string $table, array $keys, array $values): stri
190190
$this->QBOptions['sql'] = $sql;
191191
}
192192

193-
if (isset($this->QBOptions['fromQuery'])) {
194-
$data = $this->QBOptions['fromQuery'];
193+
if (isset($this->QBOptions['setQueryAsData'])) {
194+
$data = $this->QBOptions['setQueryAsData'];
195195
} else {
196196
$data = 'VALUES ' . implode(', ', $this->formatValues($values));
197197
}
@@ -756,12 +756,20 @@ protected function _upsertBatch(string $table, array $keys, array $values): stri
756756
$this->QBOptions['sql'] = $sql;
757757
}
758758

759-
if (isset($this->QBOptions['fromQuery'])) {
760-
$data = $this->QBOptions['fromQuery'];
759+
if (isset($this->QBOptions['setQueryAsData'])) {
760+
$data = $this->QBOptions['setQueryAsData'];
761761
} else {
762762
$data = 'VALUES ' . implode(', ', $this->formatValues($values)) . "\n";
763763
}
764764

765765
return str_replace('{:_table_:}', $data, $sql);
766766
}
767+
768+
/**
769+
* Gets column names from a select query
770+
*/
771+
protected function fieldsFromQuery(string $sql): array
772+
{
773+
return $this->db->query('SELECT TOP 1 * FROM (' . $sql . ') _u_')->getFieldNames();
774+
}
767775
}

0 commit comments

Comments
 (0)