Skip to content

Commit 3bc55c5

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 e910d7f commit 3bc55c5

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
@@ -3077,6 +3077,56 @@ public function testGroupByHaving() {
30773077
);
30783078
}
30793079

3080+
public function testHavingWithoutGroupBy() {
3081+
$this->assertQuery(
3082+
'CREATE TABLE _tmp_table (
3083+
name varchar(20)
3084+
);'
3085+
);
3086+
3087+
$this->assertQuery(
3088+
"INSERT INTO _tmp_table VALUES ('a'), ('b'), ('b'), ('c'), ('c'), ('c')"
3089+
);
3090+
3091+
// HAVING condition satisfied
3092+
$result = $this->assertQuery(
3093+
"SELECT 'T' FROM _tmp_table HAVING COUNT(*) > 1"
3094+
);
3095+
$this->assertEquals(
3096+
array(
3097+
(object) array(
3098+
':param0' => 'T',
3099+
),
3100+
),
3101+
$result
3102+
);
3103+
3104+
// HAVING condition not satisfied
3105+
$result = $this->assertQuery(
3106+
"SELECT 'T' FROM _tmp_table HAVING COUNT(*) > 100"
3107+
);
3108+
$this->assertEquals(
3109+
array(),
3110+
$result
3111+
);
3112+
3113+
// DISTINCT ... HAVING, where only some results meet the HAVING condition
3114+
$result = $this->assertQuery(
3115+
'SELECT DISTINCT name FROM _tmp_table HAVING COUNT(*) > 1'
3116+
);
3117+
$this->assertEquals(
3118+
array(
3119+
(object) array(
3120+
'name' => 'b',
3121+
),
3122+
(object) array(
3123+
'name' => 'c',
3124+
),
3125+
),
3126+
$result
3127+
);
3128+
}
3129+
30803130
/**
30813131
* @dataProvider mysqlVariablesToTest
30823132
*/

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

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

26212621
/**
2622-
* Translate WHERE something HAVING something to WHERE something AND something.
2622+
* Translate HAVING without GROUP BY to GROUP BY 1 HAVING.
26232623
*
26242624
* @param WP_SQLite_Token $token The token to translate.
26252625
*
@@ -2638,8 +2638,15 @@ private function translate_ungrouped_having( $token ) {
26382638
if ( $this->has_group_by ) {
26392639
return false;
26402640
}
2641-
$this->rewriter->skip();
2642-
$this->rewriter->add( new WP_SQLite_Token( 'AND', WP_SQLite_Token::TYPE_KEYWORD ) );
2641+
2642+
// GROUP BY is missing, add "GROUP BY 1" before the HAVING clause.
2643+
$having = $this->rewriter->skip();
2644+
$this->rewriter->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_DELIMITER ) );
2645+
$this->rewriter->add( new WP_SQLite_Token( 'GROUP BY', WP_SQLite_Token::TYPE_KEYWORD ) );
2646+
$this->rewriter->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_DELIMITER ) );
2647+
$this->rewriter->add( new WP_SQLite_Token( '1', WP_SQLite_Token::TYPE_NUMBER ) );
2648+
$this->rewriter->add( new WP_SQLite_Token( ' ', WP_SQLite_Token::TYPE_DELIMITER ) );
2649+
$this->rewriter->add( $having );
26432650

26442651
return true;
26452652
}

0 commit comments

Comments
 (0)