You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by li...@apache.org on 2022/05/06 08:22:36 UTC
[incubator-doris] branch master updated: [WIP-feature](Optimizer) Nereids code base (#9392)
This is an automated email from the ASF dual-hosted git repository.
lingmiao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git
The following commit(s) were added to refs/heads/master by this push:
new ce02c661e3 [WIP-feature](Optimizer) Nereids code base (#9392)
ce02c661e3 is described below
commit ce02c661e353c1f7df3a9cc8d11aae4aa4851a6a
Author: morrySnow <10...@users.noreply.github.com>
AuthorDate: Fri May 6 16:22:29 2022 +0800
[WIP-feature](Optimizer) Nereids code base (#9392)
Nereids(new optimizer) code base
Nereids is new query planner for Doris. It include three main parts: parser, analyzer and optimizer.
The parser, generated by ANTLR4, transforms SQL into a logical plan with a tree structure. Analysis and optimization are performed on the logical plan of the tree structure. Each transformation is defined as a rule. The rule is applied to the logical plan using pattern matching. The implementation of the optimizer follows the approach in the Cascades paper.
---
dist/LICENSE-dist.txt | 2 +-
fe/fe-core/pom.xml | 27 +
.../antlr4/org/apache/doris/nereids/DorisLexer.g4 | 485 ++++++++++++++
.../antlr4/org/apache/doris/nereids/DorisParser.g4 | 723 +++++++++++++++++++++
.../org/apache/doris/nereids/OptimizerContext.java | 77 +++
.../java/org/apache/doris/nereids/Planner.java | 72 ++
.../org/apache/doris/nereids/PlannerContext.java | 79 +++
.../src/main/java/org/apache/doris/nereids/README | 19 +
.../doris/nereids/analyzer/UnboundAlias.java | 63 ++
.../doris/nereids/analyzer/UnboundRelation.java | 75 +++
.../apache/doris/nereids/analyzer/UnboundSlot.java | 67 ++
.../apache/doris/nereids/analyzer/UnboundStar.java | 53 ++
.../identifier/IdentifierWithDatabase.java | 65 ++
.../analyzer/identifier/TableIdentifier.java | 36 +
.../doris/nereids/exceptions/UnboundException.java | 29 +
.../java/org/apache/doris/nereids/jobs/Job.java | 53 ++
.../org/apache/doris/nereids/jobs/JobType.java | 34 +
.../doris/nereids/jobs/cascades/ApplyRuleJob.java | 83 +++
.../nereids/jobs/cascades/CostAndEnforcerJob.java | 40 ++
.../nereids/jobs/cascades/DeriveStatsJob.java | 72 ++
.../nereids/jobs/cascades/ExploreGroupJob.java | 53 ++
.../nereids/jobs/cascades/ExplorePlanJob.java | 65 ++
.../nereids/jobs/cascades/OptimizeGroupJob.java | 53 ++
.../nereids/jobs/cascades/OptimizePlanJob.java | 70 ++
.../nereids/jobs/rewrite/RewriteBottomUpJob.java | 40 ++
.../nereids/jobs/rewrite/RewriteTopDownJob.java | 40 ++
.../doris/nereids/jobs/scheduler/JobPool.java | 31 +
.../doris/nereids/jobs/scheduler/JobScheduler.java | 31 +
.../doris/nereids/jobs/scheduler/JobStack.java | 44 ++
.../nereids/jobs/scheduler/SimpleJobScheduler.java | 41 ++
.../java/org/apache/doris/nereids/memo/Group.java | 126 ++++
.../org/apache/doris/nereids/memo/GroupId.java | 59 ++
.../java/org/apache/doris/nereids/memo/Memo.java | 73 +++
.../apache/doris/nereids/memo/PlanReference.java | 96 +++
.../apache/doris/nereids/parser/AstBuilder.java | 438 +++++++++++++
.../nereids/parser/CaseInsensitiveStream.java | 86 +++
.../apache/doris/nereids/parser/ParserUtils.java | 31 +
.../org/apache/doris/nereids/parser/SqlParser.java | 69 ++
.../org/apache/doris/nereids/pattern/Pattern.java | 96 +++
.../doris/nereids/pattern/PatternMatching.java | 48 ++
.../nereids/properties/LogicalProperties.java | 39 ++
.../nereids/properties/PhysicalProperties.java | 25 +
.../java/org/apache/doris/nereids/qe/Executor.java | 59 ++
.../java/org/apache/doris/nereids/rules/Rule.java | 65 ++
.../apache/doris/nereids/rules/RulePromise.java | 34 +
.../org/apache/doris/nereids/rules/RuleSet.java | 42 ++
.../org/apache/doris/nereids/rules/RuleType.java | 42 ++
.../doris/nereids/rules/analysis/AnalysisRule.java | 32 +
.../analysis/AnalysisUnboundRelationRule.java | 78 +++
.../nereids/rules/exploration/ExplorationRule.java | 32 +
.../nereids/rules/expression/ExpressionRule.java | 33 +
.../rules/implementation/ImplementationRule.java | 32 +
.../implementation/LogicalJoinToHashJoinRule.java | 54 ++
.../doris/nereids/rules/rewrite/RewriteRule.java | 32 +
.../org/apache/doris/nereids/trees/NodeType.java | 53 ++
.../org/apache/doris/nereids/trees/TreeNode.java | 66 ++
.../doris/nereids/trees/expressions/Alias.java | 82 +++
.../nereids/trees/expressions/BinaryPredicate.java | 127 ++++
.../doris/nereids/trees/expressions/ExprId.java | 60 ++
.../nereids/trees/expressions/Expression.java | 44 ++
.../doris/nereids/trees/expressions/Literal.java | 103 +++
.../nereids/trees/expressions/NamedExpression.java | 73 +++
.../doris/nereids/trees/expressions/Slot.java | 34 +
.../nereids/trees/expressions/SlotReference.java | 126 ++++
.../apache/doris/nereids/trees/plans/JoinType.java | 69 ++
.../org/apache/doris/nereids/trees/plans/Plan.java | 105 +++
.../nereids/trees/plans/logical/LogicalBinary.java | 52 ++
.../nereids/trees/plans/logical/LogicalFilter.java | 57 ++
.../nereids/trees/plans/logical/LogicalJoin.java | 90 +++
.../nereids/trees/plans/logical/LogicalLeaf.java | 34 +
.../nereids/trees/plans/logical/LogicalPlan.java | 44 ++
.../trees/plans/logical/LogicalProject.java | 78 +++
.../trees/plans/logical/LogicalRelation.java | 72 ++
.../nereids/trees/plans/logical/LogicalUnary.java | 39 ++
.../plans/physical/PhysicalBroadcastHashJoin.java | 66 ++
.../trees/plans/physical/PhysicalFilter.java | 48 ++
.../trees/plans/physical/PhysicalOlapScan.java | 74 +++
.../nereids/trees/plans/physical/PhysicalPlan.java | 47 ++
.../trees/plans/physical/PhysicalProject.java | 46 ++
.../nereids/trees/plans/physical/PhysicalScan.java | 48 ++
.../apache/doris/nereids/types/BooleanType.java | 32 +
.../org/apache/doris/nereids/types/DataType.java | 64 ++
.../org/apache/doris/nereids/types/DoubleType.java | 32 +
.../apache/doris/nereids/types/FractionalType.java | 24 +
.../apache/doris/nereids/types/IntegerType.java | 32 +
.../apache/doris/nereids/types/IntegralType.java | 24 +
.../org/apache/doris/nereids/types/NullType.java | 32 +
.../apache/doris/nereids/types/NumericType.java | 24 +
.../apache/doris/nereids/types/PrimitiveType.java | 24 +
.../org/apache/doris/nereids/types/StringType.java | 32 +
.../java/org/apache/doris/nereids/util/Utils.java | 37 ++
.../org/apache/doris/utframe/UtFrameUtils.java | 1 -
92 files changed, 6436 insertions(+), 2 deletions(-)
diff --git a/dist/LICENSE-dist.txt b/dist/LICENSE-dist.txt
index 67ef8132a7..74ceaa0387 100644
--- a/dist/LICENSE-dist.txt
+++ b/dist/LICENSE-dist.txt
@@ -1431,7 +1431,7 @@ The 2-Clause BSD License
The 3-Clause BSD License
* ANTLR 4 Runtime -- licenses/LICENSE-antlr4.txt
- - org.antlr:antlr4-runtime:4.7 (http://www.antlr.org/antlr4-runtime)
+ - org.antlr:antlr4-runtime:4.9.3 (http://www.antlr.org/)
* Automaton -- licenses/LICENSE-automaton.txt
- dk.brics.automaton:automaton:1.11-8 (http://www.brics.dk/automaton/)
* JLine -- licenses/LICENSE-jline.txt
diff --git a/fe/fe-core/pom.xml b/fe/fe-core/pom.xml
index 2da7e9ce4c..363058f2de 100644
--- a/fe/fe-core/pom.xml
+++ b/fe/fe-core/pom.xml
@@ -33,6 +33,7 @@ under the License.
<fe_ut_parallel>1</fe_ut_parallel>
<doris.thirdparty>${basedir}/../../thirdparty</doris.thirdparty>
<log4j2.version>2.17.2</log4j2.version>
+ <antlr4.version>4.9.3</antlr4.version>
</properties>
<profiles>
<profile>
@@ -607,6 +608,13 @@ under the License.
<artifactId>mariadb-java-client</artifactId>
</dependency>
+ <!-- antl4 -->
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr4-runtime</artifactId>
+ <version>${antlr4.version}</version>
+ </dependency>
+
</dependencies>
<build>
<finalName>palo-fe</finalName>
@@ -655,6 +663,25 @@ under the License.
</execution>
</executions>
</plugin>
+ <!--antlr-->
+ <plugin>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr4-maven-plugin</artifactId>
+ <version>${antlr4.version}</version>
+ <executions>
+ <execution>
+ <id>antlr</id>
+ <goals>
+ <goal>antlr4</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <visitor>true</visitor>
+ <sourceDirectory>src/main/antlr4</sourceDirectory>
+ <treatWarningsAsErrors>true</treatWarningsAsErrors>
+ </configuration>
+ </plugin>
<!-- jmockit -->
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
new file mode 100644
index 0000000000..bd1737b7ac
--- /dev/null
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisLexer.g4
@@ -0,0 +1,485 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Copied from Apache Spark and modified for Apache Doris
+
+lexer grammar DorisLexer;
+
+@members {
+ /**
+ * When true, parser should throw ParseExcetion for unclosed bracketed comment.
+ */
+ public boolean has_unclosed_bracketed_comment = false;
+
+ /**
+ * Verify whether current token is a valid decimal token (which contains dot).
+ * Returns true if the character that follows the token is not a digit or letter or underscore.
+ *
+ * For example:
+ * For char stream "2.3", "2." is not a valid decimal token, because it is followed by digit '3'.
+ * For char stream "2.3_", "2.3" is not a valid decimal token, because it is followed by '_'.
+ * For char stream "2.3W", "2.3" is not a valid decimal token, because it is followed by 'W'.
+ * For char stream "12.0D 34.E2+0.12 " 12.0D is a valid decimal token because it is followed
+ * by a space. 34.E2 is a valid decimal token because it is followed by symbol '+'
+ * which is not a digit or letter or underscore.
+ */
+ public boolean isValidDecimal() {
+ int nextChar = _input.LA(1);
+ if (nextChar >= 'A' && nextChar <= 'Z' || nextChar >= '0' && nextChar <= '9' ||
+ nextChar == '_') {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * This method will be called when we see '/*' and try to match it as a bracketed comment.
+ * If the next character is '+', it should be parsed as hint later, and we cannot match
+ * it as a bracketed comment.
+ *
+ * Returns true if the next character is '+'.
+ */
+ public boolean isHint() {
+ int nextChar = _input.LA(1);
+ if (nextChar == '+') {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * This method will be called when the character stream ends and try to find out the
+ * unclosed bracketed comment.
+ * If the method be called, it means the end of the entire character stream match,
+ * and we set the flag and fail later.
+ */
+ public void markUnclosedComment() {
+ has_unclosed_bracketed_comment = true;
+ }
+}
+
+SEMICOLON: ';';
+
+LEFT_PAREN: '(';
+RIGHT_PAREN: ')';
+COMMA: ',';
+DOT: '.';
+LEFT_BRACKET: '[';
+RIGHT_BRACKET: ']';
+
+// TODO: add a doc to list reserved words
+
+//============================
+// Start of the keywords list
+//============================
+//--DORIS-KEYWORD-LIST-START
+ADD: 'ADD';
+AFTER: 'AFTER';
+ALL: 'ALL';
+ALTER: 'ALTER';
+ANALYZE: 'ANALYZE';
+AND: 'AND';
+ANTI: 'ANTI';
+ANY: 'ANY';
+ARCHIVE: 'ARCHIVE';
+ARRAY: 'ARRAY';
+AS: 'AS';
+ASC: 'ASC';
+AT: 'AT';
+AUTHORIZATION: 'AUTHORIZATION';
+BETWEEN: 'BETWEEN';
+BOTH: 'BOTH';
+BUCKET: 'BUCKET';
+BUCKETS: 'BUCKETS';
+BY: 'BY';
+CACHE: 'CACHE';
+CASCADE: 'CASCADE';
+CASE: 'CASE';
+CAST: 'CAST';
+CATALOG: 'CATALOG';
+CATALOGS: 'CATALOGS';
+CHANGE: 'CHANGE';
+CHECK: 'CHECK';
+CLEAR: 'CLEAR';
+CLUSTER: 'CLUSTER';
+CLUSTERED: 'CLUSTERED';
+CODEGEN: 'CODEGEN';
+COLLATE: 'COLLATE';
+COLLECTION: 'COLLECTION';
+COLUMN: 'COLUMN';
+COLUMNS: 'COLUMNS';
+COMMENT: 'COMMENT';
+COMMIT: 'COMMIT';
+COMPACT: 'COMPACT';
+COMPACTIONS: 'COMPACTIONS';
+COMPUTE: 'COMPUTE';
+CONCATENATE: 'CONCATENATE';
+CONSTRAINT: 'CONSTRAINT';
+COST: 'COST';
+CREATE: 'CREATE';
+CROSS: 'CROSS';
+CUBE: 'CUBE';
+CURRENT: 'CURRENT';
+CURRENT_DATE: 'CURRENT_DATE';
+CURRENT_TIME: 'CURRENT_TIME';
+CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP';
+CURRENT_USER: 'CURRENT_USER';
+DAY: 'DAY';
+DATA: 'DATA';
+DATABASE: 'DATABASE';
+DATABASES: 'DATABASES';
+DATEADD: 'DATEADD';
+DATE_ADD: 'DATE_ADD';
+DATEDIFF: 'DATEDIFF';
+DATE_DIFF: 'DATE_DIFF';
+DBPROPERTIES: 'DBPROPERTIES';
+DEFINED: 'DEFINED';
+DELETE: 'DELETE';
+DELIMITED: 'DELIMITED';
+DESC: 'DESC';
+DESCRIBE: 'DESCRIBE';
+DFS: 'DFS';
+DIRECTORIES: 'DIRECTORIES';
+DIRECTORY: 'DIRECTORY';
+DISTINCT: 'DISTINCT';
+DISTRIBUTE: 'DISTRIBUTE';
+DIV: 'DIV';
+DROP: 'DROP';
+ELSE: 'ELSE';
+END: 'END';
+ESCAPE: 'ESCAPE';
+ESCAPED: 'ESCAPED';
+EXCEPT: 'EXCEPT';
+EXCHANGE: 'EXCHANGE';
+EXISTS: 'EXISTS';
+EXPLAIN: 'EXPLAIN';
+EXPORT: 'EXPORT';
+EXTENDED: 'EXTENDED';
+EXTERNAL: 'EXTERNAL';
+EXTRACT: 'EXTRACT';
+FALSE: 'FALSE';
+FETCH: 'FETCH';
+FIELDS: 'FIELDS';
+FILTER: 'FILTER';
+FILEFORMAT: 'FILEFORMAT';
+FIRST: 'FIRST';
+FOLLOWING: 'FOLLOWING';
+FOR: 'FOR';
+FOREIGN: 'FOREIGN';
+FORMAT: 'FORMAT';
+FORMATTED: 'FORMATTED';
+FROM: 'FROM';
+FULL: 'FULL';
+FUNCTION: 'FUNCTION';
+FUNCTIONS: 'FUNCTIONS';
+GLOBAL: 'GLOBAL';
+GRANT: 'GRANT';
+GROUP: 'GROUP';
+GROUPING: 'GROUPING';
+HAVING: 'HAVING';
+HOUR: 'HOUR';
+IF: 'IF';
+IGNORE: 'IGNORE';
+IMPORT: 'IMPORT';
+IN: 'IN';
+INDEX: 'INDEX';
+INDEXES: 'INDEXES';
+INNER: 'INNER';
+INPATH: 'INPATH';
+INPUTFORMAT: 'INPUTFORMAT';
+INSERT: 'INSERT';
+INTERSECT: 'INTERSECT';
+INTERVAL: 'INTERVAL';
+INTO: 'INTO';
+IS: 'IS';
+ITEMS: 'ITEMS';
+JOIN: 'JOIN';
+KEYS: 'KEYS';
+LAST: 'LAST';
+LATERAL: 'LATERAL';
+LAZY: 'LAZY';
+LEADING: 'LEADING';
+LEFT: 'LEFT';
+LIKE: 'LIKE';
+ILIKE: 'ILIKE';
+LIMIT: 'LIMIT';
+LINES: 'LINES';
+LIST: 'LIST';
+LOAD: 'LOAD';
+LOCAL: 'LOCAL';
+LOCATION: 'LOCATION';
+LOCK: 'LOCK';
+LOCKS: 'LOCKS';
+LOGICAL: 'LOGICAL';
+MACRO: 'MACRO';
+MAP: 'MAP';
+MATCHED: 'MATCHED';
+MERGE: 'MERGE';
+MINUTE: 'MINUTE';
+MONTH: 'MONTH';
+MSCK: 'MSCK';
+NAMESPACE: 'NAMESPACE';
+NAMESPACES: 'NAMESPACES';
+NATURAL: 'NATURAL';
+NO: 'NO';
+NOT: 'NOT' | '!';
+NULL: 'NULL';
+NULLS: 'NULLS';
+OF: 'OF';
+ON: 'ON';
+ONLY: 'ONLY';
+OPTION: 'OPTION';
+OPTIONS: 'OPTIONS';
+OR: 'OR';
+ORDER: 'ORDER';
+OUT: 'OUT';
+OUTER: 'OUTER';
+OUTPUTFORMAT: 'OUTPUTFORMAT';
+OVER: 'OVER';
+OVERLAPS: 'OVERLAPS';
+OVERLAY: 'OVERLAY';
+OVERWRITE: 'OVERWRITE';
+PARTITION: 'PARTITION';
+PARTITIONED: 'PARTITIONED';
+PARTITIONS: 'PARTITIONS';
+PERCENTILE_CONT: 'PERCENTILE_CONT';
+PERCENTLIT: 'PERCENT';
+PIVOT: 'PIVOT';
+PLACING: 'PLACING';
+POSITION: 'POSITION';
+PRECEDING: 'PRECEDING';
+PRIMARY: 'PRIMARY';
+PRINCIPALS: 'PRINCIPALS';
+PROPERTIES: 'PROPERTIES';
+PURGE: 'PURGE';
+QUERY: 'QUERY';
+RANGE: 'RANGE';
+RECORDREADER: 'RECORDREADER';
+RECORDWRITER: 'RECORDWRITER';
+RECOVER: 'RECOVER';
+REDUCE: 'REDUCE';
+REFERENCES: 'REFERENCES';
+REFRESH: 'REFRESH';
+RENAME: 'RENAME';
+REPAIR: 'REPAIR';
+REPEATABLE: 'REPEATABLE';
+REPLACE: 'REPLACE';
+RESET: 'RESET';
+RESPECT: 'RESPECT';
+RESTRICT: 'RESTRICT';
+REVOKE: 'REVOKE';
+RIGHT: 'RIGHT';
+RLIKE: 'RLIKE' | 'REGEXP';
+ROLE: 'ROLE';
+ROLES: 'ROLES';
+ROLLBACK: 'ROLLBACK';
+ROLLUP: 'ROLLUP';
+ROW: 'ROW';
+ROWS: 'ROWS';
+SECOND: 'SECOND';
+SCHEMA: 'SCHEMA';
+SCHEMAS: 'SCHEMAS';
+SELECT: 'SELECT';
+SEMI: 'SEMI';
+SEPARATED: 'SEPARATED';
+SERDE: 'SERDE';
+SERDEPROPERTIES: 'SERDEPROPERTIES';
+SESSION_USER: 'SESSION_USER';
+SET: 'SET';
+SETMINUS: 'MINUS';
+SETS: 'SETS';
+SHOW: 'SHOW';
+SKEWED: 'SKEWED';
+SOME: 'SOME';
+SORT: 'SORT';
+SORTED: 'SORTED';
+START: 'START';
+STATISTICS: 'STATISTICS';
+STORED: 'STORED';
+STRATIFY: 'STRATIFY';
+STRUCT: 'STRUCT';
+SUBSTR: 'SUBSTR';
+SUBSTRING: 'SUBSTRING';
+SYNC: 'SYNC';
+SYSTEM_TIME: 'SYSTEM_TIME';
+SYSTEM_VERSION: 'SYSTEM_VERSION';
+TABLE: 'TABLE';
+TABLES: 'TABLES';
+TABLESAMPLE: 'TABLESAMPLE';
+TBLPROPERTIES: 'TBLPROPERTIES';
+TEMPORARY: 'TEMPORARY' | 'TEMP';
+TERMINATED: 'TERMINATED';
+THEN: 'THEN';
+TIME: 'TIME';
+TIMESTAMP: 'TIMESTAMP';
+TIMESTAMPADD: 'TIMESTAMPADD';
+TIMESTAMPDIFF: 'TIMESTAMPDIFF';
+TO: 'TO';
+TOUCH: 'TOUCH';
+TRAILING: 'TRAILING';
+TRANSACTION: 'TRANSACTION';
+TRANSACTIONS: 'TRANSACTIONS';
+TRANSFORM: 'TRANSFORM';
+TRIM: 'TRIM';
+TRUE: 'TRUE';
+TRUNCATE: 'TRUNCATE';
+TRY_CAST: 'TRY_CAST';
+TYPE: 'TYPE';
+UNARCHIVE: 'UNARCHIVE';
+UNBOUNDED: 'UNBOUNDED';
+UNCACHE: 'UNCACHE';
+UNION: 'UNION';
+UNIQUE: 'UNIQUE';
+UNKNOWN: 'UNKNOWN';
+UNLOCK: 'UNLOCK';
+UNSET: 'UNSET';
+UPDATE: 'UPDATE';
+USE: 'USE';
+USER: 'USER';
+USING: 'USING';
+VALUES: 'VALUES';
+VERSION: 'VERSION';
+VIEW: 'VIEW';
+VIEWS: 'VIEWS';
+WHEN: 'WHEN';
+WHERE: 'WHERE';
+WINDOW: 'WINDOW';
+WITH: 'WITH';
+WITHIN: 'WITHIN';
+YEAR: 'YEAR';
+ZONE: 'ZONE';
+//--DORIS-KEYWORD-LIST-END
+//============================
+// End of the keywords list
+//============================
+
+EQ : '=' | '==';
+NSEQ: '<=>';
+NEQ : '<>';
+NEQJ: '!=';
+LT : '<';
+LTE : '<=' | '!>';
+GT : '>';
+GTE : '>=' | '!<';
+
+PLUS: '+';
+MINUS: '-';
+ASTERISK: '*';
+SLASH: '/';
+PERCENT: '%';
+TILDE: '~';
+AMPERSAND: '&';
+PIPE: '|';
+CONCAT_PIPE: '||';
+HAT: '^';
+COLON: ':';
+ARROW: '->';
+HENT_START: '/*+';
+HENT_END: '*/';
+
+STRING
+ : '\'' ( ~('\''|'\\') | ('\\' .) )* '\''
+ | '"' ( ~('"'|'\\') | ('\\' .) )* '"'
+ | 'R\'' (~'\'')* '\''
+ | 'R"'(~'"')* '"'
+ ;
+
+BIGINT_LITERAL
+ : DIGIT+ 'L'
+ ;
+
+SMALLINT_LITERAL
+ : DIGIT+ 'S'
+ ;
+
+TINYINT_LITERAL
+ : DIGIT+ 'Y'
+ ;
+
+INTEGER_VALUE
+ : DIGIT+
+ ;
+
+EXPONENT_VALUE
+ : DIGIT+ EXPONENT
+ | DECIMAL_DIGITS EXPONENT {isValidDecimal()}?
+ ;
+
+DECIMAL_VALUE
+ : DECIMAL_DIGITS {isValidDecimal()}?
+ ;
+
+FLOAT_LITERAL
+ : DIGIT+ EXPONENT? 'F'
+ | DECIMAL_DIGITS EXPONENT? 'F' {isValidDecimal()}?
+ ;
+
+DOUBLE_LITERAL
+ : DIGIT+ EXPONENT? 'D'
+ | DECIMAL_DIGITS EXPONENT? 'D' {isValidDecimal()}?
+ ;
+
+BIGDECIMAL_LITERAL
+ : DIGIT+ EXPONENT? 'BD'
+ | DECIMAL_DIGITS EXPONENT? 'BD' {isValidDecimal()}?
+ ;
+
+IDENTIFIER
+ : (LETTER | DIGIT | '_')+
+ ;
+
+BACKQUOTED_IDENTIFIER
+ : '`' ( ~'`' | '``' )* '`'
+ ;
+
+fragment DECIMAL_DIGITS
+ : DIGIT+ '.' DIGIT*
+ | '.' DIGIT+
+ ;
+
+fragment EXPONENT
+ : 'E' [+-]? DIGIT+
+ ;
+
+fragment DIGIT
+ : [0-9]
+ ;
+
+fragment LETTER
+ : [A-Z]
+ ;
+
+SIMPLE_COMMENT
+ : '--' ('\\\n' | ~[\r\n])* '\r'? '\n'? -> channel(HIDDEN)
+ ;
+
+BRACKETED_COMMENT
+ : '/*' {!isHint()}? ( BRACKETED_COMMENT | . )*? ('*/' | {markUnclosedComment();} EOF) -> channel(HIDDEN)
+ ;
+
+WS
+ : [ \r\n\t]+ -> channel(HIDDEN)
+ ;
+
+// Catch-all for anything we can't recognize.
+// We use this to be able to ignore and recover all the text
+// when splitting statements with DelimiterLexer
+UNRECOGNIZED
+ : .
+ ;
diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
new file mode 100644
index 0000000000..602a5ed394
--- /dev/null
+++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4
@@ -0,0 +1,723 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+// Copied from Apache Spark and modified for Apache Doris
+
+parser grammar DorisParser;
+
+options { tokenVocab = DorisLexer; }
+
+@members {
+ /**
+ * When false, INTERSECT is given the greater precedence over the other set
+ * operations (UNION, EXCEPT and MINUS) as per the SQL standard.
+ */
+ public boolean legacy_setops_precedence_enabled = false;
+
+ /**
+ * When false, a literal with an exponent would be converted into
+ * double type rather than decimal type.
+ */
+ public boolean legacy_exponent_literal_as_decimal_enabled = false;
+
+ /**
+ * When true, the behavior of keywords follows ANSI SQL standard.
+ */
+ public boolean SQL_standard_keyword_behavior = false;
+}
+
+multiStatements
+ : (statement SEMICOLON*)+ EOF
+ ;
+
+singleStatement
+ : statement SEMICOLON* EOF
+ ;
+
+statement
+ : query #statementDefault
+ ;
+
+query
+ : queryTerm
+ ;
+
+queryTerm
+ : queryPrimary #queryTermDefault
+ ;
+
+queryPrimary
+ : querySpecification #queryPrimaryDefault
+ | TABLE multipartIdentifier #table
+ ;
+
+querySpecification
+ : selectClause
+ fromClause?
+ whereClause? #regularQuerySpecification
+ ;
+
+selectClause
+ : SELECT namedExpressionSeq
+ ;
+
+whereClause
+ : WHERE booleanExpression
+ ;
+
+fromClause
+ : FROM relation (COMMA relation)*
+ ;
+
+relation
+ : LATERAL? relationPrimary joinRelation*
+ ;
+
+joinRelation
+ : (joinType) JOIN right=relationPrimary joinCriteria?
+ ;
+
+joinType
+ : INNER?
+ | CROSS
+ | LEFT OUTER?
+ | LEFT? SEMI
+ | RIGHT OUTER?
+ | FULL OUTER?
+ | LEFT? ANTI
+ ;
+
+joinCriteria
+ : ON booleanExpression
+ | USING identifierList
+ ;
+
+identifierList
+ : LEFT_PAREN identifierSeq RIGHT_PAREN
+ ;
+
+identifierSeq
+ : ident+=errorCapturingIdentifier (COMMA ident+=errorCapturingIdentifier)*
+ ;
+
+relationPrimary
+ : multipartIdentifier tableAlias #tableName
+ | LEFT_PAREN query RIGHT_PAREN tableAlias #aliasedQuery
+ | LEFT_PAREN relation RIGHT_PAREN tableAlias #aliasedRelation
+ ;
+
+tableAlias
+ : (AS? strictIdentifier identifierList?)?
+ ;
+
+multipartIdentifier
+ : parts+=errorCapturingIdentifier (DOT parts+=errorCapturingIdentifier)*
+ ;
+
+namedExpression
+ : expression (AS? name=errorCapturingIdentifier)?
+ ;
+
+namedExpressionSeq
+ : namedExpression (COMMA namedExpression)*
+ ;
+
+expression
+ : booleanExpression
+ ;
+
+booleanExpression
+ : valueExpression #predicated
+ ;
+
+valueExpression
+ : primaryExpression #valueExpressionDefault
+ | left=valueExpression comparisonOperator right=valueExpression #comparison
+ ;
+
+primaryExpression
+ : constant #constantDefault
+ | ASTERISK #star
+ | qualifiedName DOT ASTERISK #star
+ | LEFT_PAREN query RIGHT_PAREN #subqueryExpression
+ | identifier #columnReference
+ | base=primaryExpression DOT fieldName=identifier #dereference
+ ;
+
+qualifiedName
+ : identifier (DOT identifier)*
+ ;
+
+constant
+ : NULL #nullLiteral
+ | number #numericLiteral
+ | booleanValue #booleanLiteral
+ | STRING+ #stringLiteral
+ ;
+
+comparisonOperator
+ : EQ | NEQ | NEQJ | LT | LTE | GT | GTE | NSEQ
+ ;
+
+booleanValue
+ : TRUE | FALSE
+ ;
+
+// this rule is used for explicitly capturing wrong identifiers such as test-table, which should actually be `test-table`
+// replace identifier with errorCapturingIdentifier where the immediate follow symbol is not an expression, otherwise
+// valid expressions such as "a-b" can be recognized as an identifier
+errorCapturingIdentifier
+ : identifier errorCapturingIdentifierExtra
+ ;
+
+// extra left-factoring grammar
+errorCapturingIdentifierExtra
+ : (MINUS identifier)+ #errorIdent
+ | #realIdent
+ ;
+
+identifier
+ : strictIdentifier
+ | {!SQL_standard_keyword_behavior}? strictNonReserved
+ ;
+
+strictIdentifier
+ : IDENTIFIER #unquotedIdentifier
+ | quotedIdentifier #quotedIdentifierAlternative
+ | {SQL_standard_keyword_behavior}? ansiNonReserved #unquotedIdentifier
+ | {!SQL_standard_keyword_behavior}? nonReserved #unquotedIdentifier
+ ;
+
+quotedIdentifier
+ : BACKQUOTED_IDENTIFIER
+ ;
+
+number
+ : MINUS? INTEGER_VALUE #integerLiteral
+ ;
+
+
+
+// When `SQL_standard_keyword_behavior=true`, there are 2 kinds of keywords in Spark SQL.
+// - Reserved keywords:
+// Keywords that are reserved and can't be used as identifiers for table, view, column,
+// function, alias, etc.
+// - Non-reserved keywords:
+// Keywords that have a special meaning only in particular contexts and can be used as
+// identifiers in other contexts. For example, `EXPLAIN SELECT ...` is a command, but EXPLAIN
+// can be used as identifiers in other places.
+// You can find the full keywords list by searching "Start of the keywords list" in this file.
+// The non-reserved keywords are listed below. Keywords not in this list are reserved keywords.
+ansiNonReserved
+//--ANSI-NON-RESERVED-START
+ : ADD
+ | AFTER
+ | ALTER
+ | ANALYZE
+ | ANTI
+ | ARCHIVE
+ | ARRAY
+ | ASC
+ | AT
+ | BETWEEN
+ | BUCKET
+ | BUCKETS
+ | BY
+ | CACHE
+ | CASCADE
+ | CATALOG
+ | CATALOGS
+ | CHANGE
+ | CLEAR
+ | CLUSTER
+ | CLUSTERED
+ | CODEGEN
+ | COLLECTION
+ | COLUMNS
+ | COMMENT
+ | COMMIT
+ | COMPACT
+ | COMPACTIONS
+ | COMPUTE
+ | CONCATENATE
+ | COST
+ | CUBE
+ | CURRENT
+ | DATA
+ | DATABASE
+ | DATABASES
+ | DATEADD
+ | DATE_ADD
+ | DATEDIFF
+ | DATE_DIFF
+ | DAY
+ | DBPROPERTIES
+ | DEFINED
+ | DELETE
+ | DELIMITED
+ | DESC
+ | DESCRIBE
+ | DFS
+ | DIRECTORIES
+ | DIRECTORY
+ | DISTRIBUTE
+ | DIV
+ | DROP
+ | ESCAPED
+ | EXCHANGE
+ | EXISTS
+ | EXPLAIN
+ | EXPORT
+ | EXTENDED
+ | EXTERNAL
+ | EXTRACT
+ | FIELDS
+ | FILEFORMAT
+ | FIRST
+ | FOLLOWING
+ | FORMAT
+ | FORMATTED
+ | FUNCTION
+ | FUNCTIONS
+ | GLOBAL
+ | GROUPING
+ | HOUR
+ | IF
+ | IGNORE
+ | IMPORT
+ | INDEX
+ | INDEXES
+ | INPATH
+ | INPUTFORMAT
+ | INSERT
+ | INTERVAL
+ | ITEMS
+ | KEYS
+ | LAST
+ | LAZY
+ | LIKE
+ | ILIKE
+ | LIMIT
+ | LINES
+ | LIST
+ | LOAD
+ | LOCAL
+ | LOCATION
+ | LOCK
+ | LOCKS
+ | LOGICAL
+ | MACRO
+ | MAP
+ | MATCHED
+ | MERGE
+ | MINUTE
+ | MONTH
+ | MSCK
+ | NAMESPACE
+ | NAMESPACES
+ | NO
+ | NULLS
+ | OF
+ | OPTION
+ | OPTIONS
+ | OUT
+ | OUTPUTFORMAT
+ | OVER
+ | OVERLAY
+ | OVERWRITE
+ | PARTITION
+ | PARTITIONED
+ | PARTITIONS
+ | PERCENTLIT
+ | PIVOT
+ | PLACING
+ | POSITION
+ | PRECEDING
+ | PRINCIPALS
+ | PROPERTIES
+ | PURGE
+ | QUERY
+ | RANGE
+ | RECORDREADER
+ | RECORDWRITER
+ | RECOVER
+ | REDUCE
+ | REFRESH
+ | RENAME
+ | REPAIR
+ | REPEATABLE
+ | REPLACE
+ | RESET
+ | RESPECT
+ | RESTRICT
+ | REVOKE
+ | RLIKE
+ | ROLE
+ | ROLES
+ | ROLLBACK
+ | ROLLUP
+ | ROW
+ | ROWS
+ | SCHEMA
+ | SCHEMAS
+ | SECOND
+ | SEMI
+ | SEPARATED
+ | SERDE
+ | SERDEPROPERTIES
+ | SET
+ | SETMINUS
+ | SETS
+ | SHOW
+ | SKEWED
+ | SORT
+ | SORTED
+ | START
+ | STATISTICS
+ | STORED
+ | STRATIFY
+ | STRUCT
+ | SUBSTR
+ | SUBSTRING
+ | SYNC
+ | SYSTEM_TIME
+ | SYSTEM_VERSION
+ | TABLES
+ | TABLESAMPLE
+ | TBLPROPERTIES
+ | TEMPORARY
+ | TERMINATED
+ | TIMESTAMP
+ | TIMESTAMPADD
+ | TIMESTAMPDIFF
+ | TOUCH
+ | TRANSACTION
+ | TRANSACTIONS
+ | TRANSFORM
+ | TRIM
+ | TRUE
+ | TRUNCATE
+ | TRY_CAST
+ | TYPE
+ | UNARCHIVE
+ | UNBOUNDED
+ | UNCACHE
+ | UNLOCK
+ | UNSET
+ | UPDATE
+ | USE
+ | VALUES
+ | VERSION
+ | VIEW
+ | VIEWS
+ | WINDOW
+ | YEAR
+ | ZONE
+//--ANSI-NON-RESERVED-END
+ ;
+
+// When `SQL_standard_keyword_behavior=false`, there are 2 kinds of keywords in Spark SQL.
+// - Non-reserved keywords:
+// Same definition as the one when `SQL_standard_keyword_behavior=true`.
+// - Strict-non-reserved keywords:
+// A strict version of non-reserved keywords, which can not be used as table alias.
+// You can find the full keywords list by searching "Start of the keywords list" in this file.
+// The strict-non-reserved keywords are listed in `strictNonReserved`.
+// The non-reserved keywords are listed in `nonReserved`.
+// These 2 together contain all the keywords.
+strictNonReserved
+ : ANTI
+ | CROSS
+ | EXCEPT
+ | FULL
+ | INNER
+ | INTERSECT
+ | JOIN
+ | LATERAL
+ | LEFT
+ | NATURAL
+ | ON
+ | RIGHT
+ | SEMI
+ | SETMINUS
+ | UNION
+ | USING
+ ;
+
+nonReserved
+//--DEFAULT-NON-RESERVED-START
+ : ADD
+ | AFTER
+ | ALL
+ | ALTER
+ | ANALYZE
+ | AND
+ | ANY
+ | ARCHIVE
+ | ARRAY
+ | AS
+ | ASC
+ | AT
+ | AUTHORIZATION
+ | BETWEEN
+ | BOTH
+ | BUCKET
+ | BUCKETS
+ | BY
+ | CACHE
+ | CASCADE
+ | CASE
+ | CAST
+ | CATALOG
+ | CATALOGS
+ | CHANGE
+ | CHECK
+ | CLEAR
+ | CLUSTER
+ | CLUSTERED
+ | CODEGEN
+ | COLLATE
+ | COLLECTION
+ | COLUMN
+ | COLUMNS
+ | COMMENT
+ | COMMIT
+ | COMPACT
+ | COMPACTIONS
+ | COMPUTE
+ | CONCATENATE
+ | CONSTRAINT
+ | COST
+ | CREATE
+ | CUBE
+ | CURRENT
+ | CURRENT_DATE
+ | CURRENT_TIME
+ | CURRENT_TIMESTAMP
+ | CURRENT_USER
+ | DATA
+ | DATABASE
+ | DATABASES
+ | DATEADD
+ | DATE_ADD
+ | DATEDIFF
+ | DATE_DIFF
+ | DAY
+ | DBPROPERTIES
+ | DEFINED
+ | DELETE
+ | DELIMITED
+ | DESC
+ | DESCRIBE
+ | DFS
+ | DIRECTORIES
+ | DIRECTORY
+ | DISTINCT
+ | DISTRIBUTE
+ | DIV
+ | DROP
+ | ELSE
+ | END
+ | ESCAPE
+ | ESCAPED
+ | EXCHANGE
+ | EXISTS
+ | EXPLAIN
+ | EXPORT
+ | EXTENDED
+ | EXTERNAL
+ | EXTRACT
+ | FALSE
+ | FETCH
+ | FILTER
+ | FIELDS
+ | FILEFORMAT
+ | FIRST
+ | FOLLOWING
+ | FOR
+ | FOREIGN
+ | FORMAT
+ | FORMATTED
+ | FROM
+ | FUNCTION
+ | FUNCTIONS
+ | GLOBAL
+ | GRANT
+ | GROUP
+ | GROUPING
+ | HAVING
+ | HOUR
+ | IF
+ | IGNORE
+ | IMPORT
+ | IN
+ | INDEX
+ | INDEXES
+ | INPATH
+ | INPUTFORMAT
+ | INSERT
+ | INTERVAL
+ | INTO
+ | IS
+ | ITEMS
+ | KEYS
+ | LAST
+ | LAZY
+ | LEADING
+ | LIKE
+ | ILIKE
+ | LIMIT
+ | LINES
+ | LIST
+ | LOAD
+ | LOCAL
+ | LOCATION
+ | LOCK
+ | LOCKS
+ | LOGICAL
+ | MACRO
+ | MAP
+ | MATCHED
+ | MERGE
+ | MINUTE
+ | MONTH
+ | MSCK
+ | NAMESPACE
+ | NAMESPACES
+ | NO
+ | NOT
+ | NULL
+ | NULLS
+ | OF
+ | ONLY
+ | OPTION
+ | OPTIONS
+ | OR
+ | ORDER
+ | OUT
+ | OUTER
+ | OUTPUTFORMAT
+ | OVER
+ | OVERLAPS
+ | OVERLAY
+ | OVERWRITE
+ | PARTITION
+ | PARTITIONED
+ | PARTITIONS
+ | PERCENTILE_CONT
+ | PERCENTLIT
+ | PIVOT
+ | PLACING
+ | POSITION
+ | PRECEDING
+ | PRIMARY
+ | PRINCIPALS
+ | PROPERTIES
+ | PURGE
+ | QUERY
+ | RANGE
+ | RECORDREADER
+ | RECORDWRITER
+ | RECOVER
+ | REDUCE
+ | REFERENCES
+ | REFRESH
+ | RENAME
+ | REPAIR
+ | REPEATABLE
+ | REPLACE
+ | RESET
+ | RESPECT
+ | RESTRICT
+ | REVOKE
+ | RLIKE
+ | ROLE
+ | ROLES
+ | ROLLBACK
+ | ROLLUP
+ | ROW
+ | ROWS
+ | SCHEMA
+ | SCHEMAS
+ | SECOND
+ | SELECT
+ | SEPARATED
+ | SERDE
+ | SERDEPROPERTIES
+ | SESSION_USER
+ | SET
+ | SETS
+ | SHOW
+ | SKEWED
+ | SOME
+ | SORT
+ | SORTED
+ | START
+ | STATISTICS
+ | STORED
+ | STRATIFY
+ | STRUCT
+ | SUBSTR
+ | SUBSTRING
+ | SYNC
+ | SYSTEM_TIME
+ | SYSTEM_VERSION
+ | TABLE
+ | TABLES
+ | TABLESAMPLE
+ | TBLPROPERTIES
+ | TEMPORARY
+ | TERMINATED
+ | THEN
+ | TIME
+ | TIMESTAMP
+ | TIMESTAMPADD
+ | TIMESTAMPDIFF
+ | TO
+ | TOUCH
+ | TRAILING
+ | TRANSACTION
+ | TRANSACTIONS
+ | TRANSFORM
+ | TRIM
+ | TRUE
+ | TRUNCATE
+ | TRY_CAST
+ | TYPE
+ | UNARCHIVE
+ | UNBOUNDED
+ | UNCACHE
+ | UNIQUE
+ | UNKNOWN
+ | UNLOCK
+ | UNSET
+ | UPDATE
+ | USE
+ | USER
+ | VALUES
+ | VERSION
+ | VIEW
+ | VIEWS
+ | WHEN
+ | WHERE
+ | WINDOW
+ | WITH
+ | WITHIN
+ | YEAR
+ | ZONE
+//--DEFAULT-NON-RESERVED-END
+ ;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/OptimizerContext.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/OptimizerContext.java
new file mode 100644
index 0000000000..9439931c7d
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/OptimizerContext.java
@@ -0,0 +1,77 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids;
+
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.scheduler.JobPool;
+import org.apache.doris.nereids.jobs.scheduler.JobScheduler;
+import org.apache.doris.nereids.memo.Memo;
+import org.apache.doris.nereids.rules.RuleSet;
+
+/**
+ * Context used in memo.
+ */
+public class OptimizerContext {
+ private final Memo memo;
+ private RuleSet ruleSet;
+ private JobPool jobPool;
+ private final JobScheduler jobScheduler;
+
+ /**
+ * Constructor of OptimizerContext.
+ *
+ * @param memo {@link Memo} reference
+ * @param ruleSet All rules to apply on query plan
+ * @param jobPool {@link JobPool} reference contain pending rules
+ * @param jobScheduler schedule pending jobs
+ */
+ public OptimizerContext(Memo memo, RuleSet ruleSet, JobPool jobPool, JobScheduler jobScheduler) {
+ this.memo = memo;
+ this.ruleSet = ruleSet;
+ this.jobPool = jobPool;
+ this.jobScheduler = jobScheduler;
+ }
+
+ public JobPool getJobPool() {
+ return jobPool;
+ }
+
+ public void setJobPool(JobPool jobPool) {
+ this.jobPool = jobPool;
+ }
+
+ public RuleSet getRuleSet() {
+ return ruleSet;
+ }
+
+ public void setRuleSet(RuleSet ruleSet) {
+ this.ruleSet = ruleSet;
+ }
+
+ public Memo getMemo() {
+ return memo;
+ }
+
+ public void pushTask(Job task) {
+ jobPool.push(task);
+ }
+
+ public JobScheduler getJobScheduler() {
+ return jobScheduler;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/Planner.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/Planner.java
new file mode 100644
index 0000000000..a980090412
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/Planner.java
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids;
+
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.nereids.jobs.cascades.OptimizeGroupJob;
+import org.apache.doris.nereids.jobs.scheduler.JobStack;
+import org.apache.doris.nereids.jobs.scheduler.SimpleJobScheduler;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.Memo;
+import org.apache.doris.nereids.properties.PhysicalProperties;
+import org.apache.doris.nereids.rules.RuleSet;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan;
+import org.apache.doris.qe.ConnectContext;
+
+/**
+ * Planner to do query plan in Nereids.
+ */
+public class Planner {
+ private PlannerContext plannerContext;
+
+ /**
+ * Do analyze and optimize for query plan.
+ *
+ * @param plan wait for plan
+ * @param outputProperties physical properties constraints
+ * @param connectContext connect context for this query
+ * @return physical plan generated by this planner
+ * @throws AnalysisException throw exception if failed in ant stage
+ */
+ // TODO: refactor, just demo code here
+ public PhysicalPlan plan(
+ LogicalPlan plan,
+ PhysicalProperties outputProperties,
+ ConnectContext connectContext) throws AnalysisException {
+ OptimizerContext optimizerContext = new OptimizerContext(
+ new Memo(),
+ new RuleSet(),
+ new JobStack(),
+ new SimpleJobScheduler()
+ );
+ plannerContext = new PlannerContext(optimizerContext, connectContext, outputProperties);
+ plannerContext.getOptimizerContext().getMemo().initialize(plan);
+ plannerContext.getOptimizerContext().pushTask(new OptimizeGroupJob(getRoot(), plannerContext));
+ plannerContext.getOptimizerContext().getJobScheduler().executeJobStack(plannerContext);
+ return getBestPlan();
+ }
+
+ public Group getRoot() {
+ return plannerContext.getOptimizerContext().getMemo().getRootSet();
+ }
+
+ private PhysicalPlan getBestPlan() {
+ return null;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/PlannerContext.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/PlannerContext.java
new file mode 100644
index 0000000000..472d0a1a3b
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/PlannerContext.java
@@ -0,0 +1,79 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids;
+
+import org.apache.doris.nereids.properties.PhysicalProperties;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.qe.ConnectContext;
+
+import com.google.common.collect.Sets;
+
+import java.util.Set;
+
+/**
+ * Context used in all stage in Nereids.
+ */
+public class PlannerContext {
+ private final OptimizerContext optimizerContext;
+ private final ConnectContext connectContext;
+ private final PhysicalProperties physicalProperties;
+ private double costUpperBound;
+ private Set<Slot> neededSlots;
+
+ /**
+ * Constructor of OptimizationContext.
+ *
+ * @param optimizerContext context includes all data struct used in memo
+ * @param connectContext connect context of this query
+ * @param physicalProperties target physical properties
+ */
+ public PlannerContext(
+ OptimizerContext optimizerContext,
+ ConnectContext connectContext,
+ PhysicalProperties physicalProperties) {
+ this.optimizerContext = optimizerContext;
+ this.connectContext = connectContext;
+ this.physicalProperties = physicalProperties;
+ this.costUpperBound = Double.MAX_VALUE;
+ this.neededSlots = Sets.newHashSet();
+ }
+
+ public double getCostUpperBound() {
+ return costUpperBound;
+ }
+
+ public void setCostUpperBound(double costUpperBound) {
+ this.costUpperBound = costUpperBound;
+ }
+
+ public OptimizerContext getOptimizerContext() {
+ return optimizerContext;
+ }
+
+ public ConnectContext getConnectContext() {
+ return connectContext;
+ }
+
+ public PhysicalProperties getPhysicalProperties() {
+ return physicalProperties;
+ }
+
+ public Set<Slot> getNeededAttributes() {
+ return neededSlots;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/README b/fe/fe-core/src/main/java/org/apache/doris/nereids/README
new file mode 100644
index 0000000000..b2fafd6b93
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/README
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+Parser and expressions is inspired by Spark: https://spark.apache.org
+Optimizer is inspired by NoisePage: https://github.com/cmu-db/noisepage
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundAlias.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundAlias.java
new file mode 100644
index 0000000000..0681381003
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundAlias.java
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.analyzer;
+
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.ExprId;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+
+import java.util.List;
+
+/**
+ * Expression for unbound alias.
+ */
+public class UnboundAlias extends NamedExpression {
+ private final Expression child;
+
+ public UnboundAlias(Expression child) {
+ super(NodeType.UNBOUND_ALIAS);
+ this.child = child;
+ }
+
+ @Override
+ public String sql() {
+ return null;
+ }
+
+ @Override
+ public String getName() throws UnboundException {
+ return null;
+ }
+
+ @Override
+ public ExprId getExprId() throws UnboundException {
+ return null;
+ }
+
+ @Override
+ public List<String> getQualifier() throws UnboundException {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "UnboundAlias(" + child + ", None)";
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java
new file mode 100644
index 0000000000..45a91682ed
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java
@@ -0,0 +1,75 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.analyzer;
+
+import org.apache.doris.nereids.analyzer.identifier.TableIdentifier;
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.logical.LogicalLeaf;
+import org.apache.doris.nereids.util.Utils;
+
+import com.clearspring.analytics.util.Lists;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+/**
+ * Represent a relation plan node that has not been bound.
+ */
+public class UnboundRelation extends LogicalLeaf {
+ private final List<String> nameParts;
+
+ public UnboundRelation(List<String> nameParts) {
+ super(NodeType.LOGICAL_UNBOUND_RELATION);
+ this.nameParts = nameParts;
+ }
+
+ /**
+ * Constructor for UnboundRelation.
+ *
+ * @param identifier relation identifier
+ */
+ public UnboundRelation(TableIdentifier identifier) {
+ super(NodeType.LOGICAL_UNBOUND_RELATION);
+ this.nameParts = Lists.newArrayList();
+ if (identifier.getDatabaseName().isPresent()) {
+ nameParts.add(identifier.getDatabaseName().get());
+ }
+ nameParts.add(identifier.getTableName());
+ }
+
+ public List<String> getNameParts() {
+ return nameParts;
+ }
+
+ public String getTableName() {
+ return nameParts.stream().map(Utils::quoteIfNeeded)
+ .reduce((left, right) -> left + "." + right).orElse("");
+ }
+
+ @Override
+ public List<Slot> getOutput() throws UnboundException {
+ throw new UnboundException("output");
+ }
+
+ @Override
+ public String toString() {
+ return "UnresolvedRelation" + "(" + StringUtils.join(nameParts, ".") + ")";
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundSlot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundSlot.java
new file mode 100644
index 0000000000..739dac5333
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundSlot.java
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.analyzer;
+
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.util.Utils;
+
+import com.alibaba.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Slot has not been bound.
+ */
+public class UnboundSlot extends Slot {
+ private final List<String> nameParts;
+
+ public UnboundSlot(List<String> nameParts) {
+ super(NodeType.UNBOUND_SLOT);
+ this.nameParts = nameParts;
+ }
+
+ public List<String> getNameParts() {
+ return nameParts;
+ }
+
+ @Override
+ public String getName() {
+ return nameParts.stream().map(n -> {
+ if (n.contains(".")) {
+ return "`" + n + "`";
+ } else {
+ return n;
+ }
+ }).reduce((left, right) -> left + "." + right).orElse("");
+ }
+
+ @Override
+ public String sql() {
+ return nameParts.stream().map(Utils::quoteIfNeeded).reduce((left, right) -> left + "." + right).orElse("");
+ }
+
+ public static UnboundSlot quoted(String name) {
+ return new UnboundSlot(Lists.newArrayList(name));
+ }
+
+ @Override
+ public String toString() {
+ return "'" + getName();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundStar.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundStar.java
new file mode 100644
index 0000000000..6b345c59ff
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundStar.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.analyzer;
+
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.util.Utils;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.List;
+
+/**
+ * Star expression.
+ */
+public class UnboundStar extends NamedExpression {
+ private final List<String> target;
+
+ public UnboundStar(List<String> target) {
+ super(NodeType.UNBOUND_STAR);
+ this.target = target;
+ }
+
+ @Override
+ public String sql() {
+ String targetString = target.stream().map(Utils::quoteIfNeeded).reduce((t1, t2) -> t1 + "." + t2).orElse("");
+ if (StringUtils.isNotEmpty(targetString)) {
+ return targetString + ".*";
+ } else {
+ return "*";
+ }
+ }
+
+ @Override
+ public String toString() {
+ return sql();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/identifier/IdentifierWithDatabase.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/identifier/IdentifierWithDatabase.java
new file mode 100644
index 0000000000..21855ac99a
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/identifier/IdentifierWithDatabase.java
@@ -0,0 +1,65 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.analyzer.identifier;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.Optional;
+
+/**
+ * Identifier in Nereids with its database name.
+ */
+public abstract class IdentifierWithDatabase {
+ protected String identifier;
+ protected String databaseName;
+
+ private String quoteIdentifier(String name) {
+ return name.replace("`", "``");
+ }
+
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ public Optional<String> getDatabaseName() {
+ return Optional.of(databaseName);
+ }
+
+ protected String quotedString() {
+ String replacedId = quoteIdentifier(identifier);
+ if (StringUtils.isNotEmpty(databaseName)) {
+ String replacedDb = quoteIdentifier(databaseName);
+ return String.format("`%s`.`%s`", replacedDb, replacedId);
+ } else {
+ return String.format("`%s`", replacedId);
+ }
+ }
+
+ protected String unquotedString() {
+ if (StringUtils.isNotEmpty(databaseName)) {
+ return String.format("%s.%s", databaseName, identifier);
+ } else {
+ return String.format("%s", identifier);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return quotedString();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/identifier/TableIdentifier.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/identifier/TableIdentifier.java
new file mode 100644
index 0000000000..bf4cc04af0
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/identifier/TableIdentifier.java
@@ -0,0 +1,36 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.analyzer.identifier;
+
+/**
+ * Identifier used for table.
+ */
+public class TableIdentifier extends IdentifierWithDatabase {
+ public TableIdentifier(String tableName, String databaseName) {
+ this.identifier = tableName;
+ this.databaseName = databaseName;
+ }
+
+ public TableIdentifier(String tableName) {
+ this.identifier = tableName;
+ }
+
+ public String getTableName() {
+ return identifier;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/exceptions/UnboundException.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/exceptions/UnboundException.java
new file mode 100644
index 0000000000..7b2d7700f1
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/exceptions/UnboundException.java
@@ -0,0 +1,29 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.exceptions;
+
+import org.apache.doris.common.AnalysisException;
+
+/**
+ * Exception for calling function only implement in bound expression or plan.
+ */
+public class UnboundException extends AnalysisException {
+ public UnboundException(String msg) {
+ super(String.format("Invalid call to %s on unbound object", msg));
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/Job.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/Job.java
new file mode 100644
index 0000000000..b9a7f02666
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/Job.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs;
+
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.memo.PlanReference;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleSet;
+
+import java.util.List;
+
+/**
+ * Abstract class for all job using for analyze and optimize query plan in Nereids.
+ */
+public abstract class Job {
+ protected JobType type;
+ protected PlannerContext context;
+
+ public Job(JobType type, PlannerContext context) {
+ this.type = type;
+ this.context = context;
+ }
+
+ public void pushTask(Job job) {
+ context.getOptimizerContext().pushTask(job);
+ }
+
+ public RuleSet getRuleSet() {
+ return context.getOptimizerContext().getRuleSet();
+ }
+
+ public void prunedInvalidRules(PlanReference planReference, List<Rule> candidateRules) {
+
+ }
+
+ public abstract void execute() throws AnalysisException;
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/JobType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/JobType.java
new file mode 100644
index 0000000000..856773028d
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/JobType.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs;
+
+/**
+ * All job types in Nereids.
+ */
+public enum JobType {
+ OPTIMIZE_PLAN_SET,
+ OPTIMIZE_PLAN,
+ OPTIMIZE_CHILDREN,
+ EXPLORE_PLAN_SET,
+ EXPLORE_PLAN,
+ APPLY_RULE,
+ DERIVE_STATS,
+ TOP_DOWN_REWRITE,
+ BOTTOM_UP_REWRITE,
+ ;
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java
new file mode 100644
index 0000000000..69dba02425
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ApplyRuleJob.java
@@ -0,0 +1,83 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.cascades;
+
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.memo.PlanReference;
+import org.apache.doris.nereids.pattern.PatternMatching;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.trees.plans.Plan;
+
+import java.util.List;
+
+/**
+ * Job to apply rule on {@link PlanReference}.
+ */
+public class ApplyRuleJob extends Job {
+ private final PlanReference planReference;
+ private final Rule rule;
+ private final boolean exploredOnly;
+
+ /**
+ * Constructor of ApplyRuleJob.
+ *
+ * @param planReference apply rule on this {@link PlanReference}
+ * @param rule rule to be applied
+ * @param context context of optimization
+ */
+ public ApplyRuleJob(PlanReference planReference, Rule rule, PlannerContext context) {
+ super(JobType.APPLY_RULE, context);
+ this.planReference = planReference;
+ this.rule = rule;
+ this.exploredOnly = false;
+ }
+
+ @Override
+ public void execute() throws AnalysisException {
+ if (planReference.hasExplored(rule)) {
+ return;
+ }
+
+ // TODO: need to find all plan reference tree that match this pattern
+ PatternMatching patternMatching = new PatternMatching();
+ for (Plan<?> plan : patternMatching) {
+ if (!rule.check(plan, context)) {
+ continue;
+ }
+ List<Plan<?>> newPlanList = rule.transform(plan, context);
+ for (Plan<?> newPlan : newPlanList) {
+ PlanReference newReference = context.getOptimizerContext().getMemo()
+ .newPlanReference(newPlan, planReference.getParent());
+ // TODO need to check return is a new Reference, other wise will be into a dead loop
+ if (newPlan.isLogical()) {
+ pushTask(new DeriveStatsJob(newReference, context));
+ if (exploredOnly) {
+ pushTask(new ExplorePlanJob(newReference, context));
+ }
+ pushTask(new OptimizePlanJob(newReference, context));
+ } else {
+ pushTask(new CostAndEnforcerJob(newReference, context));
+ }
+ }
+ }
+ planReference.setExplored(rule);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/CostAndEnforcerJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/CostAndEnforcerJob.java
new file mode 100644
index 0000000000..2711f4679a
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/CostAndEnforcerJob.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.cascades;
+
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.memo.PlanReference;
+
+/**
+ * Job to compute cost and add enforcer.
+ */
+public class CostAndEnforcerJob extends Job {
+ private final PlanReference planReference;
+
+ public CostAndEnforcerJob(PlanReference planReference, PlannerContext context) {
+ super(JobType.OPTIMIZE_CHILDREN, context);
+ this.planReference = planReference;
+ }
+
+ @Override
+ public void execute() {
+ // TODO
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/DeriveStatsJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/DeriveStatsJob.java
new file mode 100644
index 0000000000..59bd9744a2
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/DeriveStatsJob.java
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.cascades;
+
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.PlanReference;
+
+/**
+ * Job to derive stats for {@link PlanReference} in {@link org.apache.doris.nereids.memo.Memo}.
+ */
+public class DeriveStatsJob extends Job {
+ private final PlanReference planReference;
+ private boolean deriveChildren;
+
+ /**
+ * Constructor for DeriveStatsJob.
+ *
+ * @param planReference Derive stats on this {@link PlanReference}
+ * @param context context of optimization
+ */
+ public DeriveStatsJob(PlanReference planReference, PlannerContext context) {
+ super(JobType.DERIVE_STATS, context);
+ this.planReference = planReference;
+ this.deriveChildren = false;
+ }
+
+ /**
+ * Copy constructor for DeriveStatsJob.
+ *
+ * @param other DeriveStatsJob copied from
+ */
+ public DeriveStatsJob(DeriveStatsJob other) {
+ super(JobType.DERIVE_STATS, other.context);
+ this.planReference = other.planReference;
+ this.deriveChildren = other.deriveChildren;
+ }
+
+ @Override
+ public void execute() {
+ if (!deriveChildren) {
+ deriveChildren = true;
+ pushTask(new DeriveStatsJob(this));
+ for (Group childSet : planReference.getChildren()) {
+ if (!childSet.getLogicalPlanList().isEmpty()) {
+ pushTask(new DeriveStatsJob(childSet.getLogicalPlanList().get(0), context));
+ }
+ }
+ } else {
+ // TODO: derive stat here
+ planReference.setStatDerived(true);
+ }
+
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExploreGroupJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExploreGroupJob.java
new file mode 100644
index 0000000000..2bac5493f0
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExploreGroupJob.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.cascades;
+
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.PlanReference;
+
+/**
+ * Job to explore {@link Group} in {@link org.apache.doris.nereids.memo.Memo}.
+ */
+public class ExploreGroupJob extends Job {
+ private final Group group;
+
+ /**
+ * Constructor for ExploreGroupJob.
+ *
+ * @param group {@link Group} to be explored
+ * @param context context of optimization
+ */
+ public ExploreGroupJob(Group group, PlannerContext context) {
+ super(JobType.EXPLORE_PLAN_SET, context);
+ this.group = group;
+ }
+
+ @Override
+ public void execute() {
+ if (group.isExplored()) {
+ return;
+ }
+ for (PlanReference planReference : group.getLogicalPlanList()) {
+ pushTask(new ExplorePlanJob(planReference, context));
+ }
+ group.setExplored(true);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExplorePlanJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExplorePlanJob.java
new file mode 100644
index 0000000000..a987f6825d
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/ExplorePlanJob.java
@@ -0,0 +1,65 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.cascades;
+
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.PlanReference;
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.rules.Rule;
+
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Job to explore {@link PlanReference} in {@link org.apache.doris.nereids.memo.Memo}.
+ */
+public class ExplorePlanJob extends Job {
+ private final PlanReference planReference;
+
+ /**
+ * Constructor for ExplorePlanJob.
+ *
+ * @param planReference {@link PlanReference} to be explored
+ * @param context context of optimization
+ */
+ public ExplorePlanJob(PlanReference planReference, PlannerContext context) {
+ super(JobType.EXPLORE_PLAN, context);
+ this.planReference = planReference;
+ }
+
+ @Override
+ public void execute() {
+ List<Rule> explorationRules = getRuleSet().getExplorationRules();
+ prunedInvalidRules(planReference, explorationRules);
+ explorationRules.sort(Comparator.comparingInt(o -> o.getRulePromise().promise()));
+
+ for (Rule rule : explorationRules) {
+ pushTask(new ApplyRuleJob(planReference, rule, context));
+ for (int i = 0; i < rule.getPattern().getChildren().size(); ++i) {
+ Pattern childPattern = rule.getPattern().getChild(i);
+ if (!childPattern.getChildren().isEmpty()) {
+ Group childSet = planReference.getChildren().get(i);
+ pushTask(new ExploreGroupJob(childSet, context));
+ }
+ }
+ }
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
new file mode 100644
index 0000000000..1b2676c832
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizeGroupJob.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.cascades;
+
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.PlanReference;
+
+/**
+ * Job to optimize {@link Group} in {@link org.apache.doris.nereids.memo.Memo}.
+ */
+public class OptimizeGroupJob extends Job {
+ private final Group group;
+
+ public OptimizeGroupJob(Group group, PlannerContext context) {
+ super(JobType.OPTIMIZE_PLAN_SET, context);
+ this.group = group;
+ }
+
+ @Override
+ public void execute() {
+ if (group.getCostLowerBound() > context.getCostUpperBound()
+ || group.getLowestCostPlan(context.getPhysicalProperties()).isPresent()) {
+ return;
+ }
+ if (!group.isExplored()) {
+ for (PlanReference logicalPlanReference : group.getLogicalPlanList()) {
+ context.getOptimizerContext().pushTask(new OptimizePlanJob(logicalPlanReference, context));
+ }
+ }
+ for (PlanReference physicalPlanReference : group.getPhysicalPlanList()) {
+ context.getOptimizerContext().pushTask(new CostAndEnforcerJob(physicalPlanReference, context));
+ }
+ group.setExplored(true);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizePlanJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizePlanJob.java
new file mode 100644
index 0000000000..b9e2e38324
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/cascades/OptimizePlanJob.java
@@ -0,0 +1,70 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.cascades;
+
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.memo.Group;
+import org.apache.doris.nereids.memo.PlanReference;
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.rules.Rule;
+
+import com.clearspring.analytics.util.Lists;
+
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Job to optimize {@link org.apache.doris.nereids.trees.plans.Plan} in {@link org.apache.doris.nereids.memo.Memo}.
+ */
+public class OptimizePlanJob extends Job {
+ private final PlanReference planReference;
+
+ public OptimizePlanJob(PlanReference planReference, PlannerContext context) {
+ super(JobType.OPTIMIZE_PLAN, context);
+ this.planReference = planReference;
+ }
+
+ @Override
+ public void execute() {
+ List<Rule> validRules = Lists.newArrayList();
+ List<Rule> explorationRules = getRuleSet().getExplorationRules();
+ List<Rule> implementationRules = getRuleSet().getImplementationRules();
+ prunedInvalidRules(planReference, explorationRules);
+ prunedInvalidRules(planReference, implementationRules);
+ validRules.addAll(explorationRules);
+ validRules.addAll(implementationRules);
+ validRules.sort(Comparator.comparingInt(o -> o.getRulePromise().promise()));
+
+ for (Rule rule : validRules) {
+ pushTask(new ApplyRuleJob(planReference, rule, context));
+
+ // If child_pattern has any more children (i.e non-leaf), then we will explore the
+ // child before applying the rule. (assumes task pool is effectively a stack)
+ for (int i = 0; i < rule.getPattern().getChildren().size(); ++i) {
+ Pattern childPattern = rule.getPattern().getChild(i);
+ if (!childPattern.getChildren().isEmpty()) {
+ Group childSet = planReference.getChildren().get(i);
+ pushTask(new ExploreGroupJob(childSet, context));
+ }
+ }
+ }
+
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
new file mode 100644
index 0000000000..312e8a9f8c
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteBottomUpJob.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.rewrite;
+
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.memo.Group;
+
+/**
+ * Bottom up job for rewrite, use pattern match.
+ */
+public class RewriteBottomUpJob extends Job {
+ private final Group group;
+
+ public RewriteBottomUpJob(Group group, PlannerContext context) {
+ super(JobType.BOTTOM_UP_REWRITE, context);
+ this.group = group;
+ }
+
+ @Override
+ public void execute() {
+
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
new file mode 100644
index 0000000000..baf343c654
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/RewriteTopDownJob.java
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.rewrite;
+
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+import org.apache.doris.nereids.jobs.JobType;
+import org.apache.doris.nereids.memo.Group;
+
+/**
+ * Top down job for rewrite, use pattern match.
+ */
+public class RewriteTopDownJob extends Job {
+ private final Group group;
+
+ public RewriteTopDownJob(Group group, PlannerContext context) {
+ super(JobType.TOP_DOWN_REWRITE, context);
+ this.group = group;
+ }
+
+ @Override
+ public void execute() {
+
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/JobPool.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/JobPool.java
new file mode 100644
index 0000000000..a66d1a68d1
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/JobPool.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.scheduler;
+
+import org.apache.doris.nereids.jobs.Job;
+
+/**
+ * Pool for all pending jobs.
+ */
+public interface JobPool {
+ void push(Job job);
+
+ Job pop();
+
+ boolean isEmpty();
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/JobScheduler.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/JobScheduler.java
new file mode 100644
index 0000000000..cd3d1a993a
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/JobScheduler.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.scheduler;
+
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+
+/**
+ * Scheduler to schedule jobs in Nereids.
+ */
+public interface JobScheduler {
+ void executeJob(Job job, PlannerContext context);
+
+ void executeJobStack(PlannerContext plannerContext) throws AnalysisException;
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/JobStack.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/JobStack.java
new file mode 100644
index 0000000000..ada1118a08
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/JobStack.java
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.scheduler;
+
+import org.apache.doris.nereids.jobs.Job;
+
+import java.util.Stack;
+
+/**
+ * LIFO implementation of {@link JobPool}.
+ */
+public class JobStack implements JobPool {
+ Stack<Job> stack = new Stack<>();
+
+ @Override
+ public void push(Job job) {
+ stack.push(job);
+ }
+
+ @Override
+ public Job pop() {
+ return stack.pop();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return stack.isEmpty();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/SimpleJobScheduler.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/SimpleJobScheduler.java
new file mode 100644
index 0000000000..fa11f826b3
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/scheduler/SimpleJobScheduler.java
@@ -0,0 +1,41 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.jobs.scheduler;
+
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.jobs.Job;
+
+/**
+ * Single thread, serial scheduler.
+ */
+public class SimpleJobScheduler implements JobScheduler {
+ @Override
+ public void executeJob(Job job, PlannerContext context) {
+
+ }
+
+ @Override
+ public void executeJobStack(PlannerContext plannerContext) throws AnalysisException {
+ JobPool pool = plannerContext.getOptimizerContext().getJobPool();
+ while (!pool.isEmpty()) {
+ Job job = pool.pop();
+ job.execute();
+ }
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java
new file mode 100644
index 0000000000..8e64d36190
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Group.java
@@ -0,0 +1,126 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.memo;
+
+import org.apache.doris.common.Pair;
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.properties.LogicalProperties;
+import org.apache.doris.nereids.properties.PhysicalProperties;
+
+import com.clearspring.analytics.util.Lists;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Representation for group in cascades optimizer.
+ */
+public class Group {
+ private final GroupId groupId = GroupId.newPlanSetId();
+
+ private final List<PlanReference> logicalPlanList = Lists.newArrayList();
+ private final List<PlanReference> physicalPlanList = Lists.newArrayList();
+ private final LogicalProperties logicalProperties;
+
+ private Map<PhysicalProperties, Pair<Double, PlanReference>> lowestCostPlans;
+ private double costLowerBound = -1;
+ private boolean isExplored = false;
+
+ /**
+ * Constructor for Group.
+ *
+ * @param planReference first {@link PlanReference} in this Group
+ */
+ public Group(PlanReference planReference) {
+ if (planReference.getPlan().isLogical()) {
+ this.logicalPlanList.add(planReference);
+ } else {
+ this.physicalPlanList.add(planReference);
+ }
+ logicalProperties = new LogicalProperties();
+ try {
+ logicalProperties.setOutput(planReference.getPlan().getOutput());
+ } catch (UnboundException e) {
+ throw new RuntimeException(e);
+ }
+ planReference.setParent(this);
+ }
+
+ public GroupId getGroupId() {
+ return groupId;
+ }
+
+ /**
+ * Add new {@link PlanReference} into this group.
+ *
+ * @param planReference {@link PlanReference} to be added
+ * @return added {@link PlanReference}
+ */
+ public PlanReference addPlanReference(PlanReference planReference) {
+ if (planReference.getPlan().isLogical()) {
+ logicalPlanList.add(planReference);
+ } else {
+ physicalPlanList.add(planReference);
+ }
+ return planReference;
+ }
+
+ public double getCostLowerBound() {
+ return costLowerBound;
+ }
+
+ public void setCostLowerBound(double costLowerBound) {
+ this.costLowerBound = costLowerBound;
+ }
+
+ public List<PlanReference> getLogicalPlanList() {
+ return logicalPlanList;
+ }
+
+ public List<PlanReference> getPhysicalPlanList() {
+ return physicalPlanList;
+ }
+
+ public LogicalProperties getLogicalProperties() {
+ return logicalProperties;
+ }
+
+ public boolean isExplored() {
+ return isExplored;
+ }
+
+ public void setExplored(boolean explored) {
+ isExplored = explored;
+ }
+
+ /**
+ * Get the lowest cost {@link org.apache.doris.nereids.trees.plans.physical.PhysicalPlan}
+ * which meeting the physical property constraints in this Group.
+ *
+ * @param physicalProperties the physical property constraints
+ * @return {@link Optional} of cost and {@link PlanReference} of physical plan pair.
+ */
+ public Optional<Pair<Double, PlanReference>> getLowestCostPlan(PhysicalProperties physicalProperties) {
+ if (physicalProperties == null || CollectionUtils.isEmpty(lowestCostPlans)) {
+ return Optional.empty();
+ }
+ return Optional.ofNullable(lowestCostPlans.get(physicalProperties));
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupId.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupId.java
new file mode 100644
index 0000000000..b3842f06b9
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupId.java
@@ -0,0 +1,59 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.memo;
+
+import java.util.Objects;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * UUID for {@link Group}.
+ */
+public class GroupId {
+ private static final AtomicLong CURRENT_ID = new AtomicLong();
+ private static final UUID JVM_ID = UUID.randomUUID();
+
+ private final long id;
+ private final UUID jvmId;
+
+ public GroupId(long id, UUID jvmId) {
+ this.id = id;
+ this.jvmId = jvmId;
+ }
+
+ public static GroupId newPlanSetId() {
+ return new GroupId(CURRENT_ID.getAndIncrement(), JVM_ID);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GroupId groupId = (GroupId) o;
+ return id == groupId.id && jvmId.equals(groupId.jvmId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, jvmId);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
new file mode 100644
index 0000000000..0da9a4dcdb
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.memo;
+
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Representation for memo in cascades optimizer.
+ */
+public class Memo {
+ private final List<Group> groups = Lists.newArrayList();
+ private final List<PlanReference> planReferences = Lists.newArrayList();
+ private Group rootSet;
+
+ public void initialize(LogicalPlan plan) {
+ rootSet = newPlanReference(plan, null).getParent();
+ }
+
+ public Group getRootSet() {
+ return rootSet;
+ }
+
+ /**
+ * Add plan to Memo.
+ *
+ * @param plan {@link Plan} to be added
+ * @param target target group to add plan. null to generate new Group
+ * @return Reference of plan in Memo
+ */
+ // TODO: need to merge PlanRefSet if new PlanRef is same with some one already in memo
+ public PlanReference newPlanReference(Plan<?> plan, Group target) {
+ if (plan.getPlanReference() != null) {
+ return plan.getPlanReference();
+ }
+ List<PlanReference> childReferences = Lists.newArrayList();
+ for (Plan<?> childrenPlan : plan.getChildren()) {
+ childReferences.add(newPlanReference(childrenPlan, null));
+ }
+ PlanReference newPlanReference = new PlanReference(plan);
+ planReferences.add(newPlanReference);
+ for (PlanReference childReference : childReferences) {
+ newPlanReference.addChild(childReference.getParent());
+ }
+
+ if (target != null) {
+ target.addPlanReference(newPlanReference);
+ } else {
+ Group group = new Group(newPlanReference);
+ groups.add(group);
+ }
+ return newPlanReference;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/PlanReference.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/PlanReference.java
new file mode 100644
index 0000000000..2b3b79e038
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/PlanReference.java
@@ -0,0 +1,96 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.memo;
+
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.trees.plans.Plan;
+
+import com.clearspring.analytics.util.Lists;
+
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * Representation for group expression in cascades optimizer.
+ */
+public class PlanReference {
+ private Group parent;
+ private List<Group> children;
+ private final Plan<?> plan;
+ private final BitSet ruleMasks;
+ private boolean statDerived;
+
+ public PlanReference(Plan<?> plan) {
+ this(plan, Lists.newArrayList());
+ }
+
+ /**
+ * Constructor for PlanReference.
+ *
+ * @param plan {@link Plan} to reference
+ * @param children children groups in memo
+ */
+ public PlanReference(Plan<?> plan, List<Group> children) {
+ this.plan = plan;
+ this.children = children;
+ this.ruleMasks = new BitSet(RuleType.SENTINEL.ordinal());
+ this.statDerived = false;
+ plan.setPlanReference(this);
+ }
+
+ public void addChild(Group child) {
+ children.add(child);
+ }
+
+ public Group getParent() {
+ return parent;
+ }
+
+ public void setParent(Group parent) {
+ this.parent = parent;
+ }
+
+ public Plan<?> getPlan() {
+ return plan;
+ }
+
+ public List<Group> getChildren() {
+ return children;
+ }
+
+ public void setChildren(List<Group> children) {
+ this.children = children;
+ }
+
+ public boolean hasExplored(Rule rule) {
+ return ruleMasks.get(rule.getRuleType().ordinal());
+ }
+
+ public void setExplored(Rule rule) {
+ ruleMasks.set(rule.getRuleType().ordinal());
+ }
+
+ public boolean isStatDerived() {
+ return statDerived;
+ }
+
+ public void setStatDerived(boolean statDerived) {
+ this.statDerived = statDerived;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/AstBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/AstBuilder.java
new file mode 100644
index 0000000000..7a93b88e0d
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/AstBuilder.java
@@ -0,0 +1,438 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.parser;
+
+
+import org.apache.doris.nereids.DorisParser;
+import org.apache.doris.nereids.DorisParser.BooleanLiteralContext;
+import org.apache.doris.nereids.DorisParser.ColumnReferenceContext;
+import org.apache.doris.nereids.DorisParser.ComparisonContext;
+import org.apache.doris.nereids.DorisParser.DereferenceContext;
+import org.apache.doris.nereids.DorisParser.FromClauseContext;
+import org.apache.doris.nereids.DorisParser.IdentifierListContext;
+import org.apache.doris.nereids.DorisParser.IdentifierSeqContext;
+import org.apache.doris.nereids.DorisParser.IntegerLiteralContext;
+import org.apache.doris.nereids.DorisParser.JoinCriteriaContext;
+import org.apache.doris.nereids.DorisParser.JoinRelationContext;
+import org.apache.doris.nereids.DorisParser.MultipartIdentifierContext;
+import org.apache.doris.nereids.DorisParser.NamedExpressionContext;
+import org.apache.doris.nereids.DorisParser.NamedExpressionSeqContext;
+import org.apache.doris.nereids.DorisParser.NullLiteralContext;
+import org.apache.doris.nereids.DorisParser.PredicatedContext;
+import org.apache.doris.nereids.DorisParser.QualifiedNameContext;
+import org.apache.doris.nereids.DorisParser.QueryContext;
+import org.apache.doris.nereids.DorisParser.RegularQuerySpecificationContext;
+import org.apache.doris.nereids.DorisParser.RelationContext;
+import org.apache.doris.nereids.DorisParser.SelectClauseContext;
+import org.apache.doris.nereids.DorisParser.SingleStatementContext;
+import org.apache.doris.nereids.DorisParser.StarContext;
+import org.apache.doris.nereids.DorisParser.StringLiteralContext;
+import org.apache.doris.nereids.DorisParser.TableNameContext;
+import org.apache.doris.nereids.DorisParser.WhereClauseContext;
+import org.apache.doris.nereids.DorisParserBaseVisitor;
+import org.apache.doris.nereids.analyzer.UnboundAlias;
+import org.apache.doris.nereids.analyzer.UnboundRelation;
+import org.apache.doris.nereids.analyzer.UnboundSlot;
+import org.apache.doris.nereids.analyzer.UnboundStar;
+import org.apache.doris.nereids.trees.expressions.Alias;
+import org.apache.doris.nereids.trees.expressions.BinaryPredicate;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Literal;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.plans.JoinType;
+import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+
+import com.clearspring.analytics.util.Lists;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.RuleContext;
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.antlr.v4.runtime.tree.RuleNode;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/**
+ * Build an AST that consisting of logical plans.
+ */
+public class AstBuilder extends DorisParserBaseVisitor<Object> {
+
+ /**
+ * Create a logical plan using a where clause.
+ */
+ private final BiFunction<WhereClauseContext, LogicalPlan, LogicalPlan> withWhereClause =
+ (WhereClauseContext ctx, LogicalPlan plan)
+ -> new LogicalFilter(expression((ctx.booleanExpression())), plan);
+
+ protected <T> T typedVisit(ParseTree ctx) {
+ return (T) ctx.accept(this);
+ }
+
+ /**
+ * Override the default behavior for all visit methods. This will only return a non-null result
+ * when the context has only one child. This is done because there is no generic method to
+ * combine the results of the context children. In all other cases null is returned.
+ */
+ @Override
+ public Object visitChildren(RuleNode node) {
+ if (node.getChildCount() == 1) {
+ return node.getChild(0).accept(this);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public LogicalPlan visitSingleStatement(SingleStatementContext ctx) {
+ Supplier<LogicalPlan> f = () -> (LogicalPlan) visit(ctx.statement());
+ return ParserUtils.withOrigin(ctx, f);
+ }
+
+ /* ********************************************************************************************
+ * Plan parsing
+ * ******************************************************************************************** */
+ private LogicalPlan plan(ParserRuleContext tree) {
+ return (LogicalPlan) tree.accept(this);
+ }
+
+ @Override
+ public LogicalPlan visitQuery(QueryContext ctx) {
+ Supplier<LogicalPlan> f = () -> {
+ // TODO: need to add withQueryResultClauses and withCTE
+ return plan(ctx.queryTerm());
+ };
+ return ParserUtils.withOrigin(ctx, f);
+ }
+
+ @Override
+ public LogicalPlan visitRegularQuerySpecification(RegularQuerySpecificationContext ctx) {
+ Supplier<LogicalPlan> f = () -> {
+ // TODO: support on row relation
+ LogicalPlan from = visitFromClause(ctx.fromClause());
+ return withSelectQuerySpecification(
+ ctx,
+ ctx.selectClause(),
+ ctx.whereClause(),
+ from);
+ };
+ return ParserUtils.withOrigin(ctx, f);
+ }
+
+ @Override
+ public List<Expression> visitNamedExpressionSeq(NamedExpressionSeqContext ctx) {
+ List<Expression> expressions = Lists.newArrayList();
+ if (ctx != null) {
+ for (NamedExpressionContext namedExpressionContext : ctx.namedExpression()) {
+ NamedExpression namedExpression = typedVisit(namedExpressionContext);
+ expressions.add(namedExpression);
+ }
+ }
+ return expressions;
+ }
+
+ /**
+ * Add a regular (SELECT) query specification to a logical plan. The query specification
+ * is the core of the logical plan, this is where sourcing (FROM clause), projection (SELECT),
+ * aggregation (GROUP BY ... HAVING ...) and filtering (WHERE) takes place.
+ *
+ * <p>Note that query hints are ignored (both by the parser and the builder).
+ */
+ private LogicalPlan withSelectQuerySpecification(
+ ParserRuleContext ctx,
+ SelectClauseContext selectClause,
+ WhereClauseContext whereClause,
+ LogicalPlan relation) {
+ Supplier<LogicalPlan> f = () -> {
+ // Filter(expression(ctx.booleanExpression), plan);
+ LogicalPlan plan = visitCommonSelectQueryClausePlan(
+ relation,
+ visitNamedExpressionSeq(selectClause.namedExpressionSeq()),
+ whereClause);
+ // TODO: process hint
+ return plan;
+ };
+ return ParserUtils.withOrigin(ctx, f);
+ }
+
+ private LogicalPlan visitCommonSelectQueryClausePlan(
+ LogicalPlan relation,
+ List<Expression> expressions,
+ WhereClauseContext whereClause) {
+ // TODO: add lateral views
+ // val withLateralView = lateralView.asScala.foldLeft(relation)(withGenerate)
+
+ // add where
+ LogicalPlan withFilter = relation.optionalMap(whereClause, withWhereClause);
+
+ List<NamedExpression> namedExpressions = expressions.stream().map(expression -> {
+ if (expression instanceof NamedExpression) {
+ return (NamedExpression) expression;
+ } else {
+ return new UnboundAlias(expression);
+ }
+ }).collect(Collectors.toList());
+
+ LogicalPlan withProject;
+ if (CollectionUtils.isNotEmpty(namedExpressions)) {
+ withProject = new LogicalProject(namedExpressions, withFilter);
+ } else {
+ withProject = withFilter;
+ }
+
+ return withProject;
+ }
+
+ @Override
+ public LogicalPlan visitFromClause(FromClauseContext ctx) {
+ LogicalPlan left = null;
+ for (RelationContext relation : ctx.relation()) {
+ LogicalPlan right = plan(relation.relationPrimary());
+ if (left == null) {
+ left = right;
+ } else {
+ left = new LogicalJoin(JoinType.INNER_JOIN, null, left, right);
+ }
+ left = withJoinRelations(left, relation);
+ }
+ // TODO: pivot and lateral view
+ return left;
+ }
+
+ /**
+ * Join one more [[LogicalPlan]]s to the current logical plan.
+ */
+ private LogicalPlan withJoinRelations(LogicalPlan base, RelationContext ctx) {
+ LogicalPlan last = base;
+ for (JoinRelationContext join : ctx.joinRelation()) {
+ JoinType joinType;
+ if (join.joinType().LEFT() != null) {
+ joinType = JoinType.LEFT_OUTER_JOIN;
+ } else if (join.joinType().RIGHT() != null) {
+ joinType = JoinType.RIGHT_OUTER_JOIN;
+ } else if (join.joinType().FULL() != null) {
+ joinType = JoinType.FULL_OUTER_JOIN;
+ } else if (join.joinType().SEMI() != null) {
+ joinType = JoinType.LEFT_SEMI_JOIN;
+ } else if (join.joinType().ANTI() != null) {
+ joinType = JoinType.LEFT_ANTI_JOIN;
+ } else if (join.joinType().CROSS() != null) {
+ joinType = JoinType.CROSS_JOIN;
+ } else {
+ joinType = JoinType.INNER_JOIN;
+ }
+
+ // TODO: natural join, lateral join, using join
+ JoinCriteriaContext joinCriteria = join.joinCriteria();
+ Expression condition;
+ if (joinCriteria == null) {
+ condition = null;
+ } else {
+ condition = expression(joinCriteria.booleanExpression());
+ }
+
+ last = new LogicalJoin(joinType, condition, last, plan(join.relationPrimary()));
+ }
+ return last;
+ }
+
+ /**
+ * Create an aliased table reference. This is typically used in FROM clauses.
+ */
+ @Override
+ public LogicalPlan visitTableName(TableNameContext ctx) {
+ List<String> tableId = visitMultipartIdentifier(ctx.multipartIdentifier());
+ UnboundRelation relation = new UnboundRelation(tableId);
+ // TODO: sample and time travel, alias, sub query
+ return relation;
+ }
+
+ /**
+ * Create a Sequence of Strings for a parenthesis enclosed alias list.
+ */
+ @Override
+ public List<String> visitIdentifierList(IdentifierListContext ctx) {
+ return visitIdentifierSeq(ctx.identifierSeq());
+ }
+
+ /**
+ * Create a Sequence of Strings for an identifier list.
+ */
+ @Override
+ public List<String> visitIdentifierSeq(IdentifierSeqContext ctx) {
+ return ctx.ident.stream().map(RuleContext::getText).collect(Collectors.toList());
+ }
+
+ /* ********************************************************************************************
+ * Table Identifier parsing
+ * ******************************************************************************************** */
+
+ @Override
+ public List<String> visitMultipartIdentifier(MultipartIdentifierContext ctx) {
+ return ctx.parts.stream().map(RuleContext::getText).collect(Collectors.toList());
+ }
+
+ /* ********************************************************************************************
+ * Expression parsing
+ * ******************************************************************************************** */
+
+ /**
+ * Create an expression from the given context. This method just passes the context on to the
+ * visitor and only takes care of typing (We assume that the visitor returns an Expression here).
+ */
+ private Expression expression(ParserRuleContext ctx) {
+ return typedVisit(ctx);
+ }
+
+ /**
+ * Create a star (i.e. all) expression; this selects all elements (in the specified object).
+ * Both un-targeted (global) and targeted aliases are supported.
+ */
+ @Override
+ public Expression visitStar(StarContext ctx) {
+ Supplier<Expression> f = () -> {
+ final QualifiedNameContext qualifiedNameContext = ctx.qualifiedName();
+ List<String> target;
+ if (qualifiedNameContext != null) {
+ target = qualifiedNameContext.identifier().stream()
+ .map(RuleContext::getText).collect(Collectors.toList());
+ } else {
+ target = Lists.newArrayList();
+ }
+ return new UnboundStar(target);
+ };
+ return ParserUtils.withOrigin(ctx, f);
+ }
+
+ /**
+ * Create an aliased expression if an alias is specified. Both single and multi-aliases are
+ * supported.
+ */
+ @Override
+ public Expression visitNamedExpression(NamedExpressionContext ctx) {
+ final Expression expression = expression(ctx.expression());
+ if (ctx.name != null) {
+ return new Alias(expression, ctx.name.getText());
+ } else {
+ return expression;
+ }
+ }
+
+ /**
+ * Create a comparison expression. This compares two expressions. The following comparison
+ * operators are supported:
+ * - Equal: '=' or '=='
+ * - Null-safe Equal: '<=>'
+ * - Not Equal: '<>' or '!='
+ * - Less than: '<'
+ * - Less then or Equal: '<='
+ * - Greater than: '>'
+ * - Greater then or Equal: '>='
+ */
+ @Override
+ public Expression visitComparison(ComparisonContext ctx) {
+ Expression left = expression(ctx.left);
+ Expression right = expression(ctx.right);
+ TerminalNode operator = (TerminalNode) ctx.comparisonOperator().getChild(0);
+ switch (operator.getSymbol().getType()) {
+ case DorisParser.EQ:
+ return new BinaryPredicate(left, right, BinaryPredicate.Operator.EQ);
+ case DorisParser.NSEQ:
+ return new BinaryPredicate(left, right, BinaryPredicate.Operator.NSEQ);
+ case DorisParser.LT:
+ return new BinaryPredicate(left, right, BinaryPredicate.Operator.LT);
+ case DorisParser.GT:
+ return new BinaryPredicate(left, right, BinaryPredicate.Operator.GT);
+ case DorisParser.LTE:
+ return new BinaryPredicate(left, right, BinaryPredicate.Operator.LE);
+ case DorisParser.GTE:
+ return new BinaryPredicate(left, right, BinaryPredicate.Operator.GE);
+ case DorisParser.NEQ:
+ case DorisParser.NEQJ:
+ return new BinaryPredicate(left, right, BinaryPredicate.Operator.EQ);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Create a predicated expression. A predicated expression is a normal expression with a
+ * predicate attached to it, for example:
+ * {{{
+ * a + 1 IS NULL
+ * }}}
+ */
+ @Override
+ public Expression visitPredicated(PredicatedContext ctx) {
+ Expression e = expression(ctx.valueExpression());
+ // TODO: add predicate(is not null ...)
+ return e;
+ }
+
+ @Override
+ public Expression visitDereference(DereferenceContext ctx) {
+ Expression e = expression(ctx.base);
+ if (e instanceof UnboundSlot) {
+ UnboundSlot unboundAttribute = (UnboundSlot) e;
+ List<String> nameParts = Lists.newArrayList(unboundAttribute.getNameParts());
+ nameParts.add(ctx.fieldName.getText());
+ return new UnboundSlot(nameParts);
+ } else {
+ // todo: base is an expression, may be not a table name.
+ return null;
+ }
+ }
+
+ @Override
+ public UnboundSlot visitColumnReference(ColumnReferenceContext ctx) {
+ // todo: handle quoted and unquoted
+ return UnboundSlot.quoted(ctx.getText());
+ }
+
+ /**
+ * Create a NULL literal expression.
+ */
+ @Override
+ public Expression visitNullLiteral(NullLiteralContext ctx) {
+ return new Literal(null);
+ }
+
+ @Override
+ public Literal visitBooleanLiteral(BooleanLiteralContext ctx) {
+ Boolean b = Boolean.valueOf(ctx.getText());
+ return new Literal(b);
+ }
+
+ @Override
+ public Literal visitIntegerLiteral(IntegerLiteralContext ctx) {
+ // TODO: throw NumberFormatException
+ Integer l = Integer.valueOf(ctx.getText());
+ return new Literal(l);
+ }
+
+ @Override
+ public Literal visitStringLiteral(StringLiteralContext ctx) {
+ String s = ctx.STRING().stream().map(ParseTree::getText).reduce((s1, s2) -> s1 + s2).orElse("");
+ return new Literal(s);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/CaseInsensitiveStream.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/CaseInsensitiveStream.java
new file mode 100644
index 0000000000..54fe54ab8b
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/CaseInsensitiveStream.java
@@ -0,0 +1,86 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.parser;
+
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.IntStream;
+import org.antlr.v4.runtime.misc.Interval;
+
+/**
+ * Translate parser stream to insensitive.
+ */
+public class CaseInsensitiveStream implements CharStream {
+ private final CharStream stream;
+
+ public CaseInsensitiveStream(CharStream stream) {
+ this.stream = stream;
+ }
+
+ @Override
+ public String getText(Interval interval) {
+ return stream.getText(interval);
+ }
+
+ @Override
+ public void consume() {
+ stream.consume();
+ }
+
+ @Override
+ public int LA(int i) {
+ int result = stream.LA(i);
+
+ switch (result) {
+ case 0:
+ case IntStream.EOF:
+ return result;
+ default:
+ return Character.toUpperCase(result);
+ }
+ }
+
+ @Override
+ public int mark() {
+ return stream.mark();
+ }
+
+ @Override
+ public void release(int marker) {
+ stream.release(marker);
+ }
+
+ @Override
+ public int index() {
+ return stream.index();
+ }
+
+ @Override
+ public void seek(int index) {
+ stream.seek(index);
+ }
+
+ @Override
+ public int size() {
+ return stream.size();
+ }
+
+ @Override
+ public String getSourceName() {
+ return stream.getSourceName();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java
new file mode 100644
index 0000000000..5cb1a488ab
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/ParserUtils.java
@@ -0,0 +1,31 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.parser;
+
+import org.antlr.v4.runtime.ParserRuleContext;
+
+import java.util.function.Supplier;
+
+/**
+ * Utils for parser.
+ */
+public class ParserUtils {
+ public static <T> T withOrigin(ParserRuleContext ctx, Supplier<T> f) {
+ return f.get();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/SqlParser.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/SqlParser.java
new file mode 100644
index 0000000000..a2a44378a9
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/SqlParser.java
@@ -0,0 +1,69 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.parser;
+
+import org.apache.doris.nereids.DorisLexer;
+import org.apache.doris.nereids.DorisParser;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.atn.PredictionMode;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+
+/**
+ * Sql parser, convert sql DSL to logical plan.
+ */
+public class SqlParser {
+
+ /**
+ * parse sql DSL string.
+ *
+ * @param sql sql string
+ * @return logical plan
+ * @throws Exception throw exception when failed in parse stage
+ */
+ public LogicalPlan parse(String sql) throws Exception {
+ DorisLexer lexer = new DorisLexer(new CaseInsensitiveStream(CharStreams.fromString(sql)));
+
+ CommonTokenStream tokenStream = new CommonTokenStream(lexer);
+ DorisParser parser = new DorisParser(tokenStream);
+
+ // parser.addParseListener(PostProcessor)
+ // parser.removeErrorListeners()
+ // parser.addErrorListener(ParseErrorListener)
+
+ ParserRuleContext tree;
+ try {
+ // first, try parsing with potentially faster SLL mode
+ parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
+ tree = parser.singleStatement();
+ } catch (ParseCancellationException ex) {
+ // if we fail, parse with LL mode
+ tokenStream.seek(0); // rewind input stream
+ parser.reset();
+
+ parser.getInterpreter().setPredictionMode(PredictionMode.LL);
+ tree = parser.singleStatement();
+ }
+
+ AstBuilder astBuilder = new AstBuilder();
+ return (LogicalPlan) astBuilder.visit(tree);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java
new file mode 100644
index 0000000000..42467e155c
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/Pattern.java
@@ -0,0 +1,96 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.pattern;
+
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.TreeNode;
+import org.apache.doris.nereids.trees.plans.Plan;
+
+import java.util.Objects;
+
+/**
+ * Pattern node used in pattern matching.
+ */
+public class Pattern extends TreeNode<Pattern> {
+ public static final Pattern PATTERN_MULTI_LEAF_INSTANCE = new Pattern(NodeType.PATTERN_MULTI_LEAF);
+ public static final Pattern PATTERN_LEAF_INSTANCE = new Pattern(NodeType.PATTERN_LEAF);
+
+ private final NodeType nodeType;
+
+ /**
+ * Constructor for Pattern.
+ *
+ * @param nodeType node type to matching
+ * @param children sub pattern
+ */
+ public Pattern(NodeType nodeType, Pattern... children) {
+ super(NodeType.PATTERN);
+ this.nodeType = nodeType;
+ for (Pattern child : children) {
+ addChild(child);
+ }
+ }
+
+ /**
+ * get current type in Pattern.
+ *
+ * @return node type in pattern
+ */
+ public NodeType getNodeType() {
+ return nodeType;
+ }
+
+ /**
+ * Return ture if current Pattern match Plan in params.
+ *
+ * @param plan wait to match
+ * @return ture if current Pattern match Plan in params
+ */
+ public boolean matchRoot(Plan<?> plan) {
+ if (plan == null) {
+ return false;
+ }
+
+ if (plan.getChildren().size() < this.getChildren().size() && children.contains(PATTERN_MULTI_LEAF_INSTANCE)) {
+ return false;
+ }
+
+ if (nodeType == NodeType.PATTERN_MULTI_LEAF || nodeType == NodeType.PATTERN_LEAF) {
+ return true;
+ }
+
+ return getNodeType().equals(plan.getType());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ Pattern pattern = (Pattern) o;
+ return nodeType == pattern.nodeType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(nodeType);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/PatternMatching.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/PatternMatching.java
new file mode 100644
index 0000000000..73ffa296dc
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/pattern/PatternMatching.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.pattern;
+
+import org.apache.doris.nereids.trees.plans.Plan;
+
+import java.util.Iterator;
+
+/**
+ * Get all pattern matching subtree in query plan.
+ */
+public class PatternMatching implements Iterable<Plan<?>> {
+
+ @Override
+ public Iterator<Plan<?>> iterator() {
+ return new PatternMatchingIterator();
+ }
+
+ /**
+ * Iterator to get all subtrees.
+ */
+ public static class PatternMatchingIterator implements Iterator<Plan<?>> {
+ @Override
+ public boolean hasNext() {
+ return false;
+ }
+
+ @Override
+ public Plan<?> next() {
+ return null;
+ }
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java
new file mode 100644
index 0000000000..28e0910984
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java
@@ -0,0 +1,39 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.properties;
+
+import org.apache.doris.nereids.trees.expressions.Slot;
+
+import com.clearspring.analytics.util.Lists;
+
+import java.util.List;
+
+/**
+ * Logical properties used for analysis and optimize in Nereids.
+ */
+public class LogicalProperties {
+ protected List<Slot> output = Lists.newArrayList();
+
+ public List<Slot> getOutput() {
+ return output;
+ }
+
+ public void setOutput(List<Slot> output) {
+ this.output = output;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/PhysicalProperties.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/PhysicalProperties.java
new file mode 100644
index 0000000000..fe0db693a5
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/PhysicalProperties.java
@@ -0,0 +1,25 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.properties;
+
+/**
+ * Physical properties used in cascades.
+ */
+public class PhysicalProperties {
+
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/qe/Executor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/qe/Executor.java
new file mode 100644
index 0000000000..342585f932
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/qe/Executor.java
@@ -0,0 +1,59 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.qe;
+
+import org.apache.doris.nereids.parser.SqlParser;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.qe.ConnectContext;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * Temporary executor in Nereids.
+ */
+public class Executor {
+ private static final Logger LOG = LogManager.getLogger(Executor.class);
+
+ private final String sql;
+ private final ConnectContext context;
+
+ public Executor(String sql, ConnectContext context) {
+ this.sql = sql;
+ this.context = context;
+ }
+
+ public void dryRun() throws Exception {
+ doExecute(false);
+ }
+
+ public void execute() throws Exception {
+ doExecute(true);
+ }
+
+ private void doExecute(boolean sendFragments) throws Exception {
+ LOG.info("==== input SQL: ====\n{}", sql);
+ System.out.println("==== input SQL: ====\n" + sql + "\n");
+
+ // parse phase
+ SqlParser parser = new SqlParser();
+ LogicalPlan parsedPlan = parser.parse(sql);
+ LOG.info("==== parsed plan: ====\n{}", parsedPlan.treeString());
+ System.out.println("==== parsed plan: ====\n" + parsedPlan.treeString() + "\n");
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/Rule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/Rule.java
new file mode 100644
index 0000000000..014f5fd35f
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/Rule.java
@@ -0,0 +1,65 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules;
+
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.trees.plans.Plan;
+
+import java.util.List;
+
+/**
+ * Abstract class for all rules.
+ */
+public abstract class Rule {
+ private final RuleType ruleType;
+ private final Pattern pattern;
+ private final RulePromise rulePromise;
+
+ /**
+ * Constructor for Rule.
+ *
+ * @param ruleType type of rule
+ * @param pattern target pattern of rule
+ * @param rulePromise rule promise
+ */
+ public Rule(RuleType ruleType, Pattern pattern, RulePromise rulePromise) {
+ this.ruleType = ruleType;
+ this.pattern = pattern;
+ this.rulePromise = rulePromise;
+ }
+
+ public RuleType getRuleType() {
+ return ruleType;
+ }
+
+ public RulePromise getRulePromise() {
+ return rulePromise;
+ }
+
+ public Pattern getPattern() {
+ return pattern;
+ }
+
+ public boolean check(Plan<?> plan, PlannerContext context) {
+ return true;
+ }
+
+ public abstract List<Plan<?>> transform(Plan<?> plan, PlannerContext context) throws AnalysisException;
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RulePromise.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RulePromise.java
new file mode 100644
index 0000000000..3b4c8f3756
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RulePromise.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules;
+
+/**
+ * Promise of rule, The value with a large promise has a higher priority.
+ */
+public enum RulePromise {
+ EXPLORE,
+ IMPLEMENT,
+ REWRITE,
+ EXPRESSION,
+ ANALYSIS,
+ ;
+
+ public int promise() {
+ return ordinal();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
new file mode 100644
index 0000000000..3eb4eb85d6
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules;
+
+import org.apache.doris.nereids.rules.analysis.AnalysisUnboundRelationRule;
+
+import com.clearspring.analytics.util.Lists;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+
+/**
+ * Containers for set of different type rules.
+ */
+public class RuleSet {
+ public static List<Rule> ANALYSIS_RULES = ImmutableList.<Rule>builder()
+ .add(new AnalysisUnboundRelationRule())
+ .build();
+
+ public List<Rule> getExplorationRules() {
+ return Lists.newArrayList();
+ }
+
+ public List<Rule> getImplementationRules() {
+ return Lists.newArrayList();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
new file mode 100644
index 0000000000..8de67fe29d
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
@@ -0,0 +1,42 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules;
+
+/**
+ * Type of rules, each rule has its unique type.
+ */
+public enum RuleType {
+ // binding rules
+ BINDING_UNBOUND_RELATION_RULE,
+
+ // rewrite rules
+ COLUMN_PRUNE_PROJECTION,
+
+ // exploration rules
+
+ // implementation rules
+ LOGICAL_JOIN_TO_HASH_JOIN_RULE,
+
+ // sentinel, use to count rules
+ SENTINEL,
+ ;
+
+ public int type() {
+ return ordinal();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisRule.java
new file mode 100644
index 0000000000..c28a00ec86
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisRule.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.analysis;
+
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RulePromise;
+import org.apache.doris.nereids.rules.RuleType;
+
+/**
+ * Abstract class for all rules used in analysis stage.
+ */
+public abstract class AnalysisRule extends Rule {
+ public AnalysisRule(RuleType ruleType, Pattern pattern) {
+ super(ruleType, pattern, RulePromise.ANALYSIS);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisUnboundRelationRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisUnboundRelationRule.java
new file mode 100644
index 0000000000..329d43db02
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/AnalysisUnboundRelationRule.java
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.analysis;
+
+import org.apache.doris.catalog.Catalog;
+import org.apache.doris.catalog.Database;
+import org.apache.doris.catalog.Table;
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.analyzer.UnboundRelation;
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalRelation;
+
+import com.alibaba.google.common.collect.ImmutableList;
+import com.alibaba.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Rule to bind relations in query plan.
+ */
+public class AnalysisUnboundRelationRule extends AnalysisRule {
+ public AnalysisUnboundRelationRule() {
+ super(RuleType.BINDING_UNBOUND_RELATION_RULE, new Pattern(NodeType.LOGICAL_UNBOUND_RELATION));
+ }
+
+ @Override
+ public List<Plan<?>> transform(Plan<?> plan, PlannerContext context) throws AnalysisException {
+ UnboundRelation unboundRelation = (UnboundRelation) plan;
+ List<String> nameParts = unboundRelation.getNameParts();
+ switch (nameParts.size()) {
+ case 1: {
+ List<String> qualifier = Lists.newArrayList(
+ context.getConnectContext().getDatabase(), nameParts.get(0));
+ Table table = getTable(qualifier, context.getConnectContext().getCatalog());
+ return ImmutableList.of(new LogicalRelation(table, qualifier));
+ }
+ case 2: {
+ Table table = getTable(nameParts, context.getConnectContext().getCatalog());
+ return ImmutableList.of(new LogicalRelation(table, nameParts));
+ }
+ default:
+ throw new AnalysisException("Table name [" + unboundRelation.getTableName() + "] is invalid.");
+ }
+ }
+
+ private Table getTable(List<String> qualifier, Catalog catalog) {
+ String dbName = qualifier.get(0);
+ Database db = catalog.getDb(dbName)
+ .orElseThrow(() -> new RuntimeException("Database [" + dbName + "] does not exist."));
+ db.readLock();
+ try {
+ String tableName = qualifier.get(1);
+ return db.getTable(tableName).orElseThrow(() -> new RuntimeException(
+ "Table [" + tableName + "] does not exist in database [" + dbName + "]."));
+ } finally {
+ db.readUnlock();
+ }
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/ExplorationRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/ExplorationRule.java
new file mode 100644
index 0000000000..4f47d12f47
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/ExplorationRule.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.exploration;
+
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RulePromise;
+import org.apache.doris.nereids.rules.RuleType;
+
+/**
+ * Abstract class for all exploration rules.
+ */
+public abstract class ExplorationRule extends Rule {
+ public ExplorationRule(RuleType ruleType, Pattern pattern) {
+ super(ruleType, pattern, RulePromise.EXPLORE);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRule.java
new file mode 100644
index 0000000000..a1de729789
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/ExpressionRule.java
@@ -0,0 +1,33 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.expression;
+
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RulePromise;
+import org.apache.doris.nereids.rules.RuleType;
+
+/**
+ * Abstract class for all expression rules.
+ */
+public abstract class ExpressionRule extends Rule {
+ public ExpressionRule(RuleType ruleType, Pattern pattern) {
+ super(ruleType, pattern, RulePromise.EXPRESSION);
+ }
+
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/ImplementationRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/ImplementationRule.java
new file mode 100644
index 0000000000..3b31f4a792
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/ImplementationRule.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.implementation;
+
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RulePromise;
+import org.apache.doris.nereids.rules.RuleType;
+
+/**
+ * Abstract class for all implementation rules.
+ */
+public abstract class ImplementationRule extends Rule {
+ public ImplementationRule(RuleType ruleType, Pattern pattern) {
+ super(ruleType, pattern, RulePromise.IMPLEMENT);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoinRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoinRule.java
new file mode 100644
index 0000000000..796114ec44
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalJoinToHashJoinRule.java
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.implementation;
+
+import org.apache.doris.nereids.PlannerContext;
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+import org.apache.doris.nereids.trees.plans.physical.PhysicalBroadcastHashJoin;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Implementation rule that convert logical join to physical hash join.
+ */
+public class LogicalJoinToHashJoinRule extends ImplementationRule {
+ /**
+ * Constructor for LogicalJoinToHashJoinRule.
+ */
+ public LogicalJoinToHashJoinRule() {
+ super(RuleType.LOGICAL_JOIN_TO_HASH_JOIN_RULE,
+ new Pattern(NodeType.LOGICAL_JOIN,
+ Pattern.PATTERN_LEAF_INSTANCE,
+ Pattern.PATTERN_LEAF_INSTANCE));
+ }
+
+ @Override
+ public List<Plan<?>> transform(Plan<?> plan, PlannerContext context) {
+ LogicalJoin originPlan = (LogicalJoin) plan;
+ PhysicalBroadcastHashJoin physicalBroadcastHashJoin = new PhysicalBroadcastHashJoin(
+ originPlan.getJoinType(),
+ originPlan.getOnClause());
+ return Lists.newArrayList(physicalBroadcastHashJoin);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/RewriteRule.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/RewriteRule.java
new file mode 100644
index 0000000000..0106a22971
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/RewriteRule.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.rules.rewrite;
+
+import org.apache.doris.nereids.pattern.Pattern;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RulePromise;
+import org.apache.doris.nereids.rules.RuleType;
+
+/**
+ * Abstract class for all rewrite rules.
+ */
+public abstract class RewriteRule extends Rule {
+ public RewriteRule(RuleType ruleType, Pattern pattern) {
+ super(ruleType, pattern, RulePromise.REWRITE);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/NodeType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/NodeType.java
new file mode 100644
index 0000000000..ee6ca56f0e
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/NodeType.java
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees;
+
+/**
+ * Types for all TreeNode in Nereids, include Plan and Expression.
+ */
+public enum NodeType {
+ // logical plan
+ LOGICAL,
+ LOGICAL_UNBOUND_RELATION,
+ LOGICAL_BOUND_RELATION,
+ LOGICAL_PROJECT,
+ LOGICAL_FILTER,
+ LOGICAL_JOIN,
+
+ // physical plan
+ PHYSICAL,
+ PHYSICAL_OLAP_SCAN,
+ PHYSICAL_PROJECT,
+ PHYSICAL_FILTER,
+ PHYSICAL_BROADCAST_HASH_JOIN,
+
+ // expressions
+ EXPRESSION,
+ UNBOUND_ALIAS,
+ UNBOUND_SLOT,
+ UNBOUND_STAR,
+ LITERAL,
+ SLOT_REFERENCE,
+ BINARY_PREDICATE,
+ ALIAS,
+
+ // pattern
+ PATTERN,
+ PATTERN_LEAF,
+ PATTERN_MULTI_LEAF,
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
new file mode 100644
index 0000000000..9ffa6b2c24
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java
@@ -0,0 +1,66 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees;
+
+import com.google.common.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Abstract class for all node in Nereids, include plan node and expression.
+ *
+ * @param <NodeType> either {@link org.apache.doris.nereids.trees.plans.Plan}
+ * or {@link org.apache.doris.nereids.trees.expressions.Expression}
+ */
+public abstract class TreeNode<NodeType extends TreeNode<NodeType>> {
+ protected final org.apache.doris.nereids.trees.NodeType type;
+ protected List<NodeType> children = Lists.newArrayList();
+
+ public TreeNode(org.apache.doris.nereids.trees.NodeType type) {
+ this.type = type;
+ }
+
+ public NodeType getChild(int i) {
+ return children.get(i);
+ }
+
+ public void addChild(NodeType child) {
+ children.add(child);
+ }
+
+ public List<NodeType> getChildren() {
+ return children;
+ }
+
+ public int arity() {
+ return children.size();
+ }
+
+ public void replaceChild(int index, NodeType child) {
+ children.remove(index);
+ children.add(index, child);
+ }
+
+ public void removeAllChildren() {
+ children.clear();
+ }
+
+ public void setChildren(List<NodeType> children) {
+ this.children = children;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java
new file mode 100644
index 0000000000..3fdd644b10
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java
@@ -0,0 +1,82 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions;
+
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+
+import com.clearspring.analytics.util.Lists;
+
+import java.util.List;
+
+/**
+ * Expression for alias, such as col1 as c1.
+ */
+public class Alias extends NamedExpression {
+ private final ExprId exprId;
+ private final String name;
+ private final List<String> qualifier;
+
+ /**
+ * constructor of Alias.
+ *
+ * @param child expression that alias represents for
+ * @param name alias name
+ */
+ public Alias(Expression child, String name) {
+ super(NodeType.ALIAS);
+ exprId = NamedExpression.newExprId();
+ this.name = name;
+ qualifier = Lists.newArrayList();
+ addChild(child);
+ }
+
+ public Expression child() {
+ return getChild(0);
+ }
+
+ @Override
+ public String getName() throws UnboundException {
+ return name;
+ }
+
+ @Override
+ public ExprId getExprId() throws UnboundException {
+ return exprId;
+ }
+
+ @Override
+ public List<String> getQualifier() {
+ return qualifier;
+ }
+
+ @Override
+ public Slot toAttribute() throws UnboundException {
+ return new SlotReference(exprId, name, child().getDataType(), child().nullable(), qualifier);
+ }
+
+ @Override
+ public String sql() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return child().toString() + " AS " + name;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryPredicate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryPredicate.java
new file mode 100644
index 0000000000..5c7bd69255
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/BinaryPredicate.java
@@ -0,0 +1,127 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions;
+
+import org.apache.doris.common.AnalysisException;
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DataType;
+
+/**
+ * Binary predicate expression.
+ */
+public class BinaryPredicate extends Expression {
+ private final Operator operator;
+
+ /**
+ * Operator for binary predicate.
+ */
+ public enum Operator {
+ EQ("="),
+ NSEQ("<=>"),
+ LT("<"),
+ GT(">"),
+ LE("<="),
+ GE(">="),
+ ;
+
+ private final String operand;
+
+ Operator(String operand) {
+ this.operand = operand;
+ }
+
+ /**
+ * Translate expression op in Nereids to legacy one in Doris.
+ *
+ * @param operator expression operator in Nereids
+ * @return legacy expression operator in Doris
+ * @throws AnalysisException throw exception when operator cannot be recognized
+ */
+ public static org.apache.doris.analysis.BinaryPredicate.Operator toExprOp(Operator operator)
+ throws AnalysisException {
+ switch (operator) {
+ case EQ:
+ return org.apache.doris.analysis.BinaryPredicate.Operator.EQ;
+ case GE:
+ return org.apache.doris.analysis.BinaryPredicate.Operator.GE;
+ case GT:
+ return org.apache.doris.analysis.BinaryPredicate.Operator.GT;
+ case LE:
+ return org.apache.doris.analysis.BinaryPredicate.Operator.LE;
+ case LT:
+ return org.apache.doris.analysis.BinaryPredicate.Operator.LT;
+ case NSEQ:
+ return org.apache.doris.analysis.BinaryPredicate.Operator.EQ_FOR_NULL;
+ default:
+ throw new AnalysisException("Not support operator: " + operator.name());
+ }
+ }
+ }
+
+ /**
+ * Constructor of BinaryPredicate.
+ *
+ * @param left left child of binary predicate
+ * @param right right child of binary predicate
+ * @param operator operator of binary predicate
+ */
+ public BinaryPredicate(Expression left, Expression right, Operator operator) {
+ super(NodeType.BINARY_PREDICATE);
+ this.operator = operator;
+ addChild(left);
+ addChild(right);
+ }
+
+ public Expression left() {
+ return getChild(0);
+ }
+
+ public Expression right() {
+ return getChild(1);
+ }
+
+ public Operator getOperator() {
+ return operator;
+ }
+
+ @Override
+ public boolean nullable() throws UnboundException {
+ if (operator == Operator.NSEQ) {
+ return false;
+ } else {
+ return left().nullable() || right().nullable();
+ }
+ }
+
+ @Override
+ public DataType getDataType() throws UnboundException {
+ return BooleanType.INSTANCE;
+ }
+
+ @Override
+ public String sql() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + left() + " " + operator.operand + " " + right() + ")";
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExprId.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExprId.java
new file mode 100644
index 0000000000..9be4db50b9
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/ExprId.java
@@ -0,0 +1,60 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions;
+
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * UUID for Expression in Nereids.
+ */
+public class ExprId {
+ private final long id;
+ private final UUID jvmId;
+
+ public ExprId(long id, UUID jvmId) {
+ this.id = id;
+ this.jvmId = jvmId;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ExprId exprId = (ExprId) o;
+ return id == exprId.id && jvmId.equals(exprId.jvmId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, jvmId);
+ }
+
+ @Override
+ public String toString() {
+ return "" + id;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
new file mode 100644
index 0000000000..8edad09673
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions;
+
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.TreeNode;
+import org.apache.doris.nereids.types.DataType;
+
+/**
+ * Abstract class for all Expression in Nereids.
+ */
+public abstract class Expression extends TreeNode<Expression> {
+ public Expression(NodeType type) {
+ super(type);
+ }
+
+ public DataType getDataType() throws UnboundException {
+ throw new UnboundException("dataType");
+ }
+
+ public String sql() throws UnboundException {
+ throw new UnboundException("sql");
+ }
+
+ public boolean nullable() throws UnboundException {
+ throw new UnboundException("nullable");
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Literal.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Literal.java
new file mode 100644
index 0000000000..187127caf5
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Literal.java
@@ -0,0 +1,103 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions;
+
+import org.apache.doris.analysis.Expr;
+import org.apache.doris.analysis.IntLiteral;
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.types.BooleanType;
+import org.apache.doris.nereids.types.DataType;
+import org.apache.doris.nereids.types.IntegerType;
+import org.apache.doris.nereids.types.NullType;
+import org.apache.doris.nereids.types.StringType;
+
+/**
+ * All data type literal expression in Nereids.
+ */
+public class Literal extends Expression {
+ private final DataType dataType;
+ private final Object value;
+
+ /**
+ * Constructor for Literal.
+ *
+ * @param value real value stored in java object
+ * @param dataType logical data type in Nereids
+ */
+ public Literal(Object value, DataType dataType) {
+ super(NodeType.LITERAL);
+ this.dataType = dataType;
+ this.value = value;
+ }
+
+ /**
+ * Constructor for Literal. Recognize data type Automatically.
+ *
+ * @param value real value stored in java object
+ */
+ public Literal(Object value) {
+ super(NodeType.LITERAL);
+ this.value = value;
+ if (value == null) {
+ dataType = NullType.INSTANCE;
+ } else if (value instanceof Integer) {
+ dataType = IntegerType.INSTANCE;
+ } else if (value instanceof Boolean) {
+ dataType = BooleanType.INSTANCE;
+ } else if (value instanceof String) {
+ dataType = StringType.INSTANCE;
+ } else {
+ throw new RuntimeException();
+ }
+ }
+
+
+ /**
+ * Convert to legacy literal expression in Doris.
+ *
+ * @return legacy literal expression in Doris
+ */
+ public Expr toExpr() {
+ if (dataType instanceof IntegerType) {
+ return new IntLiteral((Integer) value);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public DataType getDataType() throws UnboundException {
+ return dataType;
+ }
+
+ @Override
+ public boolean nullable() throws UnboundException {
+ return value == null;
+ }
+
+ @Override
+ public String sql() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return value.toString();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java
new file mode 100644
index 0000000000..bbcc6b0d3c
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java
@@ -0,0 +1,73 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions;
+
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+
+import org.apache.commons.collections.CollectionUtils;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Expression in Nereids that having name.
+ */
+public abstract class NamedExpression extends Expression {
+ private static final AtomicLong CURRENT_ID = new AtomicLong();
+ private static final UUID JVM_ID = UUID.randomUUID();
+
+ public NamedExpression(NodeType type) {
+ super(type);
+ }
+
+ public static ExprId newExprId() {
+ return new ExprId(CURRENT_ID.getAndIncrement(), JVM_ID);
+ }
+
+ public Slot toAttribute() throws UnboundException {
+ throw new UnboundException("toAttribute");
+ }
+
+ public String getName() throws UnboundException {
+ throw new UnboundException("name");
+ }
+
+ public ExprId getExprId() throws UnboundException {
+ throw new UnboundException("exprId");
+ }
+
+ public List<String> getQualifier() throws UnboundException {
+ throw new UnboundException("qualifier");
+ }
+
+ /**
+ * Get qualified name of NamedExpression.
+ *
+ * @return qualified name
+ * @throws UnboundException throw this exception if this expression is unbound
+ */
+ public String getQualifiedName() throws UnboundException {
+ String qualifiedName = "";
+ if (CollectionUtils.isNotEmpty(getQualifier())) {
+ qualifiedName = String.join(".", getQualifier()) + ".";
+ }
+ return qualifiedName + getName();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
new file mode 100644
index 0000000000..8102361d29
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Slot.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions;
+
+import org.apache.doris.nereids.trees.NodeType;
+
+/**
+ * Abstract class for all slot in expression.
+ */
+public abstract class Slot extends NamedExpression {
+ public Slot(NodeType type) {
+ super(type);
+ }
+
+ @Override
+ public Slot toAttribute() {
+ return this;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java
new file mode 100644
index 0000000000..97329a50a1
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java
@@ -0,0 +1,126 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.expressions;
+
+import org.apache.doris.catalog.Column;
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.types.DataType;
+
+import org.apache.commons.lang.StringUtils;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Reference to slot in expression.
+ */
+public class SlotReference extends Slot {
+ private final ExprId exprId;
+ private final String name;
+ private final List<String> qualifier;
+ private final DataType dataType;
+ private final boolean nullable;
+
+ public SlotReference(String name, DataType dataType, boolean nullable, List<String> qualifier) {
+ this(NamedExpression.newExprId(), name, dataType, nullable, qualifier);
+ }
+
+ /**
+ * Constructor for SlotReference.
+ *
+ * @param exprId UUID for this slot reference
+ * @param name slot reference name
+ * @param dataType slot reference logical data type
+ * @param nullable true if nullable
+ * @param qualifier slot reference qualifier
+ */
+ public SlotReference(ExprId exprId, String name, DataType dataType, boolean nullable, List<String> qualifier) {
+ super(NodeType.SLOT_REFERENCE);
+ this.exprId = exprId;
+ this.name = name;
+ this.dataType = dataType;
+ this.qualifier = qualifier;
+ this.nullable = nullable;
+ }
+
+ public static SlotReference fromColumn(Column column, List<String> qualifier) {
+ DataType dataType = DataType.convertFromCatalogDataType(column.getType());
+ return new SlotReference(column.getName(), dataType, column.isAllowNull(), qualifier);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public ExprId getExprId() {
+ return exprId;
+ }
+
+ @Override
+ public List<String> getQualifier() {
+ return qualifier;
+ }
+
+ @Override
+ public DataType getDataType() throws UnboundException {
+ return dataType;
+ }
+
+ @Override
+ public boolean nullable() throws UnboundException {
+ return nullable;
+ }
+
+ @Override
+ public String sql() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ String uniqueName = name + "#" + exprId;
+ if (qualifier.isEmpty()) {
+ return uniqueName;
+ } else {
+ return StringUtils.join(qualifier, ".") + "." + uniqueName;
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SlotReference that = (SlotReference) o;
+ return nullable == that.nullable
+ && exprId.equals(that.exprId)
+ && name.equals(that.name)
+ && qualifier.equals(that.qualifier);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(exprId, name, qualifier, nullable);
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/JoinType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/JoinType.java
new file mode 100644
index 0000000000..858715d2c5
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/JoinType.java
@@ -0,0 +1,69 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans;
+
+import org.apache.doris.analysis.JoinOperator;
+import org.apache.doris.common.AnalysisException;
+
+/**
+ * All job type in Nereids.
+ */
+public enum JoinType {
+ INNER_JOIN,
+ LEFT_OUTER_JOIN,
+ RIGHT_OUTER_JOIN,
+ FULL_OUTER_JOIN,
+ LEFT_SEMI_JOIN,
+ RIGHT_SEMI_JOIN,
+ LEFT_ANTI_JOIN,
+ RIGHT_ANTI_JOIN,
+ CROSS_JOIN,
+ ;
+
+ /**
+ * Convert join type in Nereids to legacy join type in Doris.
+ *
+ * @param joinType join type in Nereids
+ * @return legacy join type in Doris
+ * @throws AnalysisException throw this exception when input join type cannot convert to legacy join type in Doris
+ */
+ public static JoinOperator toJoinOperator(JoinType joinType) throws AnalysisException {
+ switch (joinType) {
+ case INNER_JOIN:
+ return JoinOperator.INNER_JOIN;
+ case LEFT_OUTER_JOIN:
+ return JoinOperator.LEFT_OUTER_JOIN;
+ case RIGHT_OUTER_JOIN:
+ return JoinOperator.RIGHT_OUTER_JOIN;
+ case FULL_OUTER_JOIN:
+ return JoinOperator.FULL_OUTER_JOIN;
+ case LEFT_ANTI_JOIN:
+ return JoinOperator.LEFT_ANTI_JOIN;
+ case RIGHT_ANTI_JOIN:
+ return JoinOperator.RIGHT_ANTI_JOIN;
+ case LEFT_SEMI_JOIN:
+ return JoinOperator.LEFT_SEMI_JOIN;
+ case RIGHT_SEMI_JOIN:
+ return JoinOperator.RIGHT_SEMI_JOIN;
+ case CROSS_JOIN:
+ return JoinOperator.CROSS_JOIN;
+ default:
+ throw new AnalysisException("Not support join operator: " + joinType.name());
+ }
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
new file mode 100644
index 0000000000..e458226f73
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java
@@ -0,0 +1,105 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans;
+
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.memo.PlanReference;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.TreeNode;
+import org.apache.doris.nereids.trees.expressions.Slot;
+
+import com.alibaba.google.common.collect.Lists;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Abstract class for all plan node.
+ *
+ * @param <PlanType> either {@link org.apache.doris.nereids.trees.plans.logical.LogicalPlan}
+ * or {@link org.apache.doris.nereids.trees.plans.physical.PhysicalPlan}
+ */
+public abstract class Plan<PlanType extends Plan<PlanType>> extends TreeNode<PlanType> {
+
+ protected final boolean isPhysical;
+ protected PlanReference planReference;
+ protected List<Slot> output = Lists.newArrayList();
+
+ public Plan(NodeType type, boolean isPhysical) {
+ super(type);
+ this.isPhysical = isPhysical;
+ }
+
+ public org.apache.doris.nereids.trees.NodeType getType() {
+ return type;
+ }
+
+ public boolean isPhysical() {
+ return isPhysical;
+ }
+
+ public boolean isLogical() {
+ return !isPhysical;
+ }
+
+ public abstract List<Slot> getOutput() throws UnboundException;
+
+ public PlanReference getPlanReference() {
+ return planReference;
+ }
+
+ public void setPlanReference(PlanReference planReference) {
+ this.planReference = planReference;
+ }
+
+ /**
+ * Get tree like string describing query plan.
+ *
+ * @return tree like string describing query plan
+ */
+ public String treeString() {
+ List<String> lines = new ArrayList<>();
+ treeString(lines, 0, new ArrayList<>(), this);
+ return StringUtils.join(lines, "\n");
+ }
+
+ private void treeString(List<String> lines, int depth, List<Boolean> lastChildren, Plan<PlanType> plan) {
+ StringBuilder sb = new StringBuilder();
+ if (depth > 0) {
+ if (lastChildren.size() > 1) {
+ for (int i = 0; i < lastChildren.size() - 1; i++) {
+ sb.append(lastChildren.get(i) ? " " : "| ");
+ }
+ }
+ if (lastChildren.size() > 0) {
+ Boolean last = lastChildren.get(lastChildren.size() - 1);
+ sb.append(last ? "+--" : "|--");
+ }
+ }
+ sb.append(plan.toString());
+ lines.add(sb.toString());
+
+ List<PlanType> children = plan.getChildren();
+ for (int i = 0; i < children.size(); i++) {
+ List<Boolean> newLasts = new ArrayList<>(lastChildren);
+ newLasts.add(i + 1 == children.size());
+ treeString(lines, depth + 1, newLasts, children.get(i));
+ }
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java
new file mode 100644
index 0000000000..d266a6188f
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalBinary.java
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.logical;
+
+import org.apache.doris.nereids.trees.NodeType;
+
+/**
+ * Abstract class for all {@link LogicalPlan} that have two children.
+ */
+public abstract class LogicalBinary extends LogicalPlan {
+
+ /**
+ * Constructor for LogicalBinary.
+ *
+ * @param type type for this plan.
+ * @param left left child for LogicalBinary
+ * @param right right child for LogicalBinary
+ */
+ public LogicalBinary(NodeType type, LogicalPlan left, LogicalPlan right) {
+ super(type);
+ addChild(left);
+ addChild(right);
+ }
+
+ public LogicalPlan left() {
+ return getChild(0);
+ }
+
+ public LogicalPlan right() {
+ return getChild(1);
+ }
+
+ @Override
+ public int arity() {
+ return 2;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
new file mode 100644
index 0000000000..e0f467f415
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java
@@ -0,0 +1,57 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.logical;
+
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Slot;
+
+import java.util.List;
+
+/**
+ * Logical filter plan node.
+ */
+public class LogicalFilter extends LogicalUnary {
+ private final Expression predicates;
+
+ public LogicalFilter(Expression predicates, LogicalPlan child) {
+ super(NodeType.LOGICAL_FILTER, child);
+ this.predicates = predicates;
+ }
+
+ public Expression getPredicates() {
+ return predicates;
+ }
+
+ @Override
+ public List<Slot> getOutput() throws UnboundException {
+ return output;
+ }
+
+ @Override
+ public String toString() {
+ String cond;
+ if (predicates == null) {
+ cond = "<null>";
+ } else {
+ cond = predicates.toString();
+ }
+ return "Filter (" + cond + ")";
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
new file mode 100644
index 0000000000..a5346485dd
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java
@@ -0,0 +1,90 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.logical;
+
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.JoinType;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+/**
+ * Logical join plan node.
+ */
+public class LogicalJoin extends LogicalBinary {
+ private final JoinType joinType;
+ private final Expression onClause;
+
+ /**
+ * Constructor for LogicalJoinPlan.
+ *
+ * @param joinType logical type for join
+ * @param onClause on clause for join node
+ * @param left left child of join node
+ * @param right right child of join node
+ */
+ public LogicalJoin(JoinType joinType, Expression onClause, LogicalPlan left, LogicalPlan right) {
+ super(NodeType.LOGICAL_JOIN, left, right);
+ this.joinType = joinType;
+ this.onClause = onClause;
+ }
+
+ public Expression getOnClause() {
+ return onClause;
+ }
+
+ public JoinType getJoinType() {
+ return joinType;
+ }
+
+ @Override
+ public List<Slot> getOutput() throws UnboundException {
+ if (CollectionUtils.isEmpty(output)) {
+ switch (joinType) {
+ case LEFT_SEMI_JOIN:
+ output.addAll(left().getOutput());
+ break;
+ case RIGHT_SEMI_JOIN:
+ output.addAll(right().getOutput());
+ break;
+ default:
+ output.addAll(left().getOutput());
+ output.addAll(right().getOutput());
+ break;
+ }
+ }
+ return output;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Join (").append(joinType);
+ if (onClause != null) {
+ sb.append(", ").append(onClause);
+ }
+ if (CollectionUtils.isNotEmpty(output)) {
+ sb.append(", output: ").append(StringUtils.join(output, ", "));
+ }
+ return sb.append(")").toString();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
new file mode 100644
index 0000000000..93c1227eb5
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalLeaf.java
@@ -0,0 +1,34 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.logical;
+
+import org.apache.doris.nereids.trees.NodeType;
+
+/**
+ * Abstract class for all plan node that have no child.
+ */
+public abstract class LogicalLeaf extends LogicalPlan {
+ public LogicalLeaf(NodeType type) {
+ super(type);
+ }
+
+ @Override
+ public int arity() {
+ return 0;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java
new file mode 100644
index 0000000000..1434808607
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalPlan.java
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.logical;
+
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.plans.Plan;
+
+import java.util.function.BiFunction;
+
+/**
+ * Abstract class for all logical plan in Nereids.
+ */
+public abstract class LogicalPlan extends Plan<LogicalPlan> {
+ public LogicalPlan(NodeType type) {
+ super(type, false);
+ }
+
+ /**
+ * Map a [[LogicalPlan]] to another [[LogicalPlan]] if the passed context exists using the
+ * passed function. The original plan is returned when the context does not exist.
+ */
+ public <C> LogicalPlan optionalMap(C ctx, BiFunction<C, LogicalPlan, LogicalPlan> f) {
+ if (ctx != null) {
+ return f.apply(ctx, this);
+ } else {
+ return this;
+ }
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
new file mode 100644
index 0000000000..4afa96ba70
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalProject.java
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.logical;
+
+import org.apache.doris.nereids.exceptions.UnboundException;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.Slot;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+/**
+ * Logical project plan node.
+ */
+public class LogicalProject extends LogicalUnary {
+ private final List<? extends NamedExpression> projects;
+
+ /**
+ * Constructor for LogicalProjectPlan.
+ *
+ * @param projects project list
+ * @param child child plan node
+ */
+ public LogicalProject(List<? extends NamedExpression> projects, LogicalPlan child) {
+ super(NodeType.LOGICAL_PROJECT, child);
+ this.projects = projects;
+ updateOutput();
+ }
+
+ /**
+ * Get project list.
+ *
+ * @return all project of this node.
+ */
+ public List<? extends NamedExpression> getProjects() {
+ return projects;
+ }
+
+ @Override
+ public List<Slot> getOutput() {
+ return output;
+ }
+
+ private void updateOutput() {
+ output = Lists.newArrayListWithCapacity(projects.size());
+ for (NamedExpression projection : projects) {
+ try {
+ output.add(projection.toAttribute());
+ } catch (UnboundException e) {
+ output.clear();
+ break;
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Project (" + StringUtils.join(projects, ", ") + ")";
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
new file mode 100644
index 0000000000..135ba10ef5
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalRelation.java
@@ -0,0 +1,72 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.logical;
+
+import org.apache.doris.catalog.Table;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Logical relation plan node.
+ */
+public class LogicalRelation extends LogicalLeaf {
+ private final Table table;
+ private final List<String> qualifier;
+
+ /**
+ * Constructor for LogicalRelationPlan.
+ *
+ * @param table Doris table
+ * @param qualifier qualified relation name
+ */
+ public LogicalRelation(Table table, List<String> qualifier) {
+ super(NodeType.LOGICAL_BOUND_RELATION);
+ this.table = table;
+ this.qualifier = qualifier;
+ this.output = table.getBaseSchema()
+ .stream()
+ .map(col -> SlotReference.fromColumn(col, qualifier))
+ .collect(Collectors.toList());
+ }
+
+ public Table getTable() {
+ return table;
+ }
+
+ public List<String> getQualifier() {
+ return qualifier;
+ }
+
+ @Override
+ public List<Slot> getOutput() {
+ return output;
+ }
+
+ @Override
+ public String toString() {
+ return "Relation(" + StringUtils.join(qualifier, ".") + "." + table.getName()
+ + ", output: " + StringUtils.join(output, ", ")
+ + ")";
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
new file mode 100644
index 0000000000..fec54ab5f5
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUnary.java
@@ -0,0 +1,39 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.logical;
+
+import org.apache.doris.nereids.trees.NodeType;
+
+/**
+ * Abstract class for all logical plan that have on child.
+ */
+public abstract class LogicalUnary extends LogicalPlan {
+ public LogicalUnary(NodeType type, LogicalPlan child) {
+ super(type);
+ addChild(child);
+ }
+
+ public LogicalPlan child() {
+ return getChild(0);
+ }
+
+ @Override
+ public int arity() {
+ return 1;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBroadcastHashJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBroadcastHashJoin.java
new file mode 100644
index 0000000000..e26102c842
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBroadcastHashJoin.java
@@ -0,0 +1,66 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.physical;
+
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.plans.JoinType;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Optional;
+
+/**
+ * Physical node represents broadcast hash join.
+ */
+public class PhysicalBroadcastHashJoin extends PhysicalPlan {
+ private final JoinType joinType;
+ private final Expression onClause;
+
+ /**
+ * Constructor for PhysicalBroadcastHashJoin.
+ *
+ * @param joinType logical join type in Nereids
+ * @param onClause on clause expression
+ */
+ public PhysicalBroadcastHashJoin(JoinType joinType, Expression onClause) {
+ super(NodeType.PHYSICAL_BROADCAST_HASH_JOIN);
+ this.joinType = joinType;
+ this.onClause = onClause;
+ }
+
+ public JoinType getJoinType() {
+ return joinType;
+ }
+
+ public Optional<Expression> getOnClause() {
+ return Optional.ofNullable(onClause);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("Broadcast Hash Join (").append(joinType);
+ if (onClause != null) {
+ sb.append(", ").append(onClause);
+ }
+ if (logicalProperties != null && !logicalProperties.getOutput().isEmpty()) {
+ sb.append(", output: ").append(StringUtils.join(logicalProperties.getOutput(), ", "));
+ }
+ return sb.append(")").toString();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
new file mode 100644
index 0000000000..454c105b1d
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalFilter.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.physical;
+
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.Expression;
+
+/**
+ * Physical filter plan node.
+ */
+public class PhysicalFilter extends PhysicalPlan {
+ private final Expression predicates;
+
+ public PhysicalFilter(Expression predicates) {
+ super(NodeType.PHYSICAL_FILTER);
+ this.predicates = predicates;
+ }
+
+ public Expression getPredicates() {
+ return predicates;
+ }
+
+ @Override
+ public String toString() {
+ String cond;
+ if (predicates == null) {
+ cond = "<null>";
+ } else {
+ cond = predicates.toString();
+ }
+ return "Filter (" + cond + ")";
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
new file mode 100644
index 0000000000..6a133f117c
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java
@@ -0,0 +1,74 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.physical;
+
+import org.apache.doris.catalog.OlapTable;
+import org.apache.doris.catalog.Partition;
+import org.apache.doris.nereids.trees.NodeType;
+
+import com.clearspring.analytics.util.Lists;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+/**
+ * Physical olap scan plan node.
+ */
+public class PhysicalOlapScan extends PhysicalScan {
+ private final long selectedIndexId;
+ private final List<Long> selectedTabletId;
+ private final List<Long> selectedPartitionId;
+
+ /**
+ * Constructor for PhysicalOlapScan.
+ *
+ * @param olapTable OlapTable in Doris
+ * @param qualifier table's name
+ */
+ public PhysicalOlapScan(OlapTable olapTable, List<String> qualifier) {
+ super(NodeType.PHYSICAL_OLAP_SCAN, olapTable, qualifier);
+ this.selectedIndexId = olapTable.getBaseIndexId();
+ this.selectedTabletId = Lists.newArrayList();
+ this.selectedPartitionId = olapTable.getPartitionIds();
+ for (Partition partition : olapTable.getAllPartitions()) {
+ selectedTabletId.addAll(partition.getBaseIndex().getTabletIdsInOrder());
+ }
+ }
+
+ public long getSelectedIndexId() {
+ return selectedIndexId;
+ }
+
+ public List<Long> getSelectedTabletId() {
+ return selectedTabletId;
+ }
+
+ public List<Long> getSelectedPartitionId() {
+ return selectedPartitionId;
+ }
+
+ @Override
+ public String toString() {
+ return "Scan Olap Table " + StringUtils.join(qualifier, ".") + "." + table.getName()
+ + " (output: " + logicalProperties.getOutput()
+ + ", selected index id: " + selectedTabletId
+ + ", selected partition ids: " + selectedPartitionId
+ + ", selected tablet ids: " + selectedTabletId
+ + ")";
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java
new file mode 100644
index 0000000000..e3cf733850
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalPlan.java
@@ -0,0 +1,47 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.physical;
+
+import org.apache.doris.nereids.properties.LogicalProperties;
+import org.apache.doris.nereids.properties.PhysicalProperties;
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.Plan;
+
+import java.util.List;
+
+/**
+ * Abstract class for all physical plan node.
+ */
+public abstract class PhysicalPlan extends Plan<PhysicalPlan> {
+ protected LogicalProperties logicalProperties;
+ protected PhysicalProperties physicalProperties;
+
+ public PhysicalPlan(NodeType type) {
+ super(type, true);
+ }
+
+ public void setLogicalProperties(LogicalProperties logicalProperties) {
+ this.logicalProperties = logicalProperties;
+ }
+
+ @Override
+ public List<Slot> getOutput() {
+ return logicalProperties.getOutput();
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
new file mode 100644
index 0000000000..79438ac946
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalProject.java
@@ -0,0 +1,46 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.physical;
+
+import org.apache.doris.nereids.trees.NodeType;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+/**
+ * Physical project plan node.
+ */
+public class PhysicalProject extends PhysicalPlan {
+ private final List<? extends NamedExpression> projects;
+
+ public PhysicalProject(List<? extends NamedExpression> projects) {
+ super(NodeType.PHYSICAL_PROJECT);
+ this.projects = projects;
+ }
+
+ public List<? extends NamedExpression> getProjects() {
+ return projects;
+ }
+
+ @Override
+ public String toString() {
+ return "Project (" + StringUtils.join(projects, ", ") + ")";
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalScan.java
new file mode 100644
index 0000000000..5d8430d773
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalScan.java
@@ -0,0 +1,48 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.trees.plans.physical;
+
+import org.apache.doris.catalog.Table;
+import org.apache.doris.nereids.trees.NodeType;
+
+import java.util.List;
+
+/**
+ * Abstract class for all physical scan node.
+ */
+public abstract class PhysicalScan extends PhysicalPlan {
+ protected final Table table;
+ protected final List<String> qualifier;
+
+ /**
+ * Constructor for PhysicalScan.
+ *
+ * @param type node type
+ * @param table scan table
+ * @param qualifier table's name
+ */
+ public PhysicalScan(NodeType type, Table table, List<String> qualifier) {
+ super(type);
+ this.table = table;
+ this.qualifier = qualifier;
+ }
+
+ public Table getTable() {
+ return table;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/BooleanType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/BooleanType.java
new file mode 100644
index 0000000000..9c1e5f566c
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/BooleanType.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+import org.apache.doris.catalog.Type;
+
+/**
+ * Boolean type in Nereids.
+ */
+public class BooleanType extends DataType {
+ public static BooleanType INSTANCE = new BooleanType();
+
+ @Override
+ public Type toCatalogDataType() {
+ return Type.BOOLEAN;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java
new file mode 100644
index 0000000000..f9d19a26d2
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java
@@ -0,0 +1,64 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+import org.apache.doris.catalog.ArrayType;
+import org.apache.doris.catalog.MapType;
+import org.apache.doris.catalog.MultiRowType;
+import org.apache.doris.catalog.ScalarType;
+import org.apache.doris.catalog.StructType;
+import org.apache.doris.catalog.Type;
+
+/**
+ * Abstract class for all data type in Nereids.
+ */
+public abstract class DataType {
+ /**
+ * Convert data type in Doris catalog to data type in Nereids.
+ *
+ * @param catalogType data type in Doris catalog
+ * @return data type in Nereids
+ */
+ public static DataType convertFromCatalogDataType(Type catalogType) {
+ if (catalogType instanceof ScalarType) {
+ ScalarType scalarType = (ScalarType) catalogType;
+ switch (scalarType.getPrimitiveType()) {
+ case INT:
+ return IntegerType.INSTANCE;
+ case DOUBLE:
+ return DoubleType.INSTANCE;
+ case STRING:
+ return StringType.INSTANCE;
+ default:
+ return null;
+ }
+ } else if (catalogType instanceof MapType) {
+ return null;
+ } else if (catalogType instanceof StructType) {
+ return null;
+ } else if (catalogType instanceof ArrayType) {
+ return null;
+ } else if (catalogType instanceof MultiRowType) {
+ return null;
+ } else {
+ return null;
+ }
+ }
+
+ public abstract Type toCatalogDataType();
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DoubleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DoubleType.java
new file mode 100644
index 0000000000..fc69063abe
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DoubleType.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+import org.apache.doris.catalog.Type;
+
+/**
+ * Double data type in Nereids.
+ */
+public class DoubleType extends FractionalType {
+ public static IntegerType INSTANCE = new IntegerType();
+
+ @Override
+ public Type toCatalogDataType() {
+ return Type.DOUBLE;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/FractionalType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/FractionalType.java
new file mode 100644
index 0000000000..bc6e95b59c
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/FractionalType.java
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+/**
+ * Abstract for all fractional type in Nereids.
+ */
+public abstract class FractionalType extends NumericType {
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/IntegerType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/IntegerType.java
new file mode 100644
index 0000000000..1a95ff7550
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/IntegerType.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+import org.apache.doris.catalog.Type;
+
+/**
+ * Integer data type in Nereids.
+ */
+public class IntegerType extends IntegralType {
+ public static IntegerType INSTANCE = new IntegerType();
+
+ @Override
+ public Type toCatalogDataType() {
+ return Type.INT;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/IntegralType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/IntegralType.java
new file mode 100644
index 0000000000..b3eb5e1e54
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/IntegralType.java
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+/**
+ * Abstract class for all integral data type in Nereids.
+ */
+public abstract class IntegralType extends NumericType {
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/NullType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/NullType.java
new file mode 100644
index 0000000000..6da6be9859
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/NullType.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+import org.apache.doris.catalog.Type;
+
+/**
+ * Null data type in Nereids.
+ */
+public class NullType extends DataType {
+ public static NullType INSTANCE = new NullType();
+
+ @Override
+ public Type toCatalogDataType() {
+ return Type.NULL;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/NumericType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/NumericType.java
new file mode 100644
index 0000000000..8f641e2830
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/NumericType.java
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+/**
+ * Abstract class for all numeric type in Nereids.
+ */
+public abstract class NumericType extends PrimitiveType {
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/PrimitiveType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/PrimitiveType.java
new file mode 100644
index 0000000000..9551053d27
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/PrimitiveType.java
@@ -0,0 +1,24 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+/**
+ * Primitive data type in Nereids.
+ */
+public abstract class PrimitiveType extends DataType {
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StringType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StringType.java
new file mode 100644
index 0000000000..744053acd6
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StringType.java
@@ -0,0 +1,32 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.types;
+
+import org.apache.doris.catalog.Type;
+
+/**
+ * String data type in Nereids.
+ */
+public class StringType extends DataType {
+ public static StringType INSTANCE = new StringType();
+
+ @Override
+ public Type toCatalogDataType() {
+ return Type.STRING;
+ }
+}
diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/Utils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/Utils.java
new file mode 100644
index 0000000000..a01a867593
--- /dev/null
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/Utils.java
@@ -0,0 +1,37 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.nereids.util;
+
+/**
+ * Utils for Nereids.
+ */
+public class Utils {
+ /**
+ * Quoted string if it contains special character or all characters are digit.
+ *
+ * @param part string to be quoted
+ * @return quoted string
+ */
+ public static String quoteIfNeeded(String part) {
+ if (part.matches("[a-zA-Z0-9_]+") && !part.matches("\\d+")) {
+ return part;
+ } else {
+ return part.replace("`", "``");
+ }
+ }
+}
diff --git a/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java b/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java
index 9635130739..d69159c549 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/UtFrameUtils.java
@@ -48,7 +48,6 @@ import org.apache.doris.utframe.MockedFrontend.NotInitException;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
-
import org.apache.commons.io.FileUtils;
import java.io.File;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org