Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/tajo into window_function

Conflicts:
	tajo-core/src/main/java/org/apache/tajo/engine/parser/HiveQLAnalyzer.java
diff --git a/CHANGES b/CHANGES
index c7ea93f..3dd67a9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -68,6 +68,10 @@
     TAJO-789: Improve shuffle URI. (jinho)
 
     TAJO-769: A minor improvements for HCatalogStore (Fengdong Yu via hyunsik)
+    
+  SUB TASKS:
+
+    TAJO-757: Add parser rule and algebraic expression for window function. (hyunsik)
 
     TAJO-734: Arrange TajoCli output message. (hyoungjunkim via jihoon)
 
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Expr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Expr.java
index daf59b6..26e0831 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Expr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Expr.java
@@ -26,8 +26,8 @@
 import java.lang.reflect.Type;
 
 public abstract class Expr implements JsonSerializable {
+  @Expose @SerializedName("type")
   private static final String SERIALIZED_NAME_OF_OP_TYPE = "OpType";
-
   @Expose @SerializedName(SERIALIZED_NAME_OF_OP_TYPE)
   protected OpType opType;
 
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/GeneralSetFunctionExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/GeneralSetFunctionExpr.java
index fcb48df..3d812e7 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/GeneralSetFunctionExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/GeneralSetFunctionExpr.java
@@ -42,10 +42,10 @@
    *
    * @param signature Function name
    * @param distinct True if this function is a distinct aggregation function
-   * @param param Function parameter
+   * @param params Function parameters
    */
-  public GeneralSetFunctionExpr(String signature, boolean distinct, Expr param) {
-    this(OpType.GeneralSetFunction, signature, distinct, new Expr [] {param});
+  public GeneralSetFunctionExpr(String signature, boolean distinct, Expr[] params) {
+    this(OpType.GeneralSetFunction, signature, distinct, params);
   }
 
   /**
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/OpType.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/OpType.java
index 0ba087a..bc6e89b 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/OpType.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/OpType.java
@@ -41,6 +41,7 @@
   Relation(Relation.class),
   ScalarSubQuery(ScalarSubQuery.class),
   Explain(Explain.class),
+  Window(Window.class),
 
   // Data definition language
   CreateDatabase(CreateDatabase.class),
@@ -93,6 +94,8 @@
   Column(ColumnReferenceExpr.class),
   Target(NamedExpr.class),
   Function(FunctionExpr.class),
+  WindowFunction(WindowFunctionExpr.class),
+  WindowSpec(WindowSpecExpr.class),
   Asterisk(QualifiedAsteriskExpr.class),
 
   // Set Functions
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/Window.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Window.java
new file mode 100644
index 0000000..e9cd21c
--- /dev/null
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/Window.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.tajo.algebra;
+
+import com.google.common.base.Objects;
+import org.apache.tajo.util.TUtil;
+
+public class Window extends UnaryOperator {
+  private WindowDefinition [] definitions;
+
+  public Window(WindowDefinition [] definitions) {
+    super(OpType.Window);
+    this.definitions = definitions;
+  }
+
+  public WindowDefinition [] getWindowDefinitions() {
+    return definitions;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(definitions);
+  }
+
+  @Override
+  boolean equalsTo(Expr expr) {
+    Window another = (Window) expr;
+    return TUtil.checkEquals(definitions, another.definitions);
+  }
+
+  public static class WindowDefinition {
+    private String windowName;
+    private WindowSpecExpr windowSpec;
+
+    public WindowDefinition(String windowName, WindowSpecExpr spec) {
+      this.windowName = windowName;
+      this.windowSpec = spec;
+    }
+
+    public String getWindowName() {
+      return windowName;
+    }
+
+    public WindowSpecExpr getWindowSpec() {
+      return windowSpec;
+    }
+  }
+}
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/WindowFunctionExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/WindowFunctionExpr.java
new file mode 100644
index 0000000..517ec0f
--- /dev/null
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/WindowFunctionExpr.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.tajo.algebra;
+
+import com.google.common.base.Objects;
+import org.apache.tajo.util.TUtil;
+
+public class WindowFunctionExpr extends Expr {
+  // set function
+  GeneralSetFunctionExpr function;
+
+  // over clause - only one of both is used.
+  private String windowName;
+  private WindowSpecExpr windowSpec;
+
+  public WindowFunctionExpr(GeneralSetFunctionExpr function) {
+    super(OpType.WindowFunction);
+    this.function = function;
+  }
+
+  public boolean hasWindowName() {
+    return windowName != null;
+  }
+
+  public void setWindowName(String windowName) {
+    this.windowName = windowName;
+  }
+
+  public String getWindowName() {
+    return this.windowName;
+  }
+
+  public boolean hasWidowSpec() {
+    return windowSpec != null;
+  }
+
+  public void setWindowSpec(WindowSpecExpr windowSpec) {
+    this.windowSpec = windowSpec;
+  }
+
+  public WindowSpecExpr getWindowSpec() {
+    return this.windowSpec;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(windowName, windowSpec);
+  }
+
+  @Override
+  boolean equalsTo(Expr expr) {
+    return TUtil.checkEquals(windowName, windowSpec);
+  }
+}
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/WindowSpecExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/WindowSpecExpr.java
new file mode 100644
index 0000000..37c2ff1
--- /dev/null
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/WindowSpecExpr.java
@@ -0,0 +1,181 @@
+/**
+ * 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.tajo.algebra;
+
+import com.google.common.base.Objects;
+import org.apache.tajo.util.TUtil;
+
+public class WindowSpecExpr extends Expr {
+  private String windowName;
+  private Expr [] partitionKeys; // OVER (PARTITION BY ?,...,?)
+  private Sort.SortSpec [] sortSpecs; // OVER (... ORDER BY ?,...,?)
+  private WindowFrame windowFrame;
+
+  public WindowSpecExpr() {
+    super(OpType.WindowSpec);
+  }
+
+  public boolean hasWindowName() {
+    return windowName != null;
+  }
+
+  public void setWindowName(String windowName) {
+    this.windowName = windowName;
+  }
+
+  public String getWindowName() {
+    return this.windowName;
+  }
+
+  public boolean hasPartitionBy() {
+    return this.partitionKeys != null;
+  }
+
+  public void setPartitionKeys(Expr[] partitionKeys) {
+    this.partitionKeys = partitionKeys;
+  }
+
+  public Expr [] getPartitionKeys() {
+    return this.partitionKeys;
+  }
+
+  public boolean hasOrderBy() {
+    return this.sortSpecs != null;
+  }
+
+  public void setSortSpecs(Sort.SortSpec [] sortSpecs) {
+    this.sortSpecs = sortSpecs;
+  }
+
+  public Sort.SortSpec [] getSortSpecs() {
+    return this.sortSpecs;
+  }
+
+  public boolean hasWindowFrame() {
+    return windowFrame != null;
+  }
+
+  public void setWindowFrame(WindowFrame frame) {
+    this.windowFrame = frame;
+  }
+
+  public WindowFrame getWindowFrame() {
+    return windowFrame;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(windowName, partitionKeys, sortSpecs);
+  }
+
+  @Override
+  boolean equalsTo(Expr expr) {
+    WindowSpecExpr another = (WindowSpecExpr) expr;
+    return TUtil.checkEquals(windowName, another.windowName) &&
+        TUtil.checkEquals(partitionKeys, another.partitionKeys) &&
+        TUtil.checkEquals(sortSpecs, another.sortSpecs);
+  }
+
+  public static enum WindowFrameUnit {
+    ROW,
+    RANGE
+  }
+
+  public static enum WindowFrameStartBoundType {
+    UNBOUNDED_PRECEDING,
+    CURRENT_ROW,
+    PRECEDING
+  }
+
+  public static enum WindowFrameEndBoundType {
+    UNBOUNDED_FOLLOWING,
+    CURRENT_ROW,
+    FOLLOWING
+  }
+
+  public static class WindowFrame {
+    WindowFrameUnit unit;
+    private WindowStartBound startBound;
+    private WindowEndBound endBound;
+
+    public WindowFrame(WindowFrameUnit unit, WindowStartBound startBound) {
+      this.unit = unit;
+      this.startBound = startBound;
+    }
+
+    public WindowFrame(WindowFrameUnit unit, WindowStartBound startBound, WindowEndBound endBound) {
+      this(unit, startBound);
+      this.endBound = endBound;
+    }
+
+    public WindowStartBound getStartBound() {
+      return startBound;
+    }
+
+    public boolean hasEndBound() {
+      return endBound != null;
+    }
+
+    public WindowEndBound getEndBound() {
+      return endBound;
+    }
+  }
+
+  public static class WindowStartBound {
+    private WindowFrameStartBoundType boundType;
+    private Expr number;
+
+    public WindowStartBound(WindowFrameStartBoundType type) {
+      this.boundType = type;
+    }
+
+    public WindowFrameStartBoundType getBoundType() {
+      return boundType;
+    }
+
+    public void setNumber(Expr number) {
+      this.number = number;
+    }
+
+    public Expr getNumber() {
+      return number;
+    }
+  }
+
+  public static class WindowEndBound {
+    private WindowFrameEndBoundType boundType;
+    private Expr number;
+
+    public WindowEndBound(WindowFrameEndBoundType type) {
+      this.boundType = type;
+    }
+
+    public WindowFrameEndBoundType getBoundType() {
+      return boundType;
+    }
+
+    public Expr setNumber(Expr number) {
+      return number;
+    }
+
+    public Expr getNumber() {
+      return number;
+    }
+  }
+}
diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java
index 4f86028..ae00084 100644
--- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java
+++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/CatalogUtil.java
@@ -729,8 +729,9 @@
       "RIGHT",
       "SELECT", "SOME", "SYMMETRIC",
       "TABLE", "THEN", "TRAILING", "TRUE",
+      "OVER",
       "UNION", "UNIQUE", "USING",
-      "WHEN", "WHERE", "WITH"
+      "WHEN", "WHERE", "WINDOW", "WITH"
   };
 
   static {
diff --git a/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLLexer.g4 b/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLLexer.g4
index da5f355..4bdbc3d 100644
--- a/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLLexer.g4
+++ b/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLLexer.g4
@@ -167,9 +167,10 @@
 NULL : N U L L;
 
 ON : O N;
-OUTER : O U T E R;
 OR : O R;
 ORDER : O R D E R;
+OUTER : O U T E R;
+OVER : O V E R;
 RIGHT : R I G H T;
 SELECT : S E L E C T;
 SOME : S O M E;
@@ -187,6 +188,7 @@
 WHEN : W H E N;
 WHERE : W H E R E;
 WITH : W I T H;
+WINDOW : W I N D O W;
 
 /*
 ===============================================================================
@@ -207,17 +209,21 @@
 COLUMN : C O L U M N;
 COUNT : C O U N T;
 CUBE : C U B E;
+CUME_DIST : C U M E UNDERLINE D I S T;
+CURRENT : C U R R E N T;
 
 DAY : D A Y;
 DATABASE : D A T A B A S E;
 DEC : D E C;
 DECADE : D E C A D E;
+DENSE_RANK : D E N S E UNDERLINE R A N K;
 DOW : D O W;
 DOY : D O Y;
 DROP : D R O P;
 
 EPOCH : E P O C H;
 EVERY : E V E R Y;
+EXCLUDE : E X C L U D E;
 EXISTS : E X I S T S;
 EXPLAIN : E X P L A I N;
 EXTERNAL : E X T E R N A L;
@@ -225,6 +231,7 @@
 
 FILTER : F I L T E R;
 FIRST : F I R S T;
+FOLLOWING : F O L L O W I N G;
 FORMAT : F O R M A T;
 FUSION : F U S I O N;
 
@@ -256,20 +263,28 @@
 
 NATIONAL : N A T I O N A L;
 NULLIF : N U L L I F;
+NO : N O;
 
 OVERWRITE : O V E R W R I T E;
+OTHERS: O T H E R S;
 
 PARTITION : P A R T I T I O N;
 PARTITIONS : P A R T I T I O N S;
+PERCENT_RANK : P E R C E N T UNDERLINE R A N K;
+PRECEDING : P R E C E D I N G;
 PRECISION : P R E C I S I O N;
 PURGE : P U R G E;
 
 QUARTER : Q U A R T E R;
 
 RANGE : R A N G E;
+RANK : R A N K;
 REGEXP : R E G E X P;
 RLIKE : R L I K E;
 ROLLUP : R O L L U P;
+ROW : R O W;
+ROWS : R O W S;
+ROW_NUMBER :  R O W UNDERLINE N U M B E R;
 RENAME : R E N A M E;
 
 SECOND : S E C O N D;
@@ -282,6 +297,7 @@
 
 TABLESPACE : T A B L E S P A C E;
 THAN : T H A N;
+TIES : T I E S;
 TIMEZONE: T I M E Z O N E;
 TIMEZONE_HOUR: T I M E Z O N E UNDERLINE H O U R;
 TIMEZONE_MINUTE: T I M E Z O N E UNDERLINE M I N U T E;
@@ -289,6 +305,7 @@
 TO : T O;
 TRUNCATE : T R U N C A T E;
 
+UNBOUNDED : U N B O U N D E D;
 UNKNOWN : U N K N O W N;
 
 VALUES : V A L U E S;
diff --git a/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4 b/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
index c601d37..beba248 100644
--- a/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
+++ b/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
@@ -228,20 +228,25 @@
   | COLUMN
   | COUNT
   | CUBE
+  | CUME_DIST
+  | CURRENT
   | DAY
   | DEC
   | DECADE
+  | DENSE_RANK
   | DOW
   | DOY
   | DROP
   | EPOCH
   | EVERY
   | EXISTS
+  | EXCLUDE
   | EXPLAIN
   | EXTERNAL
   | EXTRACT
   | FILTER
   | FIRST
+  | FOLLOWING
   | FORMAT
   | FUSION
   | GROUPING
@@ -264,18 +269,26 @@
   | MINUTE
   | MONTH
   | NATIONAL
+  | NO
   | NULLIF
   | OVERWRITE
+  | OTHERS
   | PARTITION
   | PARTITIONS
+  | PERCENT_RANK
+  | PRECEDING
   | PRECISION
   | PURGE
   | QUARTER
   | RANGE
+  | RANK
   | REGEXP
   | RENAME
   | RLIKE
   | ROLLUP
+  | ROW
+  | ROWS
+  | ROW_NUMBER
   | SECOND
   | SET
   | SIMILAR
@@ -285,11 +298,13 @@
   | SUM
   | TABLESPACE
   | THAN
+  | TIES
   | TIMEZONE
   | TIMEZONE_HOUR
   | TIMEZONE_MINUTE
   | TRIM
   | TO
+  | UNBOUNDED
   | UNKNOWN
   | VALUES
   | VAR_POP
@@ -513,6 +528,7 @@
   : unsigned_value_specification
   | column_reference
   | set_function_specification
+  | window_function
   | scalar_subquery
   | case_expression
   | cast_specification
@@ -586,6 +602,32 @@
 
 /*
 ===============================================================================
+  6.10 window function
+===============================================================================
+*/
+
+window_function
+  : window_function_type OVER window_name_or_specification
+  ;
+
+window_function_type
+  : rank_function_type LEFT_PAREN RIGHT_PAREN
+  | ROW_NUMBER LEFT_PAREN RIGHT_PAREN
+  | aggregate_function
+  ;
+
+rank_function_type
+  : RANK | DENSE_RANK | PERCENT_RANK | CUME_DIST
+  ;
+
+
+window_name_or_specification
+  : window_name
+  | window_specification
+  ;
+
+/*
+===============================================================================
   6.11 <case expression>
 ===============================================================================
 */
@@ -906,6 +948,7 @@
     groupby_clause?
     having_clause?
     orderby_clause?
+    window_clause?
     limit_clause?
   ;
 
@@ -1070,6 +1113,84 @@
   : row_value_predicand (COMMA row_value_predicand)*
   ;
 
+
+ /*
+ ===============================================================================
+   7.11 <window clause> (p331)
+ ===============================================================================
+ */
+
+window_clause
+  : WINDOW window_definition_list;
+
+window_definition_list
+  : window_definition (COMMA window_definition)*
+  ;
+
+window_definition
+  : window_name AS window_specification
+  ;
+
+window_name
+  : identifier
+  ;
+
+window_specification
+  : LEFT_PAREN window_specification_details RIGHT_PAREN
+  ;
+
+window_specification_details
+  : (existing_window_name)? (window_partition_clause)? (window_order_clause)? (window_frame_clause)?
+  ;
+
+existing_window_name
+  : window_name
+  ;
+
+window_partition_clause
+  : PARTITION BY row_value_predicand_list
+  ;
+
+window_order_clause
+  : orderby_clause
+  ;
+
+window_frame_clause
+  : window_frame_units window_frame_extent (window_frame_exclusion)?
+  ;
+
+window_frame_units
+  : ROWS | RANGE
+  ;
+
+window_frame_extent
+  : window_frame_start_bound
+  | window_frame_between
+  ;
+
+window_frame_start_bound
+  : UNBOUNDED PRECEDING
+  | unsigned_value_specification PRECEDING // window_frame_preceding
+  | CURRENT ROW
+  ;
+
+window_frame_between
+  : BETWEEN bound1=window_frame_start_bound AND bound2=window_frame_end_bound
+  ;
+
+window_frame_end_bound
+  : UNBOUNDED FOLLOWING
+  | unsigned_value_specification FOLLOWING // window_frame_following FOLLOWING
+  | CURRENT ROW
+  ;
+
+window_frame_exclusion
+  : EXCLUDE CURRENT ROW
+  | EXCLUDE GROUP
+  | EXCLUDE TIES
+  | EXCLUDE NO OTHERS
+  ;
+
 /*
 ===============================================================================
   7.13 <query expression>
diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java b/tajo-core/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
index 01568af..59a9b46 100644
--- a/tajo-core/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
+++ b/tajo-core/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
@@ -36,6 +36,8 @@
 
 import static org.apache.tajo.algebra.Aggregation.GroupElement;
 import static org.apache.tajo.algebra.CreateTable.*;
+import static org.apache.tajo.algebra.WindowSpecExpr.WindowFrameEndBoundType;
+import static org.apache.tajo.algebra.WindowSpecExpr.WindowFrameStartBoundType;
 import static org.apache.tajo.common.TajoDataTypes.Type;
 import static org.apache.tajo.engine.parser.SQLParser.*;
 
@@ -192,6 +194,12 @@
         current = sort;
       }
 
+      if (checkIfExist(ctx.table_expression().window_clause())) {
+        Window window = visitWindow_clause(ctx.table_expression().window_clause());
+        window.setChild(current);
+        current = window;
+      }
+
       if (ctx.table_expression().limit_clause() != null) {
         Limit limit = visitLimit_clause(ctx.table_expression().limit_clause());
         limit.setChild(current);
@@ -312,14 +320,146 @@
     return clause;
   }
 
+  @Override public WindowFunctionExpr visitWindow_function(@NotNull SQLParser.Window_functionContext context) {
+    WindowFunctionExpr windowFunction = null;
+
+    Window_function_typeContext functionType = context.window_function_type();
+    GeneralSetFunctionExpr functionBody;
+    if (checkIfExist(functionType.rank_function_type())) {
+      Rank_function_typeContext rankFunction = functionType.rank_function_type();
+      if (checkIfExist(rankFunction.RANK())) {
+        functionBody = new GeneralSetFunctionExpr("rank", false, new Expr[] {});
+      } else if (checkIfExist(rankFunction.DENSE_RANK())) {
+        functionBody = new GeneralSetFunctionExpr("dense_rank", false, new Expr[] {});
+      } else if (checkIfExist(rankFunction.PERCENT_RANK())) {
+        functionBody = new GeneralSetFunctionExpr("percent_rank", false, new Expr[] {});
+      } else {
+        functionBody = new GeneralSetFunctionExpr("cume_dist", false, new Expr[] {});
+      }
+    } else if (checkIfExist(functionType.ROW_NUMBER())) {
+      functionBody = new GeneralSetFunctionExpr("row_number", false, new Expr[] {});
+    } else {
+      functionBody = visitAggregate_function(functionType.aggregate_function());
+    }
+    windowFunction = new WindowFunctionExpr(functionBody);
+
+    Window_name_or_specificationContext windowNameOrSpec = context.window_name_or_specification();
+    if (checkIfExist(windowNameOrSpec.window_name())) {
+      windowFunction.setWindowName(windowNameOrSpec.window_name().getText());
+    } else {
+      windowFunction.setWindowSpec(visitWindow_specification(windowNameOrSpec.window_specification()));
+    }
+
+    return windowFunction;
+  }
+
   @Override
-  public Sort visitOrderby_clause(SQLParser.Orderby_clauseContext ctx) {
-    int size = ctx.sort_specifier_list().sort_specifier().size();
+  public Window visitWindow_clause(@NotNull SQLParser.Window_clauseContext ctx) {
+    Window.WindowDefinition [] definitions =
+        new Window.WindowDefinition[ctx.window_definition_list().window_definition().size()];
+    for (int i = 0; i < definitions.length; i++) {
+      Window_definitionContext windowDefinitionContext = ctx.window_definition_list().window_definition(i);
+      String windowName = windowDefinitionContext.window_name().identifier().getText();
+      WindowSpecExpr windowSpec = visitWindow_specification(windowDefinitionContext.window_specification());
+      definitions[i] = new Window.WindowDefinition(windowName, windowSpec);
+    }
+    return new Window(definitions);
+  }
+
+  @Override public WindowSpecExpr visitWindow_specification(@NotNull SQLParser.Window_specificationContext ctx) {
+    WindowSpecExpr windowSpec = new WindowSpecExpr();
+    if (checkIfExist(ctx.window_specification_details())) {
+      Window_specification_detailsContext windowSpecDetail = ctx.window_specification_details();
+
+      if (checkIfExist(windowSpecDetail.existing_window_name())) {
+        windowSpec.setWindowName(windowSpecDetail.existing_window_name().getText());
+      }
+
+      if (checkIfExist(windowSpecDetail.window_partition_clause())) {
+        windowSpec.setPartitionKeys(
+            buildRowValuePredicands(windowSpecDetail.window_partition_clause().row_value_predicand_list()));
+      }
+
+      if (checkIfExist(windowSpecDetail.window_order_clause())) {
+        windowSpec.setSortSpecs(
+            buildSortSpecs(windowSpecDetail.window_order_clause().orderby_clause().sort_specifier_list()));
+      }
+
+      if (checkIfExist(windowSpecDetail.window_frame_clause())) {
+        Window_frame_clauseContext frameContext = windowSpecDetail.window_frame_clause();
+
+        WindowSpecExpr.WindowFrameUnit unit;
+        // frame unit - there are only two cases: RANGE and ROW
+        if (checkIfExist(frameContext.window_frame_units().RANGE())) {
+          unit = WindowSpecExpr.WindowFrameUnit.RANGE;
+        } else {
+          unit = WindowSpecExpr.WindowFrameUnit.ROW;
+        }
+
+        WindowSpecExpr.WindowFrame windowFrame;
+
+        if (checkIfExist(frameContext.window_frame_extent().window_frame_between())) { // when 'between' is given
+          Window_frame_betweenContext between = frameContext.window_frame_extent().window_frame_between();
+          WindowSpecExpr.WindowStartBound startBound = buildWindowStartBound(between.window_frame_start_bound());
+          WindowSpecExpr.WindowEndBound endBound = buildWindowEndBound(between.window_frame_end_bound());
+
+          windowFrame = new WindowSpecExpr.WindowFrame(unit, startBound, endBound);
+        } else { // if there is only start bound
+          WindowSpecExpr.WindowStartBound startBound =
+              buildWindowStartBound(frameContext.window_frame_extent().window_frame_start_bound());
+          windowFrame = new WindowSpecExpr.WindowFrame(unit, startBound);
+        }
+
+        windowSpec.setWindowFrame(windowFrame);
+      }
+    }
+    return windowSpec;
+  }
+
+  public WindowSpecExpr.WindowStartBound buildWindowStartBound(Window_frame_start_boundContext context) {
+    WindowFrameStartBoundType boundType = null;
+    if (checkIfExist(context.UNBOUNDED())) {
+      boundType = WindowFrameStartBoundType.UNBOUNDED_PRECEDING;
+    } else if (checkIfExist(context.unsigned_value_specification())) {
+      boundType = WindowFrameStartBoundType.PRECEDING;
+    } else {
+      boundType = WindowFrameStartBoundType.CURRENT_ROW;
+    }
+
+    WindowSpecExpr.WindowStartBound bound = new WindowSpecExpr.WindowStartBound(boundType);
+    if (boundType == WindowFrameStartBoundType.PRECEDING) {
+      bound.setNumber(visitUnsigned_value_specification(context.unsigned_value_specification()));
+    }
+
+    return bound;
+  }
+
+  public WindowSpecExpr.WindowEndBound buildWindowEndBound(Window_frame_end_boundContext context) {
+    WindowFrameEndBoundType boundType;
+    if (checkIfExist(context.UNBOUNDED())) {
+      boundType = WindowFrameEndBoundType.UNBOUNDED_FOLLOWING;
+    } else if (checkIfExist(context.unsigned_value_specification())) {
+      boundType = WindowFrameEndBoundType.FOLLOWING;
+    } else {
+      boundType = WindowFrameEndBoundType.CURRENT_ROW;
+    }
+
+    WindowSpecExpr.WindowEndBound endBound = new WindowSpecExpr.WindowEndBound(boundType);
+    if (boundType == WindowFrameEndBoundType.FOLLOWING) {
+      endBound.setNumber(visitUnsigned_value_specification(context.unsigned_value_specification()));
+    }
+
+    return endBound;
+  }
+
+  public Sort.SortSpec[] buildSortSpecs(Sort_specifier_listContext context) {
+    int size = context.sort_specifier().size();
+
     Sort.SortSpec specs[] = new Sort.SortSpec[size];
     for (int i = 0; i < size; i++) {
-      SQLParser.Sort_specifierContext specContext = ctx.sort_specifier_list().sort_specifier(i);
-      Expr column = visitRow_value_predicand(specContext.key);
-      specs[i] = new Sort.SortSpec(column);
+      SQLParser.Sort_specifierContext specContext = context.sort_specifier(i);
+      Expr sortKeyExpr = visitRow_value_predicand(specContext.key);
+      specs[i] = new Sort.SortSpec(sortKeyExpr);
       if (specContext.order_specification() != null) {
         if (specContext.order.DESC() != null) {
           specs[i].setDescending();
@@ -333,7 +473,12 @@
       }
     }
 
-    return new Sort(specs);
+    return specs;
+  }
+
+  @Override
+  public Sort visitOrderby_clause(SQLParser.Orderby_clauseContext ctx) {
+    return new Sort(buildSortSpecs(ctx.sort_specifier_list()));
   }
 
   @Override
@@ -388,7 +533,7 @@
               join_condition().search_condition());
           join.setQual(searchCondition);
         } else if (ctx.join_specification().named_columns_join() != null) {
-          ColumnReferenceExpr[] columns = getColumnReferences(ctx.join_specification().
+          ColumnReferenceExpr[] columns = buildColumnReferenceList(ctx.join_specification().
               named_columns_join().column_reference_list());
           join.setJoinColumns(columns);
         }
@@ -413,12 +558,12 @@
       rowValuePredicands.add(visitRow_value_predicand(ctx.row_value_predicand()));
     }
     if (ctx.row_value_predicand_list() != null) {
-      Collections.addAll(rowValuePredicands, getRowValuePredicands(ctx.row_value_predicand_list()));
+      Collections.addAll(rowValuePredicands, buildRowValuePredicands(ctx.row_value_predicand_list()));
     }
     return rowValuePredicands.toArray(new Expr[rowValuePredicands.size()]);
   }
 
-  private Expr[] getRowValuePredicands(Row_value_predicand_listContext ctx) {
+  private Expr[] buildRowValuePredicands(Row_value_predicand_listContext ctx) {
     Expr[] rowValuePredicands = new Expr[ctx.row_value_predicand().size()];
     for (int i = 0; i < rowValuePredicands.length; i++) {
       rowValuePredicands[i] = visitRow_value_predicand(ctx.row_value_predicand(i));
@@ -426,7 +571,7 @@
     return rowValuePredicands;
   }
 
-  private ColumnReferenceExpr[] getColumnReferences(Column_reference_listContext ctx) {
+  private ColumnReferenceExpr[] buildColumnReferenceList(Column_reference_listContext ctx) {
     ColumnReferenceExpr[] columnRefs = new ColumnReferenceExpr[ctx.column_reference().size()];
     for (int i = 0; i < columnRefs.length; i++) {
       columnRefs[i] = visitColumn_reference(ctx.column_reference(i));
@@ -853,7 +998,7 @@
   }
 
   @Override
-  public FunctionExpr visitAggregate_function(SQLParser.Aggregate_functionContext ctx) {
+  public GeneralSetFunctionExpr visitAggregate_function(SQLParser.Aggregate_functionContext ctx) {
     if (ctx.COUNT() != null && ctx.MULTIPLY() != null) {
       return new CountRowsFunctionExpr();
     } else {
@@ -862,12 +1007,12 @@
   }
 
   @Override
-  public FunctionExpr visitGeneral_set_function(SQLParser.General_set_functionContext ctx) {
+  public GeneralSetFunctionExpr visitGeneral_set_function(SQLParser.General_set_functionContext ctx) {
     String signature = ctx.set_function_type().getText();
     boolean distinct = checkIfExist(ctx.set_qualifier()) && checkIfExist(ctx.set_qualifier().DISTINCT());
     Expr param = visitValue_expression(ctx.value_expression());
 
-    return new GeneralSetFunctionExpr(signature, distinct, param);
+    return new GeneralSetFunctionExpr(signature, distinct, new Expr [] {param});
   }
 
   @Override
@@ -1094,14 +1239,14 @@
               visitValue_expression(rangeValue.value_expression())));
         }
       }
-      return new CreateTable.RangePartition(getColumnReferences(ctx.range_partitions().column_reference_list()),
+      return new CreateTable.RangePartition(buildColumnReferenceList(ctx.range_partitions().column_reference_list()),
           specifiers);
 
     } else if (checkIfExist(ctx.hash_partitions())) { // For Hash Partition
       Hash_partitionsContext hashPartitions = ctx.hash_partitions();
 
       if (checkIfExist(hashPartitions.hash_partitions_by_quantity())) { // PARTITIONS (num)
-        return new HashPartition(getColumnReferences(hashPartitions.column_reference_list()),
+        return new HashPartition(buildColumnReferenceList(hashPartitions.column_reference_list()),
             visitNumeric_value_expression(hashPartitions.hash_partitions_by_quantity().quantity));
 
       } else { // ( PARTITION part_name , ...)
@@ -1110,7 +1255,7 @@
             hashPartitions.individual_hash_partitions().individual_hash_partition()) {
           specifiers.add(new CreateTable.PartitionSpecifier(partition.partition_name().getText()));
         }
-        return new HashPartition(getColumnReferences(hashPartitions.column_reference_list()), specifiers);
+        return new HashPartition(buildColumnReferenceList(hashPartitions.column_reference_list()), specifiers);
       }
 
     } else if (checkIfExist(ctx.list_partitions())) { // For List Partition
@@ -1127,7 +1272,7 @@
         specifiers.add(new ListPartitionSpecifier(listValuePartition.partition_name().getText(),
             new ValueListExpr(exprs)));
       }
-      return new ListPartition(getColumnReferences(ctx.list_partitions().column_reference_list()), specifiers);
+      return new ListPartition(buildColumnReferenceList(ctx.list_partitions().column_reference_list()), specifiers);
 
     } else if (checkIfExist(ctx.column_partitions())) { // For Column Partition (Hive Style)
       return new CreateTable.ColumnPartition(getDefinitions(ctx.column_partitions().table_elements()), true);
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java b/tajo-core/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java
index 5423813..1dc54f6 100644
--- a/tajo-core/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java
@@ -52,6 +52,14 @@
     return visitor.visitSql(context);
   }
 
+  public void assertParseResult(String sqlFileName, String resultFileName) throws IOException {
+    String sql = FileUtil.readTextFileFromResource("queries/TestSQLAnalyzer/" + sqlFileName);
+    String result = FileUtil.readTextFileFromResource("results/TestSQLAnalyzer/" + resultFileName);
+
+    Expr expr = parseQuery(sql);
+    assertEquals(expr.toJson().trim(), result.trim());
+  }
+
 
   @Test
   public void testSelect1() throws IOException {
@@ -479,4 +487,49 @@
       parseExpr(exprs[i]);
     }
   }
+
+  @Test
+  public void windowFunction1() throws IOException {
+    assertParseResult("window1.sql", "window1.result");
+  }
+
+  @Test
+  public void windowFunction2() throws IOException {
+    assertParseResult("window2.sql", "window2.result");
+  }
+
+  @Test
+  public void windowFunction3() throws IOException {
+    assertParseResult("window3.sql", "window3.result");
+  }
+
+  @Test
+  public void windowFunction4() throws IOException {
+    assertParseResult("window4.sql", "window4.result");
+  }
+
+  @Test
+  public void windowFunction5() throws IOException {
+    assertParseResult("window5.sql", "window5.result");
+  }
+
+  @Test
+  public void windowFunction6() throws IOException {
+    assertParseResult("window6.sql", "window6.result");
+  }
+
+  @Test
+  public void windowFunction7() throws IOException {
+    assertParseResult("window7.sql", "window7.result");
+  }
+
+  @Test
+  public void windowFunction8() throws IOException {
+    assertParseResult("window8.sql", "window8.result");
+  }
+
+  @Test
+  public void windowFunction9() throws IOException {
+    assertParseResult("window9.sql", "window9.result");
+  }
 }
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window1.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window1.sql
new file mode 100644
index 0000000..52156b8
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window1.sql
@@ -0,0 +1,5 @@
+ SELECT
+  dt,
+  sum(xy) over()
+FROM
+  sum_example;
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window2.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window2.sql
new file mode 100644
index 0000000..60f1fbf
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window2.sql
@@ -0,0 +1,5 @@
+ SELECT
+  dt,
+  sum(xy) over(partition by dt)
+FROM
+  sum_example;
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window3.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window3.sql
new file mode 100644
index 0000000..01dd542
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window3.sql
@@ -0,0 +1,5 @@
+ SELECT
+  dt,
+  sum(xy) over(partition by round(dt))
+FROM
+  sum_example;
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window4.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window4.sql
new file mode 100644
index 0000000..629d5e4
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window4.sql
@@ -0,0 +1,5 @@
+ SELECT
+  dt,
+  sum(xy) over(order by dt)
+FROM
+  sum_example;
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window5.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window5.sql
new file mode 100644
index 0000000..6338817
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window5.sql
@@ -0,0 +1,6 @@
+ SELECT
+  dt,
+  dt2,
+  sum(xy) over(partition by round(dt),dt2 order by ceil(dt) asc null last)
+FROM
+  sum_example;
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window6.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window6.sql
new file mode 100644
index 0000000..1f1870e
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window6.sql
@@ -0,0 +1,6 @@
+ SELECT
+  dt,
+  dt2,
+  sum(xy) over(partition by round(dt),dt2 order by ceil(dt) asc null last ROWS UNBOUNDED PRECEDING)
+FROM
+  sum_example;
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window7.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window7.sql
new file mode 100644
index 0000000..6daa806
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window7.sql
@@ -0,0 +1,6 @@
+ SELECT
+  dt,
+  dt2,
+  row_number() over(partition by round(dt),dt2 order by ceil(dt) asc null last ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
+FROM
+  sum_example;
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window8.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window8.sql
new file mode 100644
index 0000000..6f70690
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window8.sql
@@ -0,0 +1,6 @@
+ SELECT
+  dt,
+  dt2,
+  row_number() over(partition by round(dt),dt2 order by ceil(dt) asc null last ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)
+FROM
+  sum_example;
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window9.sql b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window9.sql
new file mode 100644
index 0000000..b289ebf
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/queries/TestSQLAnalyzer/window9.sql
@@ -0,0 +1,9 @@
+ SELECT
+  dt,
+  dt2,
+  row_number() over(window1),
+  rank() over(window1)
+FROM
+  sum_example
+WINDOW
+  window1 AS (partition by round(dt),dt2 order by ceil(dt) asc null last ROWS BETWEEN 1 PRECEDING AND CURRENT ROW);
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window1.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window1.result
new file mode 100644
index 0000000..31ed149
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window1.result
@@ -0,0 +1,42 @@
+{
+  "distinct": false,
+  "targets": [
+    {
+      "child": {
+        "name": "dt",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "sum",
+          "params": [
+            {
+              "name": "xy",
+              "type": "Column"
+            }
+          ],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    }
+  ],
+  "child": {
+    "relations": [
+      {
+        "tableName": "sum_example",
+        "type": "Relation"
+      }
+    ],
+    "type": "RelationList"
+  },
+  "type": "Projection"
+}
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window2.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window2.result
new file mode 100644
index 0000000..378232c
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window2.result
@@ -0,0 +1,48 @@
+{
+  "distinct": false,
+  "targets": [
+    {
+      "child": {
+        "name": "dt",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "sum",
+          "params": [
+            {
+              "name": "xy",
+              "type": "Column"
+            }
+          ],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "partitionKeys": [
+            {
+              "name": "dt",
+              "type": "Column"
+            }
+          ],
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    }
+  ],
+  "child": {
+    "relations": [
+      {
+        "tableName": "sum_example",
+        "type": "Relation"
+      }
+    ],
+    "type": "RelationList"
+  },
+  "type": "Projection"
+}
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window3.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window3.result
new file mode 100644
index 0000000..c5bc47d
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window3.result
@@ -0,0 +1,54 @@
+{
+  "distinct": false,
+  "targets": [
+    {
+      "child": {
+        "name": "dt",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "sum",
+          "params": [
+            {
+              "name": "xy",
+              "type": "Column"
+            }
+          ],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "partitionKeys": [
+            {
+              "signature": "round",
+              "params": [
+                {
+                  "name": "dt",
+                  "type": "Column"
+                }
+              ],
+              "type": "Function"
+            }
+          ],
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    }
+  ],
+  "child": {
+    "relations": [
+      {
+        "tableName": "sum_example",
+        "type": "Relation"
+      }
+    ],
+    "type": "RelationList"
+  },
+  "type": "Projection"
+}
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window4.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window4.result
new file mode 100644
index 0000000..0edd7d4
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window4.result
@@ -0,0 +1,52 @@
+{
+  "distinct": false,
+  "targets": [
+    {
+      "child": {
+        "name": "dt",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "sum",
+          "params": [
+            {
+              "name": "xy",
+              "type": "Column"
+            }
+          ],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "sortSpecs": [
+            {
+              "key": {
+                "name": "dt",
+                "type": "Column"
+              },
+              "asc": true,
+              "nullFirst": false
+            }
+          ],
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    }
+  ],
+  "child": {
+    "relations": [
+      {
+        "tableName": "sum_example",
+        "type": "Relation"
+      }
+    ],
+    "type": "RelationList"
+  },
+  "type": "Projection"
+}
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window5.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window5.result
new file mode 100644
index 0000000..06192ff
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window5.result
@@ -0,0 +1,81 @@
+{
+  "distinct": false,
+  "targets": [
+    {
+      "child": {
+        "name": "dt",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "name": "dt2",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "sum",
+          "params": [
+            {
+              "name": "xy",
+              "type": "Column"
+            }
+          ],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "partitionKeys": [
+            {
+              "signature": "round",
+              "params": [
+                {
+                  "name": "dt",
+                  "type": "Column"
+                }
+              ],
+              "type": "Function"
+            },
+            {
+              "name": "dt2",
+              "type": "Column"
+            }
+          ],
+          "sortSpecs": [
+            {
+              "key": {
+                "signature": "ceil",
+                "params": [
+                  {
+                    "name": "dt",
+                    "type": "Column"
+                  }
+                ],
+                "type": "Function"
+              },
+              "asc": true,
+              "nullFirst": false
+            }
+          ],
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    }
+  ],
+  "child": {
+    "relations": [
+      {
+        "tableName": "sum_example",
+        "type": "Relation"
+      }
+    ],
+    "type": "RelationList"
+  },
+  "type": "Projection"
+}
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window6.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window6.result
new file mode 100644
index 0000000..97bd236
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window6.result
@@ -0,0 +1,87 @@
+{
+  "distinct": false,
+  "targets": [
+    {
+      "child": {
+        "name": "dt",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "name": "dt2",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "sum",
+          "params": [
+            {
+              "name": "xy",
+              "type": "Column"
+            }
+          ],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "partitionKeys": [
+            {
+              "signature": "round",
+              "params": [
+                {
+                  "name": "dt",
+                  "type": "Column"
+                }
+              ],
+              "type": "Function"
+            },
+            {
+              "name": "dt2",
+              "type": "Column"
+            }
+          ],
+          "sortSpecs": [
+            {
+              "key": {
+                "signature": "ceil",
+                "params": [
+                  {
+                    "name": "dt",
+                    "type": "Column"
+                  }
+                ],
+                "type": "Function"
+              },
+              "asc": true,
+              "nullFirst": false
+            }
+          ],
+          "windowFrame": {
+            "unit": "ROW",
+            "startBound": {
+              "boundType": "UNBOUNDED_PRECEDING"
+            }
+          },
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    }
+  ],
+  "child": {
+    "relations": [
+      {
+        "tableName": "sum_example",
+        "type": "Relation"
+      }
+    ],
+    "type": "RelationList"
+  },
+  "type": "Projection"
+}
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window7.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window7.result
new file mode 100644
index 0000000..9ae01bd
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window7.result
@@ -0,0 +1,85 @@
+{
+  "distinct": false,
+  "targets": [
+    {
+      "child": {
+        "name": "dt",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "name": "dt2",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "row_number",
+          "params": [],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "partitionKeys": [
+            {
+              "signature": "round",
+              "params": [
+                {
+                  "name": "dt",
+                  "type": "Column"
+                }
+              ],
+              "type": "Function"
+            },
+            {
+              "name": "dt2",
+              "type": "Column"
+            }
+          ],
+          "sortSpecs": [
+            {
+              "key": {
+                "signature": "ceil",
+                "params": [
+                  {
+                    "name": "dt",
+                    "type": "Column"
+                  }
+                ],
+                "type": "Function"
+              },
+              "asc": true,
+              "nullFirst": false
+            }
+          ],
+          "windowFrame": {
+            "unit": "ROW",
+            "startBound": {
+              "boundType": "UNBOUNDED_PRECEDING"
+            },
+            "endBound": {
+              "boundType": "UNBOUNDED_FOLLOWING"
+            }
+          },
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    }
+  ],
+  "child": {
+    "relations": [
+      {
+        "tableName": "sum_example",
+        "type": "Relation"
+      }
+    ],
+    "type": "RelationList"
+  },
+  "type": "Projection"
+}
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window8.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window8.result
new file mode 100644
index 0000000..b9abace
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window8.result
@@ -0,0 +1,90 @@
+{
+  "distinct": false,
+  "targets": [
+    {
+      "child": {
+        "name": "dt",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "name": "dt2",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "row_number",
+          "params": [],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "partitionKeys": [
+            {
+              "signature": "round",
+              "params": [
+                {
+                  "name": "dt",
+                  "type": "Column"
+                }
+              ],
+              "type": "Function"
+            },
+            {
+              "name": "dt2",
+              "type": "Column"
+            }
+          ],
+          "sortSpecs": [
+            {
+              "key": {
+                "signature": "ceil",
+                "params": [
+                  {
+                    "name": "dt",
+                    "type": "Column"
+                  }
+                ],
+                "type": "Function"
+              },
+              "asc": true,
+              "nullFirst": false
+            }
+          ],
+          "windowFrame": {
+            "unit": "ROW",
+            "startBound": {
+              "boundType": "PRECEDING",
+              "number": {
+                "valueType": "Unsigned_Integer",
+                "value": "1",
+                "type": "Literal"
+              }
+            },
+            "endBound": {
+              "boundType": "CURRENT_ROW"
+            }
+          },
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    }
+  ],
+  "child": {
+    "relations": [
+      {
+        "tableName": "sum_example",
+        "type": "Relation"
+      }
+    ],
+    "type": "RelationList"
+  },
+  "type": "Projection"
+}
\ No newline at end of file
diff --git a/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window9.result b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window9.result
new file mode 100644
index 0000000..613fb9b
--- /dev/null
+++ b/tajo-core/tajo-core-backend/src/test/resources/results/TestSQLAnalyzer/window9.result
@@ -0,0 +1,118 @@
+{
+  "distinct": false,
+  "targets": [
+    {
+      "child": {
+        "name": "dt",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "name": "dt2",
+        "type": "Column"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "row_number",
+          "params": [],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "windowName": "window1",
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    },
+    {
+      "child": {
+        "function": {
+          "distinct": false,
+          "signature": "rank",
+          "params": [],
+          "type": "GeneralSetFunction"
+        },
+        "windowSpec": {
+          "windowName": "window1",
+          "type": "WindowSpec"
+        },
+        "type": "WindowFunction"
+      },
+      "type": "Target"
+    }
+  ],
+  "child": {
+    "definitions": [
+      {
+        "windowName": "window1",
+        "windowSpec": {
+          "partitionKeys": [
+            {
+              "signature": "round",
+              "params": [
+                {
+                  "name": "dt",
+                  "type": "Column"
+                }
+              ],
+              "type": "Function"
+            },
+            {
+              "name": "dt2",
+              "type": "Column"
+            }
+          ],
+          "sortSpecs": [
+            {
+              "key": {
+                "signature": "ceil",
+                "params": [
+                  {
+                    "name": "dt",
+                    "type": "Column"
+                  }
+                ],
+                "type": "Function"
+              },
+              "asc": true,
+              "nullFirst": false
+            }
+          ],
+          "windowFrame": {
+            "unit": "ROW",
+            "startBound": {
+              "boundType": "PRECEDING",
+              "number": {
+                "valueType": "Unsigned_Integer",
+                "value": "1",
+                "type": "Literal"
+              }
+            },
+            "endBound": {
+              "boundType": "CURRENT_ROW"
+            }
+          },
+          "type": "WindowSpec"
+        }
+      }
+    ],
+    "child": {
+      "relations": [
+        {
+          "tableName": "sum_example",
+          "type": "Relation"
+        }
+      ],
+      "type": "RelationList"
+    },
+    "type": "Window"
+  },
+  "type": "Projection"
+}
\ No newline at end of file