tajo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jihoon...@apache.org
Subject [2/5] tajo git commit: TAJO-1300: Merge the index branch into the master branch.
Date Thu, 30 Jul 2015 04:39:00 GMT
http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java b/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java
index 3880585..0d996de 100644
--- a/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestHashSemiJoinExec.java
@@ -62,6 +62,7 @@ public class TestHashSemiJoinExec {
   private LogicalPlanner planner;
   private LogicalOptimizer optimizer;
   private Path testDir;
+  private QueryContext queryContext;
 
   private TableDesc employee;
   private TableDesc people;
@@ -130,11 +131,12 @@ public class TestHashSemiJoinExec {
     appender.flush();
     appender.close();
 
+    queryContext = new QueryContext(conf);
     people = CatalogUtil.newTableDesc("default.people", peopleSchema, peopleMeta, peoplePath);
     catalog.createTable(people);
     analyzer = new SQLAnalyzer();
     planner = new LogicalPlanner(catalog, TablespaceManager.getInstance());
-    optimizer = new LogicalOptimizer(conf);
+    optimizer = new LogicalOptimizer(conf, catalog);
   }
 
   @After
@@ -161,7 +163,7 @@ public class TestHashSemiJoinExec {
     FileFragment[] merged = TUtil.concat(empFrags, peopleFrags);
 
     Path workDir = CommonTestingUtil.getTestDir(TajoTestingCluster.DEFAULT_TEST_DIRECTORY + "/testHashSemiJoin");
-    TaskAttemptContext ctx = new TaskAttemptContext(new QueryContext(conf),
+    TaskAttemptContext ctx = new TaskAttemptContext(queryContext,
         LocalTajoTestingUtility.newTaskAttemptId(), merged, workDir);
     ctx.setEnforcer(new Enforcer());
     Expr expr = analyzer.parse(QUERIES[0]);

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java b/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
index dae2351..0d4e6a4 100644
--- a/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestPhysicalPlanner.java
@@ -162,12 +162,12 @@ public class TestPhysicalPlanner {
     }
     appender.flush();
     appender.close();
+
+    defaultContext = LocalTajoTestingUtility.createDummyContext(conf);
     catalog.createTable(score);
     analyzer = new SQLAnalyzer();
     planner = new LogicalPlanner(catalog, TablespaceManager.getInstance());
-    optimizer = new LogicalOptimizer(conf);
-
-    defaultContext = LocalTajoTestingUtility.createDummyContext(conf);
+    optimizer = new LogicalOptimizer(conf, catalog);
     masterPlan = new MasterPlan(LocalTajoTestingUtility.newQueryId(), null, null);
 
     createLargeScoreTable();
@@ -970,17 +970,23 @@ public class TestPhysicalPlanner {
   }
 
   public final String [] createIndexStmt = {
-      "create index idx_employee on employee using bst (name null first, empId desc)"
+      "create index idx_employee on employee using TWO_LEVEL_BIN_TREE (name null first, empId desc)"
   };
 
-  //@Test
+  @Test
   public final void testCreateIndex() throws IOException, TajoException {
     FileFragment[] frags = FileTablespace.splitNG(conf, "default.employee", employee.getMeta(),
         new Path(employee.getUri()), Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir(TajoTestingCluster.DEFAULT_TEST_DIRECTORY + "/testCreateIndex");
+    Path indexPath = StorageUtil.concatPath(TajoConf.getWarehouseDir(conf), "default/idx_employee");
+    if (sm.getFileSystem().exists(indexPath)) {
+      sm.getFileSystem().delete(indexPath, true);
+    }
+
     TaskAttemptContext ctx = new TaskAttemptContext(new QueryContext(conf),
         LocalTajoTestingUtility.newTaskAttemptId(masterPlan),
         new FileFragment[] {frags[0]}, workDir);
+    ctx.setEnforcer(new Enforcer());
     Expr context = analyzer.parse(createIndexStmt[0]);
     LogicalPlan plan = planner.createPlan(defaultContext, context);
     LogicalNode rootNode = optimizer.optimize(plan);
@@ -992,7 +998,7 @@ public class TestPhysicalPlanner {
     }
     exec.close();
 
-    FileStatus [] list = sm.getFileSystem().listStatus(StorageUtil.concatPath(workDir, "index"));
+    FileStatus[] list = sm.getFileSystem().listStatus(indexPath);
     assertEquals(2, list.length);
   }
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java b/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java
index 1c55d10..81cb945 100644
--- a/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortExec.java
@@ -66,6 +66,7 @@ public class TestSortExec {
   private static Path workDir;
   private static Path tablePath;
   private static TableMeta employeeMeta;
+  private static QueryContext queryContext;
 
   private static Random rnd = new Random(System.currentTimeMillis());
 
@@ -107,9 +108,10 @@ public class TestSortExec {
         tablePath.toUri());
     catalog.createTable(desc);
 
+    queryContext = new QueryContext(conf);
     analyzer = new SQLAnalyzer();
     planner = new LogicalPlanner(catalog, TablespaceManager.getInstance());
-    optimizer = new LogicalOptimizer(conf);
+    optimizer = new LogicalOptimizer(conf, catalog);
   }
 
   public static String[] QUERIES = {
@@ -119,7 +121,7 @@ public class TestSortExec {
   public final void testNext() throws IOException, TajoException {
     FileFragment[] frags = FileTablespace.splitNG(conf, "default.employee", employeeMeta, tablePath, Integer.MAX_VALUE);
     Path workDir = CommonTestingUtil.getTestDir(TajoTestingCluster.DEFAULT_TEST_DIRECTORY + "/TestSortExec");
-    TaskAttemptContext ctx = new TaskAttemptContext(new QueryContext(conf),
+    TaskAttemptContext ctx = new TaskAttemptContext(queryContext,
         LocalTajoTestingUtility
         .newTaskAttemptId(), new FileFragment[] { frags[0] }, workDir);
     ctx.setEnforcer(new Enforcer());

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortIntersectExec.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortIntersectExec.java b/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortIntersectExec.java
index 440eb31..7289472 100644
--- a/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortIntersectExec.java
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/planner/physical/TestSortIntersectExec.java
@@ -140,7 +140,7 @@ public class TestSortIntersectExec {
 
     analyzer = new SQLAnalyzer();
     planner = new LogicalPlanner(catalog, TablespaceManager.getInstance());
-    optimizer = new LogicalOptimizer(conf);
+    optimizer = new LogicalOptimizer(conf, catalog);
   }
 
   @After

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCreateIndex.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCreateIndex.java b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCreateIndex.java
new file mode 100644
index 0000000..1a55870
--- /dev/null
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestCreateIndex.java
@@ -0,0 +1,113 @@
+/*
+ * 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.engine.query;
+
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.tajo.IntegrationTest;
+import org.apache.tajo.QueryTestCaseBase;
+import org.apache.tajo.TajoConstants;
+import org.apache.tajo.catalog.IndexDesc;
+import org.apache.tajo.conf.TajoConf.ConfVars;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+@Category(IntegrationTest.class)
+public class TestCreateIndex extends QueryTestCaseBase {
+
+  public TestCreateIndex() {
+    super(TajoConstants.DEFAULT_DATABASE_NAME);
+  }
+
+  private static void assertIndexNotExist(String databaseName, String indexName) throws IOException {
+    Path indexPath = new Path(conf.getVar(ConfVars.WAREHOUSE_DIR), databaseName + "/" + indexName);
+    FileSystem fs = indexPath.getFileSystem(conf);
+    if (fs.exists(indexPath)) {
+      fs.deleteOnExit(indexPath);
+      assertFalse("Index is not deleted from the file system.", true);
+    }
+  }
+
+  @Test
+  public final void testCreateIndex() throws Exception {
+    executeQuery();
+    assertTrue(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_idx"));
+    assertTrue(catalog.existIndexByColumnNames(getCurrentDatabase(), "lineitem", new String[]{"l_orderkey"}));
+    executeString("drop index l_orderkey_idx");
+    assertFalse(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_idx"));
+    assertIndexNotExist(getCurrentDatabase(), "l_orderkey_idx");
+  }
+
+  @Test
+  public final void testCreateIndexOnMultiAttrs() throws Exception {
+    executeQuery();
+    assertTrue(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_partkey_idx"));
+    assertTrue(catalog.existIndexByColumnNames(getCurrentDatabase(), "lineitem", new String[]{"l_orderkey", "l_partkey"}));
+    executeString("drop index l_orderkey_partkey_idx");
+    assertFalse(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_partkey_idx"));
+    assertIndexNotExist(getCurrentDatabase(), "l_orderkey_partkey_idx");
+  }
+
+  @Test
+  public final void testCreateIndexWithCondition() throws Exception {
+    executeQuery();
+    assertTrue(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_partkey_lt10_idx"));
+    assertTrue(catalog.existIndexByColumnNames(getCurrentDatabase(), "lineitem", new String[]{"l_orderkey", "l_partkey"}));
+    executeString("drop index l_orderkey_partkey_lt10_idx");
+    assertFalse(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_partkey_lt10_idx"));
+    assertIndexNotExist(getCurrentDatabase(), "l_orderkey_partkey_lt10_idx");
+  }
+
+  @Test
+  public final void testCreateIndexOnExpression() throws Exception {
+    executeQuery();
+    assertTrue(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_100_lt10_idx"));
+    executeString("drop index l_orderkey_100_lt10_idx");
+    assertFalse(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_100_lt10_idx"));
+    assertIndexNotExist(getCurrentDatabase(), "l_orderkey_100_lt10_idx");
+  }
+
+  @Test
+  public final void testCreateIndexOnMultiExprs() throws Exception {
+    executeQuery();
+    assertTrue(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_100_l_linenumber_10_lt10_idx"));
+    executeString("drop index l_orderkey_100_l_linenumber_10_lt10_idx");
+    assertFalse(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_100_l_linenumber_10_lt10_idx"));
+    assertIndexNotExist(getCurrentDatabase(), "l_orderkey_100_l_linenumber_10_lt10_idx");
+  }
+
+  @Test
+  public final void testCreateIndexOnLocation() throws Exception {
+    executeQuery();
+    assertTrue(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_idx"));
+    assertTrue(catalog.existIndexByColumnNames(getCurrentDatabase(), "lineitem", new String[]{"l_orderkey"}));
+    catalog.dropIndex(getCurrentDatabase(), "l_orderkey_idx");
+    assertFalse(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_idx"));
+    executeString("create index l_orderkey_idx on lineitem (l_orderkey asc null first) location '/tajo/warehouse/default/l_orderkey_idx';");
+    assertTrue(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_idx"));
+    assertTrue(catalog.existIndexByColumnNames(getCurrentDatabase(), "lineitem", new String[]{"l_orderkey"}));
+    executeString("drop index l_orderkey_idx");
+    assertFalse(catalog.existIndexByName(getCurrentDatabase(), "l_orderkey_idx"));
+    assertIndexNotExist(getCurrentDatabase(), "l_orderkey_idx");
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/java/org/apache/tajo/engine/query/TestIndexScan.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestIndexScan.java b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestIndexScan.java
new file mode 100644
index 0000000..75127d2
--- /dev/null
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestIndexScan.java
@@ -0,0 +1,144 @@
+/*
+ * 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.engine.query;
+
+import com.google.protobuf.ServiceException;
+import org.apache.tajo.IntegrationTest;
+import org.apache.tajo.QueryTestCaseBase;
+import org.apache.tajo.SessionVars;
+import org.apache.tajo.TajoConstants;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
+@Category(IntegrationTest.class)
+public class TestIndexScan extends QueryTestCaseBase {
+
+  public TestIndexScan() throws ServiceException, SQLException {
+    super(TajoConstants.DEFAULT_DATABASE_NAME);
+    Map<String,String> sessionVars = new HashMap<String, String>();
+    sessionVars.put(SessionVars.INDEX_ENABLED.keyname(), "true");
+    sessionVars.put(SessionVars.INDEX_SELECTIVITY_THRESHOLD.keyname(), "0.01f");
+    client.updateSessionVariables(sessionVars);
+  }
+
+  @Test
+  public final void testOnSortedNonUniqueKeys() throws Exception {
+    executeString("create index l_orderkey_idx on lineitem (l_orderkey)");
+    try {
+      ResultSet res = executeString("select * from lineitem where l_orderkey = 1;");
+      assertResultSet(res);
+      cleanupQuery(res);
+    } finally {
+      executeString("drop index l_orderkey_idx");
+    }
+  }
+
+  @Test
+  public final void testOnUnsortedTextKeys() throws Exception {
+    executeString("create index l_shipdate_idx on lineitem (l_shipdate)");
+    try {
+      ResultSet res = executeString("select l_orderkey, l_shipdate, l_comment from lineitem where l_shipdate = '1997-01-28';");
+      assertResultSet(res);
+      cleanupQuery(res);
+    } finally {
+      executeString("drop index l_shipdate_idx");
+    }
+  }
+
+  @Test
+  public final void testOnMultipleKeys() throws Exception {
+    executeString("create index multikey_idx on lineitem (l_shipdate asc null last, l_tax desc null first, l_shipmode, l_linenumber desc null last)");
+    try {
+      ResultSet res = executeString("select l_orderkey, l_shipdate, l_comment from lineitem " +
+          "where l_shipdate = '1997-01-28' and l_tax = 0.05 and l_shipmode = 'RAIL' and l_linenumber = 1;");
+      assertResultSet(res);
+      cleanupQuery(res);
+    } finally {
+      executeString("drop index multikey_idx");
+    }
+  }
+
+  @Test
+  public final void testOnMultipleKeys2() throws Exception {
+    executeString("create index multikey_idx on lineitem (l_shipdate asc null last, l_tax desc null first)");
+    try {
+      ResultSet res = executeString("select l_orderkey, l_shipdate, l_comment from lineitem " +
+          "where l_shipdate = '1997-01-28' and l_tax = 0.05 and l_shipmode = 'RAIL' and l_linenumber = 1;");
+      assertResultSet(res);
+      cleanupQuery(res);
+    } finally {
+      executeString("drop index multikey_idx");
+    }
+  }
+
+  @Test
+  public final void testOnMultipleExprs() throws Exception {
+    executeString("create index l_orderkey_100_l_linenumber_10_idx on lineitem (l_orderkey*100-l_linenumber*10 asc null first);");
+    try {
+      ResultSet res = executeString("select l_orderkey, l_linenumber from lineitem where l_orderkey*100-l_linenumber*10 = 280");
+      assertResultSet(res);
+      cleanupQuery(res);
+    } finally {
+      executeString("drop index l_orderkey_100_l_linenumber_10_idx");
+    }
+  }
+
+  @Test
+  public final void testWithGroupBy() throws Exception {
+    executeString("create index l_shipdate_idx on lineitem (l_shipdate)");
+    try {
+      ResultSet res = executeString("select l_shipdate, count(*) from lineitem where l_shipdate = '1997-01-28' group by l_shipdate;");
+      assertResultSet(res);
+      cleanupQuery(res);
+    } finally {
+      executeString("drop index l_shipdate_idx");
+    }
+  }
+
+  @Test
+  public final void testWithSort() throws Exception {
+    executeString("create index l_orderkey_idx on lineitem (l_orderkey)");
+    try {
+      ResultSet res = executeString("select l_shipdate from lineitem where l_orderkey = 1 order by l_shipdate;");
+      assertResultSet(res);
+      cleanupQuery(res);
+    } finally {
+      executeString("drop index l_orderkey_idx");
+    }
+  }
+
+  @Test
+  public final void testWithJoin() throws Exception {
+    executeString("create index l_orderkey_idx on lineitem (l_orderkey)");
+    executeString("create index o_orderkey_idx on orders (o_orderkey)");
+    try {
+      ResultSet res = executeString("select l_shipdate, o_orderstatus from lineitem, orders where l_orderkey = o_orderkey and l_orderkey = 1 and o_orderkey = 1;");
+      assertResultSet(res);
+      cleanupQuery(res);
+    } finally {
+      executeString("drop index l_orderkey_idx");
+      executeString("drop index o_orderkey_idx");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java
index 265c726..d18db71 100644
--- a/tajo-core/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java
+++ b/tajo-core/src/test/java/org/apache/tajo/engine/query/TestTablePartitions.java
@@ -19,7 +19,10 @@
 package org.apache.tajo.engine.query;
 
 import com.google.common.collect.Maps;
-import org.apache.hadoop.fs.*;
+import org.apache.hadoop.fs.FSDataOutputStream;
+import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.io.compress.CompressionCodec;
 import org.apache.hadoop.io.compress.CompressionCodecFactory;
 import org.apache.hadoop.io.compress.DeflateCodec;
@@ -31,12 +34,12 @@ import org.apache.tajo.catalog.CatalogService;
 import org.apache.tajo.catalog.CatalogUtil;
 import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.catalog.TableDesc;
-import org.apache.tajo.exception.ReturnStateUtil;
 import org.apache.tajo.common.TajoDataTypes;
 import org.apache.tajo.conf.TajoConf;
 import org.apache.tajo.engine.planner.global.DataChannel;
 import org.apache.tajo.engine.planner.global.ExecutionBlock;
 import org.apache.tajo.engine.planner.global.MasterPlan;
+import org.apache.tajo.exception.ReturnStateUtil;
 import org.apache.tajo.ipc.ClientProtos;
 import org.apache.tajo.jdbc.FetchResultSet;
 import org.apache.tajo.jdbc.TajoMemoryResultSet;
@@ -57,7 +60,6 @@ import java.util.*;
 import static org.apache.tajo.TajoConstants.DEFAULT_DATABASE_NAME;
 import static org.apache.tajo.plan.serder.PlanProto.ShuffleType.SCATTERED_HASH_SHUFFLE;
 import static org.junit.Assert.*;
-import static org.junit.Assert.assertEquals;
 
 @RunWith(Parameterized.class)
 public class TestTablePartitions extends QueryTestCaseBase {

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java b/tajo-core/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java
index 169f375..b139645 100644
--- a/tajo-core/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java
+++ b/tajo-core/src/test/java/org/apache/tajo/master/TestExecutionBlockCursor.java
@@ -80,7 +80,7 @@ public class TestExecutionBlockCursor {
 
     analyzer = new SQLAnalyzer();
     logicalPlanner = new LogicalPlanner(catalog, TablespaceManager.getInstance());
-    optimizer = new LogicalOptimizer(conf);
+    optimizer = new LogicalOptimizer(conf, catalog);
 
     dispatcher = new AsyncDispatcher();
     dispatcher.init(conf);

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/java/org/apache/tajo/querymaster/TestKillQuery.java
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/java/org/apache/tajo/querymaster/TestKillQuery.java b/tajo-core/src/test/java/org/apache/tajo/querymaster/TestKillQuery.java
index 8738dba..0e3e63e 100644
--- a/tajo-core/src/test/java/org/apache/tajo/querymaster/TestKillQuery.java
+++ b/tajo-core/src/test/java/org/apache/tajo/querymaster/TestKillQuery.java
@@ -100,7 +100,7 @@ public class TestKillQuery {
     CatalogService catalog = cluster.getMaster().getCatalog();
 
     LogicalPlanner planner = new LogicalPlanner(catalog, TablespaceManager.getInstance());
-    LogicalOptimizer optimizer = new LogicalOptimizer(conf);
+    LogicalOptimizer optimizer = new LogicalOptimizer(conf, catalog);
     Expr expr =  analyzer.parse(queryStr);
     LogicalPlan plan = planner.createPlan(defaultContext, expr);
 
@@ -164,7 +164,7 @@ public class TestKillQuery {
     CatalogService catalog = cluster.getMaster().getCatalog();
 
     LogicalPlanner planner = new LogicalPlanner(catalog, TablespaceManager.getInstance());
-    LogicalOptimizer optimizer = new LogicalOptimizer(conf);
+    LogicalOptimizer optimizer = new LogicalOptimizer(conf, catalog);
     Expr expr =  analyzer.parse(queryStr);
     LogicalPlan plan = planner.createPlan(defaultContext, expr);
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndex.sql
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndex.sql b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndex.sql
new file mode 100644
index 0000000..1cb8936
--- /dev/null
+++ b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndex.sql
@@ -0,0 +1 @@
+create index l_orderkey_idx on lineitem (l_orderkey asc null first);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnExpression.sql
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnExpression.sql b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnExpression.sql
new file mode 100644
index 0000000..0d19cb3
--- /dev/null
+++ b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnExpression.sql
@@ -0,0 +1 @@
+create index l_orderkey_100_lt10_idx on lineitem (l_orderkey*100 asc null first) where l_orderkey*100 > 10;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnLocation.sql
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnLocation.sql b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnLocation.sql
new file mode 100644
index 0000000..1cb8936
--- /dev/null
+++ b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnLocation.sql
@@ -0,0 +1 @@
+create index l_orderkey_idx on lineitem (l_orderkey asc null first);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnMultiAttrs.sql
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnMultiAttrs.sql b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnMultiAttrs.sql
new file mode 100644
index 0000000..3487d2e
--- /dev/null
+++ b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnMultiAttrs.sql
@@ -0,0 +1 @@
+create index l_orderkey_partkey_idx on lineitem (l_orderkey asc, l_partkey desc null last);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnMultiExprs.sql
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnMultiExprs.sql b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnMultiExprs.sql
new file mode 100644
index 0000000..7938005
--- /dev/null
+++ b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexOnMultiExprs.sql
@@ -0,0 +1 @@
+create index l_orderkey_100_l_linenumber_10_lt10_idx on lineitem (l_orderkey*100-l_linenumber*10 asc null first) where l_orderkey*100 > 10;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexWithCondition.sql
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexWithCondition.sql b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexWithCondition.sql
new file mode 100644
index 0000000..ad4ee47
--- /dev/null
+++ b/tajo-core/src/test/resources/queries/TestCreateIndex/testCreateIndexWithCondition.sql
@@ -0,0 +1 @@
+create index l_orderkey_partkey_lt10_idx on lineitem (l_orderkey asc, l_partkey desc) where l_partkey > 10;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleExprs.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleExprs.result b/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleExprs.result
new file mode 100644
index 0000000..bcb645d
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleExprs.result
@@ -0,0 +1,3 @@
+l_orderkey,l_linenumber
+-------------------------------
+3,2
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleKeys.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleKeys.result b/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleKeys.result
new file mode 100644
index 0000000..86d468e
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleKeys.result
@@ -0,0 +1,3 @@
+l_orderkey,l_shipdate,l_comment
+-------------------------------
+2,1997-01-28,ven requests. deposits breach a
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleKeys2.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleKeys2.result b/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleKeys2.result
new file mode 100644
index 0000000..86d468e
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestIndexScan/testOnMultipleKeys2.result
@@ -0,0 +1,3 @@
+l_orderkey,l_shipdate,l_comment
+-------------------------------
+2,1997-01-28,ven requests. deposits breach a
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestIndexScan/testOnSortedNonUniqueKeys.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestIndexScan/testOnSortedNonUniqueKeys.result b/tajo-core/src/test/resources/results/TestIndexScan/testOnSortedNonUniqueKeys.result
new file mode 100644
index 0000000..fb8a4c2
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestIndexScan/testOnSortedNonUniqueKeys.result
@@ -0,0 +1,4 @@
+l_orderkey,l_partkey,l_suppkey,l_linenumber,l_quantity,l_extendedprice,l_discount,l_tax,l_returnflag,l_linestatus,l_shipdate,l_commitdate,l_receiptdate,l_shipinstruct,l_shipmode,l_comment
+-------------------------------
+1,1,7706,1,17.0,21168.23,0.04,0.02,N,O,1996-03-13,1996-02-12,1996-03-22,DELIVER IN PERSON,TRUCK,egular courts above the
+1,1,7311,2,36.0,45983.16,0.09,0.06,N,O,1996-04-12,1996-02-28,1996-04-20,TAKE BACK RETURN,MAIL,ly final dependencies: slyly bold
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestIndexScan/testOnUnsortedTextKeys.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestIndexScan/testOnUnsortedTextKeys.result b/tajo-core/src/test/resources/results/TestIndexScan/testOnUnsortedTextKeys.result
new file mode 100644
index 0000000..86d468e
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestIndexScan/testOnUnsortedTextKeys.result
@@ -0,0 +1,3 @@
+l_orderkey,l_shipdate,l_comment
+-------------------------------
+2,1997-01-28,ven requests. deposits breach a
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestIndexScan/testWithGroupBy.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestIndexScan/testWithGroupBy.result b/tajo-core/src/test/resources/results/TestIndexScan/testWithGroupBy.result
new file mode 100644
index 0000000..2d1d12e
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestIndexScan/testWithGroupBy.result
@@ -0,0 +1,3 @@
+l_shipdate,?count
+-------------------------------
+1997-01-28,1
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestIndexScan/testWithJoin.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestIndexScan/testWithJoin.result b/tajo-core/src/test/resources/results/TestIndexScan/testWithJoin.result
new file mode 100644
index 0000000..d119969
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestIndexScan/testWithJoin.result
@@ -0,0 +1,4 @@
+l_shipdate,o_orderstatus
+-------------------------------
+1996-03-13,O
+1996-04-12,O
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestIndexScan/testWithSort.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestIndexScan/testWithSort.result b/tajo-core/src/test/resources/results/TestIndexScan/testWithSort.result
new file mode 100644
index 0000000..774a411
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestIndexScan/testWithSort.result
@@ -0,0 +1,4 @@
+l_shipdate
+-------------------------------
+1996-03-13
+1996-04-12
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestTajoCli/testHelpSessionVars.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestTajoCli/testHelpSessionVars.result b/tajo-core/src/test/resources/results/TestTajoCli/testHelpSessionVars.result
index 5c2ffe3..1f878f1 100644
--- a/tajo-core/src/test/resources/results/TestTajoCli/testHelpSessionVars.result
+++ b/tajo-core/src/test/resources/results/TestTajoCli/testHelpSessionVars.result
@@ -35,6 +35,8 @@ Available Session Variables:
 \set MAX_OUTPUT_FILE_SIZE [int value] - Maximum per-output file size (mb). 0 means infinite.
 \set NULL_CHAR [text value] - null char of text file output
 \set CODEGEN [true or false] - Runtime code generation enabled (experiment)
+\set INDEX_ENABLED [true or false] - index scan enabled
+\set INDEX_SELECTIVITY_THRESHOLD [real value] - the selectivity threshold for index scan
 \set PARTITION_NO_RESULT_OVERWRITE_ENABLED [true or false] - If True, a partitioned table is overwritten even if a sub query leads to no result. Otherwise, the table data will be kept if there is no result
 \set ARITHABORT [true or false] - If true, a running query will be terminated when an overflow or divide-by-zero occurs.
 \set FETCH_ROWNUM [int value] - Sets the number of rows at a time from Master

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-core/src/test/resources/results/TestTajoDump/testDump3.result
----------------------------------------------------------------------
diff --git a/tajo-core/src/test/resources/results/TestTajoDump/testDump3.result b/tajo-core/src/test/resources/results/TestTajoDump/testDump3.result
new file mode 100644
index 0000000..1bde41d
--- /dev/null
+++ b/tajo-core/src/test/resources/results/TestTajoDump/testDump3.result
@@ -0,0 +1,20 @@
+--
+-- Tajo database dump
+--
+
+
+--
+-- Database name: "TestTajoDump"
+--
+
+CREATE DATABASE IF NOT EXISTS "TestTajoDump";
+
+--
+-- Name: "TestTajoDump"."TableName1"; Type: TABLE; Storage: TEXT
+--
+CREATE TABLE "TestTajoDump"."TableName1" ("Age" INT4, "FirstName" TEXT, lastname TEXT) USING TEXT WITH ('text.delimiter'='|');
+
+--
+-- Name: test_idx; Type: INDEX; Index Method: TWO_LEVEL_BIN_TREE
+--
+CREATE INDEX test_idx on "TableName1" ( TestTajoDump.TableName1.Age asc null first, TestTajoDump.TableName1.FirstName desc null last )  location '${index.path}';
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-docs/src/main/sphinx/index/how_to_use.rst
----------------------------------------------------------------------
diff --git a/tajo-docs/src/main/sphinx/index/how_to_use.rst b/tajo-docs/src/main/sphinx/index/how_to_use.rst
index 09e1b72..c67af66 100644
--- a/tajo-docs/src/main/sphinx/index/how_to_use.rst
+++ b/tajo-docs/src/main/sphinx/index/how_to_use.rst
@@ -66,4 +66,4 @@ If you don't want to use the index scan feature anymore, you can simply disable
 
 .. note::
 
-     Once the index scan feature is enabled, Tajo currently always performs the index scan regardless of its efficiency. You should set this option when the expected number of retrieved tuples is sufficiently small.
\ No newline at end of file
+     Once the index scan feature is enabled, Tajo currently always performs the index scan regardless of its efficiency. You should set this option when the expected number of retrieved tuples is sufficiently small.

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java
----------------------------------------------------------------------
diff --git a/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java b/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java
index ebb19e4..22a4817 100644
--- a/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java
+++ b/tajo-jdbc/src/main/java/org/apache/tajo/jdbc/TajoStatement.java
@@ -20,10 +20,9 @@ package org.apache.tajo.jdbc;
 import com.google.common.collect.Lists;
 import org.apache.tajo.QueryId;
 import org.apache.tajo.SessionVars;
-import org.apache.tajo.exception.SQLExceptionUtil;
 import org.apache.tajo.client.TajoClient;
 import org.apache.tajo.client.TajoClientUtil;
-import org.apache.tajo.exception.TajoInternalError;
+import org.apache.tajo.exception.SQLExceptionUtil;
 import org.apache.tajo.ipc.ClientProtos;
 
 import java.sql.*;

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalOptimizer.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalOptimizer.java b/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalOptimizer.java
index fe49994..b1d8ce5 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalOptimizer.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalOptimizer.java
@@ -26,6 +26,7 @@ import org.apache.tajo.ConfigKey;
 import org.apache.tajo.OverridableConf;
 import org.apache.tajo.SessionVars;
 import org.apache.tajo.algebra.JoinType;
+import org.apache.tajo.catalog.CatalogService;
 import org.apache.tajo.conf.TajoConf;
 import org.apache.tajo.conf.TajoConf.ConfVars;
 import org.apache.tajo.exception.TajoException;
@@ -35,6 +36,7 @@ import org.apache.tajo.plan.expr.EvalTreeUtil;
 import org.apache.tajo.plan.joinorder.*;
 import org.apache.tajo.plan.logical.*;
 import org.apache.tajo.plan.rewrite.BaseLogicalPlanRewriteEngine;
+import org.apache.tajo.plan.rewrite.LogicalPlanRewriteRuleContext;
 import org.apache.tajo.plan.rewrite.LogicalPlanRewriteRuleProvider;
 import org.apache.tajo.plan.util.PlannerUtil;
 import org.apache.tajo.plan.visitor.BasicLogicalPlanVisitor;
@@ -54,11 +56,15 @@ import static org.apache.tajo.plan.joinorder.GreedyHeuristicJoinOrderAlgorithm.g
 public class LogicalOptimizer {
   private static final Log LOG = LogFactory.getLog(LogicalOptimizer.class.getName());
 
+  private CatalogService catalog;
   private BaseLogicalPlanRewriteEngine rulesBeforeJoinOpt;
   private BaseLogicalPlanRewriteEngine rulesAfterToJoinOpt;
   private JoinOrderAlgorithm joinOrderAlgorithm = new GreedyHeuristicJoinOrderAlgorithm();
 
-  public LogicalOptimizer(TajoConf conf) {
+  public LogicalOptimizer(TajoConf conf, CatalogService catalog) {
+
+    this.catalog = catalog;
+    // TODO: set the catalog instance to FilterPushdownRule
     Class clazz = conf.getClassVar(ConfVars.LOGICAL_PLAN_REWRITE_RULE_PROVIDER_CLASS);
     LogicalPlanRewriteRuleProvider provider = (LogicalPlanRewriteRuleProvider) ReflectionUtil.newInstance(clazz, conf);
 
@@ -76,7 +82,7 @@ public class LogicalOptimizer {
   }
 
   public LogicalNode optimize(OverridableConf context, LogicalPlan plan) throws TajoException {
-    rulesBeforeJoinOpt.rewrite(context, plan);
+    rulesBeforeJoinOpt.rewrite(new LogicalPlanRewriteRuleContext(context, plan, catalog));
 
     DirectedGraphCursor<String, BlockEdge> blockCursor =
         new DirectedGraphCursor<String, BlockEdge>(plan.getQueryBlockGraph(), plan.getRootBlock().getName());
@@ -89,7 +95,7 @@ public class LogicalOptimizer {
     } else {
       LOG.info("Skip join order optimization");
     }
-    rulesAfterToJoinOpt.rewrite(context, plan);
+    rulesAfterToJoinOpt.rewrite(new LogicalPlanRewriteRuleContext(context, plan, catalog));
     return plan.getRootBlock().getRoot();
   }
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlan.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlan.java b/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlan.java
index 9cc1e78..eab939d 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlan.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlan.java
@@ -27,6 +27,7 @@ import org.apache.tajo.catalog.Column;
 import org.apache.tajo.catalog.Schema;
 import org.apache.tajo.exception.TajoException;
 import org.apache.tajo.exception.TajoInternalError;
+import org.apache.tajo.plan.expr.AlgebraicUtil.IdentifiableNameBuilder;
 import org.apache.tajo.plan.expr.ConstEval;
 import org.apache.tajo.plan.expr.EvalNode;
 import org.apache.tajo.plan.logical.LogicalNode;
@@ -35,6 +36,7 @@ import org.apache.tajo.plan.logical.NodeType;
 import org.apache.tajo.plan.logical.RelationNode;
 import org.apache.tajo.plan.nameresolver.NameResolver;
 import org.apache.tajo.plan.nameresolver.NameResolvingMode;
+import org.apache.tajo.plan.rewrite.rules.AccessPathInfo;
 import org.apache.tajo.plan.visitor.ExplainLogicalPlanVisitor;
 import org.apache.tajo.util.TUtil;
 import org.apache.tajo.util.graph.DirectedGraphCursor;
@@ -168,6 +170,8 @@ public class LogicalPlan {
   /**
    * It generates an unique column name from Expr. It is usually used for an expression or predicate without
    * a specified name (i.e., alias).
+   * Here, some expressions require to be identified with their names in the future.
+   * For example, expressions must be identifiable with their names when getting targets in {@link LogicalPlanner#visitCreateIndex}.
    */
   public String generateUniqueColumnName(Expr expr) {
     String generatedName;
@@ -179,6 +183,11 @@ public class LogicalPlan {
     return generatedName;
   }
 
+  private String generateUniqueIdentifiableColumnName(Expr expr) {
+    IdentifiableNameBuilder nameBuilder = new IdentifiableNameBuilder(expr);
+    return nameBuilder.build();
+  }
+
   /**
    * It attaches a generated column name with a sequence id. It always keeps generated names unique.
    */
@@ -434,6 +443,7 @@ public class LogicalPlan {
     private final Map<String, String> columnAliasMap = TUtil.newHashMap();
     private final Map<OpType, List<Expr>> operatorToExprMap = TUtil.newHashMap();
     private final List<RelationNode> relationList = TUtil.newList();
+    private final Map<Integer, List<AccessPathInfo>> relNodePidAccessPathMap = TUtil.newHashMap();
     private boolean hasWindowFunction = false;
     private final Map<String, ConstEval> constantPoolByRef = Maps.newHashMap();
     private final Map<Expr, String> constantPool = Maps.newHashMap();
@@ -522,12 +532,30 @@ public class LogicalPlan {
       }
       canonicalNameToRelationMap.put(relation.getCanonicalName(), relation);
       relationList.add(relation);
+      relNodePidAccessPathMap.put(relation.getPID(), new ArrayList<AccessPathInfo>());
+    }
+
+    public void addRelation(RelationNode relation, List<AccessPathInfo> accessPathInfos) {
+      if (relation.hasAlias()) {
+        TUtil.putToNestedList(relationAliasMap, relation.getTableName(), relation.getCanonicalName());
+      }
+      canonicalNameToRelationMap.put(relation.getCanonicalName(), relation);
+      relationList.add(relation);
+      relNodePidAccessPathMap.put(relation.getPID(), new ArrayList<AccessPathInfo>());
+    }
+
+    public void addAccessPath(RelationNode relation, AccessPathInfo accessPathInfo) {
+      relNodePidAccessPathMap.get(relation.getPID()).add(accessPathInfo);
     }
 
     public Collection<RelationNode> getRelations() {
       return Collections.unmodifiableList(relationList);
     }
 
+    public List<AccessPathInfo> getAccessInfos(RelationNode relation) {
+      return Collections.unmodifiableList(relNodePidAccessPathMap.get(relation.getPID()));
+    }
+
     public boolean hasTableExpression() {
       return this.canonicalNameToRelationMap.size() > 0;
     }

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanPreprocessor.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanPreprocessor.java b/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanPreprocessor.java
index 0a8d1c4..f3743ee 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanPreprocessor.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanPreprocessor.java
@@ -473,6 +473,23 @@ public class LogicalPlanPreprocessor extends BaseAlgebraVisitor<LogicalPlanner.P
   }
 
   @Override
+  public LogicalNode visitCreateIndex(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, CreateIndex expr)
+      throws TajoException {
+    stack.push(expr);
+    LogicalNode child = visit(ctx, stack, expr.getChild());
+    stack.pop();
+
+    CreateIndexNode createIndex = ctx.plan.createNode(CreateIndexNode.class);
+    createIndex.setInSchema(child.getOutSchema());
+    createIndex.setOutSchema(child.getOutSchema());
+    return createIndex;
+  }
+
+  @Override
+  public LogicalNode visitDropIndex(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, DropIndex expr) {
+    return ctx.plan.createNode(DropIndexNode.class);
+  }
+
   public LogicalNode visitTruncateTable(LogicalPlanner.PlanContext ctx, Stack<Expr> stack, TruncateTable expr)
       throws TajoException {
     TruncateTableNode truncateTableNode = ctx.plan.createNode(TruncateTableNode.class);

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanner.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanner.java b/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanner.java
index 7f5cf9a..c9e101b 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanner.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/LogicalPlanner.java
@@ -39,7 +39,9 @@ import org.apache.tajo.catalog.exception.UndefinedColumnException;
 import org.apache.tajo.catalog.exception.UndefinedTableException;
 import org.apache.tajo.catalog.partition.PartitionMethodDesc;
 import org.apache.tajo.catalog.proto.CatalogProtos;
+import org.apache.tajo.catalog.proto.CatalogProtos.IndexMethod;
 import org.apache.tajo.common.TajoDataTypes;
+import org.apache.tajo.conf.TajoConf;
 import org.apache.tajo.datum.NullDatum;
 import org.apache.tajo.exception.ExceptionUtil;
 import org.apache.tajo.exception.TajoException;
@@ -54,6 +56,7 @@ import org.apache.tajo.plan.nameresolver.NameResolvingMode;
 import org.apache.tajo.plan.rewrite.rules.ProjectionPushDownRule;
 import org.apache.tajo.plan.util.ExprFinder;
 import org.apache.tajo.plan.util.PlannerUtil;
+import org.apache.tajo.plan.verifier.VerifyException;
 import org.apache.tajo.storage.StorageService;
 import org.apache.tajo.util.KeyValueSet;
 import org.apache.tajo.util.Pair;
@@ -879,6 +882,17 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
 
 
     // Building sort keys
+    SortSpec[] annotatedSortSpecs = annotateSortSpecs(block, referNames, sortSpecs);
+    if (annotatedSortSpecs.length == 0) {
+      return child;
+    } else {
+      sortNode.setSortSpecs(annotatedSortSpecs);
+      return sortNode;
+    }
+  }
+
+  private static SortSpec[] annotateSortSpecs(QueryBlock block, String [] referNames, Sort.SortSpec[] rawSortSpecs) {
+    int sortKeyNum = rawSortSpecs.length;
     Column column;
     List<SortSpec> annotatedSortSpecs = Lists.newArrayList();
     for (int i = 0; i < sortKeyNum; i++) {
@@ -888,17 +902,11 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
       } else if (block.namedExprsMgr.isEvaluated(refName)) {
         column = block.namedExprsMgr.getTarget(refName).getNamedColumn();
       } else {
-        throw new IllegalStateException("Unexpected State: " + StringUtils.join(sortSpecs));
+        throw new IllegalStateException("Unexpected State: " + StringUtils.join(rawSortSpecs));
       }
-      annotatedSortSpecs.add(new SortSpec(column, sortSpecs[i].isAscending(), sortSpecs[i].isNullFirst()));
-    }
-
-    if (annotatedSortSpecs.size() == 0) {
-      return child;
-    } else {
-      sortNode.setSortSpecs(annotatedSortSpecs.toArray(new SortSpec[annotatedSortSpecs.size()]));
-      return sortNode;
+      annotatedSortSpecs.add(new SortSpec(column, rawSortSpecs[i].isAscending(), rawSortSpecs[i].isNullFirst()));
     }
+    return annotatedSortSpecs.toArray(new SortSpec[annotatedSortSpecs.size()]);
   }
 
   /*===============================================================================================
@@ -2145,6 +2153,73 @@ public class LogicalPlanner extends BaseAlgebraVisitor<LogicalPlanner.PlanContex
     return alterTableNode;
   }
 
+  private static URI getIndexPath(PlanContext context, String databaseName, String indexName) {
+    return new Path(TajoConf.getWarehouseDir(context.queryContext.getConf()),
+        databaseName + "/" + indexName + "/").toUri();
+  }
+
+  @Override
+  public LogicalNode visitCreateIndex(PlanContext context, Stack<Expr> stack, CreateIndex createIndex)
+      throws TajoException {
+    stack.push(createIndex);
+    LogicalNode child = visit(context, stack, createIndex.getChild());
+    stack.pop();
+
+    QueryBlock block = context.queryBlock;
+    CreateIndexNode createIndexNode = block.getNodeFromExpr(createIndex);
+    if (CatalogUtil.isFQTableName(createIndex.getIndexName())) {
+      createIndexNode.setIndexName(createIndex.getIndexName());
+    } else {
+      createIndexNode.setIndexName(
+          CatalogUtil.buildFQName(context.queryContext.get(SessionVars.CURRENT_DATABASE), createIndex.getIndexName()));
+    }
+    createIndexNode.setUnique(createIndex.isUnique());
+    Sort.SortSpec[] sortSpecs = createIndex.getSortSpecs();
+    int sortKeyNum = sortSpecs.length;
+    String[] referNames = new String[sortKeyNum];
+
+    ExprNormalizedResult[] normalizedExprList = new ExprNormalizedResult[sortKeyNum];
+    for (int i = 0; i < sortKeyNum; i++) {
+      normalizedExprList[i] = normalizer.normalize(context, sortSpecs[i].getKey());
+    }
+    for (int i = 0; i < sortKeyNum; i++) {
+      // even if base expressions don't have their name,
+      // reference names should be identifiable for the later sort spec creation.
+      referNames[i] = block.namedExprsMgr.addExpr(normalizedExprList[i].baseExpr);
+      block.namedExprsMgr.addNamedExprArray(normalizedExprList[i].aggExprs);
+      block.namedExprsMgr.addNamedExprArray(normalizedExprList[i].scalarExprs);
+    }
+
+    createIndexNode.setExternal(createIndex.isExternal());
+    Collection<RelationNode> relations = block.getRelations();
+    assert relations.size() == 1;
+    createIndexNode.setKeySortSpecs(relations.iterator().next().getLogicalSchema(),
+        annotateSortSpecs(block, referNames, sortSpecs));
+    createIndexNode.setIndexMethod(IndexMethod.valueOf(createIndex.getMethodSpec().getName().toUpperCase()));
+    if (createIndex.isExternal()) {
+      createIndexNode.setIndexPath(new Path(createIndex.getIndexPath()).toUri());
+    } else {
+      createIndexNode.setIndexPath(
+          getIndexPath(context, context.queryContext.get(SessionVars.CURRENT_DATABASE), createIndex.getIndexName()));
+    }
+
+    if (createIndex.getParams() != null) {
+      KeyValueSet keyValueSet = new KeyValueSet();
+      keyValueSet.putAll(createIndex.getParams());
+      createIndexNode.setOptions(keyValueSet);
+    }
+
+    createIndexNode.setChild(child);
+    return createIndexNode;
+  }
+
+  @Override
+  public LogicalNode visitDropIndex(PlanContext context, Stack<Expr> stack, DropIndex dropIndex) {
+    DropIndexNode dropIndexNode = context.queryBlock.getNodeFromExpr(dropIndex);
+    dropIndexNode.setIndexName(dropIndex.getIndexName());
+    return dropIndexNode;
+  }
+
   @Override
   public LogicalNode visitTruncateTable(PlanContext context, Stack<Expr> stack, TruncateTable truncateTable)
       throws TajoException {

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/NamedExprsManager.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/NamedExprsManager.java b/tajo-plan/src/main/java/org/apache/tajo/plan/NamedExprsManager.java
index 08a9bd1..3ca2fe5 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/NamedExprsManager.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/NamedExprsManager.java
@@ -141,6 +141,7 @@ public class NamedExprsManager {
 
   /**
    * Adds an expression and returns a reference name.
+   * @param expr added expression
    */
   public String addExpr(Expr expr) {
     if (idToExprBiMap.inverse().containsKey(expr)) {

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AlgebraVisitor.java b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AlgebraVisitor.java
index 942dbb9..6149080 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AlgebraVisitor.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/AlgebraVisitor.java
@@ -53,6 +53,8 @@ public interface AlgebraVisitor<CONTEXT, RESULT> {
   RESULT visitAlterTablespace(CONTEXT ctx, Stack<Expr> stack, AlterTablespace expr) throws TajoException;
   RESULT visitAlterTable(CONTEXT ctx, Stack<Expr> stack, AlterTable expr) throws TajoException;
   RESULT visitTruncateTable(CONTEXT ctx, Stack<Expr> stack, TruncateTable expr) throws TajoException;
+  RESULT visitCreateIndex(CONTEXT ctx, Stack<Expr> stack, CreateIndex expr) throws TajoException;
+  RESULT visitDropIndex(CONTEXT ctx, Stack<Expr> stack, DropIndex expr) throws TajoException;
 
     // Insert or Update
   RESULT visitInsert(CONTEXT ctx, Stack<Expr> stack, Insert expr) throws TajoException;

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/BaseAlgebraVisitor.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/BaseAlgebraVisitor.java b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/BaseAlgebraVisitor.java
index e32bd85..2b4fb30 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/BaseAlgebraVisitor.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/algebra/BaseAlgebraVisitor.java
@@ -123,9 +123,15 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
     case AlterTable:
       current = visitAlterTable(ctx, stack, (AlterTable) expr);
       break;
+    case CreateIndex:
+      current = visitCreateIndex(ctx, stack, (CreateIndex) expr);
+      break;
     case TruncateTable:
       current = visitTruncateTable(ctx, stack, (TruncateTable)expr);
       break;
+    case DropIndex:
+      current = visitDropIndex(ctx, stack, (DropIndex) expr);
+      break;
 
     case Insert:
       current = visitInsert(ctx, stack, (Insert) expr);
@@ -481,6 +487,17 @@ public class BaseAlgebraVisitor<CONTEXT, RESULT> implements AlgebraVisitor<CONTE
     return null;
   }
 
+  @Override
+  public RESULT visitCreateIndex(CONTEXT ctx, Stack<Expr> stack, CreateIndex expr) throws TajoException {
+    return null;
+  }
+
+  @Override
+  public RESULT visitDropIndex(CONTEXT ctx, Stack<Expr> stack, DropIndex expr) {
+    return null;
+  }
+
+  @Override
   public RESULT visitTruncateTable(CONTEXT ctx, Stack<Expr> stack, TruncateTable expr) throws TajoException {
     return null;
   }

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AlgebraicUtil.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AlgebraicUtil.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AlgebraicUtil.java
index c6b7354..cba41c1 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AlgebraicUtil.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/AlgebraicUtil.java
@@ -18,7 +18,11 @@
 
 package org.apache.tajo.plan.expr;
 
+import org.apache.tajo.algebra.*;
 import org.apache.tajo.catalog.Column;
+import org.apache.tajo.exception.TajoException;
+import org.apache.tajo.plan.PlanningException;
+import org.apache.tajo.plan.visitor.SimpleAlgebraVisitor;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -424,4 +428,70 @@ public class AlgebraicUtil {
       found.add(node);
     }
   }
+
+  public static class IdentifiableNameBuilder extends SimpleAlgebraVisitor<Object, Object> {
+    private Expr expr;
+    private StringBuilder nameBuilder = new StringBuilder();
+
+    public IdentifiableNameBuilder(Expr expr) {
+      this.expr = expr;
+    }
+
+    public String build() {
+      Stack<Expr> stack = new Stack<Expr>();
+      stack.push(expr);
+      try {
+        this.visit(null, stack, expr);
+      } catch (TajoException e) {
+
+      }
+      return nameBuilder.deleteCharAt(nameBuilder.length()-1).toString();
+    }
+
+    @Override
+    public Object visitBinaryOperator(Object ctx, Stack<Expr> stack, BinaryOperator expr) throws TajoException {
+      addIntermExpr(expr);
+      return super.visitBinaryOperator(ctx, stack, expr);
+    }
+
+    private void append(String str) {
+      nameBuilder.append(str).append("_");
+    }
+
+    private void addIntermExpr(Expr expr) {
+      this.append(expr.getType().name());
+    }
+
+    @Override
+    public Object visitColumnReference(Object ctx, Stack<Expr> stack, ColumnReferenceExpr expr)
+        throws TajoException {
+      this.append(expr.getName());
+      return super.visitColumnReference(ctx, stack, expr);
+    }
+
+    @Override
+    public Object visitLiteral(Object ctx, Stack<Expr> stack, LiteralValue expr) throws TajoException {
+      this.append(expr.getValue());
+      return super.visitLiteral(ctx, stack, expr);
+    }
+
+    @Override
+    public Object visitNullLiteral(Object ctx, Stack<Expr> stack, NullLiteral expr) throws TajoException {
+      this.append("null");
+      return super.visitNullLiteral(ctx, stack, expr);
+    }
+
+    @Override
+    public Object visitTimestampLiteral(Object ctx, Stack<Expr> stack, TimestampLiteral expr) throws TajoException {
+      this.append(expr.getDate().toString());
+      this.append(expr.getTime().toString());
+      return super.visitTimestampLiteral(ctx, stack, expr);
+    }
+
+    @Override
+    public Object visitTimeLiteral(Object ctx, Stack<Expr> stack, TimeLiteral expr) throws TajoException {
+      this.append(expr.getTime().toString());
+      return super.visitTimeLiteral(ctx, stack, expr);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/expr/EvalTreeUtil.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/EvalTreeUtil.java b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/EvalTreeUtil.java
index 1227855..7ff695b 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/expr/EvalTreeUtil.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/expr/EvalTreeUtil.java
@@ -385,7 +385,7 @@ public class EvalTreeUtil {
     return !leftQualifier.equals(rightQualifier);
   }
 
-  static boolean isSingleColumn(EvalNode evalNode) {
+  public static boolean isSingleColumn(EvalNode evalNode) {
     return EvalTreeUtil.findUniqueColumns(evalNode).size() == 1;
   }
   
@@ -542,6 +542,10 @@ public class EvalTreeUtil {
 
       return evalNode;
     }
+
+    public List<EvalNode> getEvalNodes() {
+      return evalNodes;
+    }
   }
 
   public static class OuterJoinSensitiveEvalFinder extends BasicEvalNodeVisitor<Object, Object> {

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/logical/CreateIndexNode.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/logical/CreateIndexNode.java b/tajo-plan/src/main/java/org/apache/tajo/plan/logical/CreateIndexNode.java
new file mode 100644
index 0000000..df7eb34
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/logical/CreateIndexNode.java
@@ -0,0 +1,161 @@
+/*
+ * 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.plan.logical;
+
+import com.google.common.base.Objects;
+import com.google.gson.annotations.Expose;
+import org.apache.tajo.catalog.IndexMeta;
+import org.apache.tajo.catalog.Schema;
+import org.apache.tajo.catalog.SortSpec;
+import org.apache.tajo.plan.PlanString;
+import org.apache.tajo.util.KeyValueSet;
+
+import java.net.URI;
+
+import static org.apache.tajo.catalog.proto.CatalogProtos.IndexMethod;
+
+public class CreateIndexNode extends UnaryNode implements Cloneable {
+  @Expose private IndexMeta indexMeta;
+  @Expose private boolean external;
+
+  public CreateIndexNode(int pid) {
+    super(pid, NodeType.CREATE_INDEX);
+    this.indexMeta = new IndexMeta();
+  }
+
+  public void setUnique(boolean unique) {
+    indexMeta.setUnique(unique);
+  }
+
+  public boolean isUnique() {
+    return indexMeta.isUnique();
+  }
+
+  public void setIndexName(String indexName) {
+    indexMeta.setIndexName(indexName);
+  }
+
+  public String getIndexName() {
+    return indexMeta.getIndexName();
+  }
+
+  public void setIndexPath(URI indexPath) {
+    indexMeta.setIndexPath(indexPath);
+  }
+
+  public URI getIndexPath() {
+    return indexMeta.getIndexPath();
+  }
+
+  public void setKeySortSpecs(Schema targetRelationSchema, SortSpec[] sortSpecs) {
+    indexMeta.setKeySortSpecs(targetRelationSchema, sortSpecs);
+  }
+
+  public SortSpec[] getKeySortSpecs() {
+    return indexMeta.getKeySortSpecs();
+  }
+
+  public void setIndexMethod(IndexMethod indexType) {
+    indexMeta.setIndexMethod(indexType);
+  }
+
+  public IndexMethod getIndexMethod() {
+    return indexMeta.getIndexMethod();
+  }
+
+  public void setOptions(KeyValueSet options) {
+    indexMeta.setOptions(options);
+  }
+
+  public KeyValueSet getOptions() {
+    return indexMeta.getOptions();
+  }
+
+  public Schema getTargetRelationSchema() {
+    return indexMeta.getTargetRelationSchema();
+  }
+
+  public boolean hasOptions() {
+    return indexMeta.getOptions() != null;
+  }
+
+  public void setClustered(boolean clustered) {
+    indexMeta.setClustered(clustered);
+  }
+
+  public boolean isClustered() {
+    return indexMeta.isClustered();
+  }
+
+  public void setExternal(boolean external) {
+    this.external = external;
+  }
+
+  public boolean isExternal() {
+    return this.external;
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(indexMeta, external);
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj instanceof CreateIndexNode) {
+      CreateIndexNode other = (CreateIndexNode) obj;
+      return this.indexMeta.equals(other.indexMeta) && this.external == other.external;
+    }
+    return false;
+  }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    CreateIndexNode createIndexNode = (CreateIndexNode) super.clone();
+    createIndexNode.indexMeta = (IndexMeta) this.indexMeta.clone();
+    createIndexNode.external = this.external;
+    return createIndexNode;
+  }
+
+  private String getSortSpecString() {
+    StringBuilder sb = new StringBuilder("Column [key= ");
+    SortSpec[] sortSpecs = indexMeta.getKeySortSpecs();
+    for (int i = 0; i < sortSpecs.length; i++) {
+      sb.append(sortSpecs[i].getSortKey().getQualifiedName()).append(" ")
+          .append(sortSpecs[i].isAscending() ? "asc" : "desc");
+      if(i < sortSpecs.length - 1) {
+        sb.append(",");
+      }
+    }
+    sb.append("]");
+    return sb.toString();
+  }
+
+  @Override
+  public String toString() {
+    return "CreateIndex (indexName=" + indexMeta.getIndexName() + ", indexPath=" + indexMeta.getIndexPath() +
+        ", type=" + indexMeta.getIndexMethod().name() +
+        ", isUnique=" + indexMeta.isUnique() + ", " + getSortSpecString() + ", isExternal=" + isExternal() + ")";
+  }
+
+  @Override
+  public PlanString getPlanString() {
+    return new PlanString(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/logical/DropIndexNode.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/logical/DropIndexNode.java b/tajo-plan/src/main/java/org/apache/tajo/plan/logical/DropIndexNode.java
new file mode 100644
index 0000000..da7018a
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/logical/DropIndexNode.java
@@ -0,0 +1,92 @@
+/*
+ * 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.plan.logical;
+
+import com.google.common.base.Objects;
+import org.apache.tajo.plan.PlanString;
+
+public class DropIndexNode extends LogicalNode implements Cloneable {
+  private String indexName;
+
+  public DropIndexNode(int pid) {
+    super(pid, NodeType.DROP_INDEX);
+  }
+
+  public void init(String indexName) {
+    this.indexName = indexName;
+  }
+
+  public int hashCode() {
+    return Objects.hashCode(indexName);
+  }
+
+  @Override
+  public int childNum() {
+    return 0;
+  }
+
+  @Override
+  public LogicalNode getChild(int idx) {
+    return null;
+  }
+
+  public boolean equals(Object obj) {
+    if (obj instanceof DropIndexNode) {
+      DropIndexNode other = (DropIndexNode) obj;
+      return super.equals(other) &&
+          this.indexName.equals(other.indexName);
+    }
+    return false;
+  }
+
+  @Override
+  public void preOrder(LogicalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+
+  @Override
+  public void postOrder(LogicalNodeVisitor visitor) {
+    visitor.visit(this);
+  }
+
+  @Override
+  public PlanString getPlanString() {
+    return new PlanString(this);
+  }
+
+  @Override
+  public Object clone() throws CloneNotSupportedException {
+    DropIndexNode clone = (DropIndexNode) super.clone();
+    clone.indexName = this.indexName;
+    return clone;
+  }
+
+  @Override
+  public String toString() {
+    return "DROP INDEX " + indexName;
+  }
+
+  public void setIndexName(String indexName) {
+    this.indexName = indexName;
+  }
+
+  public String getIndexName() {
+    return indexName;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/logical/IndexScanNode.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/logical/IndexScanNode.java b/tajo-plan/src/main/java/org/apache/tajo/plan/logical/IndexScanNode.java
index 8b73756..ebf6c4b 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/logical/IndexScanNode.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/logical/IndexScanNode.java
@@ -24,56 +24,54 @@ import com.google.gson.Gson;
 import com.google.gson.annotations.Expose;
 
 import org.apache.tajo.catalog.Schema;
-import org.apache.tajo.catalog.SortSpec;
-import org.apache.tajo.datum.Datum;
+import org.apache.tajo.plan.rewrite.rules.IndexScanInfo.SimplePredicate;
 import org.apache.tajo.plan.serder.PlanGsonHelper;
+import org.apache.tajo.util.TUtil;
+
+import java.net.URI;
 
 public class IndexScanNode extends ScanNode {
-  @Expose private SortSpec [] sortKeys;
   @Expose private Schema keySchema = null;
-  @Expose private Datum[] datum = null;
+  @Expose private URI indexPath = null;
+  @Expose private SimplePredicate[] predicates = null;
+
+  public IndexScanNode(int pid) {
+    super(pid);
+    setType(NodeType.INDEX_SCAN);
+  }
   
   public IndexScanNode(int pid, ScanNode scanNode ,
-      Schema keySchema , Datum[] datum, SortSpec[] sortKeys ) {
-    super(pid);
+      Schema keySchema , SimplePredicate[] predicates, URI indexPath) {
+    this(pid);
     init(scanNode.getTableDesc());
     setQual(scanNode.getQual());
     setInSchema(scanNode.getInSchema());
     setTargets(scanNode.getTargets());
-    setType(NodeType.BST_INDEX_SCAN);
-    this.sortKeys = sortKeys;
-    this.keySchema = keySchema;
-    this.datum = datum;
+    this.set(keySchema, predicates, indexPath);
   }
-  
-  public SortSpec[] getSortKeys() {
-    return this.sortKeys;
+
+  public void set(Schema keySchema, SimplePredicate[] predicates, URI indexPath) {
+    this.keySchema = keySchema;
+    this.indexPath = indexPath;
+    this.predicates = predicates;
   }
   
   public Schema getKeySchema() {
     return this.keySchema;
   }
-  
-  public Datum[] getDatum() {
-    return this.datum;
-  }
-  
-  public void setSortKeys(SortSpec[] sortKeys) {
-    this.sortKeys = sortKeys;
+
+  public SimplePredicate[] getPredicates() {
+    return predicates;
   }
   
-  public void setKeySchema( Schema keySchema ) {
-    this.keySchema = keySchema;
-  }
-
   @Override
   public String toString() {
     Gson gson = PlanGsonHelper.getInstance();
     StringBuilder builder = new StringBuilder();
     builder.append("IndexScanNode : {\n");
+    builder.append("  \"indexPath\" : \"" + gson.toJson(this.indexPath) + "\"\n");
     builder.append("  \"keySchema\" : \"" + gson.toJson(this.keySchema) + "\"\n");
-    builder.append("  \"sortKeys\" : \"" + gson.toJson(this.sortKeys) + " \"\n");
-    builder.append("  \"datums\" : \"" + gson.toJson(this.datum) + "\"\n");
+    builder.append("  \"keySortSpecs\" : \"" + gson.toJson(predicates) + " \"\n");
     builder.append("      <<\"superClass\" : " + super.toString());
     builder.append(">>}");
     builder.append("}");
@@ -84,9 +82,9 @@ public class IndexScanNode extends ScanNode {
   public int hashCode() {
     final int prime = 31;
     int result = super.hashCode();
-    result = prime * result + Arrays.hashCode(datum);
+    result = prime * result + indexPath.hashCode();
     result = prime * result + ((keySchema == null) ? 0 : keySchema.hashCode());
-    result = prime * result + Arrays.hashCode(sortKeys);
+    result = prime * result + Arrays.hashCode(predicates);
     return result;
   }
 
@@ -94,25 +92,12 @@ public class IndexScanNode extends ScanNode {
   public boolean equals(Object obj) {
     if (obj instanceof IndexScanNode) {
       IndexScanNode other = (IndexScanNode) obj;
-      
       boolean eq = super.equals(other);
-      eq = eq && this.sortKeys.length == other.sortKeys.length;
-      if(eq) {
-        for(int i = 0 ; i < this.sortKeys.length ; i ++) {
-          eq = eq && this.sortKeys[i].getSortKey().equals(
-              other.sortKeys[i].getSortKey());
-          eq = eq && this.sortKeys[i].isAscending()
-              == other.sortKeys[i].isAscending();
-          eq = eq && this.sortKeys[i].isNullFirst()
-              == other.sortKeys[i].isNullFirst();
-        }
-      }
-      if(eq) {
-        for(int i = 0 ; i < this.datum.length ; i ++ ) {
-          eq = eq && this.datum[i].equals(other.datum[i]);
-        }
-      }
-     return eq;
+      eq &= this.indexPath.equals(other.indexPath);
+      eq &= TUtil.checkEquals(this.predicates, other.predicates);
+      eq &= this.keySchema.equals(other.keySchema);
+
+      return eq;
     }   
     return false;
   } 
@@ -121,15 +106,16 @@ public class IndexScanNode extends ScanNode {
   public Object clone() throws CloneNotSupportedException {
     IndexScanNode indexNode = (IndexScanNode) super.clone();
     indexNode.keySchema = (Schema) this.keySchema.clone();
-    indexNode.sortKeys = new SortSpec[this.sortKeys.length];
-    for(int i = 0 ; i < sortKeys.length ; i ++ )
-      indexNode.sortKeys[i] = (SortSpec) this.sortKeys[i].clone();
-    indexNode.datum = new Datum[this.datum.length];
-    for(int i = 0 ; i < datum.length ; i ++ ) {
-      indexNode.datum[i] = this.datum[i];
-    }
+    indexNode.predicates = new SimplePredicate[this.predicates.length];
+    for(int i = 0 ; i < this.predicates.length ; i ++ )
+      indexNode.predicates[i] = (SimplePredicate) this.predicates[i].clone();
+    indexNode.indexPath = this.indexPath;
     return indexNode;
   }
+
+  public URI getIndexPath() {
+    return indexPath;
+  }
 }
 
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/logical/NodeType.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/logical/NodeType.java b/tajo-plan/src/main/java/org/apache/tajo/plan/logical/NodeType.java
index 75ae3b7..1ebea8b 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/logical/NodeType.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/logical/NodeType.java
@@ -45,7 +45,7 @@ public enum NodeType {
   TABLE_SUBQUERY(TableSubQueryNode.class),
   SCAN(ScanNode.class),
   PARTITIONS_SCAN(PartitionedTableScanNode.class),
-  BST_INDEX_SCAN(IndexScanNode.class),
+  INDEX_SCAN(IndexScanNode.class),
   STORE(StoreTableNode.class),
   INSERT(InsertNode.class),
 
@@ -55,6 +55,8 @@ public enum NodeType {
   DROP_TABLE(DropTableNode.class),
   ALTER_TABLESPACE (AlterTablespaceNode.class),
   ALTER_TABLE (AlterTableNode.class),
+  CREATE_INDEX(CreateIndexNode.class),
+  DROP_INDEX(DropIndexNode.class),
   TRUNCATE_TABLE (TruncateTableNode.class);
 
   private final Class<? extends LogicalNode> baseClass;

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteEngine.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteEngine.java b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteEngine.java
index f6f1e63..9a541d9 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteEngine.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteEngine.java
@@ -69,18 +69,19 @@ public class BaseLogicalPlanRewriteEngine implements LogicalPlanRewriteEngine {
   /**
    * Rewrite a logical plan with all query rewrite rules added to this engine.
    *
-   * @param plan The plan to be rewritten with all query rewrite rule.
+   * @param context
    * @return The rewritten plan.
    */
-  public LogicalPlan rewrite(OverridableConf queryContext, LogicalPlan plan) throws TajoException {
+  public LogicalPlan rewrite(LogicalPlanRewriteRuleContext context) throws TajoException {
     LogicalPlanRewriteRule rule;
+    LogicalPlan plan = null;
     for (Entry<String, LogicalPlanRewriteRule> rewriteRule : rewriteRules.entrySet()) {
       rule = rewriteRule.getValue();
-      if (rule.isEligible(queryContext, plan)) {
-        plan = rule.rewrite(queryContext, plan);
+      if (rule.isEligible(context)) {
         if (LOG.isDebugEnabled()) {
           LOG.debug("The rule \"" + rule.getName() + " \" rewrites the query.");
         }
+        plan = rule.rewrite(context);
       }
     }
 

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteRuleProvider.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteRuleProvider.java b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteRuleProvider.java
index eb96149..dcfd6bf 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteRuleProvider.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/BaseLogicalPlanRewriteRuleProvider.java
@@ -19,6 +19,7 @@
 package org.apache.tajo.plan.rewrite;
 
 import org.apache.tajo.conf.TajoConf;
+import org.apache.tajo.plan.rewrite.rules.AccessPathRewriter;
 import org.apache.tajo.plan.rewrite.rules.FilterPushDownRule;
 import org.apache.tajo.plan.rewrite.rules.PartitionedTableRewriter;
 import org.apache.tajo.plan.rewrite.rules.ProjectionPushDownRule;
@@ -52,7 +53,8 @@ public class BaseLogicalPlanRewriteRuleProvider extends LogicalPlanRewriteRulePr
   public Collection<Class<? extends LogicalPlanRewriteRule>> getPostRules() {
     List<Class<? extends LogicalPlanRewriteRule>> rules = TUtil.newList(
         ProjectionPushDownRule.class,
-        PartitionedTableRewriter.class
+        PartitionedTableRewriter.class,
+        AccessPathRewriter.class
     );
     return rules;
   }

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteEngine.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteEngine.java b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteEngine.java
index 99d8979..a621921 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteEngine.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteEngine.java
@@ -18,7 +18,6 @@
 
 package org.apache.tajo.plan.rewrite;
 
-import org.apache.tajo.OverridableConf;
 import org.apache.tajo.exception.TajoException;
 import org.apache.tajo.plan.LogicalPlan;
 
@@ -29,5 +28,5 @@ public interface LogicalPlanRewriteEngine {
    * @param plan The plan to be rewritten with all query rewrite rule.
    * @return The rewritten plan.
    */
-  LogicalPlan rewrite(OverridableConf queryContext, LogicalPlan plan) throws TajoException;
+  LogicalPlan rewrite(LogicalPlanRewriteRuleContext context) throws TajoException;
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteRule.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteRule.java b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteRule.java
index d5d02f2..6643d28 100644
--- a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteRule.java
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteRule.java
@@ -18,10 +18,8 @@
 
 package org.apache.tajo.plan.rewrite;
 
-import org.apache.tajo.OverridableConf;
 import org.apache.tajo.exception.TajoException;
 import org.apache.tajo.plan.LogicalPlan;
-import org.apache.tajo.plan.PlanningException;
 
 /**
  * An interface for a rewrite rule.
@@ -44,7 +42,7 @@ public interface LogicalPlanRewriteRule {
    * @param plan The plan to be checked
    * @return True if this rule can be applied to a given plan. Otherwise, false.
    */
-  boolean isEligible(OverridableConf queryContext, LogicalPlan plan);
+  boolean isEligible(LogicalPlanRewriteRuleContext context);
 
   /**
    * Updates a logical plan and returns an updated logical plan rewritten by this rule.
@@ -54,5 +52,5 @@ public interface LogicalPlanRewriteRule {
    * @param plan Input logical plan. It will not be modified.
    * @return The rewritten logical plan.
    */
-  LogicalPlan rewrite(OverridableConf queryContext, LogicalPlan plan) throws TajoException;
+  LogicalPlan rewrite(LogicalPlanRewriteRuleContext context) throws TajoException;
 }

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteRuleContext.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteRuleContext.java b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteRuleContext.java
new file mode 100644
index 0000000..6c43112
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/LogicalPlanRewriteRuleContext.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.plan.rewrite;
+
+import org.apache.tajo.OverridableConf;
+import org.apache.tajo.catalog.CatalogService;
+import org.apache.tajo.plan.LogicalPlan;
+
+public class LogicalPlanRewriteRuleContext {
+
+  private OverridableConf queryContext;
+  private LogicalPlan plan;
+  private CatalogService catalog;
+
+  public LogicalPlanRewriteRuleContext(OverridableConf queryContext, LogicalPlan plan) {
+    setQueryContext(queryContext);
+    setPlan(plan);
+  }
+
+  public LogicalPlanRewriteRuleContext(OverridableConf queryContext, LogicalPlan plan, CatalogService catalog) {
+    setQueryContext(queryContext);
+    setPlan(plan);
+    setCatalog(catalog);
+  }
+
+  public void setCatalog(CatalogService catalog) {
+    this.catalog = catalog;
+  }
+
+  public CatalogService getCatalog() {
+    return catalog;
+  }
+
+  public OverridableConf getQueryContext() {
+    return queryContext;
+  }
+
+  public void setQueryContext(OverridableConf queryContext) {
+    this.queryContext = queryContext;
+  }
+
+  public LogicalPlan getPlan() {
+    return plan;
+  }
+
+  public void setPlan(LogicalPlan plan) {
+    this.plan = plan;
+  }
+}

http://git-wip-us.apache.org/repos/asf/tajo/blob/9840d378/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/rules/AccessPathInfo.java
----------------------------------------------------------------------
diff --git a/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/rules/AccessPathInfo.java b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/rules/AccessPathInfo.java
new file mode 100644
index 0000000..477ccaf
--- /dev/null
+++ b/tajo-plan/src/main/java/org/apache/tajo/plan/rewrite/rules/AccessPathInfo.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.tajo.plan.rewrite.rules;
+
+import org.apache.tajo.catalog.statistics.TableStats;
+
+public abstract class AccessPathInfo {
+  public enum ScanTypeControl {
+    INDEX_SCAN,
+    SEQ_SCAN
+  }
+
+  private ScanTypeControl scanType;
+  private TableStats tableStats;
+
+  public AccessPathInfo(ScanTypeControl scanType, TableStats tableStats) {
+    this.scanType = scanType;
+    this.tableStats = tableStats;
+  }
+
+  public ScanTypeControl getScanType() {
+    return scanType;
+  }
+
+  public TableStats getTableStats() {
+    return tableStats;
+  }
+
+  public void setTableStats(TableStats tableStats) {
+    this.tableStats = tableStats;
+  }
+
+  public boolean hasTableStats() {
+    return this.tableStats != null;
+  }
+}


Mime
View raw message