From b19a785e271f3e803e52dccc3606f2a6b020afa4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Apr 2024 08:56:14 +0900 Subject: [PATCH] fix: ad hoc fix for join() with BETWEEN --- system/Database/BaseBuilder.php | 8 ++++++++ system/Database/SQLSRV/Builder.php | 7 +++++++ tests/system/Database/Builder/JoinTest.php | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 1f0807cdbbde..46d94661aca6 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -654,6 +654,7 @@ public function join(string $table, $cond, string $type = '', ?bool $escape = nu $cond = ' ON ' . $cond; } else { // Split multiple conditions + // @TODO This does not parse `BETWEEN a AND b` correctly. if (preg_match_all('/\sAND\s|\sOR\s/i', $cond, $joints, PREG_OFFSET_CAPTURE)) { $conditions = []; $joints = $joints[0]; @@ -676,6 +677,13 @@ public function join(string $table, $cond, string $type = '', ?bool $escape = nu foreach ($conditions as $i => $condition) { $operator = $this->getOperator($condition); + // Workaround for BETWEEN + if ($operator === false) { + $cond .= $joints[$i] . $condition; + + continue; + } + $cond .= $joints[$i]; $cond .= preg_match('/(\(*)?([\[\]\w\.\'-]+)' . preg_quote($operator, '/') . '(.*)/i', $condition, $match) ? $match[1] . $this->db->protectIdentifiers($match[2]) . $operator . $this->db->protectIdentifiers($match[3]) : $condition; } diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index a624dced38d2..ffc72bd41d66 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -145,6 +145,13 @@ public function join(string $table, $cond, string $type = '', ?bool $escape = nu foreach ($conditions as $i => $condition) { $operator = $this->getOperator($condition); + // Workaround for BETWEEN + if ($operator === false) { + $cond .= $joints[$i] . $condition; + + continue; + } + $cond .= $joints[$i]; $cond .= preg_match('/(\(*)?([\[\]\w\.\'-]+)' . preg_quote($operator, '/') . '(.*)/i', $condition, $match) ? $match[1] . $this->db->protectIdentifiers($match[2]) . $operator . $this->db->protectIdentifiers($match[3]) : $condition; } diff --git a/tests/system/Database/Builder/JoinTest.php b/tests/system/Database/Builder/JoinTest.php index 0ab74729ed7a..83c7ea4f3ab9 100644 --- a/tests/system/Database/Builder/JoinTest.php +++ b/tests/system/Database/Builder/JoinTest.php @@ -80,6 +80,25 @@ public function testJoinMultipleConditions(): void $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/8791 + */ + public function testJoinMultipleConditionsBetween(): void + { + $builder = new BaseBuilder('table1', $this->db); + + $builder->join( + 'leases', + 'units.unit_id = leases.unit_id AND CURDATE() BETWEEN lease_start_date AND lease_exp_date', + 'LEFT' + ); + + // @TODO Should be `... CURDATE() BETWEEN "lease_start_date" AND "lease_exp_date"` + $expectedSQL = 'SELECT * FROM "table1" LEFT JOIN "leases" ON "units"."unit_id" = "leases"."unit_id" AND CURDATE() BETWEEN lease_start_date AND lease_exp_date'; + + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); + } + /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/3832 */