Skip to content

Commit e70b389

Browse files
fix: isWriteType() to recognize CTE; [Postgre] allow beginning whitespace at query start, RETURNING with DELETE
1 parent 9894b92 commit e70b389

3 files changed

Lines changed: 137 additions & 8 deletions

File tree

system/Database/BaseConnection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1657,7 +1657,7 @@ public function resetDataCache()
16571657
*/
16581658
public function isWriteType($sql): bool
16591659
{
1660-
return (bool) preg_match('/^\s*"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX|MERGE)\s/i', $sql);
1660+
return (bool) preg_match('/^\s*(WITH\s(\s|.)+(\s|[)]))?"?(SET|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|TRUNCATE|LOAD|COPY|ALTER|RENAME|GRANT|REVOKE|LOCK|UNLOCK|REINDEX|MERGE)\s/i', $sql);
16611661
}
16621662

16631663
/**

system/Database/Postgre/Connection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ protected function _transRollback(): bool
577577
*/
578578
public function isWriteType($sql): bool
579579
{
580-
if (preg_match('#^(INSERT|UPDATE).*RETURNING\s.+(\,\s?.+)*$#is', $sql)) {
580+
if (preg_match('#^\s*(WITH\s(\s|.)+(\s|[)]))?(INSERT|UPDATE|DELETE).*RETURNING\s.+(\,\s?.+)*$#is', $sql)) {
581581
return false;
582582
}
583583

tests/system/Database/Live/WriteTypeQueryTest.php

Lines changed: 135 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,49 @@ public function testInsert(): void
4848

4949
$this->assertTrue($this->db->isWriteType($sql));
5050

51-
if ($this->db->DBDriver === 'Postgre') {
52-
$sql = "INSERT INTO my_table (col1, col2) VALUES ('Joe', 'Cool') RETURNING id;";
51+
$sql = "WITH seqvals AS (SELECT '3' AS seqval)INSERT INTO my_table (col1, col2) SELECT 'Joe', seqval FROM seqvals;";
52+
53+
$this->assertTrue($this->db->isWriteType($sql));
54+
55+
$sql = <<<SQL
56+
WITH seqvals AS (SELECT '3' AS seqval)
57+
INSERT INTO my_table (col1, col2)
58+
SELECT 'Joe', seqval
59+
FROM seqvals;
60+
SQL;
5361

54-
$this->assertFalse($this->db->isWriteType($sql));
62+
$this->assertTrue($this->db->isWriteType($sql));
63+
64+
$assertionType = 'assertTrue';
65+
if ($this->db->DBDriver === 'Postgre') {
66+
$assertionType = 'assertFalse';
5567
}
68+
69+
$sql = "INSERT INTO my_table (col1, col2) VALUES ('Joe', 'Cool') RETURNING id;";
70+
71+
$this->$assertionType($this->db->isWriteType($sql));
72+
73+
$sql = "WITH seqvals AS (SELECT '3' AS seqval)INSERT INTO my_table (col1, col2) SELECT 'Joe', seqval FROM seqvals RETURNING id;";
74+
75+
$this->$assertionType($this->db->isWriteType($sql));
76+
77+
$sql = <<<SQL
78+
INSERT INTO my_table (col1, col2)
79+
VALUES ('Joe', 'Cool')
80+
RETURNING id;
81+
SQL;
82+
83+
$this->$assertionType($this->db->isWriteType($sql));
84+
85+
$sql = <<<SQL
86+
WITH seqvals AS (SELECT '3' AS seqval)
87+
INSERT INTO my_table (col1, col2)
88+
SELECT 'Joe', seqval
89+
FROM seqvals
90+
RETURNING id;
91+
SQL;
92+
93+
$this->$assertionType($this->db->isWriteType($sql));
5694
}
5795

5896
public function testUpdate(): void
@@ -63,11 +101,52 @@ public function testUpdate(): void
63101

64102
$this->assertTrue($this->db->isWriteType($sql));
65103

66-
if ($this->db->DBDriver === 'Postgre') {
67-
$sql = "UPDATE my_table SET col1 = 'foo' WHERE id = 2 RETURNING *;";
104+
$sql = "WITH seqvals AS (SELECT '3' AS seqval)UPDATE my_table SET col1 = seqval FROM seqvals WHERE id = 2;";
105+
106+
$this->assertTrue($this->db->isWriteType($sql));
107+
108+
$sql = <<<SQL
109+
WITH seqvals AS (SELECT '3' AS seqval)
110+
UPDATE my_table
111+
SET col1 = seqval
112+
FROM seqvals
113+
WHERE id = 2;
114+
SQL;
68115

69-
$this->assertFalse($this->db->isWriteType($sql));
116+
$this->assertTrue($this->db->isWriteType($sql));
117+
118+
$assertionType = 'assertTrue';
119+
if ($this->db->DBDriver === 'Postgre') {
120+
$assertionType = 'assertFalse';
70121
}
122+
123+
$sql = "UPDATE my_table SET col1 = 'foo' WHERE id = 2 RETURNING *;";
124+
125+
$this->$assertionType($this->db->isWriteType($sql));
126+
127+
$sql = "WITH seqvals AS (SELECT '3' AS seqval)UPDATE my_table SET col1 = seqval FROM seqvals WHERE id = 2 RETURNING *;";
128+
129+
$this->$assertionType($this->db->isWriteType($sql));
130+
131+
$sql = <<<SQL
132+
UPDATE my_table
133+
SET col1 = 'foo'
134+
WHERE id = 2
135+
RETURNING *;
136+
SQL;
137+
138+
$this->$assertionType($this->db->isWriteType($sql));
139+
140+
$sql = <<<SQL
141+
WITH seqvals AS (SELECT '3' AS seqval)
142+
UPDATE my_table
143+
SET col1 = seqval
144+
FROM seqvals
145+
WHERE id = 2
146+
RETURNING *;
147+
SQL;
148+
149+
$this->$assertionType($this->db->isWriteType($sql));
71150
}
72151

73152
public function testDelete(): void
@@ -76,6 +155,56 @@ public function testDelete(): void
76155
$sql = $builder->testMode()->delete(['id' => 1], null, true);
77156

78157
$this->assertTrue($this->db->isWriteType($sql));
158+
159+
$sql = "DELETE FROM my_table WHERE id = 2;";
160+
161+
$this->assertTrue($this->db->isWriteType($sql));
162+
163+
$sql = "WITH seqvals AS (SELECT '3' AS seqval)DELETE FROM my_table JOIN seqvals ON col1 = seqval;";
164+
165+
$this->assertTrue($this->db->isWriteType($sql));
166+
167+
$sql = <<<SQL
168+
WITH seqvals AS
169+
(SELECT '3' AS seqval)
170+
DELETE FROM my_table
171+
JOIN seqvals
172+
ON col1 = seqval;
173+
SQL;
174+
175+
$this->assertTrue($this->db->isWriteType($sql));
176+
177+
$assertionType = 'assertTrue';
178+
if ($this->db->DBDriver === 'Postgre') {
179+
$assertionType = 'assertFalse';
180+
}
181+
182+
$sql = "DELETE FROM my_table WHERE id = 2 RETURNING *;";
183+
184+
$this->$assertionType($this->db->isWriteType($sql));
185+
186+
$sql = "WITH seqvals AS (SELECT '3' AS seqval)DELETE FROM my_table JOIN seqvals ON col1 = seqval RETURNING *;";
187+
188+
$this->$assertionType($this->db->isWriteType($sql));
189+
190+
$sql = <<<SQL
191+
DELETE FROM my_table
192+
WHERE id = 2
193+
RETURNING *;
194+
SQL;
195+
196+
$this->$assertionType($this->db->isWriteType($sql));
197+
198+
$sql = <<<SQL
199+
WITH seqvals AS
200+
(SELECT '3' AS seqval)
201+
DELETE FROM my_table
202+
JOIN seqvals
203+
ON col1 = seqval
204+
RETURNING *;
205+
SQL;
206+
207+
$this->$assertionType($this->db->isWriteType($sql));
79208
}
80209

81210
public function testReplace(): void

0 commit comments

Comments
 (0)