[feature](hint)(mysql-compatibility) Support general hints in select statement (#7664)
Support general hints. Sql example: ```sql SELECT /*+ one_hint(1000000) another_hint(k = "v")*/ 1; ``` hints syntax is: ``` /*+ [ HINT_NAME( [ key [ =value ]? ]* ) ]+ */ ``` - support multi hints, sep with space - hint name could be any string in identifier format - hint could have zero or more parameters, sep with comma - hint parameter must have one key - hint parameter could have zero or one value - hint parameter‘s key and value connected by equal sign
This commit is contained in:
@ -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<String> opt_plan_hints;
|
||||
nonterminal ArrayList<String> opt_sort_hints;
|
||||
nonterminal HashMap<String, String> select_hints_list, opt_select_hints;
|
||||
nonterminal Map<String, Map<String, String>> opt_select_hints;
|
||||
nonterminal Map<String, Map<String, String>> query_hints;
|
||||
nonterminal Map.Entry<String, Map<String, String>> query_hint;
|
||||
nonterminal Map<String, String> query_hint_parameters;
|
||||
nonterminal Map.Entry<String, String> 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<String, String>(k, null);
|
||||
:}
|
||||
| query_hint_parameter_key:k equal literal_or_ident:v
|
||||
{:
|
||||
RESULT = new AbstractMap.SimpleEntry<String, String>(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<String, String> map = new HashMap<String, String>();
|
||||
map.put(k, v);
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put(kv.getKey(), kv.getValue());
|
||||
RESULT = map;
|
||||
:}
|
||||
|
|
||||
{:
|
||||
RESULT = new HashMap<String, String>();
|
||||
:}
|
||||
;
|
||||
|
||||
query_hint ::=
|
||||
ident:k LPAREN query_hint_parameters:v RPAREN
|
||||
{:
|
||||
RESULT = new AbstractMap.SimpleEntry<String, Map<String, String>>(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<String, Map<String, String>> 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;
|
||||
:}
|
||||
|
||||
@ -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<String, String> optHints;
|
||||
|
||||
@ -79,8 +81,10 @@ public class SelectList {
|
||||
return optHints;
|
||||
}
|
||||
|
||||
public void setOptHints(Map<String, String> optHints) {
|
||||
this.optHints = optHints;
|
||||
public void setOptHints(Map<String, Map<String, String>> optHints) {
|
||||
if (optHints != null) {
|
||||
this.optHints = optHints.get(SET_VAR_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);";
|
||||
|
||||
Reference in New Issue
Block a user