You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tajo.apache.org by hy...@apache.org on 2015/02/21 12:46:15 UTC

tajo git commit: TAJO-1353: CREATE TABLE should support the nested record definition.

Repository: tajo
Updated Branches:
  refs/heads/master 95d9cc455 -> 08f303450


TAJO-1353: CREATE TABLE should support the nested record definition.

Closes #385


Project: http://git-wip-us.apache.org/repos/asf/tajo/repo
Commit: http://git-wip-us.apache.org/repos/asf/tajo/commit/08f30345
Tree: http://git-wip-us.apache.org/repos/asf/tajo/tree/08f30345
Diff: http://git-wip-us.apache.org/repos/asf/tajo/diff/08f30345

Branch: refs/heads/master
Commit: 08f30345047ddf62dc51c33b9c350f08bf918a5c
Parents: 95d9cc4
Author: Hyunsik Choi <hy...@apache.org>
Authored: Sat Feb 21 03:40:39 2015 -0800
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Sat Feb 21 03:46:02 2015 -0800

----------------------------------------------------------------------
 CHANGES                                         |  20 +-
 .../apache/tajo/algebra/ColumnDefinition.java   |  10 +-
 .../org/apache/tajo/algebra/DataTypeExpr.java   |  20 +-
 tajo-common/src/main/proto/DataTypes.proto      |   8 +-
 .../org/apache/tajo/engine/parser/SQLLexer.g4   |   1 +
 .../org/apache/tajo/engine/parser/SQLParser.g4  |  14 +-
 .../apache/tajo/engine/parser/SQLAnalyzer.java  | 189 ++++++++++++-------
 .../tajo/engine/parser/TestSQLAnalyzer.java     |  10 +
 .../TestSQLAnalyzer/create_table_nested_1.sql   |   1 +
 .../TestSQLAnalyzer/create_table_nested_2.sql   |   1 +
 .../create_table_nested_1.result                |  40 ++++
 .../create_table_nested_2.result                |  57 ++++++
 12 files changed, 292 insertions(+), 79 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index b78b8b7..3f375a4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,7 +1,25 @@
 Tajo Change Log 
 
+Release 0.11.0 - unreleased
 
-Release 0.10.0 - unreleased
+  NEW FEATURES
+
+
+  IMPROVEMENT
+
+
+  BUG FIXES
+
+  
+  TASKS
+
+
+  SUB TASKS
+
+    TAJO-1353: Nested record support in CREATE TABLE statement. (hyunsik)
+
+
+Release 0.10.0 - Released
 
   NEW FEATURES
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnDefinition.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnDefinition.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnDefinition.java
index e6e05d4..80ecac4 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnDefinition.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/ColumnDefinition.java
@@ -31,13 +31,21 @@ public  class ColumnDefinition extends DataTypeExpr {
 
   public ColumnDefinition(String columnName, DataTypeExpr dataType) {
     super(dataType.getTypeName());
+
+    this.columnName = columnName;
+
+    // precision and scale
     if (dataType.hasLengthOrPrecision()) {
       setLengthOrPrecision(dataType.lengthOrPrecision);
       if (dataType.hasScale()) {
         setScale(dataType.scale);
       }
     }
-    this.columnName = columnName;
+
+    // nested records
+    if (dataType.isNestedRecordType()) {
+      this.nestedRecord = dataType.nestedRecord;
+    }
   }
 
   public String getColumnName() {

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
----------------------------------------------------------------------
diff --git a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java b/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
index 9dc795b..28f9a5e 100644
--- a/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
+++ b/tajo-algebra/src/main/java/org/apache/tajo/algebra/DataTypeExpr.java
@@ -21,6 +21,8 @@ package org.apache.tajo.algebra;
 import com.google.common.base.Objects;
 import com.google.gson.annotations.Expose;
 import com.google.gson.annotations.SerializedName;
+import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.common.TajoDataTypes.Type;
 import org.apache.tajo.util.TUtil;
 
 public class DataTypeExpr extends Expr {
@@ -30,16 +32,30 @@ public class DataTypeExpr extends Expr {
   Integer lengthOrPrecision;
   @Expose @SerializedName("Scale")
   Integer scale;
+  @Expose @SerializedName("Record")
+  DataTypeExpr [] nestedRecord;
 
   public DataTypeExpr(String typeName) {
     super(OpType.DataType);
     this.typeName = typeName;
   }
 
+  public DataTypeExpr(DataTypeExpr [] nestedRecordTypes) {
+    super(OpType.DataType);
+    // Please refer to DataTypes.proto. 'STRUCT' must be equivalent to Enum type in DataTypes.proto.
+    // STRUCT = 51;
+    this.typeName = Type.RECORD.name();
+    this.nestedRecord = nestedRecordTypes;
+  }
+
   public String getTypeName() {
     return this.typeName;
   }
 
+  public boolean isNestedRecordType() {
+    return this.typeName.equals(Type.RECORD.name());
+  }
+
   public boolean hasLengthOrPrecision() {
     return lengthOrPrecision != null;
   }
@@ -74,7 +90,8 @@ public class DataTypeExpr extends Expr {
     DataTypeExpr another = (DataTypeExpr) expr;
     return typeName.equals(another.typeName) &&
         TUtil.checkEquals(lengthOrPrecision, another.lengthOrPrecision) &&
-        TUtil.checkEquals(scale, another.scale);
+        TUtil.checkEquals(scale, another.scale) &&
+        TUtil.checkEquals(nestedRecord, another.nestedRecord);
   }
 
   @Override
@@ -83,6 +100,7 @@ public class DataTypeExpr extends Expr {
     dataType.typeName = typeName;
     dataType.lengthOrPrecision = lengthOrPrecision;
     dataType.scale = scale;
+    dataType.nestedRecord = nestedRecord;
     return dataType;
   }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-common/src/main/proto/DataTypes.proto
----------------------------------------------------------------------
diff --git a/tajo-common/src/main/proto/DataTypes.proto b/tajo-common/src/main/proto/DataTypes.proto
index fb9c957..04f1e12 100644
--- a/tajo-common/src/main/proto/DataTypes.proto
+++ b/tajo-common/src/main/proto/DataTypes.proto
@@ -59,9 +59,11 @@ enum Type {
   VARBINARY = 44; // variable-width binary strings
   BLOB = 45;
 
-  ANY = 51; // Any type
-  UDT = 52; // user-defined function
-  PROTOBUF = 53; // protocol buffer type
+  RECORD = 51; // nested structure type
+
+  ANY = 61; // Any type
+  UDT = 62; // user-defined function
+  PROTOBUF = 63; // protocol buffer type
 
   INET4 = 91;
   INET6 = 92;

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLLexer.g4
----------------------------------------------------------------------
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 0c144f7..f42e114 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
@@ -284,6 +284,7 @@ QUARTER : Q U A R T E R;
 
 RANGE : R A N G E;
 RANK : R A N K;
+RECORD : R E C O R D;
 REGEXP : R E G E X P;
 RENAME : R E N A M E;
 RESET : R E S E T;

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-core/src/main/antlr4/org/apache/tajo/engine/parser/SQLParser.g4
----------------------------------------------------------------------
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 a236514..420bf46 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
@@ -295,6 +295,7 @@ nonreserved_keywords
   | QUARTER
   | RANGE
   | RANK
+  | RECORD
   | REGEXP
   | RENAME
   | RESET
@@ -430,10 +431,7 @@ predefined_type
   | bit_type
   | binary_type
   | network_type
-  ;
-
-network_type
-  : INET4
+  | record_type
   ;
 
 character_string_type
@@ -525,6 +523,14 @@ binary_type
   | VARBINARY type_length?
   ;
 
+network_type
+  : INET4
+  ;
+
+record_type
+  : RECORD table_elements
+  ;
+
 /*
 ===============================================================================
   6.3 <value_expression_primary>

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-core/src/main/java/org/apache/tajo/engine/parser/SQLAnalyzer.java
----------------------------------------------------------------------
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 ab8e647..5b4054f 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
@@ -1288,7 +1288,10 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
     ColumnDefinition[] elements = new ColumnDefinition[size];
     for (int i = 0; i < size; i++) {
       String name = ctx.field_element(i).name.getText();
+
+      String dataTypeName = ctx.field_element(i).field_type().data_type().getText();
       DataTypeExpr typeDef = visitData_type(ctx.field_element(i).field_type().data_type());
+      Preconditions.checkNotNull(typeDef, dataTypeName + " is not handled correctly");
       elements[i] = new ColumnDefinition(name, typeDef);
     }
 
@@ -1359,12 +1362,17 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
     SQLParser.Predefined_typeContext predefined_type = ctx.predefined_type();
 
     DataTypeExpr typeDefinition = null;
-    if (predefined_type.character_string_type() != null) {
-      SQLParser.Character_string_typeContext character_string_type =
-          predefined_type.character_string_type();
 
-      if ((character_string_type.CHARACTER() != null || character_string_type.CHAR() != null) &&
-          character_string_type.VARYING() == null) {
+    // CHAR -> FIXED   CHAR
+    //      |- VARYING CHAR
+    // TEXT
+    if (checkIfExist(predefined_type.character_string_type())) {
+
+      SQLParser.Character_string_typeContext character_string_type = predefined_type.character_string_type();
+
+
+      if ((checkIfExist(character_string_type.CHARACTER()) || checkIfExist(character_string_type.CHAR())) &&
+          !checkIfExist(character_string_type.VARYING())) {
 
         typeDefinition = new DataTypeExpr(Type.CHAR.name());
 
@@ -1373,8 +1381,7 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
               Integer.parseInt(character_string_type.type_length().NUMBER().getText()));
         }
 
-      } else if (character_string_type.VARCHAR() != null
-          || character_string_type.VARYING() != null) {
+      } else if (checkIfExist(character_string_type.VARCHAR()) || checkIfExist(character_string_type.VARYING())) {
 
         typeDefinition = new DataTypeExpr(Type.VARCHAR.name());
 
@@ -1383,115 +1390,159 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
               Integer.parseInt(character_string_type.type_length().NUMBER().getText()));
         }
 
-      } else if (character_string_type.TEXT() != null) {
+      } else if (checkIfExist(character_string_type.TEXT())) {
         typeDefinition = new DataTypeExpr(Type.TEXT.name());
       }
 
-    } else if (predefined_type.national_character_string_type() != null) {
-      SQLParser.National_character_string_typeContext nchar_type =
-          predefined_type.national_character_string_type();
-      if ((nchar_type.CHAR() != null || nchar_type.CHARACTER() != null
-          || nchar_type.NCHAR() != null) && nchar_type.VARYING() == null) {
+    // NCHAR
+    } else if (checkIfExist(predefined_type.national_character_string_type())) {
+
+      National_character_string_typeContext nchar_type = predefined_type.national_character_string_type();
+
+      if ((checkIfExist(nchar_type.CHAR()) || checkIfExist(nchar_type.CHARACTER()) ||
+          checkIfExist(nchar_type.NCHAR()) && !checkIfExist(nchar_type.VARYING()))) {
+
         typeDefinition = new DataTypeExpr(Type.NCHAR.name());
-      } else if (nchar_type.NVARCHAR() != null || nchar_type.VARYING() != null) {
+
+      } else if (checkIfExist(nchar_type.NVARCHAR()) || checkIfExist(nchar_type.VARYING())) {
+
         typeDefinition = new DataTypeExpr(Type.NVARCHAR.name());
       }
 
-      if (nchar_type.type_length() != null) {
-        typeDefinition.setLengthOrPrecision(
-            Integer.parseInt(nchar_type.type_length().NUMBER().getText()));
+      // if a length is given
+      if (checkIfExist(nchar_type.type_length())) {
+        typeDefinition.setLengthOrPrecision(Integer.parseInt(nchar_type.type_length().NUMBER().getText()));
       }
 
-    } else if (predefined_type.binary_large_object_string_type() != null) {
-      SQLParser.Binary_large_object_string_typeContext blob_type =
-          predefined_type.binary_large_object_string_type();
+    // BLOB types
+    } else if (checkIfExist(predefined_type.binary_large_object_string_type())) {
+
+      Binary_large_object_string_typeContext blob_type = predefined_type.binary_large_object_string_type();
+
       typeDefinition = new DataTypeExpr(Type.BLOB.name());
-      if (blob_type.type_length() != null) {
-        typeDefinition.setLengthOrPrecision(
-            Integer.parseInt(blob_type.type_length().NUMBER().getText()));
+
+      if (checkIfExist(blob_type.type_length())) {
+        typeDefinition.setLengthOrPrecision(Integer.parseInt(blob_type.type_length().NUMBER().getText()));
       }
-    } else if (predefined_type.numeric_type() != null) {
+
+    // NUMERIC types
+    } else if (checkIfExist(predefined_type.numeric_type())) {
       // exact number
-      if (predefined_type.numeric_type().exact_numeric_type() != null) {
-        SQLParser.Exact_numeric_typeContext exactType =
-            predefined_type.numeric_type().exact_numeric_type();
-        if (exactType.TINYINT() != null || exactType.INT1() != null) {
+      if (checkIfExist(predefined_type.numeric_type().exact_numeric_type())) {
+
+        Exact_numeric_typeContext exactType = predefined_type.numeric_type().exact_numeric_type();
+
+        if (checkIfExist(exactType.TINYINT()) || checkIfExist(exactType.INT1())) {
           typeDefinition = new DataTypeExpr(Type.INT1.name());
-        } else if (exactType.INT2() != null || exactType.SMALLINT() != null) {
+
+        } else if (checkIfExist(exactType.INT2()) || checkIfExist(exactType.SMALLINT())) {
           typeDefinition = new DataTypeExpr(Type.INT2.name());
-        } else if (exactType.INT4() != null || exactType.INTEGER() != null ||
-            exactType.INT() != null) {
+
+        } else if (checkIfExist(exactType.INT4()) ||
+            checkIfExist(exactType.INTEGER()) ||
+            checkIfExist(exactType.INT())) {
           typeDefinition = new DataTypeExpr(Type.INT4.name());
-        } else if (exactType.INT8() != null || exactType.BIGINT() != null) {
+
+        } else if (checkIfExist(exactType.INT8()) || checkIfExist(exactType.BIGINT()) ) {
           typeDefinition = new DataTypeExpr(Type.INT8.name());
-        } else if (exactType.NUMERIC() != null) {
-          typeDefinition = new DataTypeExpr(Type.NUMERIC.name());
-        } else if (exactType.DECIMAL() != null || exactType.DEC() != null) {
+
+        } else if (checkIfExist(exactType.NUMERIC()) ||
+            checkIfExist(exactType.DECIMAL()) ||
+            checkIfExist(exactType.DEC())) {
           typeDefinition = new DataTypeExpr(Type.NUMERIC.name());
-        }
 
-        if (typeDefinition.getTypeName().equals(Type.NUMERIC.name())) {
-          if (exactType.precision_param() != null) {
-            if (exactType.precision_param().scale != null) {
-              typeDefinition.setScale(
-                  Integer.parseInt(exactType.precision_param().scale.getText()));
+          if (checkIfExist(exactType.precision_param())) {
+            typeDefinition.setLengthOrPrecision(Integer.parseInt(exactType.precision_param().precision.getText()));
+
+            if (checkIfExist(exactType.precision_param().scale)) {
+              typeDefinition.setScale(Integer.parseInt(exactType.precision_param().scale.getText()));
             }
-            typeDefinition.setLengthOrPrecision(
-                Integer.parseInt(exactType.precision_param().precision.getText()));
           }
         }
+
+
       } else { // approximate number
-        SQLParser.Approximate_numeric_typeContext approximateType =
-            predefined_type.numeric_type().approximate_numeric_type();
-        if (approximateType.FLOAT() != null || approximateType.FLOAT4() != null
-            || approximateType.REAL() != null) {
+        Approximate_numeric_typeContext approximateType = predefined_type.numeric_type().approximate_numeric_type();
+        if (checkIfExist(approximateType.FLOAT()) ||
+            checkIfExist(approximateType.FLOAT4()) ||
+            checkIfExist(approximateType.REAL())) {
           typeDefinition = new DataTypeExpr(Type.FLOAT4.name());
-        } else if (approximateType.FLOAT8() != null || approximateType.DOUBLE() != null) {
+
+        } else if (checkIfExist(approximateType.FLOAT8()) || checkIfExist(approximateType.DOUBLE())) {
           typeDefinition = new DataTypeExpr(Type.FLOAT8.name());
         }
       }
-    } else if (predefined_type.boolean_type() != null) {
+
+    } else if (checkIfExist(predefined_type.boolean_type())) {
       typeDefinition = new DataTypeExpr(Type.BOOLEAN.name());
-    } else if (predefined_type.datetime_type() != null) {
-      SQLParser.Datetime_typeContext dateTimeType = predefined_type.datetime_type();
-      if (dateTimeType.DATE() != null) {
+
+    } else if (checkIfExist(predefined_type.datetime_type())) {
+
+      Datetime_typeContext dateTimeType = predefined_type.datetime_type();
+      if (checkIfExist(dateTimeType.DATE())) {
         typeDefinition = new DataTypeExpr(Type.DATE.name());
-      } else if (dateTimeType.TIME(0) != null && dateTimeType.ZONE() == null) {
-        typeDefinition = new DataTypeExpr(Type.TIME.name());
-      } else if ((dateTimeType.TIME(0) != null && dateTimeType.ZONE() != null) ||
-          dateTimeType.TIMETZ() != null) {
+
+      } else if (checkIfExist(dateTimeType.TIME(0))) {
+        if (checkIfExist(dateTimeType.ZONE())) {
+          typeDefinition = new DataTypeExpr(Type.TIMEZ.name());
+        } else {
+          typeDefinition = new DataTypeExpr(Type.TIME.name());
+        }
+
+      } else if (checkIfExist(dateTimeType.TIMETZ())) {
         typeDefinition = new DataTypeExpr(Type.TIMEZ.name());
-      } else if (dateTimeType.TIMESTAMP() != null && dateTimeType.ZONE() == null) {
-        typeDefinition = new DataTypeExpr(Type.TIMESTAMP.name());
-      } else if ((dateTimeType.TIMESTAMP() != null && dateTimeType.ZONE() != null) ||
-          dateTimeType.TIMESTAMPTZ() != null) {
+
+      } else if (checkIfExist(dateTimeType.TIMESTAMP())) {
+         if (checkIfExist(dateTimeType.ZONE())) {
+           typeDefinition = new DataTypeExpr(Type.TIMESTAMPZ.name());
+         }  else {
+           typeDefinition = new DataTypeExpr(Type.TIMESTAMP.name());
+         }
+
+      } else if (checkIfExist(dateTimeType.TIMESTAMPTZ())) {
         typeDefinition = new DataTypeExpr(Type.TIMESTAMPZ.name());
       }
+
+      // bit data types
     } else if (predefined_type.bit_type() != null) {
-      SQLParser.Bit_typeContext bitType = predefined_type.bit_type();
-      if (bitType.VARBIT() != null || bitType.VARYING() != null) {
+      Bit_typeContext bitType = predefined_type.bit_type();
+
+      if (checkIfExist(bitType.VARBIT()) || checkIfExist(bitType.VARYING())) {
         typeDefinition = new DataTypeExpr(Type.VARBIT.name());
+
       } else {
         typeDefinition = new DataTypeExpr(Type.BIT.name());
       }
-      if (bitType.type_length() != null) {
+
+      if (checkIfExist(bitType.type_length())) {
         typeDefinition.setLengthOrPrecision(
             Integer.parseInt(bitType.type_length().NUMBER().getText()));
       }
-    } else if (predefined_type.binary_type() != null) {
+
+
+      // binary data types
+    } else if (checkIfExist(predefined_type.binary_type())) {
       SQLParser.Binary_typeContext binaryType = predefined_type.binary_type();
-      if (binaryType.VARBINARY() != null || binaryType.VARYING() != null) {
+
+      if (checkIfExist(binaryType.VARBINARY()) || checkIfExist(binaryType.VARYING())) {
         typeDefinition = new DataTypeExpr(Type.VARBINARY.name());
       } else {
         typeDefinition = new DataTypeExpr(Type.BINARY.name());
       }
 
-      if (binaryType.type_length() != null) {
-        typeDefinition.setLengthOrPrecision(
-            Integer.parseInt(binaryType.type_length().NUMBER().getText()));
+
+      if (checkIfExist(binaryType.type_length())) {
+        typeDefinition.setLengthOrPrecision(Integer.parseInt(binaryType.type_length().NUMBER().getText()));
       }
-    } else if (predefined_type.network_type() != null) {
+
+      // inet
+    } else if (checkIfExist(predefined_type.network_type())) {
       typeDefinition = new DataTypeExpr(Type.INET4.name());
+
+
+    } else if (checkIfExist(predefined_type.record_type())) {
+      ColumnDefinition [] nestedRecordDefines = getDefinitions(predefined_type.record_type().table_elements());
+      typeDefinition = new DataTypeExpr(nestedRecordDefines);
     }
 
     return typeDefinition;

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-core/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java
----------------------------------------------------------------------
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 9dfe814..d223554 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
@@ -710,4 +710,14 @@ public class TestSQLAnalyzer {
   public void testSetSession7() throws IOException {
     assertParseResult("setsession7.sql", "setsession7.result");
   }
+
+  @Test
+  public void testCreateTableWithNested1() throws IOException {
+    assertParseResult("create_table_nested_1.sql", "create_table_nested_1.result");
+  }
+
+  @Test
+  public void testCreateTableWithNested2() throws IOException {
+    assertParseResult("create_table_nested_2.sql", "create_table_nested_2.result");
+  }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-core/src/test/resources/queries/TestSQLAnalyzer/create_table_nested_1.sql
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/queries/TestSQLAnalyzer/create_table_nested_1.sql b/tajo-core/src/test/resources/queries/TestSQLAnalyzer/create_table_nested_1.sql
new file mode 100644
index 0000000..bdf76eb
--- /dev/null
+++ b/tajo-core/src/test/resources/queries/TestSQLAnalyzer/create_table_nested_1.sql
@@ -0,0 +1 @@
+CREATE TABLE T1 (A TEXT, B INT4, C RECORD (D TEXT, E INT8), F FLOAT8);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-core/src/test/resources/queries/TestSQLAnalyzer/create_table_nested_2.sql
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/queries/TestSQLAnalyzer/create_table_nested_2.sql b/tajo-core/src/test/resources/queries/TestSQLAnalyzer/create_table_nested_2.sql
new file mode 100644
index 0000000..0bfdc11
--- /dev/null
+++ b/tajo-core/src/test/resources/queries/TestSQLAnalyzer/create_table_nested_2.sql
@@ -0,0 +1 @@
+CREATE TABLE T1 (A TEXT, B INT4, C RECORD (D TEXT, E INT8, F RECORD (G INT1, H FLOAT4)), Z FLOAT8);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-core/src/test/resources/results/TestSQLAnalyzer/create_table_nested_1.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestSQLAnalyzer/create_table_nested_1.result b/tajo-core/src/test/resources/results/TestSQLAnalyzer/create_table_nested_1.result
new file mode 100644
index 0000000..d609790
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestSQLAnalyzer/create_table_nested_1.result
@@ -0,0 +1,40 @@
+{
+  "IsExternal": false,
+  "TableName": "t1",
+  "Attributes": [
+    {
+      "ColumnDefName": "a",
+      "DataTypeName": "TEXT",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "b",
+      "DataTypeName": "INT4",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "c",
+      "DataTypeName": "RECORD",
+      "Record": [
+        {
+          "ColumnDefName": "d",
+          "DataTypeName": "TEXT",
+          "OpType": "DataType"
+        },
+        {
+          "ColumnDefName": "e",
+          "DataTypeName": "INT8",
+          "OpType": "DataType"
+        }
+      ],
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "f",
+      "DataTypeName": "FLOAT8",
+      "OpType": "DataType"
+    }
+  ],
+  "IfNotExists": false,
+  "OpType": "CreateTable"
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/08f30345/tajo-core/src/test/resources/results/TestSQLAnalyzer/create_table_nested_2.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestSQLAnalyzer/create_table_nested_2.result b/tajo-core/src/test/resources/results/TestSQLAnalyzer/create_table_nested_2.result
new file mode 100644
index 0000000..4c4b343
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestSQLAnalyzer/create_table_nested_2.result
@@ -0,0 +1,57 @@
+{
+  "IsExternal": false,
+  "TableName": "t1",
+  "Attributes": [
+    {
+      "ColumnDefName": "a",
+      "DataTypeName": "TEXT",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "b",
+      "DataTypeName": "INT4",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "c",
+      "DataTypeName": "RECORD",
+      "Record": [
+        {
+          "ColumnDefName": "d",
+          "DataTypeName": "TEXT",
+          "OpType": "DataType"
+        },
+        {
+          "ColumnDefName": "e",
+          "DataTypeName": "INT8",
+          "OpType": "DataType"
+        },
+        {
+          "ColumnDefName": "f",
+          "DataTypeName": "RECORD",
+          "Record": [
+            {
+              "ColumnDefName": "g",
+              "DataTypeName": "INT1",
+              "OpType": "DataType"
+            },
+            {
+              "ColumnDefName": "h",
+              "DataTypeName": "FLOAT4",
+              "OpType": "DataType"
+            }
+          ],
+          "OpType": "DataType"
+        }
+      ],
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "z",
+      "DataTypeName": "FLOAT8",
+      "OpType": "DataType"
+    }
+  ],
+  "IfNotExists": false,
+  "OpType": "CreateTable"
+}
\ No newline at end of file