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/08/20 16:33:35 UTC

tajo git commit: TAJO-1737: Implement SQL Parser rule for Map type.

Repository: tajo
Updated Branches:
  refs/heads/master 65283b541 -> 0b59a93ba


TAJO-1737: Implement SQL Parser rule for Map type.

Closes #675


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

Branch: refs/heads/master
Commit: 0b59a93ba534434501edbc1bb2c2282f407239b7
Parents: 65283b5
Author: Hyunsik Choi <hy...@apache.org>
Authored: Thu Aug 20 23:25:54 2015 +0900
Committer: Hyunsik Choi <hy...@apache.org>
Committed: Thu Aug 20 23:31:12 2015 +0900

----------------------------------------------------------------------
 CHANGES                                         |  2 +
 .../apache/tajo/algebra/ColumnDefinition.java   |  9 ++-
 .../org/apache/tajo/algebra/DataTypeExpr.java   | 81 +++++++++++++++++---
 .../java/org/apache/tajo/QueryTestCaseBase.java |  2 +-
 tajo-common/src/main/proto/DataTypes.proto      |  1 +
 .../tajo/engine/parser/TestSQLAnalyzer.java     | 18 +++++
 .../tajo/engine/query/TestCreateTable.java      |  5 ++
 .../TestCreateTable/negative/map_type.sql       |  3 +
 .../TestSQLAnalyzer/create_table_maptype_1.sql  |  1 +
 .../TestSQLAnalyzer/create_table_maptype_2.sql  |  1 +
 .../TestSQLAnalyzer/create_table_maptype_3.sql  |  1 +
 .../TestSelectQuery/nagative/operations.sql     |  1 -
 .../queries/TestSelectQuery/nagative/tables.sql |  1 -
 .../TestSelectQuery/negative/operations.sql     |  1 +
 .../queries/TestSelectQuery/negative/tables.sql |  1 +
 .../create_table_maptype_1.result               | 38 +++++++++
 .../create_table_maptype_2.result               | 52 +++++++++++++
 .../create_table_maptype_3.result               | 66 ++++++++++++++++
 .../create_table_nested_1.result                | 26 ++++---
 .../create_table_nested_2.result                | 60 ++++++++-------
 .../org/apache/tajo/engine/parser/SQLLexer.g4   |  1 +
 .../org/apache/tajo/engine/parser/SQLParser.g4  |  6 ++
 .../apache/tajo/engine/parser/SQLAnalyzer.java  | 10 ++-
 .../org/apache/tajo/master/GlobalEngine.java    |  1 -
 .../plan/verifier/PreLogicalPlanVerifier.java   | 15 ++++
 25 files changed, 346 insertions(+), 57 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 1f4db9f..2e93f51 100644
--- a/CHANGES
+++ b/CHANGES
@@ -515,6 +515,8 @@ Release 0.11.0 - unreleased
 
   SUB TASKS
 
+    TAJO-1737: Implement SQL Parser rule for Map type. (hyunsik)
+
     TAJO-1787: Remove unused and legacy exceptions. (hyunsik)
 
     TAJO-1758: Some TajoRuntimeException should be restored as TajoException 

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/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 f8ea0f1..2a829e1 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
@@ -43,8 +43,13 @@ public  class ColumnDefinition extends DataTypeExpr {
     }
 
     // nested records
-    if (dataType.isNestedRecordType()) {
-      this.nestedRecordTypes = dataType.nestedRecordTypes;
+    if (dataType.isRecordType()) {
+      this.recordType = dataType.recordType;
+    }
+
+    // map type
+    if (dataType.isMapType()) {
+      this.mapType = dataType.mapType;
     }
   }
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/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 b280397..d63532d 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
@@ -32,30 +32,46 @@ public class DataTypeExpr extends Expr {
   @Expose @SerializedName("Scale")
   Integer scale;
   @Expose @SerializedName("Record")
-  ColumnDefinition [] nestedRecordTypes; // not null if the type is RECORD
+  RecordType recordType; // not null if the type is RECORD
+  @Expose @SerializedName("Map")
+  MapType mapType;
 
   public DataTypeExpr(String typeName) {
     super(OpType.DataType);
     this.typeName = typeName;
   }
 
-  public DataTypeExpr(ColumnDefinition [] nestedRecordTypes) {
+  public DataTypeExpr(RecordType record) {
     super(OpType.DataType);
-    // RECORD = 51 in DataTypes.proto
     this.typeName = Type.RECORD.name();
-    this.nestedRecordTypes = nestedRecordTypes;
+    this.recordType = record;
+  }
+
+  public DataTypeExpr(MapType map) {
+    super(OpType.DataType);
+    // RECORD = 51 in DataTypes.proto
+    this.typeName = Type.MAP.name();
+    this.mapType = map;
   }
 
   public String getTypeName() {
     return this.typeName;
   }
 
-  public boolean isNestedRecordType() {
+  public boolean isPrimitiveType() {
+    return !this.isRecordType() && !isMapType();
+  }
+
+  public boolean isRecordType() {
     return this.typeName.equals(Type.RECORD.name());
   }
 
+  public boolean isMapType() {
+    return this.typeName.equals(Type.MAP.name());
+  }
+
   public ColumnDefinition [] getNestedRecordTypes() {
-    return nestedRecordTypes;
+    return recordType.schema;
   }
 
   public boolean hasLengthOrPrecision() {
@@ -84,7 +100,7 @@ public class DataTypeExpr extends Expr {
 
   @Override
   public int hashCode() {
-    return Objects.hashCode(typeName, lengthOrPrecision, scale);
+    return Objects.hashCode(typeName, lengthOrPrecision, scale, recordType, mapType);
   }
 
   @Override
@@ -93,16 +109,63 @@ public class DataTypeExpr extends Expr {
     return typeName.equals(another.typeName) &&
         TUtil.checkEquals(lengthOrPrecision, another.lengthOrPrecision) &&
         TUtil.checkEquals(scale, another.scale) &&
-        TUtil.checkEquals(nestedRecordTypes, another.nestedRecordTypes);
+        TUtil.checkEquals(recordType, another.recordType) &&
+        TUtil.checkEquals(mapType, another.mapType);
   }
 
   @Override
   public Object clone() throws CloneNotSupportedException {
     DataTypeExpr dataType = (DataTypeExpr) super.clone();
     dataType.typeName = typeName;
+    // why we copy references? because they are all immutable.
     dataType.lengthOrPrecision = lengthOrPrecision;
     dataType.scale = scale;
-    dataType.nestedRecordTypes = nestedRecordTypes;
+    dataType.recordType = recordType;
+    dataType.mapType = mapType;
     return dataType;
   }
+
+  public static class RecordType implements JsonSerializable, Cloneable {
+    @Expose @SerializedName("Schema")
+    ColumnDefinition [] schema; // not null if the type is RECORD
+
+    public RecordType(ColumnDefinition [] schema) {
+      this.schema = schema;
+    }
+
+    @Override
+    public String toJson() {
+      return JsonHelper.toJson(this);
+    }
+
+    public Object clone() throws CloneNotSupportedException {
+      RecordType newRecord = (RecordType) super.clone();
+      newRecord.schema = this.schema;
+      return newRecord;
+    }
+  }
+
+  public static class MapType implements JsonSerializable, Cloneable {
+    @Expose @SerializedName("KeyType")
+    DataTypeExpr keyType;
+    @Expose @SerializedName("ValueType")
+    DataTypeExpr valueType;
+
+    public MapType(DataTypeExpr key, DataTypeExpr value) {
+      this.keyType = key;
+      this.valueType = value;
+    }
+
+    @Override
+    public String toJson() {
+      return JsonHelper.toJson(this);
+    }
+
+    public Object clone() throws CloneNotSupportedException {
+      MapType newMap = (MapType) super.clone();
+      newMap.keyType = keyType;
+      newMap.valueType = valueType;
+      return newMap;
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-cluster-tests/src/test/java/org/apache/tajo/QueryTestCaseBase.java
----------------------------------------------------------------------
diff --git a/tajo-cluster-tests/src/test/java/org/apache/tajo/QueryTestCaseBase.java b/tajo-cluster-tests/src/test/java/org/apache/tajo/QueryTestCaseBase.java
index 85b72f2..8200cec 100644
--- a/tajo-cluster-tests/src/test/java/org/apache/tajo/QueryTestCaseBase.java
+++ b/tajo-cluster-tests/src/test/java/org/apache/tajo/QueryTestCaseBase.java
@@ -856,7 +856,7 @@ public class QueryTestCaseBase {
   }
 
   private Collection<Path> getNegativeQueryFiles() throws IOException {
-    Path positiveQueryDir = StorageUtil.concatPath(currentQueryPath, "nagative");
+    Path positiveQueryDir = StorageUtil.concatPath(currentQueryPath, "negative");
     FileSystem fs = currentQueryPath.getFileSystem(testBase.getTestingCluster().getConfiguration());
 
     if (!fs.exists(positiveQueryDir)) {

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/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 fc5ac9a..53c3d0f 100644
--- a/tajo-common/src/main/proto/DataTypes.proto
+++ b/tajo-common/src/main/proto/DataTypes.proto
@@ -60,6 +60,7 @@ enum Type {
   BLOB = 45;
 
   RECORD = 51; // nested structure type
+  MAP    = 52; // map type
 
   ANY = 61; // Any type
   UDT = 62; // user-defined function

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java
index bb14aec..e9a9305 100644
--- a/tajo-core-tests/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java
+++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/parser/TestSQLAnalyzer.java
@@ -801,4 +801,22 @@ public class TestSQLAnalyzer {
   public void testCreateTableWithNested2() throws IOException {
     assertParseResult("create_table_nested_2.sql", "create_table_nested_2.result");
   }
+
+  @Test
+  public void testCreateTableWithMapType1() throws IOException {
+    // primitive key value map
+    assertParseResult("create_table_maptype_1.sql", "create_table_maptype_1.result");
+  }
+
+  @Test
+  public void testCreateTableWithMapType2() throws IOException {
+    // primitive key and record value map
+    assertParseResult("create_table_maptype_2.sql", "create_table_maptype_2.result");
+  }
+
+  @Test
+  public void testCreateTableWithMapType3() throws IOException {
+    // primitive key and nexted record value map
+    assertParseResult("create_table_maptype_3.sql", "create_table_maptype_3.result");
+  }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/java/org/apache/tajo/engine/query/TestCreateTable.java
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/query/TestCreateTable.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/query/TestCreateTable.java
index f34cbce..b7e0a48 100644
--- a/tajo-core-tests/src/test/java/org/apache/tajo/engine/query/TestCreateTable.java
+++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/query/TestCreateTable.java
@@ -39,6 +39,11 @@ import static org.junit.Assert.*;
 public class TestCreateTable extends QueryTestCaseBase {
 
   @Test
+  public final void testNegatives() throws Exception {
+    runNegativeTests();
+  }
+
+  @Test
   public final void testVariousTypes() throws Exception {
     List<String> createdNames;
     if (testingCluster.isHiveCatalogStoreRunning()) {

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/queries/TestCreateTable/negative/map_type.sql
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/queries/TestCreateTable/negative/map_type.sql b/tajo-core-tests/src/test/resources/queries/TestCreateTable/negative/map_type.sql
new file mode 100644
index 0000000..c5883e3
--- /dev/null
+++ b/tajo-core-tests/src/test/resources/queries/TestCreateTable/negative/map_type.sql
@@ -0,0 +1,3 @@
+CREATE TABLE T1 (A TEXT, B INT4, C MAP<TEXT, INT8>, F FLOAT8);
+CREATE TABLE T2 (A TEXT, B INT4, C MAP<TEXT, RECORD (name TEXT, age INT4)>, F FLOAT8);
+CREATE TABLE T3 (A TEXT, B INT4, C MAP<TEXT, RECORD (name RECORD (first_name TEXT, last_name TEXT), age INT4)>, F FLOAT8);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_1.sql
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_1.sql b/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_1.sql
new file mode 100644
index 0000000..4a9789c
--- /dev/null
+++ b/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_1.sql
@@ -0,0 +1 @@
+CREATE TABLE T1 (A TEXT, B INT4, C MAP<TEXT, INT8>, F FLOAT8);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_2.sql
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_2.sql b/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_2.sql
new file mode 100644
index 0000000..9a828ce
--- /dev/null
+++ b/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_2.sql
@@ -0,0 +1 @@
+CREATE TABLE T1 (A TEXT, B INT4, C MAP<TEXT, RECORD (name TEXT, age INT4)>, F FLOAT8);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_3.sql
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_3.sql b/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_3.sql
new file mode 100644
index 0000000..fee6829
--- /dev/null
+++ b/tajo-core-tests/src/test/resources/queries/TestSQLAnalyzer/create_table_maptype_3.sql
@@ -0,0 +1 @@
+CREATE TABLE T1 (A TEXT, B INT4, C MAP<TEXT, RECORD (name RECORD (first_name TEXT, last_name TEXT), age INT4)>, F FLOAT8);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/nagative/operations.sql
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/queries/TestSelectQuery/nagative/operations.sql b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/nagative/operations.sql
deleted file mode 100644
index 0a0ed75..0000000
--- a/tajo-core-tests/src/test/resources/queries/TestSelectQuery/nagative/operations.sql
+++ /dev/null
@@ -1 +0,0 @@
-select 1 + col1;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/nagative/tables.sql
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/queries/TestSelectQuery/nagative/tables.sql b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/nagative/tables.sql
deleted file mode 100644
index 17d0403..0000000
--- a/tajo-core-tests/src/test/resources/queries/TestSelectQuery/nagative/tables.sql
+++ /dev/null
@@ -1 +0,0 @@
-select * from lineite;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/negative/operations.sql
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/queries/TestSelectQuery/negative/operations.sql b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/negative/operations.sql
new file mode 100644
index 0000000..0a0ed75
--- /dev/null
+++ b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/negative/operations.sql
@@ -0,0 +1 @@
+select 1 + col1;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/negative/tables.sql
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/queries/TestSelectQuery/negative/tables.sql b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/negative/tables.sql
new file mode 100644
index 0000000..17d0403
--- /dev/null
+++ b/tajo-core-tests/src/test/resources/queries/TestSelectQuery/negative/tables.sql
@@ -0,0 +1 @@
+select * from lineite;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_1.result
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_1.result b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_1.result
new file mode 100644
index 0000000..fea61b5
--- /dev/null
+++ b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_1.result
@@ -0,0 +1,38 @@
+{
+  "IsExternal": false,
+  "TableName": "t1",
+  "Attributes": [
+    {
+      "ColumnDefName": "a",
+      "DataTypeName": "TEXT",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "b",
+      "DataTypeName": "INT4",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "c",
+      "DataTypeName": "MAP",
+      "Map": {
+        "KeyType": {
+          "DataTypeName": "TEXT",
+          "OpType": "DataType"
+        },
+        "ValueType": {
+          "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/0b59a93b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_2.result
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_2.result b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_2.result
new file mode 100644
index 0000000..81c0b90
--- /dev/null
+++ b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_2.result
@@ -0,0 +1,52 @@
+{
+  "IsExternal": false,
+  "TableName": "t1",
+  "Attributes": [
+    {
+      "ColumnDefName": "a",
+      "DataTypeName": "TEXT",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "b",
+      "DataTypeName": "INT4",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "c",
+      "DataTypeName": "MAP",
+      "Map": {
+        "KeyType": {
+          "DataTypeName": "TEXT",
+          "OpType": "DataType"
+        },
+        "ValueType": {
+          "DataTypeName": "RECORD",
+          "Record": {
+            "Schema": [
+              {
+                "ColumnDefName": "name",
+                "DataTypeName": "TEXT",
+                "OpType": "DataType"
+              },
+              {
+                "ColumnDefName": "age",
+                "DataTypeName": "INT4",
+                "OpType": "DataType"
+              }
+            ]
+          },
+          "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/0b59a93b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_3.result
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_3.result b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_3.result
new file mode 100644
index 0000000..3259ffb
--- /dev/null
+++ b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_maptype_3.result
@@ -0,0 +1,66 @@
+{
+  "IsExternal": false,
+  "TableName": "t1",
+  "Attributes": [
+    {
+      "ColumnDefName": "a",
+      "DataTypeName": "TEXT",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "b",
+      "DataTypeName": "INT4",
+      "OpType": "DataType"
+    },
+    {
+      "ColumnDefName": "c",
+      "DataTypeName": "MAP",
+      "Map": {
+        "KeyType": {
+          "DataTypeName": "TEXT",
+          "OpType": "DataType"
+        },
+        "ValueType": {
+          "DataTypeName": "RECORD",
+          "Record": {
+            "Schema": [
+              {
+                "ColumnDefName": "name",
+                "DataTypeName": "RECORD",
+                "Record": {
+                  "Schema": [
+                    {
+                      "ColumnDefName": "first_name",
+                      "DataTypeName": "TEXT",
+                      "OpType": "DataType"
+                    },
+                    {
+                      "ColumnDefName": "last_name",
+                      "DataTypeName": "TEXT",
+                      "OpType": "DataType"
+                    }
+                  ]
+                },
+                "OpType": "DataType"
+              },
+              {
+                "ColumnDefName": "age",
+                "DataTypeName": "INT4",
+                "OpType": "DataType"
+              }
+            ]
+          },
+          "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/0b59a93b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_1.result
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_1.result b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_1.result
index d609790..55f79da 100644
--- a/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_1.result
+++ b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_1.result
@@ -15,18 +15,20 @@
     {
       "ColumnDefName": "c",
       "DataTypeName": "RECORD",
-      "Record": [
-        {
-          "ColumnDefName": "d",
-          "DataTypeName": "TEXT",
-          "OpType": "DataType"
-        },
-        {
-          "ColumnDefName": "e",
-          "DataTypeName": "INT8",
-          "OpType": "DataType"
-        }
-      ],
+      "Record": {
+        "Schema": [
+          {
+            "ColumnDefName": "d",
+            "DataTypeName": "TEXT",
+            "OpType": "DataType"
+          },
+          {
+            "ColumnDefName": "e",
+            "DataTypeName": "INT8",
+            "OpType": "DataType"
+          }
+        ]
+      },
       "OpType": "DataType"
     },
     {

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_2.result
----------------------------------------------------------------------
diff --git a/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_2.result b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_2.result
index 4c4b343..8a95d2c 100644
--- a/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_2.result
+++ b/tajo-core-tests/src/test/resources/results/TestSQLAnalyzer/create_table_nested_2.result
@@ -15,35 +15,39 @@
     {
       "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"
+      "Record": {
+        "Schema": [
+          {
+            "ColumnDefName": "d",
+            "DataTypeName": "TEXT",
+            "OpType": "DataType"
+          },
+          {
+            "ColumnDefName": "e",
+            "DataTypeName": "INT8",
+            "OpType": "DataType"
+          },
+          {
+            "ColumnDefName": "f",
+            "DataTypeName": "RECORD",
+            "Record": {
+              "Schema": [
+                {
+                  "ColumnDefName": "g",
+                  "DataTypeName": "INT1",
+                  "OpType": "DataType"
+                },
+                {
+                  "ColumnDefName": "h",
+                  "DataTypeName": "FLOAT4",
+                  "OpType": "DataType"
+                }
+              ]
             },
-            {
-              "ColumnDefName": "h",
-              "DataTypeName": "FLOAT4",
-              "OpType": "DataType"
-            }
-          ],
-          "OpType": "DataType"
-        }
-      ],
+            "OpType": "DataType"
+          }
+        ]
+      },
       "OpType": "DataType"
     },
     {

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/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 d1daeb6..896f627 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
@@ -258,6 +258,7 @@ LESS : L E S S;
 LIST : L I S T;
 LOCATION : L O C A T I O N;
 
+MAP : M A P;
 MAX : M A X;
 MAXVALUE : M A X V A L U E;
 MICROSECONDS : M I C R O S E C O N D S;

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/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 0f72dcc..41de218 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
@@ -282,6 +282,7 @@ nonreserved_keywords
   | LESS
   | LIST
   | LOCATION
+  | MAP
   | MAX
   | MAXVALUE
   | MICROSECONDS
@@ -441,6 +442,7 @@ predefined_type
   | binary_type
   | network_type
   | record_type
+  | map_type
   ;
 
 character_string_type
@@ -540,6 +542,10 @@ record_type
   : RECORD table_elements
   ;
 
+map_type
+  : MAP LTH key_type=data_type COMMA value_type=data_type GTH
+  ;
+
 /*
 ===============================================================================
   6.3 <value_expression_primary>

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/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 357c176..b367693 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
@@ -28,6 +28,7 @@ import org.apache.tajo.SessionVars;
 import org.apache.tajo.algebra.*;
 import org.apache.tajo.algebra.Aggregation.GroupType;
 import org.apache.tajo.algebra.CreateIndex.IndexMethodSpec;
+import org.apache.tajo.algebra.DataTypeExpr.MapType;
 import org.apache.tajo.algebra.LiteralValue.LiteralType;
 import org.apache.tajo.algebra.Sort.SortSpec;
 import org.apache.tajo.engine.parser.SQLParser.*;
@@ -1602,8 +1603,13 @@ public class SQLAnalyzer extends SQLParserBaseVisitor<Expr> {
 
 
     } else if (checkIfExist(predefined_type.record_type())) {
-      ColumnDefinition [] nestedRecordDefines = getDefinitions(predefined_type.record_type().table_elements());
-      typeDefinition = new DataTypeExpr(nestedRecordDefines);
+      ColumnDefinition [] nestedRecordDefine = getDefinitions(predefined_type.record_type().table_elements());
+      typeDefinition = new DataTypeExpr(new DataTypeExpr.RecordType(nestedRecordDefine));
+
+    } else if (checkIfExist(predefined_type.map_type())) {
+      Map_typeContext mapTypeContext = predefined_type.map_type();
+      typeDefinition = new DataTypeExpr(
+          new MapType(visitData_type(mapTypeContext.key_type), visitData_type(mapTypeContext.value_type)));
     }
 
     return typeDefinition;

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java b/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java
index b6dc652..aee7972 100644
--- a/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java
+++ b/tajo-core/src/main/java/org/apache/tajo/master/GlobalEngine.java
@@ -267,7 +267,6 @@ public class GlobalEngine extends AbstractService {
     VerificationState state = new VerificationState();
     preVerifier.verify(queryContext, state, expression);
     if (!state.verified()) {
-      StringBuilder sb = new StringBuilder();
 
       for (Throwable error : state.getErrors()) {
         throw error;

http://git-wip-us.apache.org/repos/asf/tajo/blob/0b59a93b/tajo-plan/src/main/java/org/apache/tajo/plan/verifier/PreLogicalPlanVerifier.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/verifier/PreLogicalPlanVerifier.java b/tajo-plan/src/main/java/org/apache/tajo/plan/verifier/PreLogicalPlanVerifier.java
index 0ff6aba..a227187 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/verifier/PreLogicalPlanVerifier.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/verifier/PreLogicalPlanVerifier.java
@@ -160,6 +160,14 @@ public class PreLogicalPlanVerifier extends BaseAlgebraVisitor<PreLogicalPlanVer
     return true;
   }
 
+  private void assertRelationSchema(Context context, CreateTable createTable) {
+    for (ColumnDefinition colDef : createTable.getTableElements()) {
+      if (colDef.isMapType()) {
+        context.state.addVerification(new UnsupportedException("map type"));
+      }
+    }
+  }
+
   private boolean assertRelationNoExistence(Context context, String tableName) {
     String qualifiedName;
 
@@ -231,12 +239,19 @@ public class PreLogicalPlanVerifier extends BaseAlgebraVisitor<PreLogicalPlanVer
   @Override
   public Expr visitCreateTable(Context context, Stack<Expr> stack, CreateTable expr) throws TajoException {
     super.visitCreateTable(context, stack, expr);
+
     if (!expr.isIfNotExists()) {
       assertRelationNoExistence(context, expr.getTableName());
     }
+
+    if (expr.hasTableElements()) {
+      assertRelationSchema(context, expr);
+    }
+
     if (expr.hasStorageType()) {
       assertSupportedStoreType(context.state, expr.getStorageType());
     }
+
     return expr;
   }