diff --git a/fe/fe-core/src/main/cup/sql_parser.cup b/fe/fe-core/src/main/cup/sql_parser.cup index 236fbfb4f1..4589c2c5af 100644 --- a/fe/fe-core/src/main/cup/sql_parser.cup +++ b/fe/fe-core/src/main/cup/sql_parser.cup @@ -18,10 +18,12 @@ package org.apache.doris.analysis; import java.math.BigDecimal; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashSet; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import org.apache.doris.analysis.AlterDatabaseQuotaStmt.QuotaType; @@ -261,7 +263,7 @@ terminal String KW_ADD, KW_ADMIN, KW_AFTER, KW_AGGREGATE, KW_ALIAS, KW_ALL, KW_A KW_RANDOM, KW_RANGE, KW_READ, KW_RECOVER, KW_REGEXP, KW_RELEASE, KW_RENAME, KW_REPAIR, KW_REPEATABLE, KW_REPOSITORY, KW_REPOSITORIES, KW_REPLACE, KW_REPLACE_IF_NOT_NULL, KW_REPLICA, KW_RESOURCE, KW_RESOURCES, KW_RESTORE, KW_RETURNS, KW_RESUME, KW_REVOKE, KW_RIGHT, KW_ROLE, KW_ROLES, KW_ROLLBACK, KW_ROLLUP, KW_ROUTINE, KW_ROW, KW_ROWS, - KW_S3, KW_SCHEMA, KW_SCHEMAS, KW_SECOND, KW_SELECT, KW_SEMI, KW_SERIALIZABLE, KW_SESSION, KW_SET, KW_SETS, KW_SET_VAR, KW_SHOW, KW_SIGNED, + KW_S3, KW_SCHEMA, KW_SCHEMAS, KW_SECOND, KW_SELECT, KW_SEMI, KW_SERIALIZABLE, KW_SESSION, KW_SET, KW_SETS, KW_SHOW, KW_SIGNED, KW_SKEW, KW_SMALLINT, KW_SNAPSHOT, KW_SONAME, KW_SPLIT, KW_START, KW_STATUS, KW_STATS, KW_STOP, KW_STORAGE, KW_STREAM, KW_STRING, KW_STRUCT, KW_SUM, KW_SUPERUSER, KW_SYNC, KW_SYSTEM, @@ -398,7 +400,12 @@ nonterminal InlineViewRef inline_view_ref; nonterminal JoinOperator join_operator; nonterminal ArrayList opt_plan_hints; nonterminal ArrayList opt_sort_hints; -nonterminal HashMap select_hints_list, opt_select_hints; +nonterminal Map> opt_select_hints; +nonterminal Map> query_hints; +nonterminal Map.Entry> query_hint; +nonterminal Map query_hint_parameters; +nonterminal Map.Entry query_hint_parameter; +nonterminal String query_hint_parameter_key; nonterminal Expr sign_chain_expr; nonterminal Qualifier opt_set_qualifier; nonterminal Operation set_op; @@ -3851,16 +3858,65 @@ select_clause ::= :} ; -select_hints_list ::= - select_hints_list:map COMMA variable_name:k equal literal_or_ident:v +query_hint_parameter_key ::= + literal:k {: - map.put(k, v); + RESULT = k.getStringValue(); + :} + | variable_name:k + {: + RESULT = k; + :} + ; + +query_hint_parameter ::= + query_hint_parameter_key:k + {: + RESULT = new AbstractMap.SimpleEntry(k, null); + :} + | query_hint_parameter_key:k equal literal_or_ident:v + {: + RESULT = new AbstractMap.SimpleEntry(k, v); + :} + ; + + +query_hint_parameters ::= + query_hint_parameters:map COMMA query_hint_parameter:kv + {: + map.put(kv.getKey(), kv.getValue()); RESULT = map; :} - | variable_name:k equal literal_or_ident:v + | query_hint_parameter:kv {: - HashMap map = new HashMap(); - map.put(k, v); + Map map = new HashMap<>(); + map.put(kv.getKey(), kv.getValue()); + RESULT = map; + :} + | + {: + RESULT = new HashMap(); + :} + ; + +query_hint ::= + ident:k LPAREN query_hint_parameters:v RPAREN + {: + RESULT = new AbstractMap.SimpleEntry>(k.toLowerCase(Locale.ROOT), v); + :} + ; + +query_hints ::= + query_hints:map query_hint:kv + {: + map.computeIfAbsent(kv.getKey(), k -> new HashMap<>()); + map.get(kv.getKey()).putAll(kv.getValue()); + RESULT = map; + :} + | query_hint:kv + {: + Map> map = new HashMap<>(); + map.put(kv.getKey(), kv.getValue()); RESULT = map; :} ; @@ -3877,7 +3933,7 @@ literal_or_ident ::= ; opt_select_hints ::= - COMMENTED_PLAN_HINT_START KW_SET_VAR LPAREN select_hints_list:map RPAREN COMMENTED_PLAN_HINT_END + COMMENTED_PLAN_HINT_START query_hints:map COMMENTED_PLAN_HINT_END {: RESULT = map; :} diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectList.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectList.java index afa7dcec58..10d36067cb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectList.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectList.java @@ -30,6 +30,8 @@ import java.util.Map; * Select list items plus distinct clause. */ public class SelectList { + private static final String SET_VAR_KEY = "set_var"; + private boolean isDistinct; private Map optHints; @@ -79,8 +81,10 @@ public class SelectList { return optHints; } - public void setOptHints(Map optHints) { - this.optHints = optHints; + public void setOptHints(Map> optHints) { + if (optHints != null) { + this.optHints = optHints.get(SET_VAR_KEY); + } } public void reset() { diff --git a/fe/fe-core/src/main/jflex/sql_scanner.flex b/fe/fe-core/src/main/jflex/sql_scanner.flex index a4945e2254..e316512ff5 100644 --- a/fe/fe-core/src/main/jflex/sql_scanner.flex +++ b/fe/fe-core/src/main/jflex/sql_scanner.flex @@ -349,7 +349,6 @@ import org.apache.doris.qe.SqlModeHelper; keywordMap.put("serializable", new Integer(SqlParserSymbols.KW_SERIALIZABLE)); keywordMap.put("session", new Integer(SqlParserSymbols.KW_SESSION)); keywordMap.put("set", new Integer(SqlParserSymbols.KW_SET)); - keywordMap.put("set_var", new Integer(SqlParserSymbols.KW_SET_VAR)); keywordMap.put("sets", new Integer(SqlParserSymbols.KW_SETS)); keywordMap.put("show", new Integer(SqlParserSymbols.KW_SHOW)); keywordMap.put("signed", new Integer(SqlParserSymbols.KW_SIGNED)); diff --git a/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java b/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java index 2246790a12..ecb5800cea 100755 --- a/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/SelectStmtTest.java @@ -523,6 +523,35 @@ public class SelectStmtTest { Assert.assertFalse(dorisAssert.query(sql8).explainQuery().contains("`table2`.`__DORIS_DELETE_SIGN__` = 0")); } + @Test + public void testSelectHints() throws Exception { + ConnectContext ctx = UtFrameUtils.createDefaultCtx(); + + // hint with integer literal parameter + String sql = "select /*+ common_hint(1) */ 1"; + UtFrameUtils.parseAndAnalyzeStmt(sql, ctx); + + // hint with float literal parameter + sql = "select /*+ common_hint(1.1) */ 1"; + UtFrameUtils.parseAndAnalyzeStmt(sql, ctx); + + // hint with string literal parameter + sql = "select /*+ common_hint(\"string\") */ 1"; + UtFrameUtils.parseAndAnalyzeStmt(sql, ctx); + + // hint with key value parameter + sql = "select /*+ common_hint(k = \"v\") */ 1"; + UtFrameUtils.parseAndAnalyzeStmt(sql, ctx); + + // hint with multi-parameters + sql = "select /*+ common_hint(1, 1.1, \"string\") */ 1"; + UtFrameUtils.parseAndAnalyzeStmt(sql, ctx); + + // multi-hints + sql = "select /*+ common_hint(1) another_hint(2) */ 1"; + UtFrameUtils.parseAndAnalyzeStmt(sql, ctx); + } + @Test public void testSelectHintSetVar() throws Exception { String sql = "SELECT sleep(3);";