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