Skip to content

Commit 0fdc94c

Browse files
committed
Translate HAVING without GROUP BY to "GROUP BY 1 HAVING"
The previous method of translating ungrouped HAVING to "AND" had some problems: 1. If no WHERE was in the query, the query would fail with: `near "AND": syntax error` 2. When an aggregate function was used in having (e.g, COUNT(*) > 1), the query would fail with: `misuse of aggregate function COUNT()` This commit fixes both of these issues.
1 parent e7c5699 commit 0fdc94c

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

tests/WP_SQLite_Translator_Tests.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2888,6 +2888,56 @@ public function testGroupByHaving() {
28882888
);
28892889
}
28902890

2891+
public function testHavingWithoutGroupBy() {
2892+
$this->assertQuery(
2893+
'CREATE TABLE _tmp_table (
2894+
name varchar(20)
2895+
);'
2896+
);
2897+
2898+
$this->assertQuery(
2899+
"INSERT INTO _tmp_table VALUES ('a'), ('b'), ('b'), ('c'), ('c'), ('c')"
2900+
);
2901+
2902+
// HAVING condition satisfied
2903+
$result = $this->assertQuery(
2904+
"SELECT 'T' FROM _tmp_table HAVING COUNT(*) > 1"
2905+
);
2906+
$this->assertEquals(
2907+
array(
2908+
(object) array(
2909+
':param0' => 'T',
2910+
),
2911+
),
2912+
$result
2913+
);
2914+
2915+
// HAVING condition not satisfied
2916+
$result = $this->assertQuery(
2917+
"SELECT 'T' FROM _tmp_table HAVING COUNT(*) > 100"
2918+
);
2919+
$this->assertEquals(
2920+
array(),
2921+
$result
2922+
);
2923+
2924+
// DISTINCT ... HAVING, where only some results meet the HAVING condition
2925+
$result = $this->assertQuery(
2926+
'SELECT DISTINCT name FROM _tmp_table HAVING COUNT(*) > 1'
2927+
);
2928+
$this->assertEquals(
2929+
array(
2930+
(object) array(
2931+
'name' => 'b',
2932+
),
2933+
(object) array(
2934+
'name' => 'c',
2935+
),
2936+
),
2937+
$result
2938+
);
2939+
}
2940+
28912941
/**
28922942
* @dataProvider mysqlVariablesToTest
28932943
*/

wp-includes/sqlite/class-wp-sqlite-translator.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2577,7 +2577,7 @@ private function capture_group_by( $token ) {
25772577
}
25782578

25792579
/**
2580-
* Translate WHERE something HAVING something to WHERE something AND something.
2580+
* Translate HAVING without GROUP BY to GROUP BY 1 HAVING.
25812581
*
25822582
* @param WP_SQLite_Token $token The token to translate.
25832583
*
@@ -2596,8 +2596,15 @@ private function translate_ungrouped_having( $token ) {
25962596
if ( $this->has_group_by ) {
25972597
return false;
25982598
}
2599-
$this->rewriter->skip();
2600-
$this->rewriter->add( new WP_SQLite_Token( 'AND', WP_SQLite_Token::TYPE_KEYWORD ) );
2599+
2600+
// GROUP BY is missing, add "GROUP BY 1" before the HAVING clause.
2601+
$having = $this->rewriter->skip();
2602+
$this->rewriter->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_DELIMITER ) );
2603+
$this->rewriter->add( new WP_SQLite_Token( 'GROUP BY', WP_SQLite_Token::TYPE_KEYWORD ) );
2604+
$this->rewriter->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_DELIMITER ) );
2605+
$this->rewriter->add( new WP_SQLite_Token( '1', WP_SQLite_Token::TYPE_NUMBER ) );
2606+
$this->rewriter->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_DELIMITER ) );
2607+
$this->rewriter->add( $having );
26012608

26022609
return true;
26032610
}

0 commit comments

Comments
 (0)