You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by zt...@apache.org on 2022/03/16 06:37:15 UTC

[hawq] 01/02: HAWQ-1811. Sync with OushuDB - Phase IV

This is an automated email from the ASF dual-hosted git repository.

ztao1987 pushed a commit to branch ztao
in repository https://gitbox.apache.org/repos/asf/hawq.git

commit c3e91931e4340ef33abdf63a957f76788edb79d7
Author: ztao1987 <zh...@gmail.com>
AuthorDate: Wed Mar 16 14:34:58 2022 +0800

    HAWQ-1811. Sync with OushuDB - Phase IV
---
 CMakeLists.txt                                 |     3 +-
 contrib/hornet/hornet.c                        |   131 +
 contrib/hornet/load_hornet_helper_function.sql |    24 +-
 contrib/hornet/newcdbhash.c                    |   177 +
 contrib/hornet/oldcdbhash.c                    |   412 +
 contrib/magma/magma.c                          |   258 +-
 contrib/orc/orc.c                              |     6 +-
 src/all_src_files.txt                          |     8 +
 src/backend/access/appendonly/aomd.c           |    55 +
 src/backend/access/bitmap/bitmapinsert.c       |     3 +-
 src/backend/access/bitmap/bitmappages.c        |     2 +-
 src/backend/access/bitmap/bitmapsearch.c       |     4 +-
 src/backend/access/common/scankey.c            |    15 +-
 src/backend/access/external/plugstorage.c      |    54 +-
 src/backend/access/index/catquery.c            |    12 +-
 src/backend/access/index/gperf.init            |    10 +-
 src/backend/access/nbtree/nbtsearch.c          |     4 +-
 src/backend/access/orc/orcam.c                 |   417 +-
 src/backend/access/orc/orcsegfiles.c           |    34 +-
 src/backend/bootstrap/bootparse.y              |    38 +
 src/backend/catalog/Makefile                   |     2 +
 src/backend/catalog/aclchk.c                   |    83 +-
 src/backend/catalog/catalog.c                  |    24 +-
 src/backend/catalog/core/catcoregen.py         |     8 +
 src/backend/catalog/dependency.c               |    50 +
 src/backend/catalog/index.c                    |     3 +-
 src/backend/catalog/namespace.c                |    71 +
 src/backend/catalog/skylon_elabel.c            |    62 +
 src/backend/catalog/skylon_elabel_attribute.c  |    66 +
 src/backend/catalog/skylon_graph.c             |    60 +
 src/backend/catalog/skylon_graph_elabel.c      |    59 +
 src/backend/catalog/skylon_graph_vlabel.c      |    59 +
 src/backend/catalog/skylon_index.c             |    73 +
 src/backend/catalog/skylon_vlabel.c            |    60 +
 src/backend/catalog/skylon_vlabel_attribute.c  |    64 +
 src/backend/catalog/system_views.sql           |    29 +
 src/backend/cdb/Makefile                       |     1 -
 src/backend/cdb/cdbdatalocality.c              |   187 +-
 src/backend/cdb/cdbexplain.c                   |   165 +-
 src/backend/cdb/cdbplan.c                      |     8 +
 src/backend/cdb/dispatcher.c                   |     1 -
 src/backend/cdb/dispatcher_new.c               |    10 +-
 src/backend/commands/copy.c                    |     4 +
 src/backend/commands/explain.c                 |     9 -
 src/backend/commands/indexcmds.c               |    80 +-
 src/backend/commands/tablecmds.c               |  1428 ++++
 src/backend/commands/vacuum.c                  |    20 +
 src/backend/executor/execIndexscan.c           |    34 +-
 src/backend/executor/execMain.c                |    34 +-
 src/backend/executor/execUtils.c               |    13 +-
 src/backend/executor/functions.c               |     4 +-
 src/backend/executor/newExecutor.c             |    12 +-
 src/backend/executor/nodeExternalscan.c        |   104 +-
 src/backend/executor/nodeIndexscan.c           |    50 +-
 src/backend/executor/nodeNestloop.c            |    38 +-
 src/backend/executor/nodeSubplan.c             |    68 +-
 src/backend/executor/spi.c                     |     5 +-
 src/backend/nodes/copyfuncs.c                  |    35 +-
 src/backend/nodes/equalfuncs.c                 |     9 +
 src/backend/nodes/outfast.c                    |    30 +
 src/backend/nodes/outfuncs.c                   |     9 +
 src/backend/nodes/readfast.c                   |    33 +-
 src/backend/nodes/readfuncs.c                  |    12 +-
 src/backend/optimizer/path/indxpath.c          |   108 +-
 src/backend/optimizer/plan/createplan.c        |    33 +-
 src/backend/optimizer/plan/newPlanner.c        |    70 +-
 src/backend/optimizer/plan/planner.c           |     2 +-
 src/backend/optimizer/plan/setrefs.c           |    26 +
 src/backend/parser/analyze.c                   |   451 +-
 src/backend/parser/gram.y                      |   262 +-
 src/backend/parser/parse_clause.c              |   183 +-
 src/backend/parser/parse_expr.c                |    49 +-
 src/backend/parser/parse_relation.c            |    19 +-
 src/backend/tcop/postgres.c                    |    22 +-
 src/backend/tcop/utility.c                     |    56 +
 src/backend/utils/cache/lsyscache.c            |    52 +-
 src/backend/utils/init/globals.c               |     2 -
 src/backend/utils/misc/guc.c                   |    25 +-
 src/backend/utils/mmgr/Makefile                |     2 +
 src/bin/psql/tab-complete.c                    |    87 +-
 src/include/access/aomd.h                      |    10 +
 src/include/access/orcam.h                     |    60 +-
 src/include/access/orcsegfiles.h               |     3 +-
 src/include/access/plugstorage.h               |    13 +-
 src/include/access/relscan.h                   |    10 +-
 src/include/access/skey.h                      |    20 +-
 src/include/catalog/calico.pl                  |     8 +
 src/include/catalog/dependency.h               |     3 +
 src/include/catalog/indexing.h                 |    21 +
 src/include/catalog/namespace.h                |     3 +-
 src/include/catalog/pg_tidycat.h               |     8 +
 src/include/catalog/pg_type.h                  |    23 +
 src/include/catalog/skylon_elabel.h            |   113 +
 src/include/catalog/skylon_elabel_attribute.h  |   118 +
 src/include/catalog/skylon_graph.h             |   107 +
 src/include/catalog/skylon_graph_elabel.h      |   112 +
 src/include/catalog/skylon_graph_vlabel.h      |   111 +
 src/include/catalog/skylon_index.h             |    58 +
 src/include/catalog/skylon_vlabel.h            |   106 +
 src/include/catalog/skylon_vlabel_attribute.h  |   116 +
 src/include/cdb/cdbexplain.h                   |     5 -
 src/include/cdb/dispatcher_new.h               |     3 +
 src/include/commands/tablecmds.h               |    12 +
 src/include/executor/executor.h                |     7 +-
 src/include/executor/nodeIndexscan.h           |     1 +
 src/include/miscadmin.h                        |     2 -
 src/include/nodes/execnodes.h                  |    10 +-
 src/include/nodes/nodes.h                      |     4 +
 src/include/nodes/parsenodes.h                 |    43 +-
 src/include/nodes/plannodes.h                  |     9 +-
 src/include/optimizer/cost.h                   |     2 +-
 src/include/optimizer/newPlanner.h             |    20 +-
 src/include/parser/gramparse.h                 |     7 +-
 src/include/parser/kwlist.h                    |     5 +
 src/include/parser/parse_node.h                |     1 +
 src/include/utils/acl.h                        |     1 +
 src/include/utils/lsyscache.h                  |     1 +
 tools/bin/gppylib/data/3.1.json                |   620 +-
 tools/bin/gppylib/data/3.2.json                | 10458 -----------------------
 tools/bin/gppylib/data/4.0.json                | 10458 -----------------------
 tools/bin/hawq                                 |     6 +
 tools/bin/hawqbackup                           |   261 +
 tools/bin/hawqpylib/HAWQ_HELP.py               |    22 +
 tools/bin/hawqrestore                          |   105 +
 124 files changed, 7698 insertions(+), 21680 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d137340..5975f15 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -109,7 +109,6 @@ include_directories(${CMAKE_SOURCE_DIR}/hornet/univplan/src)
 include_directories(${CMAKE_SOURCE_DIR}/hornet/magma/src)
 include_directories(${CMAKE_SOURCE_DIR}/hornet/storage/src)
 include_directories(${CMAKE_SOURCE_DIR}/hornet/executor/src)
-include_directories(${CMAKE_SOURCE_DIR}/hornet/scheduler/src)
 include_directories(${CMAKE_BINARY_DIR}/hornet/dbcommon/src)
 include_directories(/opt/dependency/package/include)
 
@@ -124,7 +123,7 @@ add_dependencies(dxltranslators config)
 add_executable(postgres ${cdb_source} ${generate_source})
 target_link_libraries(postgres z bz2 lz4 snappy xml2 curl ldap json-c krb5 yarn thrift) # basic
 target_link_libraries(postgres gpos xerces-c naucrates gpdbcost gpopt dxltranslators) # gp-orca
-target_link_libraries(postgres hdfs3 dbcommon-shared univplan-shared storage-shared magma-client-shared executor-shared scheduler-shared) # hornet
+target_link_libraries(postgres hdfs3 dbcommon-shared univplan-shared storage-shared magma-client-shared storage-magma-format-shared executor-shared) # hornet
 target_link_libraries(postgres dl)
 add_dependencies(postgres config)
 
diff --git a/contrib/hornet/hornet.c b/contrib/hornet/hornet.c
index 3777459..25627b1 100644
--- a/contrib/hornet/hornet.c
+++ b/contrib/hornet/hornet.c
@@ -19,13 +19,22 @@
 
 #include "postgres.h"
 
+#include <inttypes.h>
+
 #include "funcapi.h"
 
+#include "access/fileam.h"
+#include "access/filesplit.h"
+#include "access/orcam.h"
+#include "catalog/pg_exttable.h"
 #include "hdfs/hdfs.h"
+#include "storage/cwrapper/orc-format-c.h"
 #include "storage/fd.h"
 #include "storage/filesystem.h"
 #include "utils/builtins.h"
+#include "utils/datum.h"
 #include "utils/hawq_funcoid_mapping.h"
+#include "utils/lsyscache.h"
 
 Datum ls_hdfs_dir(PG_FUNCTION_ARGS);
 
@@ -133,9 +142,131 @@ Datum ls_hdfs_dir(PG_FUNCTION_ARGS) {
   }
 }
 
+Datum is_supported_proc_in_NewQE(PG_FUNCTION_ARGS);
 PG_FUNCTION_INFO_V1(is_supported_proc_in_NewQE);
 Datum is_supported_proc_in_NewQE(PG_FUNCTION_ARGS) {
   Oid a = PG_GETARG_OID(0);
   int32_t mappingFuncId = HAWQ_FUNCOID_MAPPING(a);
   PG_RETURN_BOOL(!(IS_HAWQ_MAPPING_FUNCID_INVALID(mappingFuncId)));
 }
+
+Datum orc_tid_scan(FunctionCallInfo fcinfo, int segno, const char *url,
+                   uint64_t tid) {
+  Assert(segno == 0 || url == NULL);
+
+  // Argument checking
+  Oid argtype = get_fn_expr_argtype(fcinfo->flinfo, 0);
+  if (!type_is_rowtype(argtype))
+    ereport(ERROR,
+            (errcode(ERRCODE_DATATYPE_MISMATCH),
+             errmsg("first argument of %s must be a row type", __func__)));
+  Oid relId = get_typ_typrelid(argtype);
+  char relStorage = get_rel_relstorage(relId);
+  if (relstorage_is_external(relStorage)) {
+    ExtTableEntry *extEntry = GetExtTableEntry(relId);
+    const char *fmtName = getExtTblFormatterTypeInFmtOptsStr(extEntry->fmtopts);
+    if (strcasecmp("orc", fmtName) != 0) {
+      ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                      errmsg("Invalid external table type of %s for ORC Table.",
+                             fmtName)));
+    }
+    if (segno > 0) {
+      ereport(ERROR,
+              (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+               errmsg("Expecting URL for external ORC Table.", fmtName)));
+    }
+  } else if (RELSTORAGE_ORC != relStorage) {
+    ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("Invalid table type of '%c' for ORC Table.",
+                           get_rel_relstorage(relId))));
+  }
+
+  // Retrieve output tuple description
+  TupleDesc tupdesc;
+  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+    ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("function returning record called in context "
+                           "that cannot accept type record")));
+  TupleTableSlot *slot = TupleDescGetSlot(tupdesc);
+
+  // Setup projection
+  bool *proj = (bool *)palloc(tupdesc->natts * sizeof(bool));
+  if (fcinfo->nargs == 4) {  // specify the attribute to project
+    ArrayType *arr = PG_GETARG_ARRAYTYPE_P(3);
+    size_t num = (ARR_SIZE(arr) - ARR_DATA_OFFSET(arr)) / sizeof(int32_t);
+    int32_t *attrNums = (int32_t *)ARR_DATA_PTR(arr);
+    memset(proj, 0, tupdesc->natts);
+    for (size_t i = 0; i < num; i++) {
+      if (attrNums[i] <= 0 || attrNums[i] > tupdesc->natts)
+        ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                        errmsg("Invalid attribute number of %" PRId32 ".",
+                               attrNums[i])));
+      proj[attrNums[i] - 1] = 1;
+    }
+  } else {  // scan the whole tuple
+    memset(proj, 1, tupdesc->natts);
+  }
+
+  // Construct file splits
+  FileSplit split = makeNode(FileSplitNode);
+  split->segno = segno;
+  if (segno == 0) split->ext_file_uri_string = (char *)url;
+  split->offsets = 0;
+  split->lengths = INT64_MAX;
+  split->logiceof = INT64_MAX;
+  List *fileSplits = list_make1(split);
+
+  Relation rel = RelationIdGetRelation(relId);
+  OrcScanDescData *scanDesc =
+      orcBeginReadWithOptionsStr(rel, ActiveSnapshot, NULL, fileSplits, proj,
+                                 NULL, "{\"format\": \"APACHE_ORC_FORMAT\"}");
+  RelationClose(rel);
+
+  // XXX(chiyang): hack way to directly get `ORCFormatC *fmt;`, which is defined
+  // inside orcam.c.
+  bool scanSucceed =
+      ORCFormatTidScanC(*(ORCFormatC **)scanDesc->orcFormatData, tid);
+  checkOrcError(scanDesc->orcFormatData);
+  if (scanSucceed) {
+    orcReadNext(scanDesc, slot);
+
+    // Materialize the tuple
+    Datum *values = slot_get_values(slot);
+    bool *nulls = slot_get_isnull(slot);
+    for (size_t idx = 0; idx < tupdesc->natts; idx++) {
+      if (!nulls[idx]) {
+        values[idx] = datumCopy(values[idx], tupdesc->attrs[idx]->attbyval,
+                                tupdesc->attrs[idx]->attlen);
+      }
+    }
+  } else {
+    orcEndRead(scanDesc);
+    ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                    errmsg("TID %" PRIu64 " exceeds file tuple count.", tid)));
+  }
+  orcEndRead(scanDesc);
+
+  HeapTuple retTuple =
+      heap_form_tuple(tupdesc, slot_get_values(slot), slot_get_isnull(slot));
+
+  PG_RETURN_DATUM(HeapTupleGetDatum(retTuple));
+}
+
+Datum orc_segno_tid_scan(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(orc_segno_tid_scan);
+Datum orc_segno_tid_scan(PG_FUNCTION_ARGS) {
+  int segno = PG_GETARG_INT32(1);
+  uint64_t tid = PG_GETARG_INT64(2);
+
+  return orc_tid_scan(fcinfo, segno, NULL, tid);
+}
+
+Datum orc_url_tid_scan(PG_FUNCTION_ARGS);
+PG_FUNCTION_INFO_V1(orc_url_tid_scan);
+Datum orc_url_tid_scan(PG_FUNCTION_ARGS) {
+  const char *url = DatumGetCString(
+      DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(1))));
+  uint64_t tid = PG_GETARG_INT64(2);
+
+  return orc_tid_scan(fcinfo, 0, url, tid);
+}
diff --git a/contrib/hornet/load_hornet_helper_function.sql b/contrib/hornet/load_hornet_helper_function.sql
index 06c0dfd..8ba058e 100644
--- a/contrib/hornet/load_hornet_helper_function.sql
+++ b/contrib/hornet/load_hornet_helper_function.sql
@@ -1,3 +1,5 @@
+begin;
+
 DROP SCHEMA IF EXISTS hornet_helper CASCADE;
 CREATE SCHEMA hornet_helper;
 SET SEARCH_PATH = hornet_helper;
@@ -193,4 +195,24 @@ $$ LANGUAGE PLPGSQL;
 
 drop function if exists is_supported_proc_in_NewQE(oid);
 
-create function is_supported_proc_in_NewQE(oid) returns boolean as '$libdir/hornet','is_supported_proc_in_NewQE'language c immutable;
\ No newline at end of file
+create function is_supported_proc_in_NewQE(oid) returns boolean as '$libdir/hornet','is_supported_proc_in_NewQE'language c immutable;
+
+
+
+drop function if exists orc_tid_scan(anyelement, text, bigint, int[]);
+create function orc_tid_scan(anyelement, text, bigint, int[]) returns anyelement
+as '$libdir/hornet','orc_url_tid_scan' language c stable;
+
+drop function if exists orc_tid_scan(anyelement, text, bigint);
+create function orc_tid_scan(anyelement, text, bigint) returns anyelement
+as '$libdir/hornet','orc_url_tid_scan' language c stable;
+
+drop function if exists orc_tid_scan(anyelement, int, bigint, int[]);
+create function orc_tid_scan(anyelement, int, bigint, int[]) returns anyelement
+as '$libdir/hornet','orc_segno_tid_scan' language c stable;
+
+drop function if exists orc_tid_scan(anyelement, int, bigint);
+create function orc_tid_scan(anyelement, int, bigint) returns anyelement
+as '$libdir/hornet','orc_segno_tid_scan' language c stable;
+
+commit;
diff --git a/contrib/hornet/newcdbhash.c b/contrib/hornet/newcdbhash.c
new file mode 100644
index 0000000..7a66e23
--- /dev/null
+++ b/contrib/hornet/newcdbhash.c
@@ -0,0 +1,177 @@
+#include "postgres.h"
+
+#include "fmgr.h"
+
+#include "executor/spi.h"
+#include "utils/date.h"
+#include "utils/datetime.h"
+#include "utils/memutils.h"
+#include "utils/numeric.h"
+#include "utils/timestamp.h"
+
+#include "dbcommon/cwrapper/dbcommon-c.h"
+#include "dbcommon/type/type-kind.h"
+PG_FUNCTION_INFO_V1(timestampToout);
+Datum timestampToout(PG_FUNCTION_ARGS) {
+  Timestamp timestamp = PG_GETARG_TIMESTAMP(0);
+  char* result;
+  struct pg_tm tt, *tm = &tt;
+  fsec_t fsec;
+  char* tzn = NULL;
+  char buf[MAXDATELEN + 1];
+  if (timestamp2tm(timestamp, NULL, tm, &fsec, NULL, NULL) == 0)
+    EncodeDateTime(tm, fsec, NULL, &tzn, 1, buf);
+  result = pstrdup(buf);
+  PG_RETURN_CSTRING(result);
+}
+
+PG_FUNCTION_INFO_V1(dateToOut);
+Datum dateToOut(PG_FUNCTION_ARGS) {
+  DateADT date = PG_GETARG_DATEADT(0);
+  char* result;
+  struct pg_tm tt, *tm = &tt;
+  char buf[MAXDATELEN + 1];
+
+  j2date(date + POSTGRES_EPOCH_JDATE, &(tm->tm_year), &(tm->tm_mon),
+         &(tm->tm_mday));
+
+  EncodeDateOnly(tm, 1, buf);
+
+  result = pstrdup(buf);
+  PG_RETURN_CSTRING(result);
+}
+
+PG_FUNCTION_INFO_V1(timestamptzToout);
+Datum timestamptzToout(PG_FUNCTION_ARGS) {
+  TimestampTz dt = PG_GETARG_TIMESTAMPTZ(0);
+  char* result;
+  int tz;
+  struct pg_tm tt, *tm = &tt;
+  fsec_t fsec;
+  char* tzn;
+  char buf[MAXDATELEN + 1];
+  if (timestamp2tm(dt, &tz, tm, &fsec, &tzn, NULL) == 0)
+    EncodeDateTime(tm, fsec, &tz, &tzn, 1, buf);
+  result = pstrdup(buf);
+  PG_RETURN_CSTRING(result);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiBigInt);
+Datum cdbHashApiBigInt(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(int8out, Int64GetDatum(PG_GETARG_INT64(0))));
+  int32_t ret = dbcommonCdbHash(BIGINTID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiBool);
+Datum cdbHashApiBool(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(boolout, BoolGetDatum(PG_GETARG_BOOL(0))));
+  int32_t ret = dbcommonCdbHash(BOOLEANID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiInt);
+Datum cdbHashApiInt(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(int4out, Int32GetDatum(PG_GETARG_INT32(0))));
+  int32_t ret = dbcommonCdbHash(INTID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiSmallInt);
+Datum cdbHashApiSmallInt(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(int2out, Int16GetDatum((int16)PG_GETARG_INT32(0))));
+  int32_t ret = dbcommonCdbHash(SMALLINTID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiTimestamp);
+Datum cdbHashApiTimestamp(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(DirectFunctionCall1(
+      timestampToout, TimestampGetDatum(PG_GETARG_TIMESTAMP(0))));
+  int32_t ret = dbcommonCdbHash(TIMESTAMPID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiTimestampTz);
+Datum cdbHashApiTimestampTz(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(DirectFunctionCall1(
+      timestampToout, TimestampGetDatum(PG_GETARG_TIMESTAMP(0))));
+  int32_t ret = dbcommonCdbHash(TIMESTAMPTZID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiBpchar);
+Datum cdbHashApiBpchar(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(bpcharout, PointerGetDatum(PG_GETARG_BPCHAR_P(0))));
+  int32_t ret = dbcommonCdbHash(CHARID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiText);
+Datum cdbHashApiText(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
+  int32_t ret = dbcommonCdbHash(STRINGID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiVarchar);
+Datum cdbHashApiVarchar(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(varcharout, PointerGetDatum(PG_GETARG_VARCHAR_P(0))));
+  int32_t ret = dbcommonCdbHash(VARCHARID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiBytea);
+Datum cdbHashApiBytea(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(byteaout, PointerGetDatum(PG_GETARG_BYTEA_P(0))));
+  int32_t ret = dbcommonCdbHash(BINARYID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiFloat8);
+Datum cdbHashApiFloat8(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(float8out, Float8GetDatum(PG_GETARG_FLOAT8(0))));
+  int32_t ret = dbcommonCdbHash(DOUBLEID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiFloat4);
+Datum cdbHashApiFloat4(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(float4out, Float4GetDatum(PG_GETARG_FLOAT4(0))));
+  int32_t ret = dbcommonCdbHash(FLOATID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiDate);
+Datum cdbHashApiDate(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(dateToOut, DateADTGetDatum(PG_GETARG_DATEADT(0))));
+  int32_t ret = dbcommonCdbHash(DATEID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiTime);
+Datum cdbHashApiTime(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(time_out, TimeADTGetDatum(PG_GETARG_TIMEADT(0))));
+  int32_t ret = dbcommonCdbHash(TIMEID, str);
+  PG_RETURN_INT32(ret);
+}
+
+PG_FUNCTION_INFO_V1(cdbHashApiNumeric);
+Datum cdbHashApiNumeric(PG_FUNCTION_ARGS) {
+  char* str = DatumGetCString(
+      DirectFunctionCall1(numeric_out, NumericGetDatum(PG_GETARG_NUMERIC(0))));
+  int32_t ret = dbcommonCdbHash(DECIMALNEWID, str);
+  PG_RETURN_INT32(ret);
+}
diff --git a/contrib/hornet/oldcdbhash.c b/contrib/hornet/oldcdbhash.c
new file mode 100644
index 0000000..ab8bc97
--- /dev/null
+++ b/contrib/hornet/oldcdbhash.c
@@ -0,0 +1,412 @@
+/*
+ * 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.
+ */
+
+/*-------------------------------------------------------------------------
+ *
+ * hashapi_access.c
+ *     Test functions for accessing the Cdb Hash API.
+ *
+ * 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.
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+
+#include "cdb/cdbhash.h"
+#include "executor/spi.h"
+#include "funcapi.h"
+#include "utils/date.h"
+#include "utils/datetime.h"
+#include "utils/memutils.h"
+#include "utils/numeric.h"
+#include "utils/timestamp.h"
+#define GET_STR(textp) \
+  DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
+
+/*
+ * Pointer to the hash session characteristics.
+ */
+static CdbHash *h;
+
+/*==============================================
+ *
+ * SINGLE VALUE HASHING
+ *
+ *==============================================
+ */
+
+/*
+ * HASHAPI_Hash_1_BigInt
+ * Perform a simple 1-value bigint hash
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_BigInt);
+Datum HASHAPI_Hash_1_BigInt(PG_FUNCTION_ARGS) {
+  int32 num_segs;            /* number of segments  */
+  int16 algorithm;           /* hashing algorithm   */
+  int64 val1;                /* big int input value */
+  unsigned int targetbucket; /* 0-based  */
+  Datum d1;
+  Oid oid;
+  /* Get the value to hash */
+  val1 = PG_GETARG_INT64(0);
+  d1 = Int64GetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = INT8OID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_BigInt
+ * Perform a simple 1-value bigint hash
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_Bool);
+Datum HASHAPI_Hash_1_Bool(PG_FUNCTION_ARGS) {
+  Datum d1;
+  Oid oid;
+  bool val1; /* boolean input value */
+  /* Get the value to hash */
+  val1 = PG_GETARG_BOOL(0);
+  d1 = BoolGetDatum(val1);
+  h = makeCdbHash(1, 1);
+  cdbhashinit(h);
+  oid = BOOLOID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_Int
+ * Perform a simple 1-value int4 hash
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_Int);
+Datum HASHAPI_Hash_1_Int(PG_FUNCTION_ARGS) {
+  int32 val1; /* int input value */
+  Datum d1;
+  Oid oid;
+  val1 = PG_GETARG_INT32(0);
+  d1 = Int32GetDatum(val1);
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = INT4OID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_SmallInt
+ * Perform a simple 1-value int2 hash
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_SmallInt);
+Datum HASHAPI_Hash_1_SmallInt(PG_FUNCTION_ARGS) {
+  int32 value; /* int input value
+                                  will be cast to int16 */
+  int16 val1;
+  unsigned int targetbucket; /* 0-based   */
+  Datum d1;
+  Oid oid;
+  value = PG_GETARG_INT32(0);
+  val1 = (int16)value;
+  d1 = Int16GetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = INT2OID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_Char
+ * Perform a simple 1 character hash
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_BpChar);
+Datum HASHAPI_Hash_1_BpChar(PG_FUNCTION_ARGS) {
+  BpChar *val1; /* char value          */
+  Datum d1;
+  Oid oid;
+  val1 = PG_GETARG_BPCHAR_P(0);
+  d1 = PointerGetDatum(val1);
+  h = makeCdbHash(1, 1);
+  cdbhashinit(h);
+  oid = BPCHAROID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_Text
+ * Perform a simple 1 string hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_Text);
+Datum HASHAPI_Hash_1_Text(PG_FUNCTION_ARGS) {
+  text *val1; /* char value          */
+  Datum d1;
+  Oid oid;
+  val1 = PG_GETARG_TEXT_P(0);
+  d1 = PointerGetDatum(val1);
+  h = makeCdbHash(1, 1);
+  cdbhashinit(h);
+  oid = TEXTOID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_Varchar
+ * Perform a simple 1 string (of type VARCHAR) hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_Varchar);
+Datum HASHAPI_Hash_1_Varchar(PG_FUNCTION_ARGS) {
+  VarChar *val1; /* varchar value		  */
+  Datum d1;
+  Oid oid;
+  val1 = PG_GETARG_VARCHAR_P(0);
+  d1 = PointerGetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  cdbhashinit(h);
+  oid = VARCHAROID;
+  cdbhash(h, d1, oid);
+  /* Avoid leaking memory for toasted inputs */
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_Bytea
+ * Perform a simple 1 string (of type BYTEA) hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_Bytea);
+Datum HASHAPI_Hash_1_Bytea(PG_FUNCTION_ARGS) {
+  bytea *val1;     /* bytea value		  */
+  int16 algorithm; /* hashing algorithm   */
+  Datum d1;
+  Oid oid;
+  /* Get the value to hash */
+  val1 = PG_GETARG_BYTEA_P(0);
+  d1 = PointerGetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  cdbhashinit(h);
+  oid = BYTEAOID;
+  cdbhash(h, d1, oid);
+  /* Avoid leaking memory for toasted inputs */
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_float8
+ * Perform a single float8 value (double) hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_float8);
+Datum HASHAPI_Hash_1_float8(PG_FUNCTION_ARGS) {
+  float8 val1; /* varchar value		  */
+  Datum d1;
+  Oid oid;
+  /* Get the value to hash */
+  val1 = PG_GETARG_FLOAT8(0);
+  d1 = Float8GetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = FLOAT8OID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_float4
+ * Perform a single float4 value (double) hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_float4);
+Datum HASHAPI_Hash_1_float4(PG_FUNCTION_ARGS) {
+  float4 val1; /* varchar value		  */
+  Datum d1;
+  Oid oid;
+  /* Get the value to hash */
+  val1 = PG_GETARG_FLOAT4(0);
+  d1 = Float4GetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = FLOAT4OID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_timestamp
+ * Perform a single timestamp value hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_timestamp);
+Datum HASHAPI_Hash_1_timestamp(PG_FUNCTION_ARGS) {
+  Timestamp val1; /* varchar value		  */
+  Datum d1;
+  Oid oid;
+  val1 = PG_GETARG_TIMESTAMP(0);
+  d1 = TimestampGetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = TIMESTAMPOID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_timestamptz
+ * Perform a single timestamp with time zone value hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_timestamptz);
+Datum HASHAPI_Hash_1_timestamptz(PG_FUNCTION_ARGS) {
+  TimestampTz val1; /* varchar value		  */
+  Datum d1;
+  Oid oid;
+  /* Get the value to hash */
+  val1 = PG_GETARG_TIMESTAMPTZ(0);
+  d1 = TimestampTzGetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = TIMESTAMPTZOID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_date
+ * Perform a single date value hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_date);
+Datum HASHAPI_Hash_1_date(PG_FUNCTION_ARGS) {
+  DateADT val1; /* date value		  */
+  Datum d1;
+  Oid oid;
+  /* Get the value to hash */
+  val1 = PG_GETARG_DATEADT(0);
+  d1 = DateADTGetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = DATEOID;
+  cdbhash(h, d1, oid);
+  /* reduce the result hash value */
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_time
+ * Perform a single time value hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_time);
+Datum HASHAPI_Hash_1_time(PG_FUNCTION_ARGS) {
+  TimeADT val1; /* time value		  */
+  Datum d1;
+  Oid oid;
+  /* Get the value to hash */
+  val1 = PG_GETARG_TIMEADT(0);
+  d1 = TimeADTGetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = TIMEOID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_timetz
+ * Perform a single time with time zone value hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_timetz);
+Datum HASHAPI_Hash_1_timetz(PG_FUNCTION_ARGS) {
+  TimeTzADT *val1; /* time w/timezone value */
+  int16 algorithm; /* hashing algorithm   */
+  Datum d1;
+  Oid oid;
+  /* Get the value to hash */
+  val1 = PG_GETARG_TIMETZADT_P(0);
+  d1 = TimeTzADTPGetDatum(val1);
+  /* create a CdbHash for this hash test. */
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  oid = TIMETZOID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_numeric
+ * Perform a single NUMERIC value hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_numeric);
+Datum HASHAPI_Hash_1_numeric(PG_FUNCTION_ARGS) {
+  Numeric val1;    /* NUMERIC value */
+  int16 algorithm; /* hashing algorithm   */
+  Datum d1;
+  Oid oid;
+  val1 = PG_GETARG_NUMERIC(0);
+  d1 = NumericGetDatum(val1);
+  h = makeCdbHash(1, 1);
+  cdbhashinit(h);
+  oid = NUMERICOID;
+  cdbhash(h, d1, oid);
+  PG_RETURN_INT32(h->hash);
+}
+
+/*
+ * HASHAPI_Hash_1_null
+ * Perform a single null value hash.
+ */
+PG_FUNCTION_INFO_V1(HASHAPI_Hash_1_null);
+Datum HASHAPI_Hash_1_null(PG_FUNCTION_ARGS) {
+  h = makeCdbHash(1, 1);
+  /* init cdb hash */
+  cdbhashinit(h);
+  cdbhashnull(h);
+  PG_RETURN_INT32(h->hash);
+}
diff --git a/contrib/magma/magma.c b/contrib/magma/magma.c
index c732b85..b91ec80 100644
--- a/contrib/magma/magma.c
+++ b/contrib/magma/magma.c
@@ -174,7 +174,7 @@ typedef struct MagmaTidC {
   uint16_t rangeid;
 } MagmaTidC;
 
-typedef struct GlobalFormatUserData {
+typedef struct MagmaFormatUserData {
   MagmaFormatC *fmt;
   char *dbname;
   char *schemaname;
@@ -196,9 +196,11 @@ typedef struct GlobalFormatUserData {
 
   // for insert/update/delete
   TimestampType *colTimestamp;
-} GlobalFormatUserData;
 
-static MagmaClientC* global_magma_client;
+  bool isFirstRescan;
+} MagmaFormatUserData;
+
+static MagmaClientC *magma_client_instance;
 
 /*
  * Utility functions for magma in pluggable storage
@@ -225,15 +227,15 @@ static MagmaFormatC *create_magma_formatter_instance(List *fmt_opts_defelem,
 
 static MagmaClientC *create_magma_client_instance();
 static void init_magma_format_user_data_for_read(
-    TupleDesc tup_desc, GlobalFormatUserData *user_data);
+    TupleDesc tup_desc, MagmaFormatUserData *user_data);
 static void init_magma_format_user_data_for_write(
-    TupleDesc tup_desc, GlobalFormatUserData *user_data, Relation relation);
+    TupleDesc tup_desc, MagmaFormatUserData *user_data, Relation relation);
 
 static void build_options_in_json(char *serializeSchema, int serializeSchemaLen,
                                   List *fmt_opts_defelem, int encoding, int rangeNum,
                                   char *formatterName, char **json_str);
 static void build_magma_tuple_descrition_for_read(
-    Plan *plan, Relation relation, GlobalFormatUserData *user_data, bool skipTid);
+    Plan *plan, Relation relation, MagmaFormatUserData *user_data, bool skipTid);
 
 static void magma_scan_error_callback(void *arg);
 
@@ -256,7 +258,7 @@ static void getHostNameByIp(const char *ipaddr, char *hostname);
 
 static void magma_clear(PlugStorage ps, bool clearSlot) {
   FileScanDesc fsd = ps->ps_file_scan_desc;
-  GlobalFormatUserData *user_data = (GlobalFormatUserData *)(fsd->fs_ps_user_data);
+  MagmaFormatUserData *user_data = (MagmaFormatUserData *)(fsd->fs_ps_user_data);
   TupleTableSlot *slot = ps->ps_tuple_table_slot;
 
   if (user_data->fmt) {
@@ -1120,6 +1122,8 @@ Datum magma_beginscan(PG_FUNCTION_ARGS) {
   file_scan_desc->fs_serializeSchema =
       pnstrdup(serializeSchema, serializeSchemaLen);
   file_scan_desc->fs_serializeSchemaLen = serializeSchemaLen;
+  file_scan_desc->fs_ps_magma_splits = ps->ps_magma_splits;
+  file_scan_desc->fs_ps_magma_skip_tid = ps->ps_magma_skip_tid;
 
   /* Setup scan functions */
   get_magma_scan_functions(formatterName, file_scan_desc);
@@ -1179,7 +1183,8 @@ Datum magma_beginscan(PG_FUNCTION_ARGS) {
   /* currentSliceId == ps->ps_scan_state->ps.state->currentSliceIdInPlan */
   if (AmISegment()) {
     /* Initialize user data */
-    GlobalFormatUserData *user_data = palloc0(sizeof(GlobalFormatUserData));
+    MagmaFormatUserData *user_data = palloc0(sizeof(MagmaFormatUserData));
+    user_data->isFirstRescan = true;
     if (formatterName != NULL &&
         (strncasecmp(formatterName, "magmatp", sizeof("magmatp") - 1) == 0)) {
       user_data->isMagmatp = true;
@@ -1347,6 +1352,8 @@ void init_common_plan_context(CommonPlanContext *ctx) {
   ctx->scanReadStatsOnly = false;
   ctx->parent = NULL;
   ctx->exprBufStack = NIL;
+  ctx->isConvertingIndexQual = false;
+  ctx->idxColumns = NIL;
 }
 
 void free_common_plan_context(CommonPlanContext *ctx) {
@@ -1360,8 +1367,6 @@ void free_common_plan_context(CommonPlanContext *ctx) {
 Datum magma_getnext_init(PG_FUNCTION_ARGS) {
   checkOushuDbExtensiveFunctionSupport(__func__);
   PlugStorage ps = (PlugStorage)(fcinfo->context);
-  // PlanState *plan_state = ps->ps_plan_state;
-  // ExternalScanState *ext_scan_state = ps->ps_ext_scan_state;
 
   ExternalSelectDesc ext_select_desc = NULL;
   /*
@@ -1392,8 +1397,8 @@ Datum magma_getnext(PG_FUNCTION_ARGS) {
   checkOushuDbExtensiveFunctionSupport(__func__);
   PlugStorage ps = (PlugStorage)(fcinfo->context);
   FileScanDesc fsd = ps->ps_file_scan_desc;
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)(fsd->fs_ps_user_data);
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)(fsd->fs_ps_user_data);
   TupleTableSlot *slot = ps->ps_tuple_table_slot;
   bool *nulls = slot_get_isnull(slot);
   memset(nulls, true, user_data->numberOfColumns);
@@ -1508,81 +1513,124 @@ Datum magma_getnext(PG_FUNCTION_ARGS) {
 Datum magma_rescan(PG_FUNCTION_ARGS) {
   checkOushuDbExtensiveFunctionSupport(__func__);
   PlugStorage ps = (PlugStorage)(fcinfo->context);
+  ScanState *scan_state = ps->ps_scan_state;
   FileScanDesc fsd = ps->ps_file_scan_desc;
   MagmaSnapshot *snapshot = &(ps->ps_snapshot);
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)(fsd->fs_ps_user_data);
-
-  if (user_data == NULL) {
-    /* 1 Initialize user data */
-    user_data = palloc0(sizeof(GlobalFormatUserData));
+  MagmaRuntimeKeys runtimeKeys;
+  Assert(ps->num_run_time_keys >= 0);
+  if (ps->num_run_time_keys == 0) {
+    runtimeKeys.num = 0;
+    runtimeKeys.keys = NULL;
+  } else {
+    Assert(ps->runtime_key_info != NULL);
+    runtimeKeys.num = ps->num_run_time_keys;
+    runtimeKeys.keys = palloc0(ps->num_run_time_keys * sizeof(MagmaRuntimeKey));
+    for (int i = 0; i < ps->num_run_time_keys; ++i) {
+      ScanKey scan_key = ps->runtime_key_info[i].scan_key;
+      runtimeKeys.keys[i].flag = scan_key->sk_flags;
+      runtimeKeys.keys[i].attnoold = scan_key->sk_attnoold;
+      runtimeKeys.keys[i].value =
+          OutputFunctionCall(&scan_key->sk_out_func, scan_key->sk_argument);
+    }
+  }
 
-    if (fsd->fs_formatter_name != NULL &&
-        (strncasecmp(fsd->fs_formatter_name, "magmatp",
-                     sizeof("magmatp") - 1) == 0)) {
-      user_data->isMagmatp = true;
-    } else {
-      user_data->isMagmatp = false;
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)(fsd->fs_ps_user_data);
+  if (user_data != NULL) {
+    // There are 2 cases that user_data is not null:
+    // 1. If this is the first rescan, at this point, we have done
+    // magma_beginscan() and haven't done magma_getnext() yet.
+    // We don't need to create user_data from scratch, just use it.
+    if (user_data->isFirstRescan) {
+      user_data->isFirstRescan = false;
+      MagmaFormatReScanMagmaFormatC(user_data->fmt, &runtimeKeys);
+      if (runtimeKeys.keys) {
+        pfree(runtimeKeys.keys);
+      }
+      PG_RETURN_VOID();
     }
 
-    init_magma_format_user_data_for_read(fsd->fs_tupDesc, user_data);
+    // 2. Otherwise is not the first rescan, we should do magma_clear() here.
+    // This case happens with the Nested Loop Exists Join. In that case, as long
+    // as we can get a piece of data in magma_getnext(), we will start a new
+    // rescan. Therefore, we didn't do mamga_clear() in magma_getnext(), which
+    // resulted in the dirty user_data not being cleared.
+    // We don't reuse the user_data since that would make the code complex, just
+    // clear it and create a new one below.
+    magma_clear(ps, true);
+  }
 
-    Relation rel = fsd->fs_rd;
-    ExtTableEntry *ete = GetExtTableEntry(RelationGetRelid(rel));
+  /* Initialize user data */
+  user_data = palloc0(sizeof(MagmaFormatUserData));
+  if (fsd->fs_formatter_name != NULL &&
+      (strncasecmp(fsd->fs_formatter_name, "magmatp", sizeof("magmatp") - 1) == 0)) {
+    user_data->isMagmatp = true;
+  } else {
+    user_data->isMagmatp = false;
+  }
 
-    int formatterType = ExternalTableType_Invalid;
+  /* the number of ranges is dynamic for magma table */
+  int32_t nRanges = 0;
+  ListCell *lc_split = NULL;
+  foreach (lc_split, fsd->fs_ps_magma_splits) {
+    List *split = (List *)lfirst(lc_split);
+    nRanges += list_length(split);
+  }
 
-    char *formatterName = NULL;
-    getExternalTableTypeStr(ete->fmtcode, ete->fmtopts, &formatterType,
-                            &formatterName);
+  init_magma_format_user_data_for_read(fsd->fs_tupDesc, user_data);
 
-    bool isexternal = false;
-    char *serializeSchema = fsd->fs_serializeSchema;
-    int serializeSchemaLen = fsd->fs_serializeSchemaLen;
-    get_magma_category_info(ete->fmtopts, &isexternal);
+  /* Create formatter instance */
+  user_data->fmt = create_magma_formatter_instance(
+      NIL, fsd->fs_serializeSchema, fsd->fs_serializeSchemaLen, PG_UTF8, fsd->fs_formatter_name, nRanges);
 
-    user_data->fmt = create_magma_formatter_instance(
-        NIL, serializeSchema, serializeSchemaLen, PG_UTF8, formatterName, 0);
-
-    /* 4 Build tuple description */
-    Plan *plan = fsd->fs_ps_plan;
-    build_magma_tuple_descrition_for_read(plan, fsd->fs_rd, user_data, ps->ps_magma_skip_tid);
-
-    /* 4.1 Build plan */
-    if (AmISegment() &&
-        currentSliceId == ps->ps_scan_state->ps.state->currentSliceIdInPlan) {
-      CommonPlanContext ctx;
-      init_common_plan_context(&ctx);
-      plan->plan_parent_node_id = -1;
-      convert_extscan_to_common_plan(plan, fsd->fs_ps_scan_state->splits,
-                                     fsd->fs_rd, &ctx);
-      int32_t size = 0;
-      char *planstr = univPlanSerialize(ctx.univplan, &size, false);
-
-      /* 5 Save user data */
-      fsd->fs_ps_user_data = (void *)user_data;
-
-      /* 6 Begin scan with the formatter */
-      if (currentSliceId == ps->ps_scan_state->ps.state->currentSliceIdInPlan) {
-        bool enableShm = (strcasecmp(magma_enable_shm, "ON") == 0);
-        MagmaFormatBeginScanMagmaFormatC(user_data->fmt, user_data->colToReads,
-                                         snapshot, planstr, size,
-                                         enableShm, ps->ps_magma_skip_tid,
-                                         magma_shm_limit_per_block * 1024);
-        MagmaFormatCatchedError *e =
-            MagmaFormatGetErrorMagmaFormatC(user_data->fmt);
-
-        if (e->errCode != ERRCODE_SUCCESSFUL_COMPLETION) {
-          elog(ERROR, "magma_scan: failed to beginscan: %s(%d)", e->errMessage,
-               e->errCode);
-        }
-      }
+  /* Prepare database, schema, and table information */
+  char *dbname = database;
+  char *schemaname = getNamespaceNameByOid(RelationGetNamespace(fsd->fs_rd));
+  Assert(schemaname != NULL);
+  char *tablename = RelationGetRelationName(fsd->fs_rd);
 
-      free_common_plan_context(&ctx);
-    }
+  MagmaFormatC_SetupTarget(user_data->fmt, dbname, schemaname, tablename);
+  MagmaFormatC_SetupTupDesc(user_data->fmt, user_data->numberOfColumns,
+                            user_data->colNames, user_data->colDatatypes,
+                            user_data->colDatatypeMods,
+                            user_data->colIsNulls);
+
+  /* Build tuple description */
+  Plan *plan = fsd->fs_ps_plan;
+  build_magma_tuple_descrition_for_read(plan, fsd->fs_rd, user_data, fsd->fs_ps_magma_skip_tid);
+
+  /* Build plan */
+  CommonPlanContext ctx;
+  init_common_plan_context(&ctx);
+  plan->plan_parent_node_id = -1;
+  convert_extscan_to_common_plan(plan, scan_state->splits,
+                                 fsd->fs_rd, &ctx);
+  int32_t size = 0;
+  char *planstr = univPlanSerialize(ctx.univplan, &size, false);
+
+  /* Save user data */
+  fsd->fs_ps_user_data = (void *)user_data;
+
+  /* Begin scan with the formatter */
+  bool enableShm = (strcasecmp(magma_enable_shm, "ON") == 0);
+  MagmaFormatBeginScanMagmaFormatC(user_data->fmt, user_data->colToReads,
+                                   snapshot, planstr, size,
+                                   enableShm, fsd->fs_ps_magma_skip_tid,
+                                   magma_shm_limit_per_block * 1024);
+  MagmaFormatCatchedError *e = MagmaFormatGetErrorMagmaFormatC(user_data->fmt);
+  if (e->errCode != ERRCODE_SUCCESSFUL_COMPLETION) {
+    elog(ERROR, "magma_scan: failed to beginscan: %s(%d)", e->errMessage,
+         e->errCode);
+  }
+
+  MagmaFormatReScanMagmaFormatC(user_data->fmt, &runtimeKeys);
+  if (runtimeKeys.keys) {
+    pfree(runtimeKeys.keys);
   }
 
+  free_common_plan_context(&ctx);
+
   PG_RETURN_VOID();
 }
 
@@ -1595,7 +1643,7 @@ Datum magma_endscan(PG_FUNCTION_ARGS) {
   PlugStorage ps = (PlugStorage)(fcinfo->context);
   FileScanDesc fsd = ps->ps_file_scan_desc;
 
-  GlobalFormatUserData *user_data = (GlobalFormatUserData *)(fsd->fs_ps_user_data);
+  MagmaFormatUserData *user_data = (MagmaFormatUserData *)(fsd->fs_ps_user_data);
 
   // free memory in endscan, for some subquery scenarios "getnext" might not be called
   if (user_data != NULL) {
@@ -1662,8 +1710,8 @@ Datum magma_stopscan(PG_FUNCTION_ARGS) {
   checkOushuDbExtensiveFunctionSupport(__func__);
   PlugStorage ps = (PlugStorage)(fcinfo->context);
   FileScanDesc fsd = ps->ps_file_scan_desc;
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)(fsd->fs_ps_user_data);
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)(fsd->fs_ps_user_data);
   TupleTableSlot *tts = ps->ps_tuple_table_slot;
 
   if (!user_data) PG_RETURN_VOID();
@@ -1855,8 +1903,8 @@ Datum magma_begindelete(PG_FUNCTION_ARGS) {
   char *schema = getNamespaceNameByOid(namespaceOid);
   char *table = RelationGetRelationName(relation);
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)palloc0(sizeof(GlobalFormatUserData));
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)palloc0(sizeof(MagmaFormatUserData));
 
   if (formatterName != NULL &&
       (strncasecmp(formatterName, "magmatp", sizeof("magmatp") - 1) == 0)) {
@@ -1938,8 +1986,8 @@ Datum magma_delete(PG_FUNCTION_ARGS) {
   /* It may be memtuple, we need to transfer it to virtual tuple */
   slot_getallattrs(tts);
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)(edd->ext_ps_user_data);
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)(edd->ext_ps_user_data);
 
   user_data->colTid.rangeid = DatumGetUInt16(edd->ext_rangeId);
   user_data->colTid.rowid = DatumGetUInt64(edd->ext_rowId);
@@ -2105,8 +2153,8 @@ Datum magma_enddelete(PG_FUNCTION_ARGS) {
   PlugStorage ps = (PlugStorage)(fcinfo->context);
   ExternalInsertDesc edd = ps->ps_ext_delete_desc;
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)(edd->ext_ps_user_data);
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)(edd->ext_ps_user_data);
 
   MagmaFormatEndDeleteMagmaFormatC(user_data->fmt);
 
@@ -2297,8 +2345,8 @@ Datum magma_beginupdate(PG_FUNCTION_ARGS) {
   char *schema = getNamespaceNameByOid(namespaceOid);
   char *table = RelationGetRelationName(relation);
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)palloc0(sizeof(GlobalFormatUserData));
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)palloc0(sizeof(MagmaFormatUserData));
 
   if (formatterName != NULL &&
       (strncasecmp(formatterName, "magmatp", sizeof("magmatp") - 1) == 0)) {
@@ -2383,8 +2431,8 @@ Datum magma_update(PG_FUNCTION_ARGS) {
   /* It may be memtuple, we need to transfer it to virtual tuple */
   slot_getallattrs(tts);
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)(eud->ext_ps_user_data);
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)(eud->ext_ps_user_data);
 
   user_data->colTid.rangeid = DatumGetUInt16(eud->ext_rangeId);
   user_data->colTid.rowid = DatumGetUInt64(eud->ext_rowId);
@@ -2559,8 +2607,8 @@ Datum magma_endupdate(PG_FUNCTION_ARGS) {
   PlugStorage ps = (PlugStorage)(fcinfo->context);
   ExternalInsertDesc eud = ps->ps_ext_update_desc;
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)(eud->ext_ps_user_data);
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)(eud->ext_ps_user_data);
 
   int updateCount = MagmaFormatEndUpdateMagmaFormatC(user_data->fmt);
   ps->ps_update_count = updateCount;
@@ -2780,8 +2828,8 @@ Datum magma_insert_init(PG_FUNCTION_ARGS) {
   char *schema = getNamespaceNameByOid(namespaceOid);
   char *table = RelationGetRelationName(relation);
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)palloc0(sizeof(GlobalFormatUserData));
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)palloc0(sizeof(MagmaFormatUserData));
 
   if (formatterName != NULL &&
       (strncasecmp(formatterName, "magmatp", sizeof("magmatp") - 1) == 0)) {
@@ -2865,8 +2913,8 @@ Datum magma_insert(PG_FUNCTION_ARGS) {
   ExternalInsertDesc eid = ps->ps_ext_insert_desc;
   TupleTableSlot *tts = ps->ps_tuple_table_slot;
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)(eid->ext_ps_user_data);
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)(eid->ext_ps_user_data);
 
   user_data->colValues = slot_get_values(tts);
   user_data->colIsNulls = slot_get_isnull(tts);
@@ -3050,8 +3098,8 @@ Datum magma_insert_finish(PG_FUNCTION_ARGS) {
   PlugStorage ps = (PlugStorage)(fcinfo->context);
   ExternalInsertDesc eid = ps->ps_ext_insert_desc;
 
-  GlobalFormatUserData *user_data =
-      (GlobalFormatUserData *)(eid->ext_ps_user_data);
+  MagmaFormatUserData *user_data =
+      (MagmaFormatUserData *)(eid->ext_ps_user_data);
 
   MagmaFormatEndInsertMagmaFormatC(user_data->fmt);
 
@@ -3159,7 +3207,6 @@ Datum magma_transaction(PG_FUNCTION_ARGS) {
       break;
     case PS_TXN_CMD_GET_SNAPSHOT: {
       MagmaClientC_CleanupTableInfo(client);
-      int magmaTableFullNamesSize = list_length(ps->magma_talbe_full_names);
       int i = 0;
       ListCell *lc;
       foreach (lc, ps->magma_talbe_full_names) {
@@ -3186,7 +3233,6 @@ Datum magma_transaction(PG_FUNCTION_ARGS) {
     }
     case PS_TXN_CMD_GET_TRANSACTIONID: {
       MagmaClientC_CleanupTableInfo(client);
-      int magmaTableFullNamesSize = list_length(ps->magma_talbe_full_names);
       int i = 0;
       ListCell *lc;
       foreach (lc, ps->magma_talbe_full_names) {
@@ -3410,22 +3456,22 @@ static MagmaFormatC *create_magma_formatter_instance(List *fmt_opts_defelem,
 }
 
 static MagmaClientC *create_magma_client_instance() {
-  if (global_magma_client != NULL) {
-    MagmaClientC_ResetMagmaClient4Reuse(&global_magma_client);
-    return global_magma_client;
+  if (magma_client_instance != NULL) {
+    MagmaClientC_ResetMagmaClient4Reuse(&magma_client_instance);
+    return magma_client_instance;
   }
 
-  global_magma_client = MagmaClientC_NewMagmaClient(magma_nodes_url);
-  MagmaResult *result = MagmaClientC_GetResult(global_magma_client);
+  magma_client_instance = MagmaClientC_NewMagmaClient(magma_nodes_url);
+  MagmaResult *result = MagmaClientC_GetResult(magma_client_instance);
   if (result->level == MAGMA_ERROR) {
-    MagmaClientC_FreeMagmaClient(&global_magma_client);
+    MagmaClientC_FreeMagmaClient(&magma_client_instance);
     elog(ERROR, "%s", result->message);
   }
-  return global_magma_client;
+  return magma_client_instance;
 }
 
 static void init_magma_format_user_data_for_read(
-    TupleDesc tup_desc, GlobalFormatUserData *user_data) {
+    TupleDesc tup_desc, MagmaFormatUserData *user_data) {
   user_data->numberOfColumns = tup_desc->natts;
   user_data->colNames = palloc0(sizeof(char *) * user_data->numberOfColumns);
   user_data->colDatatypes = palloc0(sizeof(int) * user_data->numberOfColumns);
@@ -3452,7 +3498,7 @@ static void init_magma_format_user_data_for_read(
 }
 
 static void init_magma_format_user_data_for_write(
-    TupleDesc tup_desc, GlobalFormatUserData *user_data, Relation relation) {
+    TupleDesc tup_desc, MagmaFormatUserData *user_data, Relation relation) {
   user_data->numberOfColumns = tup_desc->natts;
   user_data->colNames = palloc0(sizeof(char *) * user_data->numberOfColumns);
   user_data->colDatatypes = palloc0(sizeof(int) * user_data->numberOfColumns);
@@ -3475,7 +3521,7 @@ static void init_magma_format_user_data_for_write(
 }
 
 static void build_magma_tuple_descrition_for_read(
-    Plan *plan, Relation relation, GlobalFormatUserData *user_data, bool skipTid) {
+    Plan *plan, Relation relation, MagmaFormatUserData *user_data, bool skipTid) {
   user_data->colToReads = palloc0(sizeof(bool) * user_data->numberOfColumns);
 
   for (int i = 0; i < user_data->numberOfColumns; ++i)
diff --git a/contrib/orc/orc.c b/contrib/orc/orc.c
index 8e45c1c..8c2baf8 100644
--- a/contrib/orc/orc.c
+++ b/contrib/orc/orc.c
@@ -626,7 +626,6 @@ Datum orc_beginscan(PG_FUNCTION_ARGS)
 		char *token = find_filesystem_credential_with_uri(uri_str);
 		SetToken(uri_str, token);
 	}
-	file_scan_desc->fs_ps_scan_state = scan_state; /* for orc rescan */
 	build_file_splits(uri, scan_state, user_data);
 
 	FreeExternalTableUri(uri);
@@ -671,8 +670,6 @@ Datum orc_beginscan(PG_FUNCTION_ARGS)
 Datum orc_getnext_init(PG_FUNCTION_ARGS)
 {
 	PlugStorage ps = (PlugStorage) (fcinfo->context);
-	PlanState *plan_state = ps->ps_plan_state;
-	ExternalScanState *ext_scan_state = ps->ps_ext_scan_state;
 
 	ExternalSelectDesc ext_select_desc = NULL;
 	/*
@@ -826,6 +823,7 @@ Datum orc_rescan(PG_FUNCTION_ARGS)
 {
 	PlugStorage ps = (PlugStorage) (fcinfo->context);
 	FileScanDesc fsd = ps->ps_file_scan_desc;
+	ScanState *scan_state = ps->ps_scan_state;
 	Relation relation = fsd->fs_rd;
 	TupleDesc tup_desc = RelationGetDescr(relation);
 
@@ -845,7 +843,7 @@ Datum orc_rescan(PG_FUNCTION_ARGS)
 
 		/* 3 Build file splits */
 		Uri *uri = ParseExternalTableUri(fsd->fs_uri);
-		build_file_splits(uri, fsd->fs_ps_scan_state, user_data);
+		build_file_splits(uri, scan_state, user_data);
 
 		/* 4 Build tuple description */
 		Plan *plan = fsd->fs_ps_plan;
diff --git a/src/all_src_files.txt b/src/all_src_files.txt
index f9899dd..4d85a15 100644
--- a/src/all_src_files.txt
+++ b/src/all_src_files.txt
@@ -933,6 +933,14 @@ include/catalog/pg_type.h
 include/catalog/pg_type_encoding.h
 include/catalog/pg_user_mapping.h
 include/catalog/pg_window.h
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_index.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
 include/catalog/toasting.h
 include/catalog/external/externalmd.h
 include/catalog/external/itemmd.h
diff --git a/src/backend/access/appendonly/aomd.c b/src/backend/access/appendonly/aomd.c
index b640019..77805eb 100644
--- a/src/backend/access/appendonly/aomd.c
+++ b/src/backend/access/appendonly/aomd.c
@@ -104,6 +104,38 @@ FormatAOSegmentFileName(
 	sprintf(filepathname, "%s/%u", basepath, pseudoSegNo);
 }
 
+void
+FormatAOSegmentIndexFileName(
+              char *basepath,
+              int segno,
+              int idxId,
+              int col,
+              int numCols,
+              int32 *fileSegNo,
+              char *filepathname)
+{
+  int pseudoSegNo;
+
+  if (col < 0)
+  {
+    /*
+     * Row oriented Append-Only.
+     */
+    pseudoSegNo = segno;
+  }
+  else
+  {
+    /*
+     * Column oriented Append-only.
+     */
+    pseudoSegNo = ((segno - 1) * numCols) + (col + 1);
+  }
+
+  *fileSegNo = pseudoSegNo;
+
+  sprintf(filepathname, "%s/%u_%u", basepath, pseudoSegNo, idxId);
+}
+
 /*
  * Make an Append Only relation file segment file name.
  *
@@ -132,6 +164,29 @@ MakeAOSegmentFileName(
 	pfree(basepath);
 }
 
+void
+MakeAOSegmentIndexFileName(
+              Relation rel,
+              int idxId,
+              int segno,
+              int col,
+              int32 *fileSegNo,
+              char *filepathname)
+{
+  char  *basepath;
+  int32   fileSegNoLocal;
+  int numCols;
+
+  /* Get base path for this relation file */
+  basepath = relpath(rel->rd_node);
+  numCols = rel->rd_att->natts;
+
+  FormatAOSegmentIndexFileName(basepath, segno, idxId, col, numCols, &fileSegNoLocal, filepathname);
+
+  *fileSegNo = fileSegNoLocal;
+
+  pfree(basepath);
+}
 /*
  * Open an Append Only relation file segment
  *
diff --git a/src/backend/access/bitmap/bitmapinsert.c b/src/backend/access/bitmap/bitmapinsert.c
index dcdf09e..7c7f0ce 100644
--- a/src/backend/access/bitmap/bitmapinsert.c
+++ b/src/backend/access/bitmap/bitmapinsert.c
@@ -2563,7 +2563,8 @@ _bitmap_doinsert(Relation rel, ItemPointerData ht_ctid, Datum *attdata,
 		scanKey = (ScanKey) (((char *)scanKeys) + attno * sizeof(ScanKeyData));
 
 		ScanKeyEntryInitialize(scanKey, SK_ISNULL, attno + 1, 
-							   BTEqualStrategyNumber, InvalidOid, opfuncid, 0);
+							   BTEqualStrategyNumber, InvalidOid, opfuncid, 0,
+							   InvalidAttrNumber, InvalidOid);
 
 		if (nulls[attno])
 		{
diff --git a/src/backend/access/bitmap/bitmappages.c b/src/backend/access/bitmap/bitmappages.c
index 2aa7fec..f9c4c0e 100644
--- a/src/backend/access/bitmap/bitmappages.c
+++ b/src/backend/access/bitmap/bitmappages.c
@@ -293,7 +293,7 @@ _bitmap_init_buildstate(Relation index, BMBuildState *bmstate)
 
 			ScanKeyEntryInitialize(&(bmstate->bm_lov_scanKeys[attno]), SK_ISNULL, 
 							   attno + 1, BTEqualStrategyNumber, InvalidOid, 
-							   opfuncid, 0);
+							   opfuncid, 0,  InvalidAttrNumber, InvalidOid);
 		}
 
 		bmstate->bm_lov_scanDesc = index_beginscan(bmstate->bm_lov_heap,
diff --git a/src/backend/access/bitmap/bitmapsearch.c b/src/backend/access/bitmap/bitmapsearch.c
index 7f6a3bb..1f14ab3 100644
--- a/src/backend/access/bitmap/bitmapsearch.c
+++ b/src/backend/access/bitmap/bitmapsearch.c
@@ -452,7 +452,9 @@ _bitmap_findbitmaps(IndexScanDesc scan, ScanDirection dir  __attribute__((unused
 								   scan->keyData[keyNo].sk_strategy,
 								   scan->keyData[keyNo].sk_subtype, 
 								   scan->keyData[keyNo].sk_func.fn_oid,
-								   scan->keyData[keyNo].sk_argument);
+								   scan->keyData[keyNo].sk_argument,
+								   InvalidAttrNumber,
+								   InvalidOid);
 		}
 
 		/* When there are no scan keys, all bitmap vectors are included,
diff --git a/src/backend/access/common/scankey.c b/src/backend/access/common/scankey.c
index 2524369..7a09504 100644
--- a/src/backend/access/common/scankey.c
+++ b/src/backend/access/common/scankey.c
@@ -33,21 +33,28 @@ ScanKeyEntryInitialize(ScanKey entry,
 					   AttrNumber attributeNumber,
 					   StrategyNumber strategy,
 					   Oid subtype,
-					   RegProcedure procedure,
-					   Datum argument)
+					   RegProcedure opProcedure,
+					   Datum argument,
+					   AttrNumber attributeNumberOld,
+					   RegProcedure outputProcedure)
 {
 	entry->sk_flags = flags;
 	entry->sk_attno = attributeNumber;
 	entry->sk_strategy = strategy;
 	entry->sk_subtype = subtype;
 	entry->sk_argument = argument;
-	if (RegProcedureIsValid(procedure))
-		fmgr_info(procedure, &entry->sk_func);
+	if (RegProcedureIsValid(opProcedure))
+		fmgr_info(opProcedure, &entry->sk_func);
 	else
 	{
 		Assert(flags & SK_SEARCHNULL);
 		MemSet(&entry->sk_func, 0, sizeof(entry->sk_func));
 	}
+	entry->sk_attnoold = attributeNumberOld;
+	if (RegProcedureIsValid(outputProcedure))
+		fmgr_info(outputProcedure, &entry->sk_out_func);
+	else
+	        MemSet(&entry->sk_out_func, 0, sizeof(entry->sk_out_func));
 }
 
 /*
diff --git a/src/backend/access/external/plugstorage.c b/src/backend/access/external/plugstorage.c
index f34f77c..6afc47d 100644
--- a/src/backend/access/external/plugstorage.c
+++ b/src/backend/access/external/plugstorage.c
@@ -432,8 +432,6 @@ ExternalSelectDesc InvokePlugStorageFormatGetNextInit(FmgrInfo *func,
 	FunctionCallInfoData fcinfo;
 
 	psdata.type              = T_PlugStorageData;
-	psdata.ps_plan_state     = planState;
-	psdata.ps_ext_scan_state = extScanState;
 
 	InitFunctionCallInfoData(fcinfo,  // FunctionCallInfoData
 	                         func,    // FmgrInfo
@@ -495,13 +493,53 @@ bool InvokePlugStorageFormatGetNext(FmgrInfo *func,
 }
 
 void InvokePlugStorageFormatReScan(FmgrInfo *func,
-                                   FileScanDesc fileScanDesc)
+                                   FileScanDesc fileScanDesc,
+                                   ScanState* scanState,
+                                   MagmaSnapshot* snapshot,
+                                   IndexRuntimeKeyInfo* runtimeKeyInfo,
+                                   int numRuntimeKeys,
+                                   TupleTableSlot *tupTableSlot)
 {
 	PlugStorageData psdata;
 	FunctionCallInfoData fcinfo;
 
-	psdata.type              = T_PlugStorageData;
-	psdata.ps_file_scan_desc = fileScanDesc;
+	psdata.type                = T_PlugStorageData;
+	psdata.ps_scan_state       = scanState;
+	psdata.ps_file_scan_desc   = fileScanDesc;
+	psdata.runtime_key_info    = runtimeKeyInfo;
+	psdata.num_run_time_keys   = numRuntimeKeys;
+	psdata.ps_tuple_table_slot = tupTableSlot;
+
+        if (strncmp(fileScanDesc->fs_formatter_name, "magma", strlen("magma")) == 0)
+        {
+                Insist(snapshot != NULL);
+
+                // save current transaction in snapshot
+                psdata.ps_snapshot.currentTransaction.txnId =
+                    snapshot->currentTransaction.txnId;
+                psdata.ps_snapshot.currentTransaction.txnStatus =
+                    snapshot->currentTransaction.txnStatus;;
+
+                psdata.ps_snapshot.cmdIdInTransaction = snapshot->cmdIdInTransaction;
+
+                // allocate txnActions
+                psdata.ps_snapshot.txnActions.txnActionStartOffset =
+                    snapshot->txnActions.txnActionStartOffset;
+                psdata.ps_snapshot.txnActions.txnActions =
+                    (MagmaTxnAction *)palloc0(sizeof(MagmaTxnAction) * snapshot->txnActions
+                        .txnActionSize);
+
+                // save txnActionsp
+                psdata.ps_snapshot.txnActions.txnActionSize = snapshot->txnActions
+                    .txnActionSize;
+                for (int i = 0; i < snapshot->txnActions.txnActionSize; ++i)
+                {
+                        psdata.ps_snapshot.txnActions.txnActions[i].txnId =
+                              snapshot->txnActions.txnActions[i].txnId;
+                        psdata.ps_snapshot.txnActions.txnActions[i].txnStatus =
+                              snapshot->txnActions.txnActions[i].txnStatus;
+                }
+        }
 
 	InitFunctionCallInfoData(fcinfo,  // FunctionCallInfoData
 	                         func,    // FmgrInfo
@@ -512,6 +550,12 @@ void InvokePlugStorageFormatReScan(FmgrInfo *func,
 	// Invoke function
 	FunctionCallInvoke(&fcinfo);
 
+	// free memory for magma snapshot
+	if (strncmp(fileScanDesc->fs_formatter_name, "magma", strlen("magma")) == 0)
+	{
+	        pfree(psdata.ps_snapshot.txnActions.txnActions);
+	}
+
 	// We do not expect a null result
 	if (fcinfo.isnull)
 	{
diff --git a/src/backend/access/index/catquery.c b/src/backend/access/index/catquery.c
index 5c8b44e..f4b8e36 100644
--- a/src/backend/access/index/catquery.c
+++ b/src/backend/access/index/catquery.c
@@ -124,15 +124,21 @@ ARGV: \-meta\ \/Users\/jianl\/Git\/hawq\/mn\/cdb\-pg\/\.\.\/gpMgmt\/bin\/gppylib
 #include "catalog/gp_configuration.h"
 #include "catalog/gp_segment_config.h"
 #include "catalog/gp_san_config.h"
-
 #include "catalog/gp_fastsequence.h"
-
 #include "catalog/gp_master_mirroring.h"
 #include "catalog/gp_persistent.h"
 #include "catalog/gp_global_sequence.h"
 #include "catalog/gp_version.h"
-#include "catalog/toasting.h"
 #include "catalog/gp_policy.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_index.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
+#include "catalog/toasting.h"
 
 #include "miscadmin.h"
 #include "storage/fd.h"
diff --git a/src/backend/access/index/gperf.init b/src/backend/access/index/gperf.init
index da33b47..60e30ec 100644
--- a/src/backend/access/index/gperf.init
+++ b/src/backend/access/index/gperf.init
@@ -100,8 +100,16 @@ ARGV: \-meta\ \/Users\/yjin\/hawq_main\/gpMgmt\/bin\/gppylib\/data\/2\.0\.json\
 #include "catalog/gp_persistent.h"
 #include "catalog/gp_global_sequence.h"
 #include "catalog/gp_version.h"
-#include "catalog/toasting.h"
 #include "catalog/gp_policy.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_index.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
+#include "catalog/toasting.h"
 
 #include "miscadmin.h"
 #include "storage/fd.h"
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index d01fcba..545ea06 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -725,7 +725,9 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
 									   InvalidStrategy,
 									   cur->sk_subtype,
 									   cmp_proc,
-									   cur->sk_argument);
+									   cur->sk_argument,
+									   InvalidAttrNumber,
+									   InvalidOid);
 			}
 		}
 	}
diff --git a/src/backend/access/orc/orcam.c b/src/backend/access/orc/orcam.c
index cc4893b..f226844 100644
--- a/src/backend/access/orc/orcam.c
+++ b/src/backend/access/orc/orcam.c
@@ -32,6 +32,7 @@
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/execnodes.h"
+#include "nodes/plannodes.h"
 #include "optimizer/newPlanner.h"
 #include "storage/cwrapper/hdfs-file-system-c.h"
 #include "storage/cwrapper/orc-format-c.h"
@@ -77,6 +78,54 @@ typedef struct OrcFormatData {
   struct varlena **colFixedLenUDT;
 } OrcFormatData;
 
+static void initOrcFormatIndexUserData(TupleDesc tup_desc,
+                                       OrcFormatData *orcFormatData,
+                                       bool *colToReads, List *columnsInIndex,
+                                       bool *colToReadInIndex) {
+  int natts = list_length(columnsInIndex) + 1;
+  orcFormatData->numberOfColumns = natts;
+  orcFormatData->colNames = palloc0(sizeof(char *) * natts);
+  orcFormatData->colDatatypes = palloc0(sizeof(int) * natts);
+  orcFormatData->colDatatypeMods = palloc0(sizeof(uint64) * natts);
+  orcFormatData->colRawValues = palloc0(sizeof(char *) * natts);
+  orcFormatData->colValLength = palloc0(sizeof(uint64) * natts);
+  orcFormatData->colTimestamp = palloc0(sizeof(TimestampType) * natts);
+  orcFormatData->colFixedLenUDT = palloc0(sizeof(struct varlena *) * natts);
+  int count = 0;
+  for (int i = 0; i < tup_desc->natts; ++i) {
+    for (int j = 0; j < list_length(columnsInIndex); j++) {
+      if ((int)list_nth_oid(columnsInIndex, j) - 1 == i) {
+        // allocate memory for colFixedLenUDT[i] of fixed-length type in advance
+        bool isFixedLengthType = tup_desc->attrs[i]->attlen > 0 ? true : false;
+        if (isFixedLengthType) {
+          orcFormatData->colFixedLenUDT[count] = (struct valena *)palloc0(
+              tup_desc->attrs[i]->attlen + sizeof(uint32_t));
+        }
+        orcFormatData->colNames[count] = palloc0(NAMEDATALEN);
+        strcpy(orcFormatData->colNames[count],
+               tup_desc->attrs[i]->attname.data);
+        orcFormatData->colDatatypes[count] =
+            map_hawq_type_to_common_plan((int)(tup_desc->attrs[i]->atttypid));
+        orcFormatData->colDatatypeMods[count] = tup_desc->attrs[i]->atttypmod;
+        if (orcFormatData->colDatatypes[count] == CHARID &&
+            tup_desc->attrs[i]->atttypmod == -1) {
+          // XXX(chiyang): From orc.c to determine BPCHAR's typemod
+          orcFormatData->colDatatypeMods[count] =
+              strlen(tup_desc->attrs[i]->attname.data) + VARHDRSZ;
+        }
+        if (colToReads[i]) {
+          colToReadInIndex[count] = true;
+        }
+        count++;
+      }
+    }
+  }
+  orcFormatData->colNames[count] = palloc0(NAMEDATALEN);
+  strcpy(orcFormatData->colNames[count], "tid");
+  orcFormatData->colDatatypes[count] = BIGINTID;
+  orcFormatData->colDatatypeMods[count] = -1;
+}
+
 static void initOrcFormatUserData(TupleDesc tup_desc,
                                   OrcFormatData *orcFormatData) {
   int natts = tup_desc->natts;
@@ -128,7 +177,7 @@ static freeOrcFormatUserData(OrcFormatData *orcFormatData) {
   pfree(orcFormatData->colNames);
 }
 
-static void checkOrcError(OrcFormatData *orcFormatData) {
+void checkOrcError(OrcFormatData *orcFormatData) {
   ORCFormatCatchedError *e = ORCFormatGetErrorORCFormatC(orcFormatData->fmt);
   if (e->errCode != ERRCODE_SUCCESSFUL_COMPLETION) {
     ORCFormatCatchedError errBuf = *e;
@@ -152,6 +201,85 @@ static void addFilesystemCredential(const char *uri) {
   }
 }
 
+void constructOrcFormatOptionString(StringInfoData *option, Relation rel,
+                                    ResultRelSegFileInfo *segfileinfo,
+                                    AppendOnlyEntry *aoentry) {
+  initStringInfo(option);
+  appendStringInfoChar(option, '{');
+
+  // neglect for UPDATE/DELETE
+  if (segfileinfo) {
+    appendStringInfo(option, "\"logicEof\": %" PRId64, segfileinfo->eof[0]);
+    appendStringInfo(option, ", \"uncompressedEof\": %lld, ",
+                     segfileinfo->uncompressed_eof[0]);
+  }
+
+  appendStringInfo(
+      option, "\"stripeSize\": %" PRId64,
+      ((StdRdOptions *)(rel->rd_options))->stripesize * 1024 * 1024);
+  appendStringInfo(option, ", \"rowIndexStride\": %" PRId64,
+                   ((StdRdOptions *)(rel->rd_options))->rowindexstride);
+  appendStringInfo(option, ", \"blockSize\": %" PRId64,
+                   ((StdRdOptions *)(rel->rd_options))->compressblocksize);
+  if (aoentry->compresstype)
+    appendStringInfo(option, ", %s", aoentry->compresstype);
+
+  // transform bloomfilter option from column names to column indexes.
+  if (((StdRdOptions *)(rel->rd_options))->bloomfilter) {
+    TupleDesc tupDesc = rel->rd_att;
+    int attrNum = tupDesc->natts;
+    char **attrNames = palloc0(attrNum * sizeof(char *));
+    for (int i = 0; i < attrNum; ++i) {
+      int nameLen =
+          strlen(((Form_pg_attribute)(tupDesc->attrs[i]))->attname.data);
+      char *attribute = palloc0(nameLen + 1);
+      strncpy(attribute, ((Form_pg_attribute)(tupDesc->attrs[i]))->attname.data,
+              nameLen);
+      attrNames[i] = attribute;
+    }
+
+    StringInfoData bloomFilterOptsStr;
+    initStringInfo(&bloomFilterOptsStr);
+    char *token = strtok(((StdRdOptions *)(rel->rd_options))->bloomfilter, ",");
+    while (token) {
+      for (int attrIdx = 0; attrIdx < attrNum; ++attrIdx) {
+        if (strncasecmp(token, attrNames[attrIdx],
+                        strlen(attrNames[attrIdx])) == 0) {
+          appendStringInfo(&bloomFilterOptsStr, "%d", attrIdx + 1);
+          appendStringInfoChar(&bloomFilterOptsStr, ',');
+          break;
+        }
+      }
+      token = strtok(NULL, ",");
+    }
+    if (bloomFilterOptsStr.data[bloomFilterOptsStr.len - 1] == ',')
+      bloomFilterOptsStr.data[bloomFilterOptsStr.len - 1] = '\0';
+    appendStringInfo(option, ", \"bloomfilter\": [%s]",
+                     pstrdup(bloomFilterOptsStr.data));
+  }
+
+  appendStringInfoChar(option, '}');
+}
+
+// FIXME(sxwang): In fact, upstream logic should ensure that FileSplit are all
+// valid.
+static bool IsValidFileSplit(FileSplit split, Oid idxId) {
+  return split->replicaGroup_id == idxId;
+}
+
+// Filter invalid fileSplit.
+static int32 GetSplitCount(List *fileSplits, Oid idxId) {
+  int32 splitCount = list_length(fileSplits);
+  int32 ret = 0;
+  for (int32 i = 0; i < splitCount; ++i) {
+    if (IsValidFileSplit(list_nth(fileSplits, i), idxId)) {
+      ++ret;
+    }
+  }
+  return ret;
+}
+
+>>>>>>> 7910d663d... step2
 OrcInsertDescData *orcBeginInsert(Relation rel,
                                   ResultRelSegFileInfo *segfileinfo) {
   OrcInsertDescData *insertDesc =
@@ -367,6 +495,14 @@ void orcReScan(ScanState *scanState) {
 OrcScanDescData *orcBeginRead(Relation rel, Snapshot snapshot, TupleDesc desc,
                               List *fileSplits, bool *colToReads,
                               void *pushDown) {
+  return orcBeginReadWithOptionsStr(rel, snapshot, desc, fileSplits, colToReads,
+                                    pushDown, "{}");
+}
+
+OrcScanDescData *orcBeginReadWithOptionsStr(Relation rel, Snapshot snapshot,
+                                            TupleDesc desc, List *fileSplits,
+                                            bool *colToReads, void *pushDown,
+                                            const char *optsStr) {
   OrcScanDescData *scanDesc = palloc0(sizeof(OrcScanDescData));
   OrcFormatData *orcFormatData = scanDesc->orcFormatData =
       palloc0(sizeof(OrcFormatData));
@@ -377,20 +513,30 @@ OrcScanDescData *orcBeginRead(Relation rel, Snapshot snapshot, TupleDesc desc,
     desc = RelationGetDescr(rel);
 
   scanDesc->rel = rel;
-  orcFormatData->fmt = ORCFormatNewORCFormatC("{}", 0);
+  orcFormatData->fmt = ORCFormatNewORCFormatC(optsStr, 0);
   initOrcFormatUserData(desc, orcFormatData);
 
-  int32 splitCount = list_length(fileSplits);
+  int32 splitCount = GetSplitCount(fileSplits, InvalidOid);
   ORCFormatFileSplit *splits = palloc0(sizeof(ORCFormatFileSplit) * splitCount);
   int32 filePathMaxLen = AOSegmentFilePathNameLen(rel) + 1;
-  for (int32 i = 0; i < splitCount; ++i) {
+  int32 orgSplitCount = list_length(fileSplits);
+  for (int32 i = 0, j = 0; i < orgSplitCount; ++i) {
     FileSplit split = (FileSplitNode *)list_nth(fileSplits, i);
-    splits[i].start = split->offsets;
-    splits[i].len = split->lengths;
-    splits[i].eof = split->logiceof;
-    splits[i].fileName = palloc0(filePathMaxLen);
-    MakeAOSegmentFileName(rel, split->segno, -1, dummyPlaceholder,
-                          splits[i].fileName);
+    if (IsValidFileSplit(split, InvalidOid)) {
+      splits[j].start = split->offsets;
+      splits[j].len = split->lengths;
+      splits[j].eof = split->logiceof;
+
+      if (split->ext_file_uri_string) {
+        // XXX(chiyang): hack way to manage split info manually
+        splits[j].fileName = split->ext_file_uri_string;
+      } else {
+        splits[j].fileName = palloc0(filePathMaxLen);
+        MakeAOSegmentFileName(rel, split->segno, -1, dummyPlaceholder,
+                              splits[j].fileName);
+      }
+      ++j;
+    }
   }
 
   if (splitCount > 0)
@@ -419,6 +565,108 @@ OrcScanDescData *orcBeginRead(Relation rel, Snapshot snapshot, TupleDesc desc,
   return scanDesc;
 }
 
+void orcIndexReadNext(OrcScanDescData *scanData, TupleTableSlot *slot,
+                      List *columnsInIndex) {
+  OrcFormatData *orcFormatData = scanData->orcFormatData;
+  bool *nulls = slot_get_isnull(slot);
+  bool *idxnulls = palloc0(sizeof(bool) * orcFormatData->numberOfColumns);
+  memset(idxnulls, true, orcFormatData->numberOfColumns);
+  Datum *values = slot_get_values(slot);
+  TupleDesc tupleDesc = slot->tts_tupleDescriptor;
+  int natts = tupleDesc->natts;
+  memset(nulls, true, natts);
+
+  uint64_t rowId;
+  bool res = ORCFormatNextORCFormatWithRowIdC(
+      orcFormatData->fmt, orcFormatData->colRawValues,
+      orcFormatData->colValLength, idxnulls, &rowId);
+
+  checkOrcError(orcFormatData);
+  int idx = 0;
+  if (res) {
+    for (int32_t i = 0; i < natts; ++i) {
+      // can't find the column in columnsInIndex
+      if (!list_member_oid(columnsInIndex, i + 1)) continue;
+      // index data is null
+      if (idxnulls[idx]) {
+        idx++;
+        continue;
+      }
+      nulls[i] = false;
+      switch (tupleDesc->attrs[i]->atttypid) {
+        case HAWQ_TYPE_BOOL: {
+          values[i] = BoolGetDatum(*(bool *)(orcFormatData->colRawValues[idx]));
+          break;
+        }
+        case HAWQ_TYPE_INT2: {
+          values[i] =
+              Int16GetDatum(*(int16_t *)(orcFormatData->colRawValues[idx]));
+          break;
+        }
+        case HAWQ_TYPE_INT4: {
+          values[i] =
+              Int32GetDatum(*(int32_t *)(orcFormatData->colRawValues[idx]));
+          break;
+        }
+        case HAWQ_TYPE_INT8:
+        case HAWQ_TYPE_TIME:
+        case HAWQ_TYPE_TIMESTAMP:
+        case HAWQ_TYPE_TIMESTAMPTZ: {
+          values[i] =
+              Int64GetDatum(*(int64_t *)(orcFormatData->colRawValues[idx]));
+          break;
+        }
+        case HAWQ_TYPE_FLOAT4: {
+          values[i] =
+              Float4GetDatum(*(float *)(orcFormatData->colRawValues[idx]));
+          break;
+        }
+        case HAWQ_TYPE_FLOAT8: {
+          values[i] =
+              Float8GetDatum(*(double *)(orcFormatData->colRawValues[idx]));
+          break;
+        }
+        case HAWQ_TYPE_DATE: {
+          values[i] =
+              Int32GetDatum(*(int32_t *)(orcFormatData->colRawValues[idx]) -
+                            POSTGRES_EPOCH_JDATE + UNIX_EPOCH_JDATE);
+          break;
+        }
+        default: {
+          // Check whether value[i] is fixed length udt.
+          bool isFixedLengthType =
+              tupleDesc->attrs[i]->attlen > 0 ? true : false;
+          bool isPassByVal = tupleDesc->attrs[i]->attbyval;
+          if (isFixedLengthType) {
+            if (isPassByVal) {  // pass by val
+              struct varlena *var =
+                  (struct varlena *)(orcFormatData->colRawValues[idx]);
+              uint32 valLen = *(uint32 *)(var->vl_len_);
+              memcpy((void *)&values[i], var->vl_dat, valLen);
+            } else {  // pass by pointer
+              SET_VARSIZE((struct varlena *)(orcFormatData->colRawValues[idx]),
+                          orcFormatData->colValLength[idx]);
+              values[i] = PointerGetDatum(orcFormatData->colRawValues[idx] +
+                                          sizeof(uint32_t));
+            }
+          } else {
+            SET_VARSIZE((struct varlena *)(orcFormatData->colRawValues[idx]),
+                        orcFormatData->colValLength[idx]);
+            values[i] = PointerGetDatum(orcFormatData->colRawValues[idx]);
+          }
+          break;
+        }
+      }
+      idx++;
+    }
+    TupSetVirtualTupleNValid(slot, slot->tts_tupleDescriptor->natts);
+    ItemPointerSetRowIdToFakeCtid(&scanData->cdb_fake_ctid, rowId);
+    slot_set_ctid(slot, &scanData->cdb_fake_ctid);
+  } else {
+    ExecClearTuple(slot);
+  }
+}
+
 void orcReadNext(OrcScanDescData *scanData, TupleTableSlot *slot) {
   OrcFormatData *orcFormatData = scanData->orcFormatData;
   bool *nulls = slot_get_isnull(slot);
@@ -914,7 +1162,7 @@ uint64 orcEndUpdate(OrcUpdateDescData *updateDesc) {
   return callback.processedTupleCount;
 }
 
-int64_t *orcCreateIndex(Relation rel, int idxId, List *segno, int64 *eof,
+int64_t *orcCreateIndex(Relation rel, Oid idxId, List *segno, int64 *eof,
                         List *columnsToRead, int sortIdx) {
   checkOushuDbExtensiveFeatureSupport("ORC INDEX");
   OrcScanDescData *scanDesc = palloc0(sizeof(OrcScanDescData));
@@ -939,6 +1187,10 @@ int64_t *orcCreateIndex(Relation rel, int idxId, List *segno, int64 *eof,
   for (int i = 0; i < sortIdx; i++) {
     sortIdxList[i] = list_nth_int(columnsToRead, i) - 1;
   }
+  int *segnoList = palloc0(sizeof(int) * splitCount);
+  for (int i = 0; i < splitCount; i++) {
+    segnoList[i] = list_nth_int(segno, i);
+  }
 
   ORCFormatFileSplit *splits = palloc0(sizeof(ORCFormatFileSplit) * splitCount);
   int32 filePathMaxLen = AOSegmentFilePathNameLen(rel) + 1;
@@ -954,7 +1206,148 @@ int64_t *orcCreateIndex(Relation rel, int idxId, List *segno, int64 *eof,
       idxId, splits, splitCount, eof, columnsToReadList, sortIdxList, sortIdx,
       orcFormatData->colNames, orcFormatData->colDatatypes,
       orcFormatData->colDatatypeMods, orcFormatData->numberOfColumns,
-      gp_session_id, rm_seg_tmp_dirs);
+      gp_session_id, rm_seg_tmp_dirs, segnoList);
+}
+
+static int OrcoidComparator(const void *arg1, const void *arg2) {
+  Oid oid1 = *(const Oid *)arg1;
+  Oid oid2 = *(const Oid *)arg2;
+
+  if (oid1 > oid2) return 1;
+  if (oid1 < oid2) return -1;
+  return 0;
+}
+
+void orcBeginIndexOnlyScan(ScanState *scanState, Oid idxId,
+                           List *columnsInIndex) {
+  Assert(scanState->scan_state == SCAN_INIT ||
+         scanState->scan_state == SCAN_DONE);
+  Assert(length(columnsInIndex) > 0);
+
+  Relation rel = scanState->ss_currentRelation;
+  int natts = rel->rd_att->natts;
+  bool *colToReads = palloc0(sizeof(bool) * natts);
+  GetNeededColumnsForScan((Node *)scanState->ps.plan->targetlist, colToReads,
+                          natts);
+  OrcIndexOnlyScan *plan =
+      (OrcIndexOnlyScan *)(((IndexScanState *)scanState)->ss.ps.plan);
+  GetNeededColumnsForScan((Node *)(plan->indexqualorig), colToReads, natts);
+
+  GetNeededColumnsForScan((Node *)scanState->ps.plan->qual, colToReads, natts);
+
+  ((IndexScanState *)scanState)->scandesc = orcBeginIndexOnlyRead(
+      rel, idxId, columnsInIndex, scanState->ps.state->es_snapshot, NULL,
+      scanState->splits, colToReads, scanState->ps.plan);
+
+  pfree(colToReads);
+  scanState->scan_state = SCAN_SCAN;
+}
+
+TupleTableSlot *orcIndexOnlyScanNext(ScanState *scanState) {
+  orcIndexReadNext(
+      ((IndexScanState *)scanState)->scandesc, scanState->ss_ScanTupleSlot,
+      ((IndexScan *)(((IndexScanState *)scanState)->ss.ps.plan))->idxColummns);
+  return scanState->ss_ScanTupleSlot;
+}
+
+void orcEndIndexOnlyScan(ScanState *scanState) {
+  if ((((IndexScanState *)scanState)->ss.scan_state & SCAN_SCAN) != 0) {
+    OrcScanDescData *scanDesc = ((IndexScanState *)scanState)->scandesc;
+
+    orcEndRead(scanDesc);
+
+    pfree(scanDesc);
+    scanState->scan_state = SCAN_INIT;
+  }
+}
+
+void orcIndexOnlyReScan(ScanState *scanState) {
+  orcResetRead(((IndexScanState *)scanState)->scandesc);
+}
+
+OrcScanDescData *orcBeginIndexOnlyRead(Relation rel, Oid idxId,
+                                       List *columnsInIndex, Snapshot snapshot,
+                                       TupleDesc desc, List *fileSplits,
+                                       bool *colToReads, void *pushDown) {
+  OrcScanDescData *scanDesc = palloc0(sizeof(OrcScanDescData));
+  OrcFormatData *orcFormatData = scanDesc->orcFormatData =
+      palloc0(sizeof(OrcFormatData));
+
+  RelationIncrementReferenceCount(rel);
+
+  if (desc == NULL) desc = RelationGetDescr(rel);
+
+  scanDesc->rel = rel;
+  orcFormatData->fmt = ORCFormatNewORCFormatC("{}", 0);
+  ORCFormatSetIndexFlag(orcFormatData->fmt);
+  bool *colToReadInIndex =
+      palloc0(sizeof(bool) * (list_length(columnsInIndex) + 1));
+  initOrcFormatIndexUserData(desc, orcFormatData, colToReads, columnsInIndex,
+                             colToReadInIndex);
+
+  int32 splitCount = GetSplitCount(fileSplits, idxId);
+  ORCFormatFileSplit *splits = palloc0(sizeof(ORCFormatFileSplit) * splitCount);
+  int lenOfIdxId = 0;
+  Oid idxCount = idxId;
+  while (idxCount) {
+    lenOfIdxId++;
+    idxCount /= 10;
+  }
+  if (lenOfIdxId == 0) lenOfIdxId = 1;
+  int32 filePathMaxLen = AOSegmentFilePathNameLen(rel) + lenOfIdxId + 2;
+  int32 orgSplitCount = list_length(fileSplits);
+  for (int32 i = 0, j = 0; i < orgSplitCount; ++i) {
+    FileSplit split = (FileSplitNode *)list_nth(fileSplits, i);
+    if (IsValidFileSplit(split, idxId)) {
+      splits[j].start = split->offsets;
+      splits[j].len = split->lengths;
+      splits[j].eof = split->logiceof;
+      splits[j].fileName = palloc0(filePathMaxLen);
+      MakeAOSegmentIndexFileName(rel, idxId, split->segno, -1, dummyPlaceholder,
+                                 splits[j].fileName);
+      ++j;
+    }
+  }
+
+  if (splitCount > 0) addFilesystemCredential(splits[0].fileName);
+
+  void *qualList = NULL;
+  CommonPlanContext ctx;
+  ctx.univplan = NULL;
+  Plan *plan = (Plan *)pushDown;
+
+  /*
+   * 1. the varattno of indexqualorig consistent with table columns info
+   * 2. the varattno of indexqualorig does not match the index file
+   * 3. adjust the "columnsInIndex" order
+   * 4. fix indexqualorig varattno utilization "columnsInIndex" in
+   * do_convert_expr_to_common_plan to be consistent with index file
+   */
+  int len = length(columnsInIndex);
+  Oid *value = palloc(len * sizeof(Oid));
+  for (int i = 0; i < len; ++i) {
+    value[i] = list_nth_oid(columnsInIndex, i);
+  }
+  qsort(value, len, sizeof(Oid), OrcoidComparator);
+  List *colIdxs = NIL;
+  for (int i = 0; i < len; ++i) {
+    colIdxs = lappend_oid(colIdxs, value[i]);
+  }
+  pfree(value);
+  qualList = convert_orcscan_indexqualorig_to_common_plan(plan, &ctx, colIdxs);
+
+  ORCFormatBeginORCFormatC(
+      orcFormatData->fmt, splits, splitCount, colToReadInIndex,
+      orcFormatData->colNames, orcFormatData->colDatatypes,
+      orcFormatData->colDatatypeMods, orcFormatData->numberOfColumns, qualList);
+  checkOrcError(orcFormatData);
+
+  ItemPointerSetInvalid(&scanDesc->cdb_fake_ctid);
+
+  for (int32 i = 0; i < splitCount; ++i) pfree(splits[i].fileName);
+  pfree(splits);
+
+  return scanDesc;
 }
 
 bool isDirectDispatch(Plan *plan) {
diff --git a/src/backend/access/orc/orcsegfiles.c b/src/backend/access/orc/orcsegfiles.c
index 8fea0a8..8a1a6a0 100644
--- a/src/backend/access/orc/orcsegfiles.c
+++ b/src/backend/access/orc/orcsegfiles.c
@@ -21,10 +21,14 @@
 
 #include "access/orcsegfiles.h"
 
+#include "access/aomd.h"
 #include "access/filesplit.h"
 #include "access/genam.h"
+#include "catalog/catalog.h"
 #include "nodes/relation.h"
+#include "cdb/cdbmetadatacache.h"
 #include "cdb/cdbvars.h"
+#include "storage/fd.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 
@@ -105,7 +109,31 @@ void insertOrcSegnoEntry(AppendOnlyEntry *aoEntry, int segNo, float8 tupleCount,
   heap_close(segRel, RowExclusiveLock);
 }
 
-void deleteOrcIndexFileInfo(AppendOnlyEntry *aoEntry, int idxOid)
+void deleteOrcIndexHdfsFiles(Relation rel, int32 segmentFileNum, int32 idx)
+{
+  RelFileNode rd_node = rel->rd_node;
+  char *basepath = relpath(rel->rd_node);
+  HdfsFileInfo *file_info;
+  char *path = (char*)palloc(MAXPGPATH + 1);
+
+  FormatAOSegmentIndexFileName(basepath, segmentFileNum, idx,  -1, 0, &segmentFileNum, path);
+
+  RemovePath(path, 0);
+
+  if (!IsLocalPath(path) && Gp_role == GP_ROLE_DISPATCH)
+  {
+    // Remove Hdfs block locations info in Metadata Cache
+    file_info = CreateHdfsFileInfo(rd_node, segmentFileNum);
+    LWLockAcquire(MetadataCacheLock, LW_EXCLUSIVE);
+    RemoveHdfsFileBlockLocations(file_info);
+    LWLockRelease(MetadataCacheLock);
+    DestroyHdfsFileInfo(file_info);
+  }
+
+  pfree(path);
+}
+
+void deleteOrcIndexFileInfo(Relation rel, AppendOnlyEntry *aoEntry, int idxOid)
 {
   if (aoEntry->blkdirrelid == 0) return;
   Relation segRel = heap_open(aoEntry->blkdirrelid, RowExclusiveLock);
@@ -118,6 +146,10 @@ void deleteOrcIndexFileInfo(AppendOnlyEntry *aoEntry, int idxOid)
   HeapTuple tuple;
   while ((tuple = systable_getnext(scan)))
   {
+    int segno = DatumGetInt32(fastgetattr(tuple, Anum_pg_orcseg_idx_segno, desc, NULL));
+    /* delete hdfs index files */
+    deleteOrcIndexHdfsFiles(rel, segno, idxOid);
+    /* delete catalog info */
     simple_heap_delete(segRel, &tuple->t_self);
   }
 
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index 94be0d3..21dc3e4 100755
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -67,6 +67,14 @@
 #include "catalog/pg_type.h"
 #include "catalog/pg_user_mapping.h"
 #include "catalog/pg_tidycat.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_index.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
 #include "catalog/toasting.h"
 #include "commands/defrem.h"
 #include "miscadmin.h"
@@ -320,6 +328,36 @@ Boot_CreateStmt:
 							case GpConfigHistoryRelationId:
 								typid = GP_CONFIGURATION_HISTORY_RELTYPE_OID;
 								break;
+/* relation id: 4850 - skylon_vlabel 20190603 */
+							case VlabelRelationId:
+								typid = SKYLON_VLABEL_RELTYPE_OID;
+/* relation id: 4851 - skylon_elabel 20200224 */
+							case ElabelRelationId:
+								typid = SKYLON_ELABEL_RELTYPE_OID;
+/* relation id: 4852 - skylon_vlabel_attribute 20200224 */
+							case VlabelAttrRelationId:
+								typid = SKYLON_VLABEL_ATTRIBUTE_RELTYPE_OID;
+								break;
+/* relation id: 4853 - skylon_elabel_attribute 20200224 */
+							case ElabelAttrRelationId:
+								typid = SKYLON_ELABEL_ATTRIBUTE_RELTYPE_OID;
+								break;
+/* relation id: 4854 - skylon_graph_vlabel 20200224 */
+							case GraphVlabelRelationId:
+								typid = SKYLON_GRAPH_VLABEL_RELTYPE_OID;
+								break;
+/* relation id: 4855 - skylon_graph_elabel 20200224 */
+							case GraphElabelRelationId:
+								typid = SKYLON_GRAPH_ELABEL_RELTYPE_OID;
+								break;
+/* relation id: 4856 - skylon_graph 20200224 */
+							case GraphRelationId:
+								typid = SKYLON_GRAPH_RELTYPE_OID;
+								break;
+/* relation id: 4857 - skylon_index 20200821 */
+							case SkylonIndexRelationId:
+								typid = SKYLON_INDEX_RELTYPE_OID;
+								break;
 /* relation id: 5029 - gp_db_interfaces 20101104 */
 							case GpDbInterfacesRelationId:
 								typid = GP_DB_INTERFACES_RELTYPE_OID;
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index f8302e9..24c8bdc 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -16,6 +16,7 @@ OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
        pg_exttable.o pg_extprotocol.o pg_filesystem.o pg_largeobject.o pg_namespace.o \
        pg_operator.o pg_proc.o pg_proc_callback.o pg_shdepend.o \
        pg_type.o toasting.o aoseg.o \
+       skylon_vlabel_attribute.o skylon_vlabel.o skylon_elabel_attribute.o skylon_elabel.o skylon_graph.o skylon_graph_vlabel.o skylon_graph_elabel.o skylon_index.o \
        pg_attribute_encoding.o pg_compression.o quicklz_compression.o
 
 SUBDIRS = caql core external
@@ -108,6 +109,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_database.h pg_tablespace.h pg_pltemplate.h \
 	pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h pg_resqueue.h \
 	gp_configuration.h gp_policy.h gp_version.h \
+	skylon_vlabel.h skylon_elabel.h skylon_vlabel_attribute.h skylon_elabel_attribute.h skylon_graph_vlabel.h skylon_graph_elabel.h skylon_graph.h skylon_index.h \
 	gp_segment_config.h gp_san_config.h \
 	gp_verification_history.h \
 	pg_window.h \
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index d8e4b22..062b624 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -43,6 +43,8 @@
 #include "catalog/pg_filespace.h"
 #include "catalog/pg_filesystem.h"
 #include "catalog/pg_type.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph_vlabel.h"
 #include "cdb/cdbpartition.h"
 #include "commands/dbcommands.h"
 #include "foreign/foreign.h"
@@ -84,6 +86,9 @@ static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid,
 
 static bool is_sequence(Oid object_oid);
 
+extern char *graphVertexTableName(char *gname,char *vname);
+
+extern char *graphEdgeTableName(char *gname,char *ename);
 
 #ifdef ACLDEBUG
 static void
@@ -635,6 +640,76 @@ objectNamesToOids(GrantObjectType objtype, List *objnames)
 
 				relOid = RangeVarGetRelid(relvar, false, false /*allowHcatalog*/);
 				objects = lappend_oid(objects, relOid);
+
+				/*
+				 * If relval represents a graph, then we add all vertex and edge
+				 * tables into ojbnames such that someone who is being given
+				 * privileges to access the graph will be granted to access its
+				 * vertexs and edges.
+				 */
+
+				if (0 != caql_getcount(NULL,
+							cql("SELECT COUNT(*) FROM skylon_graph "
+								" WHERE graphname = :1 ",
+								CStringGetDatum(relvar->relname)))) {
+					cqContext cqc;
+					cqContext *pcqCtx;
+					Relation relation;
+					HeapTuple tuple;
+					Form_skylon_graph_elabel formElabel;
+					Form_skylon_graph_vlabel formVlabel;
+					Oid relid;
+					char *elabelTableName, *vlabelTableName;
+
+					/*
+					 * Try to get all edge tables.
+					 */
+					relation = heap_open(GraphElabelRelationId, AccessShareLock);
+
+					pcqCtx = caql_beginscan(
+						caql_addrel(cqclr(&cqc), relation),
+						cql("SELECT * FROM skylon_graph_elabel"
+							" WHERE graphname = :1",
+							CStringGetDatum(relvar->relname)));
+					while (HeapTupleIsValid(tuple = caql_getnext(pcqCtx))) {
+						formElabel = (Form_skylon_graph_elabel) GETSTRUCT(tuple);
+						elabelTableName = graphEdgeTableName(relvar->relname,
+																&(NameStr(formElabel->elabelname)[0]));
+						relid = RelnameGetRelid(elabelTableName);
+						pfree(elabelTableName);
+
+						if (OidIsValid(relid)) {
+							objects = lappend_oid(objects, relid);
+						}
+					}
+					caql_endscan(pcqCtx);
+					heap_close(relation, AccessShareLock);
+
+					/*
+					 * Try to get all vertex tables.
+					 */
+					relation = heap_open(GraphVlabelRelationId, AccessShareLock);
+
+					pcqCtx = caql_beginscan(
+						caql_addrel(cqclr(&cqc), relation),
+						cql("SELECT * FROM skylon_graph_vlabel"
+							" WHERE graphname = :1",
+							CStringGetDatum(relvar->relname)));
+
+					while (HeapTupleIsValid(tuple = caql_getnext(pcqCtx))) {
+						formVlabel = (Form_skylon_graph_vlabel) GETSTRUCT(tuple);
+						vlabelTableName = graphVertexTableName(relvar->relname,
+																&(NameStr(formVlabel->vlabelname)[0]));
+						relid = RelnameGetRelid(vlabelTableName);
+						pfree(vlabelTableName);
+
+						if (OidIsValid(relid)) {
+							objects = lappend_oid(objects, relid);
+						}
+					}
+					caql_endscan(pcqCtx);
+					heap_close(relation, AccessShareLock);
+				}
 			}
 			break;
 		case ACL_OBJECT_DATABASE:
@@ -2197,7 +2272,9 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
 	/* ACL_KIND_FOREIGN_SERVER */
 	gettext_noop("permission denied for foreign server %s"),
 	/* ACL_KIND_EXTPROTOCOL */
-	gettext_noop("permission denied for external protocol %s")	
+	gettext_noop("permission denied for external protocol %s"),
+	/* ACL_CLASS_GRAPH */
+	gettext_noop("permission denied for graph %s")
 };
 
 static const char *const not_owner_msg[MAX_ACL_KIND] =
@@ -2233,7 +2310,9 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
 	/* ACL_KIND_FOREIGN_SERVER */
 	gettext_noop("must be owner of foreign server %s"),
 	/* ACL_KIND_EXTPROTOCOL */
-	gettext_noop("must be owner of external protocol %s")
+	gettext_noop("must be owner of external protocol %s"),
+	/* ACL_CLASS_GRAPH */
+	gettext_noop("must be owner of graph %s")
 };
 
 
diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c
index c7b1c47..0b97f95 100755
--- a/src/backend/catalog/catalog.c
+++ b/src/backend/catalog/catalog.c
@@ -14,7 +14,6 @@
  *
  *-------------------------------------------------------------------------
  */
-
 #include "postgres.h"
 
 #include <fcntl.h>
@@ -51,6 +50,15 @@
 #include "catalog/toasting.h"
 #include "catalog/gp_policy.h"
 
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_index.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
+
 #include "miscadmin.h"
 #include "storage/fd.h"
 #include "utils/fmgroids.h"
@@ -826,6 +834,20 @@ relationId == GpSanConfigRelationId ||
 relationId == GpConfigurationRelationId || 
 /* relation id: 5006 - gp_configuration_history 20101104 */
 relationId == GpConfigHistoryRelationId || 
+///* relation id: 4850 - pg_vlabel 20200224*/
+//relationId == VlabelRelationId ||
+///* relation id: 4851 - pg_elabel 20200224*/
+//relationId == ElabelRelationId ||
+///* relation id: 4852 - pg_vlabel_attribute 20200224*/
+//relationId == VlabelAttrRelationId ||
+///* relation id: 4853 - pg_elabel_attribute 20200224*/
+//relationId == ElabelAttrRelationId ||
+///* relation id: 4854 - pg_graph_vlabel 20200224*/
+//relationId == GraphVlabelRelationId ||
+///* relation id: 4855 - pg_graph_elabel 20200224*/
+//relationId == GraphElabelRelationId ||
+///* relation id: 4856 - pg_graph 20200224*/
+//relationId == GraphRelationId ||
 /* relation id: 5029 - gp_db_interfaces 20101104 */
 relationId == GpDbInterfacesRelationId || 
 /* relation id: 5030 - gp_interfaces 20101104 */
diff --git a/src/backend/catalog/core/catcoregen.py b/src/backend/catalog/core/catcoregen.py
index 327b560..0f05d3d 100644
--- a/src/backend/catalog/core/catcoregen.py
+++ b/src/backend/catalog/core/catcoregen.py
@@ -420,6 +420,14 @@ CatCoreTableTemplate = """
 #include "catalog/catcore.h"
 #include "catalog/catalog.h"
 #include "catalog/gp_configuration.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_index.h"
 #include "catalog/gp_master_mirroring.h"
 #include "catalog/gp_policy.h"
 #include "catalog/gp_san_config.h"
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index f70081a..606af47 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -50,6 +50,14 @@
 #include "catalog/pg_type.h"
 #include "catalog/pg_type_encoding.h"
 #include "catalog/pg_user_mapping.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_index.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
 #include "cdb/cdbpartition.h"
 #include "commands/comment.h"
 #include "commands/dbcommands.h"
@@ -1070,6 +1078,18 @@ doDeletion(const ObjectAddress *object)
 			elog(NOTICE, "dependency: not yet implemented!");
 			break;
 			
+		case OCLASS_GRAPH:
+      RemoveGraphByOid(object->objectId, false);
+      break;
+
+		case OCLASS_VLABEL:
+		  RemoveVlabelByOid(object->objectId);
+		  break;
+
+		case OCLASS_ELABEL:
+		  RemoveElabelByOid(object->objectId);
+		  break;
+
 		default:
 			elog(ERROR, "unrecognized object class: %u",
 				 object->classId);
@@ -1796,6 +1816,18 @@ getObjectClass(const ObjectAddress *object)
 		case CompressionRelationId:
 			Assert(object->objectSubId == 0);
 			return OCLASS_COMPRESSION;
+
+    case GraphRelationId:
+      Assert(object->objectSubId == 0);
+      return OCLASS_GRAPH;
+
+    case VlabelRelationId:
+      Assert(object->objectSubId == 0);
+      return OCLASS_VLABEL;
+
+    case ElabelRelationId:
+      Assert(object->objectSubId == 0);
+      return OCLASS_ELABEL;
 	}
 
 	/* shouldn't get here */
@@ -2197,6 +2229,24 @@ getObjectDescription(const ObjectAddress *object)
 				elog(NOTICE, "NOT YET IMPLEMENTED");
 				break;
 			}
+    case OCLASS_GRAPH:
+      {
+        appendStringInfo(&buffer, _("graph %s"),
+                         RelidGetName(object->objectId));
+        break;
+      }
+    case OCLASS_VLABEL:
+      {
+        appendStringInfo(&buffer, _("vertex %s"),
+                         RelidGetName(object->objectId));
+        break;
+      }
+    case OCLASS_ELABEL:
+      {
+        appendStringInfo(&buffer, _("edge %s"),
+                         RelidGetName(object->objectId));
+        break;
+      }
 		default:
 			appendStringInfo(&buffer, "unrecognized object %u %u %d",
 							 object->classId,
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 2966982..d32d360 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1254,10 +1254,9 @@ index_drop(Oid indexId)
 						ObjectIdGetDatum(aoEntry->blkdirrelid))))
 		{
 			Assert(aoEntry != NULL);
-			deleteOrcIndexFileInfo(aoEntry, indexId);
+			deleteOrcIndexFileInfo(userHeapRelation, aoEntry, indexId);
 			pfree(aoEntry);
 		}
-		/* todo: need to dispatch drop index to clean index data */
 	}
 
 	/*
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index 98ef039..df3441e 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -34,6 +34,7 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "catalog/skylon_graph.h"
 #include "commands/dbcommands.h"
 #include "commands/schemacmds.h"
 #include "miscadmin.h"
@@ -226,6 +227,54 @@ bool RelationExists(const RangeVar *relation, Oid dboid)
 	return OidIsValid(namespaceId) && OidIsValid(relId);
 }
 
+char *RelidGetName(Oid relid) {
+  Relation pgclassrel = heap_open(RelationRelationId, RowExclusiveLock);
+  cqContext cqctmp;
+  HeapTuple pgclasstup = caql_getfirst(
+      caql_addrel(cqclr(&cqctmp), pgclassrel),
+      cql("SELECT * FROM pg_class "
+          " WHERE oid = :1 ",
+          ObjectIdGetDatum(relid)));
+  if(!HeapTupleIsValid(pgclasstup))
+    return NULL;
+  Form_pg_class pgclassForm = (Form_pg_class) GETSTRUCT(pgclasstup);
+
+  char *name = pstrdup(NameStr(pgclassForm->relname));
+
+  heap_close(pgclassrel, RowExclusiveLock);
+  heap_freetuple(pgclasstup);
+  return name;
+}
+
+RangeVar *RelidGetRangeVar(Oid relid) {
+  Relation pgclassrel = heap_open(RelationRelationId, RowExclusiveLock);
+  cqContext cqctmp;
+  HeapTuple pgclasstup = caql_getfirst(
+      caql_addrel(cqclr(&cqctmp), pgclassrel),
+      cql("SELECT * FROM pg_class "
+          " WHERE oid = :1 ",
+          ObjectIdGetDatum(relid)));
+  Form_pg_class pgclassForm = (Form_pg_class) GETSTRUCT(pgclasstup);
+  Relation pgnmrel = heap_open(NamespaceRelationId, RowExclusiveLock);
+  HeapTuple pgnmtup = caql_getfirst(
+      caql_addrel(cqclr(&cqctmp), pgnmrel),
+      cql("SELECT * FROM pg_namespace "
+          " WHERE oid = :1 ",
+          ObjectIdGetDatum(pgclassForm->relnamespace)));
+  Form_pg_namespace pgnmForm = (Form_pg_namespace) GETSTRUCT(pgnmtup);
+
+  RangeVar *rangeVar = makeRangeVar(NULL,
+                                    pstrdup(NameStr(pgnmForm->nspname)),
+                                    pstrdup(NameStr(pgclassForm->relname)),
+                                    -1);
+
+  heap_close(pgnmrel, RowExclusiveLock);
+  heap_freetuple(pgnmtup);
+  heap_close(pgclassrel, RowExclusiveLock);
+  heap_freetuple(pgclasstup);
+  return rangeVar;
+}
+
 /*
  * RangeVarGetRelid
  *		Given a RangeVar describing an existing relation,
@@ -2003,6 +2052,28 @@ FindDefaultConversionProc(int4 for_encoding, int4 to_encoding)
 	return InvalidOid;
 }
 
+char* findGraphSchema(char *graph) {
+  char *schema = NULL;
+  recomputeNamespacePath();
+  ListCell *l;
+  cqContext cqc;
+  Relation skylon_graph_rel = heap_open(GraphRelationId, RowExclusiveLock);
+  foreach(l, namespaceSearchPath)
+  {
+    Oid namespaceId = lfirst_oid(l);
+    char *thisschema = get_namespace_name(namespaceId);
+    if (0 < caql_getcount(
+          caql_addrel(cqclr(&cqc), skylon_graph_rel),
+          cql("SELECT COUNT(*) FROM skylon_graph "
+            " WHERE graphname = :1 AND schemaname = :2",
+            CStringGetDatum(graph), CStringGetDatum(thisschema)))){
+      schema = thisschema;
+      break;
+    }
+  }
+  heap_close(skylon_graph_rel, RowExclusiveLock);
+  return schema;
+}
 
 
 /*
diff --git a/src/backend/catalog/skylon_elabel.c b/src/backend/catalog/skylon_elabel.c
new file mode 100644
index 0000000..921576f
--- /dev/null
+++ b/src/backend/catalog/skylon_elabel.c
@@ -0,0 +1,62 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+////////////////////////////////////////////////////////////////////////////
+
+#include "postgres.h"
+
+#include "access/fileam.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catquery.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "catalog/skylon_elabel.h"
+#include "mb/pg_wchar.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "utils/uri.h"
+
+void InsertElabelEntry(const char* elabelname, const char* schemaname,
+                       const char* fromvlabel, const char* tovlabel) {
+  Relation skylon_elabel_rel;
+  HeapTuple skylon_elabel_tuple = NULL;
+  bool nulls[Natts_skylon_elabel];
+  Datum values[Natts_skylon_elabel];
+  cqContext cqc;
+  cqContext* pcqCtx;
+
+  MemSet(values, 0, sizeof(values));
+  MemSet(nulls, false, sizeof(nulls));
+
+  /*
+   * Open and lock the pg_exttable catalog.
+   */
+  skylon_elabel_rel = heap_open(ElabelRelationId, RowExclusiveLock);
+
+  pcqCtx = caql_beginscan(caql_addrel(cqclr(&cqc), skylon_elabel_rel),
+                          cql("INSERT INTO skylon_elabel", NULL));
+  NameData name1;
+  namestrcpy(&name1, elabelname);
+  values[Anum_skylon_elabel_elabelname - 1] = NameGetDatum(&name1);
+  NameData name2;
+  namestrcpy(&name2, schemaname);
+  values[Anum_skylon_elabel_schemaname - 1] = NameGetDatum(&name2);
+  NameData name3;
+  namestrcpy(&name3, fromvlabel);
+  values[Anum_skylon_elabel_fromvlabel - 1] = NameGetDatum(&name3);
+  NameData name4;
+  namestrcpy(&name4, tovlabel);
+  values[Anum_skylon_elabel_tovlabel - 1] = NameGetDatum(&name4);
+  skylon_elabel_tuple = caql_form_tuple(pcqCtx, values, nulls);
+  caql_insert(pcqCtx, skylon_elabel_tuple);
+  caql_endscan(pcqCtx);
+  heap_close(skylon_elabel_rel, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/skylon_elabel_attribute.c b/src/backend/catalog/skylon_elabel_attribute.c
new file mode 100644
index 0000000..bf934c8
--- /dev/null
+++ b/src/backend/catalog/skylon_elabel_attribute.c
@@ -0,0 +1,66 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+////////////////////////////////////////////////////////////////////////////
+
+#include "postgres.h"
+
+#include "access/fileam.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catquery.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "mb/pg_wchar.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "utils/uri.h"
+
+void InsertElabelAttrEntry(const char* schemaname, const char* elabelname, const char* attrname,
+                           Oid attrtypid, int4 primaryrank, int4 rank) {
+  Relation skylon_elabel_attribute_rel;
+  HeapTuple skylon_elabel_attribute_tuple = NULL;
+  bool nulls[Natts_skylon_elabel_attribute];
+  Datum values[Natts_skylon_elabel_attribute];
+  cqContext cqc;
+  cqContext* pcqCtx;
+
+  MemSet(values, 0, sizeof(values));
+  MemSet(nulls, false, sizeof(nulls));
+
+  /*
+   * Open and lock the pg_exttable catalog.
+   */
+  skylon_elabel_attribute_rel =
+      heap_open(ElabelAttrRelationId, RowExclusiveLock);
+
+  pcqCtx = caql_beginscan(caql_addrel(cqclr(&cqc), skylon_elabel_attribute_rel),
+                          cql("INSERT INTO skylon_elabel_attribute", NULL));
+  NameData name0;
+  namestrcpy(&name0, schemaname);
+  values[Anum_skylon_elabel_attribute_schemaname - 1] = NameGetDatum(&name0);
+  NameData name1;
+  namestrcpy(&name1, elabelname);
+  values[Anum_skylon_elabel_attribute_elabelname - 1] = NameGetDatum(&name1);
+  NameData name2;
+  namestrcpy(&name2, attrname);
+  values[Anum_skylon_elabel_attribute_attrname - 1] = NameGetDatum(&name2);
+  values[Anum_skylon_elabel_attribute_attrtypid - 1] =
+      ObjectIdGetDatum(attrtypid);
+  values[Anum_skylon_elabel_attribute_primaryrank - 1] = Int32GetDatum(primaryrank);
+  values[Anum_skylon_elabel_attribute_rank - 1] = Int32GetDatum(rank);
+  skylon_elabel_attribute_tuple = caql_form_tuple(pcqCtx, values, nulls);
+  caql_insert(pcqCtx, skylon_elabel_attribute_tuple);
+  caql_endscan(pcqCtx);
+  heap_close(skylon_elabel_attribute_rel, RowExclusiveLock);
+}
+
+
diff --git a/src/backend/catalog/skylon_graph.c b/src/backend/catalog/skylon_graph.c
new file mode 100644
index 0000000..275123b
--- /dev/null
+++ b/src/backend/catalog/skylon_graph.c
@@ -0,0 +1,60 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+////////////////////////////////////////////////////////////////////////////
+
+#include "postgres.h"
+
+#include "access/fileam.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catquery.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "catalog/skylon_graph.h"
+#include "mb/pg_wchar.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "utils/uri.h"
+
+void
+InsertGraphEntry(const char* graphname,
+                  const char* schemaname){
+  Relation  skylon_graph_rel;
+  HeapTuple skylon_graph_tuple = NULL;
+  bool    nulls[Natts_skylon_graph];
+  Datum   values[Natts_skylon_graph];
+  cqContext cqc;
+  cqContext  *pcqCtx;
+
+  MemSet(values, 0, sizeof(values));
+  MemSet(nulls, false, sizeof(nulls));
+
+    /*
+     * Open and lock the pg_exttable catalog.
+     */
+  skylon_graph_rel = heap_open(GraphRelationId, RowExclusiveLock);
+
+  pcqCtx = caql_beginscan(
+      caql_addrel(cqclr(&cqc), skylon_graph_rel),
+      cql("INSERT INTO skylon_graph",
+        NULL));
+  NameData  name1;
+  namestrcpy(&name1, graphname);
+  values[Anum_skylon_graph_graphname - 1] = NameGetDatum(&name1);
+  NameData  name2;
+  namestrcpy(&name2, schemaname);
+  values[Anum_skylon_graph_schemaname - 1] = NameGetDatum(&name2);
+  skylon_graph_tuple = caql_form_tuple(pcqCtx, values, nulls);
+  caql_insert(pcqCtx, skylon_graph_tuple);
+  caql_endscan(pcqCtx);
+  heap_close(skylon_graph_rel, RowExclusiveLock);
+}
+
diff --git a/src/backend/catalog/skylon_graph_elabel.c b/src/backend/catalog/skylon_graph_elabel.c
new file mode 100644
index 0000000..f16ae75
--- /dev/null
+++ b/src/backend/catalog/skylon_graph_elabel.c
@@ -0,0 +1,59 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+////////////////////////////////////////////////////////////////////////////
+
+#include "postgres.h"
+
+#include "access/fileam.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catquery.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "mb/pg_wchar.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "utils/uri.h"
+
+void InsertGraphElabelEntry(const char* schemaname, const char* graphname, const char* elabelname, Oid reloid) {
+  Relation skylon_graph_elabel_rel;
+  HeapTuple skylon_graph_elabel_tuple = NULL;
+  bool nulls[Natts_skylon_graph_elabel];
+  Datum values[Natts_skylon_graph_elabel];
+  cqContext cqc;
+  cqContext* pcqCtx;
+
+  MemSet(values, 0, sizeof(values));
+  MemSet(nulls, false, sizeof(nulls));
+
+  /*
+   * Open and lock the pg_exttable catalog.
+   */
+  skylon_graph_elabel_rel = heap_open(GraphElabelRelationId, RowExclusiveLock);
+
+  pcqCtx = caql_beginscan(caql_addrel(cqclr(&cqc), skylon_graph_elabel_rel),
+                          cql("INSERT INTO skylon_graph_elabel", NULL));
+  NameData name0;
+  namestrcpy(&name0, schemaname);
+  values[Anum_skylon_graph_elabel_schemaname - 1] = NameGetDatum(&name0);
+  NameData name1;
+  namestrcpy(&name1, graphname);
+  values[Anum_skylon_graph_elabel_graphname - 1] = NameGetDatum(&name1);
+  NameData name2;
+  namestrcpy(&name2, elabelname);
+  values[Anum_skylon_graph_elabel_elabelname - 1] = NameGetDatum(&name2);
+  values[Anum_skylon_graph_elabel_reloid - 1] = ObjectIdGetDatum(reloid);
+  skylon_graph_elabel_tuple = caql_form_tuple(pcqCtx, values, nulls);
+  caql_insert(pcqCtx, skylon_graph_elabel_tuple);
+  caql_endscan(pcqCtx);
+  heap_close(skylon_graph_elabel_rel, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/skylon_graph_vlabel.c b/src/backend/catalog/skylon_graph_vlabel.c
new file mode 100644
index 0000000..2b7f0b8
--- /dev/null
+++ b/src/backend/catalog/skylon_graph_vlabel.c
@@ -0,0 +1,59 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+////////////////////////////////////////////////////////////////////////////
+
+#include "postgres.h"
+
+#include "access/fileam.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catquery.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "mb/pg_wchar.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "utils/uri.h"
+
+void InsertGraphVlabelEntry(const char* schemaname, const char* graphname, const char* vlabelname, Oid reloid) {
+  Relation skylon_graph_vlabel_rel;
+  HeapTuple skylon_graph_vlabel_tuple = NULL;
+  bool nulls[Natts_skylon_graph_vlabel];
+  Datum values[Natts_skylon_graph_vlabel];
+  cqContext cqc;
+  cqContext* pcqCtx;
+
+  MemSet(values, 0, sizeof(values));
+  MemSet(nulls, false, sizeof(nulls));
+
+  /*
+   * Open and lock the pg_exttable catalog.
+   */
+  skylon_graph_vlabel_rel = heap_open(GraphVlabelRelationId, RowExclusiveLock);
+
+  pcqCtx = caql_beginscan(caql_addrel(cqclr(&cqc), skylon_graph_vlabel_rel),
+                          cql("INSERT INTO skylon_graph_vlabel", NULL));
+  NameData name0;
+  namestrcpy(&name0, schemaname);
+  values[Anum_skylon_graph_vlabel_schemaname - 1] = NameGetDatum(&name0);
+  NameData name1;
+  namestrcpy(&name1, graphname);
+  values[Anum_skylon_graph_vlabel_graphname - 1] = NameGetDatum(&name1);
+  NameData name2;
+  namestrcpy(&name2, vlabelname);
+  values[Anum_skylon_graph_vlabel_vlabelname - 1] = NameGetDatum(&name2);
+  values[Anum_skylon_graph_vlabel_reloid - 1] = ObjectIdGetDatum(reloid);
+  skylon_graph_vlabel_tuple = caql_form_tuple(pcqCtx, values, nulls);
+  caql_insert(pcqCtx, skylon_graph_vlabel_tuple);
+  caql_endscan(pcqCtx);
+  heap_close(skylon_graph_vlabel_rel, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/skylon_index.c b/src/backend/catalog/skylon_index.c
new file mode 100644
index 0000000..7a0c98b
--- /dev/null
+++ b/src/backend/catalog/skylon_index.c
@@ -0,0 +1,73 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+////////////////////////////////////////////////////////////////////////////
+
+
+#include "postgres.h"
+
+#include "catalog/skylon_index.h"
+#include "catalog/pg_type.h"
+#include "catalog/pg_proc.h"
+#include "access/genam.h"
+#include "catalog/catquery.h"
+#include "access/fileam.h"
+#include "access/heapam.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "mb/pg_wchar.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "utils/fmgroids.h"
+#include "utils/uri.h"
+
+void InsertSkylonIndexEntry(const char* schemaname , const char* graphname,
+                       const char* elename, char indextype, const char* indexname,
+                       const int2* indexkeys, int indexkeysnum, const int2* includekeys, int includekeysnum) {
+  Relation  skylon_index_rel;
+  HeapTuple skylon_index_tuple = NULL;
+  bool    nulls[Natts_skylon_index];
+  Datum   values[Natts_skylon_index];
+  cqContext cqc;
+  cqContext  *pcqCtx;
+
+  MemSet(values, 0, sizeof(values));
+  MemSet(nulls, false, sizeof(nulls));
+
+  skylon_index_rel = heap_open(SkylonIndexRelationId, RowExclusiveLock);
+
+  pcqCtx = caql_beginscan(
+      caql_addrel(cqclr(&cqc), skylon_index_rel),
+      cql("INSERT INTO skylon_index",
+        NULL));
+  NameData  name1;
+  namestrcpy(&name1, schemaname);
+  values[Anum_skylon_index_schemaname - 1] = NameGetDatum(&name1);
+  NameData  name2;
+  namestrcpy(&name2, graphname);
+  values[Anum_skylon_index_graphname - 1] = NameGetDatum(&name2);
+  NameData  name3;
+  namestrcpy(&name3, elename);
+  values[Anum_skylon_index_elename - 1] = NameGetDatum(&name3);
+  NameData  name4;
+  namestrcpy(&name4, indexname);
+  values[Anum_skylon_index_indexname - 1] = NameGetDatum(&name4);
+  values[Anum_skylon_index_indextype - 1] = CharGetDatum(indextype);
+  int2vector *indkeys = buildint2vector(NULL, indexkeysnum);
+  for (int i = 0; i < indexkeysnum; i++)
+    indkeys->values[i] = indexkeys[i];
+  values[Anum_skylon_index_indexkeys - 1] = PointerGetDatum(indkeys);
+  int2vector *incldkeys = buildint2vector(NULL, includekeysnum);
+  for (int i = 0; i < includekeysnum; i++)
+    incldkeys->values[i] = includekeys[i];
+  values[Anum_skylon_index_includekeys - 1] = PointerGetDatum(incldkeys);
+
+  skylon_index_tuple = caql_form_tuple(pcqCtx, values, nulls);
+  caql_insert(pcqCtx, skylon_index_tuple);
+  caql_endscan(pcqCtx);
+  heap_close(skylon_index_rel, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/skylon_vlabel.c b/src/backend/catalog/skylon_vlabel.c
new file mode 100644
index 0000000..89770f7
--- /dev/null
+++ b/src/backend/catalog/skylon_vlabel.c
@@ -0,0 +1,60 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+////////////////////////////////////////////////////////////////////////////
+
+
+#include "postgres.h"
+
+#include "catalog/skylon_vlabel.h"
+#include "catalog/pg_type.h"
+#include "catalog/pg_proc.h"
+#include "access/genam.h"
+#include "catalog/catquery.h"
+#include "access/fileam.h"
+#include "access/heapam.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "mb/pg_wchar.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "utils/fmgroids.h"
+#include "utils/uri.h"
+
+void
+InsertVlabelEntry(const char* vlabelname,
+                  const char* schemaname){
+  Relation  skylon_vlabel_rel;
+  HeapTuple skylon_vlabel_tuple = NULL;
+  bool    nulls[Natts_skylon_vlabel];
+  Datum   values[Natts_skylon_vlabel];
+  cqContext cqc;
+  cqContext  *pcqCtx;
+
+  MemSet(values, 0, sizeof(values));
+  MemSet(nulls, false, sizeof(nulls));
+
+    /*
+     * Open and lock the pg_exttable catalog.
+     */
+  skylon_vlabel_rel = heap_open(VlabelRelationId, RowExclusiveLock);
+
+  pcqCtx = caql_beginscan(
+      caql_addrel(cqclr(&cqc), skylon_vlabel_rel),
+      cql("INSERT INTO skylon_vlabel",
+        NULL));
+  NameData  name1;
+  namestrcpy(&name1, vlabelname);
+  values[Anum_skylon_vlabel_vlabelname - 1] = NameGetDatum(&name1);
+  NameData  name2;
+  namestrcpy(&name2, schemaname);
+  values[Anum_skylon_vlabel_schemaname - 1] = NameGetDatum(&name2);
+  skylon_vlabel_tuple = caql_form_tuple(pcqCtx, values, nulls);
+  caql_insert(pcqCtx, skylon_vlabel_tuple);
+  caql_endscan(pcqCtx);
+  heap_close(skylon_vlabel_rel, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/skylon_vlabel_attribute.c b/src/backend/catalog/skylon_vlabel_attribute.c
new file mode 100644
index 0000000..da5fee9
--- /dev/null
+++ b/src/backend/catalog/skylon_vlabel_attribute.c
@@ -0,0 +1,64 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+////////////////////////////////////////////////////////////////////////////
+
+#include "postgres.h"
+
+#include "access/fileam.h"
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catquery.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_proc.h"
+#include "catalog/pg_type.h"
+#include "catalog/skylon_vlabel_attribute.h"
+#include "mb/pg_wchar.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
+#include "utils/syscache.h"
+#include "utils/uri.h"
+
+void InsertVlabelAttrEntry(const char* schemaname, const char* vlabelname, const char* attrname,
+                           Oid attrtypid, int4 primaryrank, int4 rank) {
+  Relation skylon_vlabel_attribute_rel;
+  HeapTuple skylon_vlabel_attribute_tuple = NULL;
+  bool nulls[Natts_skylon_vlabel_attribute];
+  Datum values[Natts_skylon_vlabel_attribute];
+  cqContext cqc;
+  cqContext* pcqCtx;
+
+  MemSet(values, 0, sizeof(values));
+  MemSet(nulls, false, sizeof(nulls));
+
+  /*
+   * Open and lock the pg_exttable catalog.
+   */
+  skylon_vlabel_attribute_rel =
+      heap_open(VlabelAttrRelationId, RowExclusiveLock);
+
+  pcqCtx = caql_beginscan(caql_addrel(cqclr(&cqc), skylon_vlabel_attribute_rel),
+                          cql("INSERT INTO skylon_vlabel_attribute", NULL));
+  NameData name0;
+  namestrcpy(&name0, schemaname);
+  values[Anum_skylon_vlabel_attribute_schemaname - 1] = NameGetDatum(&name0);
+  NameData name1;
+  namestrcpy(&name1, vlabelname);
+  values[Anum_skylon_vlabel_attribute_vlabelname - 1] = NameGetDatum(&name1);
+  NameData name2;
+  namestrcpy(&name2, attrname);
+  values[Anum_skylon_vlabel_attribute_attrname - 1] = NameGetDatum(&name2);
+  values[Anum_skylon_vlabel_attribute_attrtypid - 1] =
+      ObjectIdGetDatum(attrtypid);
+  values[Anum_skylon_vlabel_attribute_primaryrank - 1] = Int32GetDatum(primaryrank);
+  values[Anum_skylon_vlabel_attribute_rank - 1] = Int32GetDatum(rank);
+  skylon_vlabel_attribute_tuple = caql_form_tuple(pcqCtx, values, nulls);
+  caql_insert(pcqCtx, skylon_vlabel_attribute_tuple);
+  caql_endscan(pcqCtx);
+  heap_close(skylon_vlabel_attribute_rel, RowExclusiveLock);
+}
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 091f1a6..8ec420c 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -855,3 +855,32 @@ CREATE VIEW pg_remote_logins AS
 		 LEFT JOIN pg_authid A ON (A.oid = C.rcowner);
 
 REVOKE ALL ON pg_remote_credentials FROM public;
+
+CREATE VIEW skylon_vertex AS
+	SELECT n.vlabelname AS vertexname, n.schemaname AS schemaname FROM skylon_vlabel AS n;
+	
+CREATE VIEW skylon_edge AS
+	SELECT n.elabelname AS edgename, n.schemaname AS schemaname, n.fromvlabel AS fromvertex, n.tovlabel AS tovertex
+	FROM skylon_elabel AS n;
+	
+CREATE VIEW skylon_vertex_attribute AS
+	SELECT n.schemaname AS schemaname, n.vlabelname AS vertexname, 
+	n.attrname AS attrname, n.attrtypid AS attrtypid, n.primaryrank AS primaryrank, n.rank AS rank
+	FROM skylon_vlabel_attribute AS n;
+	
+CREATE VIEW skylon_edge_attribute AS
+	SELECT n.schemaname AS schemaname, n.elabelname AS edgename, 
+	n.attrname AS attrname, n.attrtypid AS attrtypid, n.primaryrank AS primaryrank, n.rank AS rank
+	FROM skylon_elabel_attribute AS n;
+	
+CREATE VIEW skylon_graph_vertex AS
+	SELECT n.schemaname AS schemaname, n.graphname AS graphname, n.vlabelname AS vertexname,
+	m.location AS location, l.relname
+	FROM skylon_graph_vlabel AS n, pg_exttable AS m, pg_class AS l
+	WHERE n.reloid = m.reloid AND n.reloid = l.oid;
+	
+CREATE VIEW skylon_graph_edge AS
+	SELECT n.schemaname AS schemaname, n.graphname AS graphname, n.elabelname AS edgename,
+	m.location AS location, l.relname
+	FROM skylon_graph_elabel AS n, pg_exttable AS m, pg_class AS l
+	WHERE n.reloid = m.reloid AND n.reloid = l.oid;
diff --git a/src/backend/cdb/Makefile b/src/backend/cdb/Makefile
index 24808ed..1803d70 100644
--- a/src/backend/cdb/Makefile
+++ b/src/backend/cdb/Makefile
@@ -85,7 +85,6 @@ OBJS = cdbanalyze.o \
 	   cdbdatalocality.o \
 	   dispatcher.o \
 	   dispatcher_mgt.o \
-	   scheduler.o \
 	   workermgr.o \
 	   executormgr.o \
 	   poolmgr.o \
diff --git a/src/backend/cdb/cdbdatalocality.c b/src/backend/cdb/cdbdatalocality.c
index 5a6615d..67704b8 100644
--- a/src/backend/cdb/cdbdatalocality.c
+++ b/src/backend/cdb/cdbdatalocality.c
@@ -6,9 +6,9 @@
  * 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
@@ -102,6 +102,9 @@ typedef struct HostnameIndexEntry {
  */
 typedef struct collect_scan_rangetable_context {
 	plan_tree_base_prefix base;
+	List *indexscan_range_tables;  // range table for index only scan
+	List *indexscan_indexs;  // index oid for range table
+	List *parquetscan_range_tables; // range table for parquet scan
 	List *range_tables; // range table for scan only
 	List *full_range_tables;  // full range table
 } collect_scan_rangetable_context;
@@ -428,11 +431,17 @@ static void AOGetSegFileDataLocation(Relation relation,
 		int* allblocks, GpPolicy *targetPolicy);
 
 static void ParquetGetSegFileDataLocation(Relation relation,
-		AppendOnlyEntry *aoEntry, Snapshot metadataSnapshot,
+		Oid segrelid, Snapshot metadataSnapshot, List *idx_scan_ids,
 		split_to_segment_mapping_context *context, int64 splitsize,
 		Relation_Data *rel_data, int* hitblocks,
 		int* allblocks, GpPolicy *targetPolicy);
 
+static void ParquetGetSegFileDataLocationWrapper(
+    Relation relation, AppendOnlyEntry *aoEntry, Snapshot metadataSnapshot,
+    split_to_segment_mapping_context *context, int64 splitsize,
+    Relation_Data *rel_data, int *hitblocks, int *allblocks,
+    GpPolicy *targetPolicy);
+
 static void ExternalGetHdfsFileDataLocation(
     Relation relation, split_to_segment_mapping_context *context,
     int64 splitsize, Relation_Data *rel_data, int *allblocks,
@@ -451,7 +460,7 @@ static void ExternalGetMagmaRangeDataLocation(
 Oid LookupCustomProtocolBlockLocationFunc(char *protoname);
 
 static BlockLocation *fetch_hdfs_data_block_location(char *filepath, int64 len,
-		int *block_num, RelFileNode rnode, uint32_t segno, double* hit_ratio);
+		int *block_num, RelFileNode rnode, uint32_t segno, double* hit_ratio, bool index_scan);
 
 static void free_hdfs_data_block_location(BlockLocation *locations,
 		int block_num);
@@ -614,6 +623,9 @@ static void init_datalocality_context(PlannedStmt *plannedstmt,
 
 	context->chsl_context.relations = NIL;
 	context->srtc_context.range_tables = NIL;
+	context->srtc_context.indexscan_indexs = NIL;
+	context->srtc_context.indexscan_range_tables = NIL;
+	context->srtc_context.parquetscan_range_tables = NIL;
 	context->srtc_context.full_range_tables = plannedstmt->rtable;
 	context->srtc_context.base.node = (Node *)plannedstmt;
 
@@ -671,27 +683,40 @@ static void init_datalocality_context(PlannedStmt *plannedstmt,
 	return;
 }
 
-bool collect_scan_rangetable(Node *node,
-		collect_scan_rangetable_context *cxt) {
-	if (NULL == node) return false;
-
-	switch (nodeTag(node)) {
-	case T_ExternalScan:
-	case T_MagmaIndexScan:
-	case T_MagmaIndexOnlyScan:
-	case T_OrcIndexScan:
-	case T_OrcIndexOnlyScan:
-	case T_AppendOnlyScan:
-	case T_ParquetScan: {
-		RangeTblEntry  *rte = rt_fetch(((Scan *)node)->scanrelid,
-											   cxt->full_range_tables);
-		cxt->range_tables = lappend(cxt->range_tables, rte);
-	}
-	default:
-		break;
-	}
+bool collect_scan_rangetable(Node *node, collect_scan_rangetable_context *cxt) {
+  if (NULL == node) return false;
+
+  switch (nodeTag(node)) {
+    case T_OrcIndexScan:  // Same as T_OrcIndexOnlyScan
+    case T_OrcIndexOnlyScan: {
+      RangeTblEntry *rte =
+          rt_fetch(((Scan *)node)->scanrelid, cxt->full_range_tables);
+      cxt->indexscan_range_tables =
+          lappend_oid(cxt->indexscan_range_tables, rte->relid);
+      cxt->indexscan_indexs =
+          lappend_oid(cxt->indexscan_indexs, ((IndexScan *)node)->indexid);
+      cxt->range_tables = lappend(cxt->range_tables, rte);
+      break;
+    }
+    // FIXME(sxwang): Should we append relid to parquetscan_range_tables for all
+    // these kind of scan?
+    case T_ExternalScan:        // Fall to ParquetScan
+    case T_MagmaIndexScan:      // Fall to ParquetScan
+    case T_MagmaIndexOnlyScan:  // Fall to ParquetScan
+    case T_AppendOnlyScan:      // Fall to ParquetScan
+    case T_ParquetScan: {
+      RangeTblEntry *rte =
+          rt_fetch(((Scan *)node)->scanrelid, cxt->full_range_tables);
+      cxt->parquetscan_range_tables =
+          lappend_oid(cxt->parquetscan_range_tables, rte->relid);
+      cxt->range_tables = lappend(cxt->range_tables, rte);
+      break;
+    }
+    default:
+      break;
+  }
 
-	return plan_tree_walker(node, collect_scan_rangetable, cxt);
+  return plan_tree_walker(node, collect_scan_rangetable, cxt);
 }
 
 /*
@@ -1019,7 +1044,7 @@ int64 get_block_locations_and_calculate_table_size(split_to_segment_mapping_cont
 				} else {
 				  // for orc table, we just reuse the parquet logic here
 					rel_data->type = DATALOCALITY_PARQUET;
-					ParquetGetSegFileDataLocation(rel, aoEntry, ActiveSnapshot, context,
+					ParquetGetSegFileDataLocationWrapper(rel, aoEntry, ActiveSnapshot, context,
 							context->split_size, rel_data, &hitblocks,
 							&allblocks, targetPolicy);
 				}
@@ -1436,7 +1461,7 @@ search_host_in_stat_context(split_to_segment_mapping_context *context,
  */
 static BlockLocation *
 fetch_hdfs_data_block_location(char *filepath, int64 len, int *block_num,
-		RelFileNode rnode, uint32_t segno, double* hit_ratio) {
+		RelFileNode rnode, uint32_t segno, double* hit_ratio, bool index_scan) {
 	// for fakse test, the len of file always be zero
 	if(len == 0  && !debug_fake_datalocality){
 		*hit_ratio = 0.0;
@@ -1448,7 +1473,7 @@ fetch_hdfs_data_block_location(char *filepath, int64 len, int *block_num,
 	uint64_t beginTime;
 	beginTime = gettime_microsec();
 
-	if (metadata_cache_enable) {
+	if (metadata_cache_enable && !index_scan) {
 		file_info = CreateHdfsFileInfo(rnode, segno);
 		if (metadata_cache_testfile && metadata_cache_testfile[0]) {
 			locations = GetHdfsFileBlockLocationsForTest(filepath, len, block_num);
@@ -1663,7 +1688,7 @@ static void AOGetSegFileDataLocation(Relation relation,
 				FormatAOSegmentFileName(basepath, segno, -1, 0, &segno, segfile_path);
 				double hit_ratio=0.0;
 				locations = fetch_hdfs_data_block_location(segfile_path, logic_len,
-						&block_num, relation->rd_node, segno, &hit_ratio);
+						&block_num, relation->rd_node, segno, &hit_ratio, false);
 				*allblocks += block_num;
 				*hitblocks += block_num * hit_ratio;
 				//fake data locality need to recalculate logic length
@@ -1737,7 +1762,7 @@ static void AOGetSegFileDataLocation(Relation relation,
 				FormatAOSegmentFileName(basepath, segno, -1, 0, &segno, segfile_path);
 				double hit_ratio = 0.0;
 				locations = fetch_hdfs_data_block_location(segfile_path, logic_len,
-						&block_num, relation->rd_node, segno, &hit_ratio);
+						&block_num, relation->rd_node, segno, &hit_ratio, false);
 				*allblocks += block_num;
 				*hitblocks += block_num * hit_ratio;
 				//fake data locality need to recalculate logic length
@@ -1822,7 +1847,7 @@ static void AOGetSegFileDataLocation(Relation relation,
 				FormatAOSegmentFileName(basepath, segno, -1, 0, &segno, segfile_path);
 				double hit_ratio = 0.0;
 				locations = fetch_hdfs_data_block_location(segfile_path, logic_len,
-						&block_num, relation->rd_node, segno, &hit_ratio);
+						&block_num, relation->rd_node, segno, &hit_ratio, false);
 				*allblocks += block_num;
 				*hitblocks += block_num * hit_ratio;
 				if ((locations != NULL) && (block_num > 0)) {
@@ -1883,7 +1908,7 @@ static void AOGetSegFileDataLocation(Relation relation,
 				FormatAOSegmentFileName(basepath, segno, -1, 0, &segno, segfile_path);
 				double hit_ratio = 0.0;
 				locations = fetch_hdfs_data_block_location(segfile_path, logic_len,
-						&block_num, relation->rd_node, segno, &hit_ratio);
+						&block_num, relation->rd_node, segno, &hit_ratio, false);
 				*allblocks += block_num;
 				*hitblocks += block_num * hit_ratio;
 				//fake data locality need to recalculate logic length
@@ -1959,15 +1984,37 @@ static void AOGetSegFileDataLocation(Relation relation,
 	return;
 }
 
+static List *GetAllIdxScanIds(collect_scan_rangetable_context *context,
+                              Oid rd_id) {
+  List *ret = NULL;
+
+  ListCell *table;
+  ListCell *id;
+  for (table = list_head(context->indexscan_range_tables),
+      id = list_head(context->indexscan_indexs);
+       table != NULL; table = lnext(table), id = lnext(id)) {
+    if (lfirst_oid(table) == rd_id) {
+      if (ret == NULL) {
+        ret = list_make1_oid(lfirst_oid(id));
+      } else {
+        ret = lappend_oid(ret, lfirst_oid(id));
+      }
+    }
+  }
+
+  return ret;
+}
+
 /*
  * ParquetGetSegFileDataLocation: fetch the data location of the
  * segment files of the Parquet relation.
  */
 static void ParquetGetSegFileDataLocation(Relation relation,
-		AppendOnlyEntry *aoEntry, Snapshot metadataSnapshot,
+		Oid segrelid, Snapshot metadataSnapshot, List* idx_scan_ids,
 		split_to_segment_mapping_context *context, int64 splitsize,
 		Relation_Data *rel_data, int* hitblocks,
 		int* allblocks, GpPolicy *targetPolicy) {
+	bool index_scan = idx_scan_ids != NULL;
 	char *basepath;
 	char *segfile_path;
 	int filepath_maxlen;
@@ -1979,10 +2026,10 @@ static void ParquetGetSegFileDataLocation(Relation relation,
 	SysScanDesc parquetscan;
 
 	basepath = relpath(relation->rd_node);
-	filepath_maxlen = strlen(basepath) + 9;
+	filepath_maxlen = strlen(basepath) + 25;
 	segfile_path = (char *) palloc0(filepath_maxlen);
 
-	pg_parquetseg_rel = heap_open(aoEntry->segrelid, AccessShareLock);
+	pg_parquetseg_rel = heap_open(segrelid, AccessShareLock);
 	pg_parquetseg_dsc = RelationGetDescr(pg_parquetseg_rel);
 	parquetscan = systable_beginscan(pg_parquetseg_rel, InvalidOid, FALSE,
 			metadataSnapshot, 0, NULL);
@@ -1991,22 +2038,38 @@ static void ParquetGetSegFileDataLocation(Relation relation,
 		BlockLocation *locations;
 		int block_num = 0;
 		Relation_File *file;
-
-		int segno = DatumGetInt32(
-				fastgetattr(tuple, Anum_pg_parquetseg_segno, pg_parquetseg_dsc, NULL));
-		int64 logic_len = (int64) DatumGetFloat8(
-				fastgetattr(tuple, Anum_pg_parquetseg_eof, pg_parquetseg_dsc, NULL));
+		int segno = 0;
+		int64 logic_len = 0;
+		Oid idx_scan_id = InvalidOid;
+		if (index_scan){
+		  idx_scan_id = DatumGetObjectId(
+		      fastgetattr(tuple, Anum_pg_orcseg_idx_idxoid, pg_parquetseg_dsc, NULL));
+		 if  (!list_member_oid(idx_scan_ids, idx_scan_id)) continue;
+		  segno = DatumGetInt32(
+		      fastgetattr(tuple, Anum_pg_orcseg_idx_segno, pg_parquetseg_dsc, NULL));
+		  logic_len = (int64) DatumGetFloat8(
+		      fastgetattr(tuple, Anum_pg_orcseg_idx_eof, pg_parquetseg_dsc, NULL));
+		} else {
+		  segno = DatumGetInt32(
+		      fastgetattr(tuple, Anum_pg_parquetseg_segno, pg_parquetseg_dsc, NULL));
+		  logic_len = (int64) DatumGetFloat8(
+		      fastgetattr(tuple, Anum_pg_parquetseg_eof, pg_parquetseg_dsc, NULL));
+		}
 		context->total_metadata_logic_len += logic_len;
 		bool isRelationHash = true;
 		if (targetPolicy->nattrs == 0) {
 			isRelationHash = false;
 		}
 
+		if (index_scan) {
+		  FormatAOSegmentIndexFileName(basepath, segno, idx_scan_id, -1, 0, &segno, segfile_path);
+		} else {
+		  FormatAOSegmentFileName(basepath, segno, -1, 0, &segno, segfile_path);
+		}
 		if (!context->keep_hash || !isRelationHash) {
-			FormatAOSegmentFileName(basepath, segno, -1, 0, &segno, segfile_path);
 			double hit_ratio = 0.0;
 			locations = fetch_hdfs_data_block_location(segfile_path, logic_len,
-					&block_num, relation->rd_node, segno, &hit_ratio);
+					&block_num, relation->rd_node, segno, &hit_ratio, index_scan);
 			*allblocks += block_num;
 			*hitblocks += block_num * hit_ratio;
 			//fake data locality need to recalculate logic length
@@ -2044,7 +2107,8 @@ static void ParquetGetSegFileDataLocation(Relation relation,
 					splits[realSplitNum].host = -1;
 					splits[realSplitNum].is_local_read = true;
 					splits[realSplitNum].range_id = -1;
-					splits[realSplitNum].replicaGroup_id = -1;
+					// XXX(sxwang): hack way to pass idx_scan_id.
+					splits[realSplitNum].replicaGroup_id = idx_scan_id;
 					splits[realSplitNum].offset = offset;
 					splits[realSplitNum].length = file->locations[realSplitNum].length;
 					splits[realSplitNum].logiceof = logic_len;
@@ -2064,10 +2128,9 @@ static void ParquetGetSegFileDataLocation(Relation relation,
 				rel_data->files = lappend(rel_data->files, file);
 			}
 		} else {
-			FormatAOSegmentFileName(basepath, segno, -1, 0, &segno, segfile_path);
 			double hit_ratio = 0.0;
 			locations = fetch_hdfs_data_block_location(segfile_path, logic_len,
-					&block_num, relation->rd_node, segno, &hit_ratio);
+					&block_num, relation->rd_node, segno, &hit_ratio, index_scan);
 			*allblocks += block_num;
 			*hitblocks += block_num * hit_ratio;
 			File_Split *split = (File_Split *) palloc(sizeof(File_Split));
@@ -2075,7 +2138,8 @@ static void ParquetGetSegFileDataLocation(Relation relation,
 			file->segno = segno;
 			split->offset = 0;
 			split->range_id = -1;
-			split->replicaGroup_id = -1;
+			// XXX(sxwang): hack way to pass idx_scan_id.
+			split->replicaGroup_id = idx_scan_id;
 			split->length = logic_len;
 			split->logiceof = logic_len;
 			split->host = -1;
@@ -2119,6 +2183,30 @@ static void ParquetGetSegFileDataLocation(Relation relation,
 	return;
 }
 
+static void ParquetGetSegFileDataLocationWrapper(
+    Relation relation, AppendOnlyEntry *aoEntry, Snapshot metadataSnapshot,
+    split_to_segment_mapping_context *context, int64 splitsize,
+    Relation_Data *rel_data, int *hitblocks, int *allblocks,
+    GpPolicy *targetPolicy) {
+  // ParquetScan
+  if (list_member_oid(context->srtc_context.parquetscan_range_tables,
+                      relation->rd_id)) {
+    ParquetGetSegFileDataLocation(relation, aoEntry->segrelid, metadataSnapshot,
+                                  NULL, context, splitsize, rel_data, hitblocks,
+                                  allblocks, targetPolicy);
+  }
+  // IndexScan
+  if (list_member_oid(context->srtc_context.indexscan_range_tables,
+                      relation->rd_id)) {
+    List *idx_scan_ids =
+        GetAllIdxScanIds(&(context->srtc_context), relation->rd_id);
+    ParquetGetSegFileDataLocation(
+        relation, aoEntry->blkdirrelid, metadataSnapshot, idx_scan_ids, context,
+        splitsize, rel_data, hitblocks, allblocks, targetPolicy);
+    list_free(idx_scan_ids);
+  }
+}
+
 static void InvokeHDFSProtocolBlockLocation(Oid    procOid,
                                             List  *locs,
                                             List **blockLocations)
@@ -5976,8 +6064,8 @@ run_allocation_algorithm(SplitAllocResult *result, List *virtual_segments, Query
 	uint64_t run_datalocality = 0;
 	run_datalocality = gettime_microsec();
 	int dl_overall_time = run_datalocality - before_run_allocation;
-    
-    context->cal_datalocality_time_us = dl_overall_time; 
+
+    context->cal_datalocality_time_us = dl_overall_time;
 
 	if(debug_datalocality_time){
 		elog(LOG, "datalocality overall execution time: %d us. \n", dl_overall_time);
@@ -5985,7 +6073,7 @@ run_allocation_algorithm(SplitAllocResult *result, List *virtual_segments, Query
 
     result->datalocalityTime = (double)(context->metadata_cache_time_us + context->alloc_resource_time_us + context->cal_datalocality_time_us)/ 1000;
     appendStringInfo(result->datalocalityInfo, "DFS metadatacache: %.3f ms; resource allocation: %.3f ms; datalocality calculation: %.3f ms.",
-            (double)context->metadata_cache_time_us/1000, (double)context->alloc_resource_time_us/1000, (double)context->cal_datalocality_time_us/1000);  
+            (double)context->metadata_cache_time_us/1000, (double)context->alloc_resource_time_us/1000, (double)context->cal_datalocality_time_us/1000);
 
 	return alloc_result;
 }
@@ -6396,7 +6484,7 @@ calculate_planner_segment_num(PlannedStmt *plannedstmt, Query *query,
 			}
 			uint64_t after_rm_allocate_resource = gettime_microsec();
 			int eclaspeTime = after_rm_allocate_resource - before_rm_allocate_resource;
-        
+
             context.alloc_resource_time_us = eclaspeTime;
 
 			if(debug_datalocality_time){
@@ -6824,4 +6912,3 @@ char *search_hostname_by_ipaddr(const char *ipaddr) {
   }
   return entry->hostname;
 }
-
diff --git a/src/backend/cdb/cdbexplain.c b/src/backend/cdb/cdbexplain.c
index 1ed3395..f3bc3a6 100644
--- a/src/backend/cdb/cdbexplain.c
+++ b/src/backend/cdb/cdbexplain.c
@@ -35,7 +35,6 @@
 #include "cdb/cdbexplain.h"             /* me */
 #include "cdb/cdbpartition.h"
 #include "cdb/cdbvars.h"                /* Gp_segment */
-#include "cdb/scheduler.h"
 #include "executor/executor.h"          /* ExecStateTreeWalker */
 #include "executor/instrument.h"        /* Instrumentation */
 #include "lib/stringinfo.h"             /* StringInfo */
@@ -275,11 +274,10 @@ static int
 cdbexplain_countLeafPartTables(PlanState *planstate);
 static CdbVisitOpt newplan_collectExecStats(MyInstrumentation *instr,
                                      CdbExplain_SendStatCtx *ctx);
-
-static void cdbexplain_depositSchedulerStatsToNode(
-    PlanState *planstate, struct SchedulerData *scheduler_data,
-    MyInstrumentation **myInstr, int iInst, int stageNo,
-    struct CdbExplain_ShowStatCtx *showstatctx);
+static CdbVisitOpt myinstrument_walk_node(
+    MyInstrumentation *instr,
+    CdbVisitOpt (*walker)(MyInstrumentation *instr, void *context),
+    void *context);
 
 /*
  * cdbexplain_localExecStats
@@ -519,6 +517,36 @@ static CdbVisitOpt newplan_collectExecStats(MyInstrumentation *myinstr,
   return CdbVisit_Walk;
 }
 
+CdbVisitOpt myinstrument_walk_node(
+    MyInstrumentation *instr,
+    CdbVisitOpt (*walker)(MyInstrumentation *instr, void *context),
+    void *context) {
+  CdbVisitOpt whatnext;
+
+  if (instr == NULL) return CdbVisit_Walk;
+
+  whatnext = walker(instr, context);
+  if (whatnext == CdbVisit_Walk) {
+    if (instr->leftTree && whatnext == CdbVisit_Walk)
+      whatnext = myinstrument_walk_node(instr->leftTree, walker, context);
+    if (instr->rightTree && whatnext == CdbVisit_Walk)
+      whatnext = myinstrument_walk_node(instr->rightTree, walker, context);
+    if (instr->subTree && whatnext == CdbVisit_Walk)
+      whatnext = myinstrument_walk_node(instr->subTree, walker, context);
+    if (instr->subplan && whatnext == CdbVisit_Walk) {
+      whatnext = myinstrument_walk_node(instr->subplan, walker, context);
+    }
+    if (instr->subplanSibling && whatnext == CdbVisit_Walk) {
+      whatnext = myinstrument_walk_node(instr->subplanSibling, walker, context);
+    }
+  } else if (whatnext == CdbVisit_Skip) {
+    whatnext = CdbVisit_Walk;
+  }
+
+  Assert(whatnext != CdbVisit_Skip);
+  return whatnext;
+}
+
 /*
  * cdbexplain_sendExecStats
  *    Called by qExec process to send EXPLAIN ANALYZE statistics to qDisp.
@@ -2399,128 +2427,3 @@ cdbexplain_countLeafPartTables(PlanState *planstate)
 	Oid root_oid = getrelid(scan->scanrelid, planstate->state->es_range_table);
 	return countLeafPartTables(root_oid);
 }
-
-typedef struct CdbExplain_RecvSchedulerStatCtx {
-  CdbExplain_ShowStatCtx *showstatctx;
-  struct SchedulerData *scheduler_data;
-  int stageNo;
-} CdbExplain_RecvSchedulerStatCtx;
-
-CdbVisitOpt cdbexplain_recvSchedulerStatWalker(PlanState *planstate,
-                                               void *context) {
-  CdbExplain_RecvSchedulerStatCtx *ctx =
-      (CdbExplain_RecvSchedulerStatCtx *)context;
-
-  SchedulerSliceStats *sliceStat = &ctx->scheduler_data->slices[ctx->stageNo];
-  if (ctx->stageNo > 0)
-    cdbexplain_depositSchedulerStatsToNode(
-        planstate, ctx->scheduler_data, sliceStat->instr, sliceStat->iStatInst,
-        ctx->stageNo, ctx->showstatctx);
-  sliceStat->iStatInst++;
-
-  if (IsA(planstate, MotionState)) {
-    cdbexplain_recvSchedulerExecStats(planstate->lefttree, ctx->scheduler_data,
-                                      ((Motion *)planstate->plan)->motionID,
-                                      ctx->showstatctx);
-    return CdbVisit_Skip;
-  }
-
-  return CdbVisit_Walk;
-}
-
-void cdbexplain_recvSchedulerExecStats(
-    struct PlanState *planstate, struct SchedulerData *scheduler_data,
-    int stageNo, struct CdbExplain_ShowStatCtx *showstatctx) {
-  if (!planstate || !planstate->instrument || !showstatctx) return;
-
-  CdbExplain_RecvSchedulerStatCtx ctx;
-  ctx.scheduler_data = scheduler_data;
-  ctx.showstatctx = showstatctx;
-  ctx.stageNo = stageNo;
-  SchedulerSliceStats *sliceStat = &ctx.scheduler_data->slices[ctx.stageNo];
-  sliceStat->iStatInst = 1;
-
-  MemoryContext oldcxt;
-  oldcxt = MemoryContextSwitchTo(showstatctx->explaincxt);
-
-  planstate_walk_node(planstate, cdbexplain_recvSchedulerStatWalker, &ctx);
-  if (ctx.stageNo > 0)
-    Assert(sliceStat->iStatInst * ctx.scheduler_data->segmentNum ==
-           sliceStat->nStatInst);
-
-  MemoryContextSwitchTo(oldcxt);
-}
-
-/*
- * cdbexplain_depositSchedulerStatsToNode
- *
- * Called by cdbexplain_recvSchedulerStatWalker to update the given
- * PlanState node's Instrument node with statistics received from
- * workers or collected locally.  Attaches a CdbExplain_NodeSummary
- * block to the Instrument node.  If top node of slice, per-slice
- * statistics are transferred from the StatHdr to the SliceSummary.
- */
-static void cdbexplain_depositSchedulerStatsToNode(
-    PlanState *planstate, struct SchedulerData *scheduler_data,
-    MyInstrumentation **myInstr, int iInst, int stageNo,
-    struct CdbExplain_ShowStatCtx *showstatctx) {
-  Instrumentation *instr = planstate->instrument;
-
-  /*
-   * ns is the node summary across all QEs of the segworker group. It also
-   * contains detailed "unsummarized" raw stat for a node across all QEs in
-   * current segworker group (in the insts array)
-   */
-  CdbExplain_NodeSummary *ns;
-  int nInst;
-
-  Insist(instr);
-
-  /* Caller already switched to EXPLAIN context. */
-  Assert(CurrentMemoryContext == showstatctx->explaincxt);
-
-  /* Allocate NodeSummary block. */
-  nInst = scheduler_data->segmentNum;
-  ns = (CdbExplain_NodeSummary *)palloc0(sizeof(*ns) - sizeof(ns->insts) +
-                                         nInst * sizeof(ns->insts[0]));
-  ns->segindex0 = 0;
-  ns->ninst = nInst;
-  ns->ntuples.vcnt = scheduler_data->segmentNum;
-
-  int step = scheduler_data->slices[stageNo].nStatInst / nInst;
-
-  for (int i = 0; i < scheduler_data->segmentNum; i++, iInst+=step) {
-    ns->insts[i].startup = myInstr[iInst]->firstTupleBatch / 1000000.0;
-    ns->insts[i].total = myInstr[iInst]->counter / 1000000.0;
-    ns->insts[i].firststart.tv_sec = myInstr[iInst]->firstStart / 1000000;
-    ns->insts[i].firststart.tv_usec = myInstr[iInst]->firstStart % 1000000;
-    ns->insts[i].ntuples = myInstr[iInst]->tupleCount;
-    ns->insts[i].execmemused = myInstr[iInst]->execmemused;
-    ns->insts[i].workmemused = myInstr[iInst]->workmemused;
-    ns->insts[i].workmemwanted = myInstr[iInst]->workmemwanted;
-    ns->ntuples.vsum += myInstr[iInst]->tupleCount;
-    ns->execmemused.vsum += myInstr[iInst]->execmemused;
-    ns->workmemused.vsum += myInstr[iInst]->workmemused;
-    ns->workmemwanted.vsum += myInstr[iInst]->workmemwanted;
-    if (instr->ntuples <= ns->insts[i].ntuples) {
-      ns->ntuples.imax = i;
-      strcpy(ns->ntuples.hostnamemax, scheduler_data->hosts[i]);
-      ns->ntuples.vmax = ns->insts[i].ntuples;
-      instr->ntuples = ns->insts[i].ntuples;
-      instr->startup = ns->insts[i].startup;
-      instr->total = ns->insts[i].total;
-      instr->firststart = ns->insts[i].firststart;
-    }
-    if (instr->totalLast <= ns->insts[i].total) {
-      ns->ntuples.ilast = i;
-      strcpy(ns->ntuples.hostnamelast, scheduler_data->hosts[i]);
-      ns->ntuples.vlast = ns->insts[i].ntuples;
-      instr->startupLast = ns->insts[i].startup;
-      instr->totalLast = ns->insts[i].total;
-      instr->firststartLast = ns->insts[i].firststart;
-    }
-  }
-
-  /* Attach our new NodeSummary to the Instrumentation node. */
-  instr->cdbNodeSummary = ns;
-} /* cdbexplain_depositSchedulerStatsToNode */
diff --git a/src/backend/cdb/cdbplan.c b/src/backend/cdb/cdbplan.c
index 3bc21d9..10bb0d2 100644
--- a/src/backend/cdb/cdbplan.c
+++ b/src/backend/cdb/cdbplan.c
@@ -393,9 +393,13 @@ plan_tree_mutator(Node *node,
 
 			FLATCOPY(newidxscan, idxscan, MagmaIndexScan);
 			SCANMUTATE(newidxscan, idxscan);
+
+			MUTATE(newidxscan->indexqual, idxscan->indexqual, List *);
 			MUTATE(newidxscan->indexqualorig, idxscan->indexqualorig, List *);
 			MUTATE(newidxscan->uriList, idxscan->uriList, List *);
 			MUTATE(newidxscan->fmtOpts, idxscan->fmtOpts, List *);
+			MUTATE(newidxscan->indexstrategy, idxscan->indexstrategy, List *);
+			MUTATE(newidxscan->indexsubtype, idxscan->indexsubtype, List *);
 			// MUTATE(newidxscan->indexname, idxscan->indexname, char*);
 			newidxscan->fmtType = idxscan->fmtType;
 			return (Node *) newidxscan;
@@ -409,9 +413,13 @@ plan_tree_mutator(Node *node,
 
 			FLATCOPY(newidxscan, idxscan, MagmaIndexOnlyScan);
 			SCANMUTATE(newidxscan, idxscan);
+
+			MUTATE(newidxscan->indexqual, idxscan->indexqual, List *);
 			MUTATE(newidxscan->indexqualorig, idxscan->indexqualorig, List *);
 			MUTATE(newidxscan->uriList, idxscan->uriList, List *);
 			MUTATE(newidxscan->fmtOpts, idxscan->fmtOpts, List *);
+			MUTATE(newidxscan->indexstrategy, idxscan->indexstrategy, List *);
+			MUTATE(newidxscan->indexsubtype, idxscan->indexsubtype, List *);
 			// MUTATE(newidxscan->indexname, idxscan->indexname, char*);
 			newidxscan->fmtType = idxscan->fmtType;
 			return (Node *) newidxscan;
diff --git a/src/backend/cdb/dispatcher.c b/src/backend/cdb/dispatcher.c
index f29514a..517974b 100644
--- a/src/backend/cdb/dispatcher.c
+++ b/src/backend/cdb/dispatcher.c
@@ -1167,7 +1167,6 @@ static void dispatcher_serialize_common_plan(DispatchData *data, CommonPlanConte
                    new_executor_enable_partitioned_hashjoin_mode);
     univPlanAddGuc(ctx->univplan, "enable_external_sort",
                    new_executor_enable_external_sort_mode);
-    univPlanAddGuc(ctx->univplan, "new_scheduler", "off");
     univPlanAddGuc(ctx->univplan, "filter_pushdown", orc_enable_filter_pushdown);
     univPlanAddGuc(ctx->univplan, "magma_enable_shm", magma_enable_shm);
     sprintf(numberStrBuf, "%d", magma_shm_limit_per_block * 1024);
diff --git a/src/backend/cdb/dispatcher_new.c b/src/backend/cdb/dispatcher_new.c
index abf0c5c..77939ef 100644
--- a/src/backend/cdb/dispatcher_new.c
+++ b/src/backend/cdb/dispatcher_new.c
@@ -695,7 +695,6 @@ static void dispatcher_serialize_common_plan(MainDispatchData *data,
                    new_executor_enable_partitioned_hashjoin_mode);
     univPlanAddGuc(ctx->univplan, "enable_external_sort",
                    new_executor_enable_external_sort_mode);
-    univPlanAddGuc(ctx->univplan, "new_scheduler", "off");
     univPlanAddGuc(ctx->univplan, "filter_pushdown",
                    orc_enable_filter_pushdown);
     univPlanAddGuc(ctx->univplan, "magma_enable_shm", magma_enable_shm);
@@ -1515,6 +1514,15 @@ struct CdbDispatchResults *getDispatchResults(struct MyDispatchTask *task) {
   return ((CommonDispatchData *)task->refDispatchData)->results;
 }
 
+void checkQdError(void *dispatchData) {
+  if (Gp_role == GP_ROLE_DISPATCH) {
+    MainDispatchData *data = (MainDispatchData *)dispatchData;
+    if (data && mainDispatchHasError(data))
+      ereport(ERROR, (errcode(ERRCODE_GP_INTERCONNECTION_ERROR),
+                      errmsg(CDB_MOTION_LOST_CONTACT_STRING)));
+  }
+}
+
 const char *taskIdToString(struct MyDispatchTask *task) {
   StringInfoData str;
   initStringInfo(&str);
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 20fd6a4..dfb070a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -157,6 +157,8 @@ static int calculate_virtual_segment_number(List* candidateRelations);
 
 static bool checkMultibytesDelimFound(const char *ptr, const char *delim);
 
+extern bool parseAndTransformAsGraph(ParseState *pstate, RangeVar *rangeVar);
+
 /* ==========================================================================
  * The follwing macros aid in major refactoring of data processing code (in
  * CopyFrom(+Dispatch)). We use macros because in some cases the code must be in
@@ -994,6 +996,8 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
 	/* Allocate workspace and zero all fields */
 	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
 
+	parseAndTransformAsGraph(NULL, stmt->relation);
+
 	/* Extract options from the statement node tree */
 	foreach(option, stmt->options)
 	{
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 6d27cc0..256d683 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -570,13 +570,6 @@ ExplainOnePlan_internal(PlannedStmt *plannedstmt,
                                      LocallyExecutingSliceIndex(estate),
                                      es->showstatctx,
                                      mainDispatchGetSegNum(queryDesc->estate->mainDispatchData));
-        if (estate->scheduler_data) {
-          scheduler_receive_computenode_stats(queryDesc->estate->scheduler_data,
-                                              queryDesc->planstate);
-          cdbexplain_recvSchedulerExecStats(queryDesc->planstate,
-                                            queryDesc->estate->scheduler_data,
-                                            0, es->showstatctx);
-        }
 	} else {
 		CommonPlanContext ctx;
 		queryDesc->newPlanForceAuto = true;
@@ -793,8 +786,6 @@ ExplainOnePlan_internal(PlannedStmt *plannedstmt,
 	{
 	  if (estate->mainDispatchData)
 	    mainDispatchPrintStats(buf, estate->mainDispatchData);
-	  else if (estate->scheduler_data)
-	    scheduler_print_stats(estate->scheduler_data, buf);
 		appendStringInfo(buf, "Data locality statistics:\n");
 		if(plannedstmt->datalocalityInfo ==NULL){
 		  appendStringInfo(buf, "  no data locality information in this query\n");
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index fdd065e..887b67b 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -57,6 +57,7 @@
 #include "catalog/pg_resqueue.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_type.h"
+#include "catalog/skylon_index.h"
 #include "cdb/cdbpartition.h"
 #include "commands/dbcommands.h"
 #include "commands/defrem.h"
@@ -126,7 +127,8 @@ bool CDBCreateIndex(IndexStmt *stmt, Oid relationOid, Oid indexOid)
 		if (fstotal)
 		{
 			target_segment_num = fstotal->totalfilesegs;
-			if (target_segment_num == 0)
+			int tuplecount = fstotal->totaltuples;
+			if (target_segment_num == 0 || tuplecount == 0)
 			{
 				elog(LOG, "CDBCreateIndex need not to dispatch create index statement, for not data in orc files.\n");
 				relation_close(rel, AccessShareLock);
@@ -204,10 +206,7 @@ bool CDBCreateIndex(IndexStmt *stmt, Oid relationOid, Oid indexOid)
 		if (HeapTupleIsValid(atttuple))
 		{
 			Form_pg_attribute tuple = (Form_pg_attribute) GETSTRUCT(atttuple);
-			if (!tuple->attnotnull)
-			{
-				stmt->columnsToRead = lappend_int(stmt->columnsToRead, tuple->attnum);
-			}
+			stmt->columnsToRead = lappend_int(stmt->columnsToRead, tuple->attnum);
 		}
 		caql_endscan(attcqCtx);
 	}
@@ -229,6 +228,13 @@ bool CDBCreateIndex(IndexStmt *stmt, Oid relationOid, Oid indexOid)
 	DispatchDataResult result;
 	mainDispatchStmtNode(stmt, NULL, resource, &result);
 	DropQueryContextInfo(stmt->contextdisp);
+	/* free resource */
+	if (resource)
+	{
+		FreeResource(resource);
+		resource = NULL;
+		SetActiveQueryResource(savedResource);
+	}
 	return true;
 }
 
@@ -236,6 +242,15 @@ void CDBDefineIndex(IndexStmt *stmt)
 {
 	Relation rel = relation_open(stmt->relationOid, NoLock);
 	/* 1. get orc file infos belong to this qe */
+
+	/* there might be a situation where the number
+	 * of QE's is greater than the number of Index files
+	 */
+	if (GetQEIndex() >= list_length(stmt->allidxinfos))
+	{
+		relation_close(rel, NoLock);
+		return;
+	}
 	NativeOrcIndexFile *idxs = (NativeOrcIndexFile *)(list_nth(stmt->allidxinfos, GetQEIndex()));
 	/* 2. call native orc index interface to build index data */
 	int keyCount = list_length(stmt->indexParams) - list_length(stmt->indexIncludingParams);
@@ -350,6 +365,30 @@ DefineIndex(Oid relationId,
 	          (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 	              errmsg("included columns must not intersect with key columns")));
 
+	if(stmt->graphele) {
+	  int indexnum = list_length(stmt->graphIndexAttnum);
+	  int includenum = list_length(stmt->graphIncludeAttnum);
+	  int2 *attnums = palloc0(indexnum * sizeof(int));
+	  int2 *includeattnums = palloc0(includenum * sizeof(int));
+	  ListCell *cell;
+	  int i = 0;
+	  foreach(cell, stmt->graphIndexAttnum) {
+	    Value *num = (Value *) lfirst(cell);
+	    attnums[i] = (int2)num->val.ival;
+	    i++;
+	  }
+	  i = 0;
+    foreach(cell, stmt->graphIncludeAttnum) {
+      Value *num = (Value *) lfirst(cell);
+      includeattnums[i] = (int2)num->val.ival;
+      i++;
+    }
+	  char indexType = stmt->reverse ? 'r' : 'n';
+	  InsertSkylonIndexEntry(stmt->graphele->catalogname , stmt->graphele->schemaname,
+	                         stmt->graphele->relname, indexType, stmt->idxname,
+	                         attnums, indexnum, includeattnums, includenum);
+	}
+
 	/*
 	 * count key attributes in index
 	 */
@@ -1715,6 +1754,37 @@ RemoveIndex(RangeVar *relation, DropBehavior behavior)
 
 	indOid = RangeVarGetRelid(relation, false, false /*allowHcatalog*/);
 
+	Relation pgclassrel = heap_open(RelationRelationId, RowExclusiveLock);
+	cqContext cqctmp;
+	HeapTuple pgclasstup = caql_getfirst(
+	    caql_addrel(cqclr(&cqctmp), pgclassrel),
+	    cql("SELECT * FROM pg_class "
+	        " WHERE oid = :1 ",
+	        ObjectIdGetDatum(indOid)));
+	Form_pg_class pgclassForm = (Form_pg_class) GETSTRUCT(pgclasstup);
+	Relation pgnmrel = heap_open(NamespaceRelationId, RowExclusiveLock);
+	HeapTuple pgnmtup = caql_getfirst(
+	    caql_addrel(cqclr(&cqctmp), pgnmrel),
+	    cql("SELECT * FROM pg_namespace "
+	        " WHERE oid = :1 ",
+	        ObjectIdGetDatum(pgclassForm->relnamespace)));
+	Form_pg_namespace pgnmForm = (Form_pg_namespace) GETSTRUCT(pgnmtup);
+
+	Relation  skylon_index_rel;
+	cqContext cqc;
+	skylon_index_rel = heap_open(SkylonIndexRelationId, RowExclusiveLock);
+	caql_getcount(
+	    caql_addrel(cqclr(&cqc), skylon_index_rel),
+	    cql("DELETE FROM skylon_index "
+	        " WHERE indexname = :1 AND schemaname = :2",
+	        CStringGetDatum(relation->relname), NameGetDatum(&pgnmForm->nspname)));
+	heap_close(skylon_index_rel, RowExclusiveLock);
+
+	heap_close(pgnmrel, RowExclusiveLock);
+	heap_freetuple(pgnmtup);
+	heap_close(pgclassrel, RowExclusiveLock);
+	heap_freetuple(pgclasstup);
+
 	if (Gp_role == GP_ROLE_DISPATCH)
 	{
 		LockRelationOid(RelationRelationId, RowExclusiveLock);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index fd93525..1d0a767 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -79,6 +79,14 @@
 #include "catalog/pg_authid.h"
 #include "catalog/pg_partition.h"
 #include "catalog/pg_partition_rule.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_index.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
 #include "catalog/toasting.h"
 #include "cdb/cdbappendonlyam.h"
 #include "cdb/cdbparquetam.h"
@@ -245,6 +253,20 @@ typedef struct NewColumnValue
 	ExprState  *exprstate;		/* execution state */
 } NewColumnValue;
 
+extern Query *transformCreateExternalStmtImpl(ParseState *pstate,
+                                          CreateExternalStmt *stmt,
+                                          List **extras_before,
+                                          List **extras_after);
+
+extern Query *transformCreateStmtImpl(ParseState *pstate,
+                                      CreateStmt *stmt,
+                                      List **extras_before,
+                                      List **extras_after);
+
+extern List *transformAsGraphName(ParseState *pstate, RangeVar *rangeVar);
+
+extern bool parseAndTransformAsGraph(ParseState *pstate, RangeVar *rangeVar);
+
 static void truncate_check_rel(Relation rel);
 static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
 static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel, List *inhAttrNameList,
@@ -991,6 +1013,1076 @@ static Datum AddDefaultPageRowGroupSize(Datum relOptions, List *defList){
 	}
 }
 
+static Oid CreateInCatalog(Oid tablespace_id, Oid namespaceId, RangeVar *rel, int2 attnum, char relkind) {
+  CreateStmt *createStmt = makeNode(CreateStmt);
+  createStmt->base.relKind = relkind;
+  createStmt->base.relation = rel;
+  ParseState *pstate = make_parsestate(NULL);
+  pstate->p_next_resno = 1;
+  List *extras_before = NIL;
+  List *extras_after = NIL;
+  createStmt = transformCreateStmtImpl(pstate,
+                                       createStmt,
+                                       &extras_before,
+                                       &extras_before)->utilityStmt;
+  ItemPointerData persistentTid;
+  int64     persistentSerialNum;
+  Relation pg_class_desc = heap_open(RelationRelationId, RowExclusiveLock);
+  Oid relid = GetNewRelFileNode(tablespace_id, tablespace_id == GLOBALTABLESPACE_OID,
+                    pg_class_desc,
+                    relstorage_is_ao(pg_class_desc->rd_rel->relstorage));
+  Relation new_rel_desc = heap_create(rel->relname,
+                             namespaceId,
+                             tablespace_id,
+                             relid,
+                             BuildDescForRelation(createStmt->base.tableElts),
+                             InvalidOid,
+                             createStmt->base.relKind,
+                             RELSTORAGE_HEAP,
+                             tablespace_id == GLOBALTABLESPACE_OID,
+                             allowSystemTableModsDDL,
+                             false);
+  new_rel_desc->rd_rel->relnatts = attnum;
+  new_rel_desc->rd_rel->relkind = relkind;
+  InsertPgClassTuple(pg_class_desc, new_rel_desc, relid, (Datum) 0);
+
+  heap_close(new_rel_desc, NoLock);
+  heap_close(pg_class_desc, RowExclusiveLock);
+  return relid;
+}
+
+static void InsertAttribute(Oid relid, ColumnDef *colDef,int rank) {
+  Relation attrdesc = heap_open(AttributeRelationId, RowExclusiveLock);
+  cqContext cqc;
+  cqContext  *patCtx = caql_beginscan(
+      caql_addrel(cqclr(&cqc), attrdesc),
+      cql("INSERT INTO pg_attribute ",
+        NULL));
+
+  FormData_pg_attribute attributeD;
+  HeapTuple attributeTuple = heap_addheader(Natts_pg_attribute,
+                  false,
+                  ATTRIBUTE_TUPLE_SIZE,
+                  (void *) &attributeD);
+  HeapTuple typeTuple = typenameType(NULL, colDef->typname);
+  Form_pg_type tform = (Form_pg_type) GETSTRUCT(typeTuple);
+  Form_pg_attribute attribute = (Form_pg_attribute) GETSTRUCT(attributeTuple);
+  Oid typeOid = HeapTupleGetOid(typeTuple);
+  attribute->attrelid = relid;
+  namestrcpy(&(attribute->attname), colDef->colname);
+  attribute->atttypid = colDef->typname->typid;
+  attribute->attstattarget = -1;
+  attribute->attlen = tform->typlen;
+  attribute->attcacheoff = -1;
+  attribute->atttypmod = colDef->typname->typmod;
+  attribute->attnum = rank;
+  attribute->attbyval = tform->typbyval;
+  attribute->attndims = list_length(colDef->typname->arrayBounds);
+  attribute->attstorage = tform->typstorage;
+  attribute->attalign = tform->typalign;
+  attribute->attnotnull = colDef->is_not_null;
+  attribute->atthasdef = false;
+  attribute->attisdropped = false;
+  attribute->attislocal = colDef->is_local;
+  attribute->attinhcount = colDef->inhcount;
+
+  ReleaseType(typeTuple);
+
+  caql_insert(patCtx, attributeTuple);
+
+  caql_endscan(patCtx);
+  heap_close(attrdesc, RowExclusiveLock);
+}
+
+extern void
+DefineVlabel(CreateVlabelStmt *createVlStmt)
+{
+  /*
+   * Get tablespace, database, schema for the relation
+   */
+  RangeVar *rel = createVlStmt->relation;
+  // get tablespace name for the relation
+  Oid tablespace_id = (gp_upgrade_mode) ? DEFAULTTABLESPACE_OID : GetDefaultTablespace();
+  if (!OidIsValid(tablespace_id))
+  {
+    tablespace_id = get_database_dts(MyDatabaseId);
+  }
+
+  char *filespace_name = NULL;
+  GetFilespacePathForTablespace(tablespace_id, &filespace_name);
+
+  if (filespace_name) {
+    int len = strlen(filespace_name);
+    if ((len > 0) && (filespace_name[len - 1] == '/'))
+      filespace_name[len - 1] = '\0';
+  }
+
+  char *tablespace_name = get_tablespace_name(tablespace_id);
+
+  // get database name for the relation
+  char *database_name = rel->catalogname ? rel->catalogname : get_database_name(MyDatabaseId);
+
+  // get schema name for the relation
+  char *schema_name = get_namespace_name(RangeVarGetCreationNamespace(rel));
+
+  // get table name for the relation
+  char *table_name = rel->relname;
+
+  Oid namespaceId = get_namespace_oid(schema_name);
+
+  if (get_relname_relid(table_name, namespaceId) != InvalidOid)
+    ereport(ERROR,
+        (errcode(ERRCODE_DUPLICATE_TABLE),
+         errmsg("vertex \"%s\" already exists",
+                table_name),
+         errOmitLocation(true)));
+
+  Oid relationId = CreateInCatalog(tablespace_id, namespaceId, rel,
+                                   list_length(createVlStmt->tableElts), RELKIND_VIEW);
+
+  ObjectAddress depender = {VlabelRelationId, relationId, 0, };
+  ObjectAddress ref = {NamespaceRelationId, namespaceId, 0, };
+  recordDependencyOn(&depender, &ref, DEPENDENCY_NORMAL);
+
+  {
+  cqContext cqc;
+  Relation VlabelRelation = heap_open(VlabelRelationId, RowExclusiveLock);
+  HeapTuple vlabelTuple= caql_getfirst(caql_addrel(cqclr(&cqc), VlabelRelation),
+                                       cql("SELECT * FROM skylon_vlabel"
+      " WHERE vlabelname = :1 "
+      "AND schemaname = :2",
+      CStringGetDatum(rel->relname),
+      CStringGetDatum(schema_name)));
+  if(HeapTupleIsValid(vlabelTuple))
+    ereport(ERROR,
+      (errcode(ERRCODE_UNDEFINED_COLUMN),
+       errmsg("vertex \"%s\" already exists in \"%s\"",
+              rel->relname, schema_name)));
+  heap_close(VlabelRelation, RowExclusiveLock);
+  }
+  if (filespace_name)
+    pfree(filespace_name);
+
+  List     *schema = createVlStmt->tableElts;
+  TupleDesc descriptor = BuildDescForRelation(schema);
+  InsertVlabelEntry(table_name, schema_name);
+  ListCell *cell;
+  int32 order = 1;
+  foreach(cell,schema) {
+    Node* node=lfirst(cell);
+    if(nodeTag(node) == T_ColumnDef) {
+      ColumnDef* def = (ColumnDef*)node;
+      char* colname = def->colname;
+      Oid typeid = def->typname->typid;
+      List *keys = createVlStmt->constraints?((Constraint*)lfirst(list_head(
+                   createVlStmt->constraints)))->keys : NULL;
+      ListCell *lc;
+      int32 primary = 0;
+      int32 tmp = 1;
+      foreach(lc, keys){
+        Value *key = (Value*)lfirst(lc);
+        if(strcmp(colname, key->val.str) == 0) {
+          primary = tmp;
+          break;
+        }
+        tmp++;
+      }
+      if(!keys && order==1)
+        primary = 1;
+      InsertVlabelAttrEntry(schema_name, createVlStmt->relation->relname, colname, typeid, primary, order);
+      InsertAttribute(relationId, def, order);
+      order++;
+    }
+  }
+}
+
+extern void
+DefineElabel(CreateElabelStmt *createElStmt)
+{
+  /*
+   * Get tablespace, database, schema for the relation
+   */
+  RangeVar *rel = createElStmt->relation;
+  // get tablespace name for the relation
+  Oid tablespace_id = (gp_upgrade_mode) ? DEFAULTTABLESPACE_OID : GetDefaultTablespace();
+  if (!OidIsValid(tablespace_id))
+  {
+    tablespace_id = get_database_dts(MyDatabaseId);
+  }
+
+  char *filespace_name = NULL;
+  GetFilespacePathForTablespace(tablespace_id, &filespace_name);
+
+  if (filespace_name) {
+    int len = strlen(filespace_name);
+    if ((len > 0) && (filespace_name[len - 1] == '/'))
+      filespace_name[len - 1] = '\0';
+  }
+
+  char *tablespace_name = get_tablespace_name(tablespace_id);
+
+  // get database name for the relation
+  char *database_name = rel->catalogname ? rel->catalogname : get_database_name(MyDatabaseId);
+
+  // get schema name for the relation
+  char *schema_name = get_namespace_name(RangeVarGetCreationNamespace(rel));
+
+  // get table name for the relation
+  char *table_name = rel->relname;
+
+  Oid namespaceId = get_namespace_oid(schema_name);
+
+  if (get_relname_relid(table_name, namespaceId) != InvalidOid)
+    ereport(ERROR,
+        (errcode(ERRCODE_DUPLICATE_TABLE),
+         errmsg("edge \"%s\" already exists",
+                table_name),
+         errOmitLocation(true)));
+
+  Oid relationId = CreateInCatalog(tablespace_id, namespaceId, rel,
+                                   list_length(createElStmt->tableElts), RELKIND_VIEW);
+
+  ObjectAddress depender = {ElabelRelationId, relationId, 0, };
+  ObjectAddress ref = {NamespaceRelationId, namespaceId, 0, };
+  recordDependencyOn(&depender, &ref, DEPENDENCY_NORMAL);
+
+  {
+  cqContext cqc;
+  Relation ElabelRelation = heap_open(ElabelRelationId, RowExclusiveLock);
+  HeapTuple elabelTuple= caql_getfirst(caql_addrel(cqclr(&cqc), ElabelRelation),
+                                       cql("SELECT * FROM skylon_elabel"
+      " WHERE elabelname = :1 "
+      "AND schemaname = :2",
+      CStringGetDatum(rel->relname),
+      CStringGetDatum(schema_name)));
+  if(HeapTupleIsValid(elabelTuple))
+    ereport(ERROR,
+      (errcode(ERRCODE_UNDEFINED_COLUMN),
+       errmsg("edge \"%s\" already exists in schema \"%s\"",
+              rel->relname, schema_name)));
+  heap_close(ElabelRelation, RowExclusiveLock);
+  }
+  {
+  cqContext cqc;
+  Relation VlabelRelation = heap_open(VlabelRelationId, RowExclusiveLock);
+  HeapTuple vlabelTuple= caql_getfirst(caql_addrel(cqclr(&cqc), VlabelRelation),
+                                       cql("SELECT * FROM skylon_vlabel"
+      " WHERE vlabelname = :1 "
+      "AND schemaname = :2",
+      CStringGetDatum(createElStmt->fromVlabel->val.str),
+      CStringGetDatum(schema_name)));
+  if(!HeapTupleIsValid(vlabelTuple))
+    ereport(ERROR,
+      (errcode(ERRCODE_UNDEFINED_COLUMN),
+       errmsg("source vertex \"%s\" does not exists in schema \"%s\"",
+              createElStmt->fromVlabel->val.str, schema_name)));
+  heap_close(VlabelRelation, RowExclusiveLock);
+  }
+
+  {
+  cqContext cqc;
+  Relation VlabelRelation = heap_open(VlabelRelationId, RowExclusiveLock);
+  HeapTuple vlabelTuple= caql_getfirst(caql_addrel(cqclr(&cqc), VlabelRelation),
+                                       cql("SELECT * FROM skylon_vlabel"
+      " WHERE vlabelname = :1 "
+      "AND schemaname = :2",
+      CStringGetDatum(createElStmt->toVlabel->val.str),
+      CStringGetDatum(schema_name)));
+  if(!HeapTupleIsValid(vlabelTuple))
+    ereport(ERROR,
+      (errcode(ERRCODE_UNDEFINED_COLUMN),
+       errmsg("dest vertex \"%s\" does not exists in schema \"%s\"",
+              createElStmt->toVlabel->val.str, schema_name)));
+  heap_close(VlabelRelation, RowExclusiveLock);
+  }
+
+  if (filespace_name)
+    pfree(filespace_name);
+
+  List     *schema = createElStmt->tableElts;
+  TupleDesc descriptor = BuildDescForRelation(schema);
+  InsertElabelEntry(table_name, schema_name, createElStmt->fromVlabel->val.str, createElStmt->toVlabel->val.str);
+
+  ListCell *cell;
+  int32 order = 1;
+  foreach(cell,schema) {
+    Node* node=lfirst(cell);
+    if(nodeTag(node) == T_ColumnDef){
+      ColumnDef* def = (ColumnDef*)node;
+      char* colname = def->colname;
+      Oid typeid = def->typname->typid;
+      List *keys = createElStmt->constraints? ((Constraint*)lfirst(list_head(
+                   createElStmt->constraints)))->keys : NULL;
+      ListCell *lc;
+      int32 primary = 0;
+      int32 tmp = 1;
+      foreach(lc, keys){
+        Value *key = (Value*)lfirst(lc);
+        if(strcmp(colname, key->val.str) == 0) {
+          primary = tmp;
+          break;
+        }
+        tmp++;
+      }
+      InsertElabelAttrEntry(schema_name, createElStmt->relation->relname, colname, typeid, primary, order);
+      InsertAttribute(relationId, def, order);
+      order++;
+    }
+  }
+}
+
+char *graphVertexTableName(char *gname,char *vname)
+{
+  char extraname[] = "skylon_vertex_";
+  int len1 = strlen(gname);
+  int len2 = strlen(vname);
+  int len3 = strlen(extraname);
+  char * newname = palloc0(len1 + len2 + len3 + 2);
+  memcpy(newname, extraname, len3);
+  memcpy(newname + len3, gname, len1);
+  memcpy(newname + len3 + len1, "_", 1);
+  memcpy(newname + len3 + len1 + 1, vname, len2);
+  newname[len1 + len2 + len3 + 1] = '\0';
+  return newname;
+}
+
+char *graphEdgeTableName(char *gname,char *ename)
+{
+  char extraname[] = "skylon_edge_";
+  int len1 = strlen(gname);
+  int len2 = strlen(ename);
+  int len3 = strlen(extraname);
+  char * newname = palloc0(len1 + len2 + len3 + 2);
+  memcpy(newname, extraname, len3);
+  memcpy(newname + len3, gname, len1);
+  memcpy(newname + len3 + len1, "_", 1);
+  memcpy(newname + len3 + len1 + 1, ename, len2);
+  newname[len1 + len2 + len3 + 1] = '\0';
+  return newname;
+}
+
+static List * vertexPrimary(const char* schemaname, const char *vname) {
+  cqContext cqc;
+  Relation catalogRelation = heap_open(VlabelAttrRelationId, RowExclusiveLock);
+
+  int primaryNum = caql_getcount(
+            caql_addrel(cqclr(&cqc), catalogRelation),
+            cql("SELECT COUNT(*) FROM skylon_vlabel_attribute "
+              " WHERE vlabelname = :1 AND schemaname = :2 "
+                "AND primaryrank > :3",
+              CStringGetDatum(vname), CStringGetDatum(schemaname), Int32GetDatum(0)));
+  ColumnDef **colVec = (ColumnDef **)palloc0(sizeof(ColumnDef*)*primaryNum);
+
+  cqContext *pcqCtx = caql_beginscan(
+      caql_addrel(cqclr(&cqc), catalogRelation),
+      cql("SELECT * FROM skylon_vlabel_attribute "
+        " WHERE vlabelname = :1 AND schemaname = :2 "
+          "AND primaryrank > :3",
+          CStringGetDatum(vname), CStringGetDatum(schemaname), Int32GetDatum(0)));
+  HeapTuple attributeTuple;
+  List *newCols = NIL;
+  while (HeapTupleIsValid(attributeTuple = caql_getnext(pcqCtx))){
+    Form_skylon_vlabel_attribute att = (Form_skylon_vlabel_attribute) GETSTRUCT(attributeTuple);
+    ColumnDef *column = makeNode(ColumnDef);
+    Value *attstr = makeString(pstrdup(NameStr(att->attrname)));
+    column->colname = attstr->val.str;
+    Type type = typeidType(att->attrtypid);
+    column->typname = SystemTypeName(typeTypeName(type));
+    column->constraints = NULL;
+    column->is_local = true;
+    column->encoding = NULL;
+    column->typname->typid = att->attrtypid;
+    ReleaseType(type);
+    colVec[att->primaryrank - 1] = column;
+  }
+  for(int i=0;i<primaryNum;i++) {
+    newCols = lappend(newCols, colVec[i]);
+  }
+  pfree(colVec);
+  caql_endscan(pcqCtx);
+  heap_close(catalogRelation, RowExclusiveLock);
+  return newCols;
+}
+
+static List * edgePrimary(const char *schemaname, const char *ename) {
+  cqContext cqc;
+  Relation catalogRelation = heap_open(ElabelAttrRelationId, RowExclusiveLock);
+
+  int primaryNum = caql_getcount(
+            caql_addrel(cqclr(&cqc), catalogRelation),
+            cql("SELECT COUNT(*) FROM skylon_elabel_attribute "
+              " WHERE elabelname = :1 AND schemaname = :2 "
+                "AND primaryrank > :3",
+              CStringGetDatum(ename), CStringGetDatum(schemaname), Int32GetDatum(0)));
+  ColumnDef **colVec = (ColumnDef **)palloc0(sizeof(ColumnDef*)*primaryNum);
+
+  cqContext *pcqCtx = caql_beginscan(
+      caql_addrel(cqclr(&cqc), catalogRelation),
+      cql("SELECT * FROM skylon_elabel_attribute "
+        " WHERE elabelname = :1 AND schemaname = :2 "
+          "AND primaryrank > :3",
+          CStringGetDatum(ename), CStringGetDatum(schemaname), Int32GetDatum(0)));
+  HeapTuple attributeTuple;
+  List *newCols = NIL;
+  while (HeapTupleIsValid(attributeTuple = caql_getnext(pcqCtx))){
+    Form_skylon_vlabel_attribute att = (Form_skylon_vlabel_attribute) GETSTRUCT(attributeTuple);
+    ColumnDef *column = makeNode(ColumnDef);
+    Value *attstr = makeString(pstrdup(NameStr(att->attrname)));
+    column->colname = attstr->val.str;
+    Type type = typeidType(att->attrtypid);
+    column->typname = SystemTypeName(typeTypeName(type));
+    column->constraints = NULL;
+    column->is_local = true;
+    column->encoding = NULL;
+    column->typname->typid = att->attrtypid;
+    ReleaseType(type);
+    colVec[att->primaryrank - 1] = column;
+  }
+  for(int i=0;i<primaryNum;i++) {
+    newCols = lappend(newCols, colVec[i]);
+  }
+  pfree(colVec);
+  caql_endscan(pcqCtx);
+  heap_close(catalogRelation, RowExclusiveLock);
+  return newCols;
+}
+
+static int4 GetTypemod(Oid namespaceId, const char *relname, const char *attname) {
+  Oid relid = caql_getoid(
+      NULL,
+      cql("SELECT oid FROM pg_class "
+        " WHERE relname = :1 "
+        " AND relnamespace = :2 ",
+        CStringGetDatum(relname),
+        ObjectIdGetDatum(namespaceId)));
+
+  Relation attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
+  cqContext cqc;
+  cqContext * pcqCtx = caql_addrel(cqclr(&cqc), attrelation);
+
+  HeapTuple atttup = caql_getfirst(
+      pcqCtx,
+      cql("SELECT * FROM pg_attribute "
+        " WHERE attrelid = :1 "
+        " AND attname = :2 ",
+        ObjectIdGetDatum(relid),
+        CStringGetDatum(attname)));
+
+
+  int4 typemod = ((Form_pg_attribute) GETSTRUCT(atttup))->atttypmod;
+
+
+  heap_freetuple(atttup);
+  heap_close(attrelation, RowExclusiveLock);
+  return typemod;
+}
+
+static bool IfMakePrimaryIndex(CreateGraphStmt *createGrStmt) {
+  Datum reloptions = transformRelOptions((Datum) 0, createGrStmt->options, true, false);
+  const char * default_keywords[] = {
+    "primaryindex"
+  };
+  char     *values[ARRAY_SIZE(default_keywords)];
+  parseRelOptions(reloptions, ARRAY_SIZE(default_keywords), default_keywords, values, false);
+  if(!values[0])
+    return false;
+  if((pg_strcasecmp(values[0], "true") == 0))
+    return true;
+  else
+    return false;
+}
+
+extern void
+DefineGraph(CreateGraphStmt *createGrStmt)
+{
+  /*
+   * Get tablespace, database, schema for the relation
+   */
+  RangeVar *rel = createGrStmt->graph;
+
+  // get tablespace name for the relation
+  Oid tablespace_id = (gp_upgrade_mode) ? DEFAULTTABLESPACE_OID : GetDefaultTablespace();
+  if (!OidIsValid(tablespace_id))
+  {
+    tablespace_id = get_database_dts(MyDatabaseId);
+  }
+
+  char *filespace_name = NULL;
+  GetFilespacePathForTablespace(tablespace_id, &filespace_name);
+
+  if (filespace_name) {
+    int len = strlen(filespace_name);
+    if ((len > 0) && (filespace_name[len - 1] == '/'))
+      filespace_name[len - 1] = '\0';
+  }
+
+  char *tablespace_name = get_tablespace_name(tablespace_id);
+
+  // get database name for the relation
+  char *database_name = rel->catalogname ? rel->catalogname : get_database_name(MyDatabaseId);
+
+  // get schema name for the relation
+  char *schema_name = get_namespace_name(RangeVarGetCreationNamespace(rel));
+
+  Oid namespaceId = get_namespace_oid(schema_name);
+  // get table name for the relation
+  char *table_name = rel->relname;
+
+  if (get_relname_relid(table_name, namespaceId) != InvalidOid)
+    ereport(ERROR,
+        (errcode(ERRCODE_DUPLICATE_TABLE),
+         errmsg("graph \"%s\" already exists",
+                table_name),
+         errOmitLocation(true)));
+
+  Oid relationId = CreateInCatalog(tablespace_id, namespaceId, rel, 0, RELKIND_VIEW);
+
+  if (filespace_name)
+    pfree(filespace_name);
+
+  InsertGraphEntry(table_name, schema_name);
+
+  ObjectAddress depender = {GraphRelationId, relationId, 0, };
+  ObjectAddress ref = {NamespaceRelationId, namespaceId, 0, };
+  recordDependencyOn(&depender, &ref, DEPENDENCY_NORMAL);
+
+  bool haspk = IfMakePrimaryIndex(createGrStmt);
+  ListCell *cell;
+  foreach(cell, createGrStmt->vlabels) {
+    Value *value = lfirst(cell);
+    cqContext cqc;
+    Relation vr = heap_open(VlabelRelationId, RowExclusiveLock);
+    if (caql_getcount(
+            caql_addrel(cqclr(&cqc), vr),
+            cql("SELECT COUNT(*) FROM skylon_vlabel "
+              " WHERE vlabelName = :1 AND schemaname = :2",
+              CStringGetDatum(value->val.str), CStringGetDatum(schema_name))) == 0)
+          ereport(ERROR,
+              (errcode(ERRCODE_DUPLICATE_TABLE),
+               errmsg("vertex \"%s\" does not exist",
+                      value->val.str),
+               errOmitLocation(true)));
+    heap_close(vr, RowExclusiveLock);
+
+    Relation vLabelAttRelation = heap_open(VlabelAttrRelationId, RowExclusiveLock);
+
+    IndexStmt *pkindex = NULL;
+    List *newCols = NIL;
+    char *primarykey = NULL;
+    List *distributedBy = NIL;
+    int2* indexkeys = NULL;
+    int indexcolnum = 0;
+    {
+      int primaryNum = caql_getcount(
+                caql_addrel(cqclr(&cqc), vLabelAttRelation),
+                cql("SELECT COUNT(*) FROM skylon_vlabel_attribute "
+                  " WHERE vlabelname = :1 AND schemaname = :2 "
+                    "AND primaryrank > :3",
+                  CStringGetDatum(value->val.str), CStringGetDatum(schema_name), Int32GetDatum(0)));
+      Value **distributedVec = (Value **)palloc0(sizeof(Value*)*primaryNum);
+
+      cqContext *pcqCtx = caql_beginscan(
+          caql_addrel(cqclr(&cqc), vLabelAttRelation),
+          cql("SELECT * FROM skylon_vlabel_attribute "
+            " WHERE vlabelname = :1 AND schemaname = :2 "
+              "AND primaryrank > :3",
+              CStringGetDatum(value->val.str), CStringGetDatum(schema_name), Int32GetDatum(0)));
+      HeapTuple attributeTuple;
+      while (HeapTupleIsValid(attributeTuple = caql_getnext(pcqCtx))){
+        Form_skylon_vlabel_attribute att = (Form_skylon_vlabel_attribute) GETSTRUCT(attributeTuple);
+        distributedVec[att->primaryrank - 1] = makeString(pstrdup(NameStr(att->attrname)));
+        if(haspk) {
+          if(!indexkeys)
+            indexkeys = palloc0(primaryNum * sizeof(int2));
+          indexkeys[att->primaryrank - 1] = (int2)att->rank;
+          indexcolnum = primaryNum;
+        }
+      }
+      for(int i = 0; i < primaryNum; i++) {
+        if(haspk) {
+          if(!pkindex)
+            pkindex = makeNode(IndexStmt);
+          IndexElem* indexElem = makeNode(IndexElem);
+          indexElem->name = distributedVec[i]->val.str;;
+          pkindex->indexParams = lappend(pkindex->indexParams, indexElem);
+        }
+        distributedBy = lappend(distributedBy, (Node *)distributedVec[i]);
+      }
+      caql_endscan(pcqCtx);
+      pfree(distributedVec);
+    }
+    int colNum = caql_getcount(
+              caql_addrel(cqclr(&cqc), vLabelAttRelation),
+              cql("SELECT COUNT(*) FROM skylon_vlabel_attribute "
+                " WHERE vlabelname = :1 AND schemaname = :2",
+                CStringGetDatum(value->val.str), CStringGetDatum(schema_name)));
+    ColumnDef **colVec = (ColumnDef **)palloc0(sizeof(ColumnDef*)*colNum);
+    cqContext *pcqCtx = caql_beginscan(
+        caql_addrel(cqclr(&cqc), vLabelAttRelation),
+        cql("SELECT * FROM skylon_vlabel_attribute "
+          " WHERE vlabelname = :1 AND schemaname = :2",
+          CStringGetDatum(value->val.str), CStringGetDatum(schema_name)));
+    HeapTuple attributeTuple;
+    while (HeapTupleIsValid(attributeTuple = caql_getnext(pcqCtx))) {
+      Form_skylon_vlabel_attribute att = (Form_skylon_vlabel_attribute) GETSTRUCT(attributeTuple);
+      ColumnDef *column = makeNode(ColumnDef);
+      Value *attstr = makeString(pstrdup(NameStr(att->attrname)));
+      column->colname = attstr->val.str;
+      Type type = typeidType(att->attrtypid);
+      column->typname = SystemTypeName(typeTypeName(type));
+      column->constraints = NULL;
+      column->is_local = true;
+      column->encoding = NULL;
+      column->typname->typid = att->attrtypid;
+      if(column->typname->typid == NUMERICOID)
+        column->typname->typmod = GetTypemod(namespaceId, value->val.str, column->colname);
+      ReleaseType(type);
+      colVec[att->rank - 1] = column;
+    }
+    for(int i = 0; i < colNum; i++)
+    {
+      newCols = lappend(newCols, colVec[i]);
+    }
+    pfree(colVec);
+    caql_endscan(pcqCtx);
+    heap_close(vLabelAttRelation, RowExclusiveLock);
+    RangeVar *relationName = makeNode(RangeVar);
+    relationName->catalogname = database_name;
+    relationName->schemaname = schema_name;
+    relationName->relname = graphVertexTableName(table_name, value->val.str);
+    if(strcmp(createGrStmt->format,"magmaap") == 0)
+    {
+      CreateExternalStmt *externalStmt = makeNode(CreateExternalStmt);
+      externalStmt->base.relKind = RELKIND_RELATION;
+      externalStmt->base.relation = relationName;
+      externalStmt->base.tableElts = newCols;
+      externalStmt->base.oncommit = ONCOMMIT_NOOP;
+      externalStmt->base.distributedBy = distributedBy;
+      ExtTableTypeDesc *extDesc = makeNode(ExtTableTypeDesc);
+      extDesc->exttabletype = EXTTBL_TYPE_UNKNOWN;
+      externalStmt->exttypedesc = extDesc;
+      externalStmt->format = pstrdup(createGrStmt->format);
+      externalStmt->iswritable = TRUE;
+      if(pkindex) {
+        Constraint *cons = makeNode(Constraint);
+        cons->contype = CONSTR_PRIMARY;
+        ListCell *cell;
+        foreach(cell, pkindex->indexParams) {
+          IndexElem *ele = (IndexElem *)lfirst(cell);
+          cons->keys = lappend(cons->keys, makeString(ele->name));
+        }
+        externalStmt->base.tableElts = lappend(externalStmt->base.tableElts, cons);
+      }
+      ParseState *pstate = make_parsestate(NULL);
+      pstate->p_next_resno = 1;
+      List *extras_before = NIL;
+      List *extras_after = NIL;
+      externalStmt = transformCreateExternalStmtImpl(pstate,
+                                                   externalStmt,
+                                                &extras_before,
+                                                &extras_before)->utilityStmt;
+      DefineExternalRelation(externalStmt);
+    }
+    else
+    {
+      if(strcmp(createGrStmt->format,"orc") && strcmp(createGrStmt->format,"heap"))
+        ereport(ERROR,
+               (errcode(ERRCODE_UNDEFINED_OBJECT),
+               errmsg("unsupported format %s ",
+                      createGrStmt->format)));
+      CreateStmt *createStmt = makeNode(CreateStmt);
+      createStmt->base.relKind = RELKIND_RELATION;
+      createStmt->base.relation = relationName;
+      createStmt->base.tableElts = newCols;
+      createStmt->base.oncommit = ONCOMMIT_NOOP;
+      createStmt->base.distributedBy = distributedBy;
+      if(strcmp(createGrStmt->format,"orc") == 0)
+        createStmt->base.options = lappend(lappend(list_make1(makeDefElem("appendonly", (Node *)makeString(pstrdup("true")))),
+                                           makeDefElem("OIDS", (Node *)makeString(pstrdup("FALSE")))),
+                                           makeDefElem("ORIENTATION", (Node *)makeString(pstrdup("orc"))));
+      else
+        createStmt->base.options = list_make1(makeDefElem("appendonly", (Node *)makeString(pstrdup("false"))));
+      if(strcmp(createGrStmt->format, "heap") == 0)
+        createStmt->base.tablespacename = "pg_default";
+      if(pkindex) {
+        Constraint *cons = makeNode(Constraint);
+        cons->contype = CONSTR_PRIMARY;
+        ListCell *cell;
+        foreach(cell, pkindex->indexParams) {
+          IndexElem *ele = (IndexElem *)lfirst(cell);
+          cons->keys = lappend(cons->keys, makeString(ele->name));
+        }
+        createStmt->base.tableElts = lappend(createStmt->base.tableElts, cons);
+      }
+      ParseState *pstate = make_parsestate(NULL);
+      pstate->p_next_resno = 1;
+      List *extras_before = NIL;
+      List *extras_after = NIL;
+      createStmt = transformCreateStmt(pstate,
+                                       createStmt,
+                                    &extras_before,
+                                    &extras_before)->utilityStmt;
+      ProcessUtility((Node *)createStmt, "", NULL, TRUE, NULL, NULL);
+    }
+    if(haspk) {
+      Oid eleid = caql_getoid_only(
+          NULL,
+          NULL,
+          cql("SELECT oid FROM pg_class "
+            " WHERE relname = :1 and relnamespace = :2",
+            CStringGetDatum(value->val.str),
+            ObjectIdGetDatum(namespaceId)));
+      char *classchar1 = (char*)palloc0(7 + VARHDRSZ);
+      char *classchar2 = (char*)palloc0(7 + VARHDRSZ);
+      pg_ltoa((int32)relationId, classchar1);
+      pg_ltoa((int32)eleid, classchar2);
+      char *indexname = palloc0(sizeof(char)*(strlen(classchar1) + strlen(classchar2) + 5 + 1));
+      sprintf(indexname, "index%s%s", classchar1, classchar2);
+      RangeVar *indexrel = makeNode(RangeVar);
+      indexrel->catalogname = database_name;
+      indexrel->schemaname = schema_name;
+      indexrel->relname = indexname;
+      Oid relid = caql_getoid_only(
+          NULL,
+          NULL,
+          cql("SELECT oid FROM pg_class "
+            " WHERE relname = :1 and relnamespace = :2",
+            CStringGetDatum(relationName->relname),
+            ObjectIdGetDatum(namespaceId)));
+      IndexStmt *indexstmt = makeNode(IndexStmt);
+      indexstmt->idxname = indexname;
+      indexstmt->accessMethod = "btree";
+      indexstmt->indexParams = pkindex->indexParams;
+      indexstmt->unique = true;
+      indexstmt->primary = true;
+      indexstmt->isconstraint = true;
+      DefineIndex(relid,
+            indexstmt->idxname,
+            InvalidOid,
+            indexstmt->accessMethod,
+            indexstmt->tableSpace,
+            indexstmt->indexParams,
+            (Expr *) indexstmt->whereClause,
+            indexstmt->rangetable,
+            indexstmt->options,
+            indexstmt->unique,
+            indexstmt->primary,
+            indexstmt->isconstraint,
+            false,
+            true,
+            false,
+            true,
+            indexstmt->concurrent,
+            false,
+            indexstmt);
+      InsertSkylonIndexEntry(schema_name , table_name,
+                             value->val.str, 'd', indexname,
+                             indexkeys, indexcolnum, NULL, 0);
+    }
+    InsertGraphVlabelEntry(schema_name, table_name, value->val.str, RangeVarGetRelid(relationName, false, false));
+  }
+
+  foreach(cell, createGrStmt->elabels) {
+    Value *value = lfirst(cell);
+    cqContext cqc;
+    Relation er = heap_open(ElabelRelationId, RowExclusiveLock);
+    if (caql_getcount(
+            caql_addrel(cqclr(&cqc), er),
+            cql("SELECT COUNT(*) FROM skylon_elabel "
+              " WHERE elabelName = :1 AND schemaname = :2",
+              CStringGetDatum(value->val.str), CStringGetDatum(schema_name))) == 0)
+          ereport(ERROR,
+              (errcode(ERRCODE_DUPLICATE_TABLE),
+               errmsg("edge \"%s\" does not exist",
+                      value->val.str),
+               errOmitLocation(true)));
+    heap_close(er, RowExclusiveLock);
+    NameData name;
+    snprintf(NameStr(name), NAMEDATALEN, "%s", value->val.str);
+    Relation ElabelRelation = heap_open(ElabelRelationId, RowExclusiveLock);
+    HeapTuple elabelTuple= caql_getfirst(caql_addrel(cqclr(&cqc), ElabelRelation),
+                                         cql("SELECT * FROM skylon_elabel"
+        " WHERE elabelname = :1 AND schemaname = :2",
+        NameGetDatum(&name), CStringGetDatum(schema_name)));
+    Form_skylon_elabel elabel = (Form_skylon_elabel) GETSTRUCT(elabelTuple);
+
+    Relation ElabelAttrRelation = heap_open(ElabelAttrRelationId, RowExclusiveLock);
+
+    IndexStmt *pkindex = NULL;
+    List *newCols = NIL;
+    List *distributedBy = NIL;
+    int2* indexkeys = NULL;
+    int indexcolnum = 0;
+    {
+      List *cols=vertexPrimary(schema_name, elabel->fromvlabel.data);
+      ListCell *lc;
+      foreach(lc, cols) {
+        ColumnDef *col= (ColumnDef*)lfirst(lc);
+        ColumnDef *column = makeNode(ColumnDef);
+        column->colname = palloc0(sizeof(char)*(4 + 1 + strlen(col->colname)));
+        memcpy(column->colname, "src_", 4 * sizeof(char));
+        memcpy(column->colname + 4, col->colname, strlen(col->colname) * sizeof(char));
+        column->colname[4 + strlen(col->colname)] = '\0';
+        Type type = typeidType(col->typname->typid);
+        column->typname = SystemTypeName(typeTypeName(type));
+        column->typname->typid = col->typname->typid;
+        if(column->typname->typid == NUMERICOID)
+                column->typname->typmod = GetTypemod(namespaceId, elabel->fromvlabel.data, col->colname);
+        column->constraints = NULL;
+        column->is_local = true;
+        column->encoding = NULL;
+        ReleaseType(type);
+        newCols = lappend(newCols, column);
+        if(haspk) {
+          if(!pkindex)
+            pkindex = makeNode(IndexStmt);
+          IndexElem* indexElem = makeNode(IndexElem);
+          indexElem->name = column->colname;
+          pkindex->indexParams = lappend(pkindex->indexParams, indexElem);
+        }
+        distributedBy = lappend(distributedBy, (Node *)makeString(column->colname));
+      }
+    }
+    {
+      List *cols=vertexPrimary(schema_name, elabel->tovlabel.data);
+      ListCell *lc;
+      foreach(lc, cols) {
+        ColumnDef *col= (ColumnDef*)lfirst(lc);
+        ColumnDef *column = makeNode(ColumnDef);
+        column->colname = palloc0(sizeof(char)*(4 + 1 + strlen(col->colname)));
+        memcpy(column->colname, "dst_", 4 * sizeof(char));
+        memcpy(column->colname + 4, col->colname, strlen(col->colname) * sizeof(char));
+        column->colname[4 + strlen(col->colname)] = '\0';
+        Type type = typeidType(col->typname->typid);
+        column->typname = SystemTypeName(typeTypeName(type));
+        column->typname->typid = col->typname->typid;
+        if(column->typname->typid == NUMERICOID)
+          column->typname->typmod = GetTypemod(namespaceId, elabel->tovlabel.data, col->colname);
+        column->constraints = NULL;
+        column->is_local = true;
+        column->encoding = NULL;
+        ReleaseType(type);
+        newCols = lappend(newCols, column);
+        if(haspk) {
+          if(!pkindex)
+            pkindex = makeNode(IndexStmt);
+          IndexElem* indexElem = makeNode(IndexElem);
+          indexElem->name = column->colname;
+          pkindex->indexParams = lappend(pkindex->indexParams, indexElem);
+        }
+        distributedBy = lappend(distributedBy, (Node *)makeString(column->colname));
+      }
+    }
+    {
+      int primaryNum = caql_getcount(
+                caql_addrel(cqclr(&cqc), ElabelAttrRelation),
+                cql("SELECT COUNT(*) FROM skylon_elabel_attribute "
+                  " WHERE elabelname = :1 AND schemaname = :2 "
+                    "AND primaryrank > :3",
+                    CStringGetDatum(value->val.str), CStringGetDatum(schema_name), Int32GetDatum(0)));
+      Value **distributedVec = (Value **)palloc0(sizeof(Value*)*primaryNum);
+
+      cqContext *pcqCtx = caql_beginscan(
+          caql_addrel(cqclr(&cqc), ElabelAttrRelation),
+          cql("SELECT * FROM skylon_elabel_attribute "
+            " WHERE elabelname = :1 AND schemaname = :2 "
+              "AND primaryrank > :3",
+              CStringGetDatum(value->val.str), CStringGetDatum(schema_name), Int32GetDatum(0)));
+      HeapTuple attributeTuple;
+      while (HeapTupleIsValid(attributeTuple = caql_getnext(pcqCtx))){
+        Form_skylon_elabel_attribute att = (Form_skylon_elabel_attribute) GETSTRUCT(attributeTuple);
+        distributedVec[att->primaryrank - 1] = makeString(pstrdup(NameStr(att->attrname)));
+        if(haspk) {
+          if(!indexkeys) {
+            indexkeys = palloc0(primaryNum * sizeof(int2));
+            indexcolnum = primaryNum;
+          }
+          indexkeys[att->primaryrank - 1] = (int2) att->rank;
+        }
+      }
+      for(int i = 0; i < primaryNum; i++) {
+        if(haspk) {
+          if(!pkindex)
+            pkindex = makeNode(IndexStmt);
+          IndexElem* indexElem = makeNode(IndexElem);
+          indexElem->name = distributedVec[i]->val.str;
+          pkindex->indexParams = lappend(pkindex->indexParams, indexElem);
+        }
+        distributedBy = lappend(distributedBy, (Node *)distributedVec[i]);
+      }
+      pfree(distributedVec);
+      caql_endscan(pcqCtx);
+    }
+    {
+      int colNum = caql_getcount(
+                caql_addrel(cqclr(&cqc), ElabelAttrRelation),
+                cql("SELECT COUNT(*) FROM skylon_elabel_attribute "
+                  " WHERE elabelname = :1 AND schemaname = :2",
+                  CStringGetDatum(value->val.str), CStringGetDatum(schema_name)));
+      ColumnDef **colVec = (ColumnDef **)palloc0(sizeof(ColumnDef*)*colNum);
+      cqContext *pcqCtx = caql_beginscan(
+          caql_addrel(cqclr(&cqc), ElabelAttrRelation),
+          cql("SELECT * FROM skylon_elabel_attribute "
+            " WHERE elabelname = :1 AND schemaname = :2",
+            CStringGetDatum(value->val.str), CStringGetDatum(schema_name)));
+      HeapTuple attributeTuple;
+      while (HeapTupleIsValid(attributeTuple = caql_getnext(pcqCtx))) {
+        Form_skylon_elabel_attribute att = (Form_skylon_elabel_attribute) GETSTRUCT(attributeTuple);
+        ColumnDef *column = makeNode(ColumnDef);
+        Value *attstr = makeString(pstrdup(NameStr(att->attrname)));
+        column->colname = attstr->val.str;
+        Type type = typeidType(att->attrtypid);
+        column->typname = SystemTypeName(typeTypeName(type));
+        column->constraints = NULL;
+        column->is_local = true;
+        column->encoding = NULL;
+        column->typname->typid = att->attrtypid;
+        if(column->typname->typid == NUMERICOID)
+          column->typname->typmod = GetTypemod(namespaceId, value->val.str, column->colname);
+        ReleaseType(type);
+        colVec[att->rank - 1] = column;
+      }
+      for(int i = 0; i < colNum; i++) {
+        newCols = lappend(newCols, colVec[i]);
+      }
+      pfree(colVec);
+      caql_endscan(pcqCtx);
+    }
+    heap_close(ElabelRelation, RowExclusiveLock);
+    heap_close(ElabelAttrRelation, RowExclusiveLock);
+
+    RangeVar *relationName = makeNode(RangeVar);
+    relationName->catalogname = database_name;
+    relationName->schemaname = schema_name;
+    relationName->relname = graphEdgeTableName(table_name, value->val.str);
+    if(strcmp(createGrStmt->format, "magmaap") == 0)
+    {
+      CreateExternalStmt *externalStmt = makeNode(CreateExternalStmt);
+      externalStmt->base.relKind = RELKIND_RELATION;
+      externalStmt->base.relation = relationName;
+      externalStmt->base.tableElts = newCols;
+      externalStmt->base.oncommit = ONCOMMIT_NOOP;
+      externalStmt->base.distributedBy = distributedBy;
+      ExtTableTypeDesc *extDesc = makeNode(ExtTableTypeDesc);
+      extDesc->exttabletype = EXTTBL_TYPE_UNKNOWN;
+      externalStmt->exttypedesc = extDesc;
+      externalStmt->format = pstrdup(createGrStmt->format);
+      externalStmt->iswritable = TRUE;
+      if(pkindex) {
+        Constraint *cons = makeNode(Constraint);
+        cons->contype = CONSTR_PRIMARY;
+        ListCell *cell;
+        foreach(cell, pkindex->indexParams) {
+          IndexElem *ele = (IndexElem *)lfirst(cell);
+          cons->keys = lappend(cons->keys, makeString(ele->name));
+        }
+        externalStmt->base.tableElts = lappend(externalStmt->base.tableElts, cons);
+      }
+      ParseState *pstate = make_parsestate(NULL);
+      pstate->p_next_resno = 1;
+      List *extras_before = NIL;
+      List *extras_after = NIL;
+      externalStmt = transformCreateExternalStmtImpl(pstate,
+                                                   externalStmt,
+                                                &extras_before,
+                                                &extras_before)->utilityStmt;
+      DefineExternalRelation(externalStmt);
+    }
+    else
+    {
+      CreateStmt *createStmt = makeNode(CreateStmt);
+      createStmt->base.relKind = RELKIND_RELATION;
+      createStmt->base.relation = relationName;
+      createStmt->base.tableElts = newCols;
+      createStmt->base.oncommit = ONCOMMIT_NOOP;
+      createStmt->base.distributedBy = distributedBy;
+      if(strcmp(createGrStmt->format,"orc") == 0)
+        createStmt->base.options = lappend(lappend(list_make1(makeDefElem("appendonly", (Node *)makeString(pstrdup("true")))),
+                                           makeDefElem("OIDS", (Node *)makeString(pstrdup("FALSE")))),
+                                           makeDefElem("ORIENTATION", (Node *)makeString(pstrdup("orc"))));
+      else
+        createStmt->base.options = list_make1(makeDefElem("appendonly", (Node *)makeString(pstrdup("false"))));
+      if(strcmp(createGrStmt->format, "heap") == 0)
+        createStmt->base.tablespacename = "pg_default";
+      ParseState *pstate = make_parsestate(NULL);
+      pstate->p_next_resno = 1;
+      List *extras_before = NIL;
+      List *extras_after = NIL;
+      if(pkindex) {
+        Constraint *cons = makeNode(Constraint);
+        cons->contype = CONSTR_PRIMARY;
+        ListCell *cell;
+        foreach(cell, pkindex->indexParams) {
+          IndexElem *ele = (IndexElem *)lfirst(cell);
+          cons->keys = lappend(cons->keys, makeString(ele->name));
+        }
+        createStmt->base.tableElts = lappend(createStmt->base.tableElts, cons);
+      }
+      createStmt = transformCreateStmt(pstate,
+                                       createStmt,
+                                    &extras_before,
+                                    &extras_before)->utilityStmt;
+      ProcessUtility((Node *)createStmt, "", NULL, TRUE, NULL, NULL);
+    }
+    if(haspk) {
+      Oid eleid = caql_getoid_only(
+          NULL,
+          NULL,
+          cql("SELECT oid FROM pg_class "
+            " WHERE relname = :1 and relnamespace = :2",
+            CStringGetDatum(value->val.str),
+            ObjectIdGetDatum(namespaceId)));
+      char *classchar1 = (char*)palloc0(7 + VARHDRSZ);
+      char *classchar2 = (char*)palloc0(7 + VARHDRSZ);
+      pg_ltoa((int32)relationId, classchar1);
+      pg_ltoa((int32)eleid, classchar2);
+      char *indexname = palloc0(sizeof(char)*(strlen(classchar1) + strlen(classchar2) + 5 + 1));
+      sprintf(indexname, "index%s%s", classchar1, classchar2);
+      RangeVar *indexrel = makeNode(RangeVar);
+      indexrel->catalogname = database_name;
+      indexrel->schemaname = schema_name;
+      indexrel->relname = indexname;
+      Oid relid = caql_getoid_only(
+          NULL,
+          NULL,
+          cql("SELECT oid FROM pg_class "
+            " WHERE relname = :1 and relnamespace = :2",
+            CStringGetDatum(relationName->relname),
+            ObjectIdGetDatum(namespaceId)));
+      IndexStmt *indexstmt = makeNode(IndexStmt);
+      indexstmt->idxname = indexname;
+      indexstmt->accessMethod = "btree";
+      indexstmt->indexParams = pkindex->indexParams;
+      indexstmt->unique = true;
+      indexstmt->primary = true;
+      indexstmt->isconstraint = true;
+      DefineIndex(relid,
+            indexstmt->idxname,
+            InvalidOid,
+            indexstmt->accessMethod,
+            indexstmt->tableSpace,
+            indexstmt->indexParams,
+            (Expr *) indexstmt->whereClause,
+            indexstmt->rangetable,
+            indexstmt->options,
+            indexstmt->unique,
+            indexstmt->primary,
+            indexstmt->isconstraint,
+            false,
+            true,
+            false,
+            true,
+            indexstmt->concurrent,
+            false,
+            indexstmt);
+      InsertSkylonIndexEntry(schema_name , table_name,
+                             value->val.str, 'd', indexname,
+                             indexkeys, indexcolnum, NULL, 0);
+    }
+    InsertGraphElabelEntry(schema_name, table_name, value->val.str, RangeVarGetRelid(relationName, false, false));
+  }
+}
+
 /* ----------------------------------------------------------------
 *		DefineExternalRelation
 *				Creates a new external relation.
@@ -2063,6 +3155,324 @@ MetaTrackValidKindNsp(Form_pg_class rd_rel)
 			&& (!(isAnyTempNamespace(nsp))));
 }
 
+void RemoveVlabelByOid(Oid relid) {
+  RangeVar *rel = RelidGetRangeVar(relid);
+  RemoveVlabel(rel, false);
+}
+
+void
+RemoveVlabel(RangeVar *rel, bool missing_ok) {
+  // get database name for the relation
+  char *database_name = rel->catalogname ? rel->catalogname : get_database_name(MyDatabaseId);
+
+  // get schema name for the relation
+  char *schema_name = get_namespace_name(RangeVarGetCreationNamespace(rel));
+  {
+    Relation  skylon_graph_vlabel_rel;
+    cqContext cqc;
+
+    skylon_graph_vlabel_rel = heap_open(GraphVlabelRelationId, RowExclusiveLock);
+
+    if (0 < caql_getcount(
+          caql_addrel(cqclr(&cqc), skylon_graph_vlabel_rel),
+          cql("SELECT COUNT(*) FROM skylon_graph_vlabel "
+            " WHERE vlabelname = :1 AND schemaname = :2",
+            CStringGetDatum(rel->relname), CStringGetDatum(schema_name))))
+    {
+      ereport(ERROR,
+          (errcode(ERRCODE_UNDEFINED_OBJECT),
+           errmsg("vlabel object name \"%s\" is still referenced to graphs",
+                  rel->relname)));
+    }
+    heap_close(skylon_graph_vlabel_rel, RowExclusiveLock);
+  }
+
+  {
+    Relation  skylon_vlabel_rel;
+    cqContext cqc;
+
+    skylon_vlabel_rel = heap_open(VlabelRelationId, RowExclusiveLock);
+
+    if (0 == caql_getcount(
+          caql_addrel(cqclr(&cqc), skylon_vlabel_rel),
+          cql("DELETE FROM skylon_vlabel "
+            " WHERE vlabelname = :1 AND schemaname = :2",
+            CStringGetDatum(rel->relname), CStringGetDatum(schema_name))))
+    {
+      if(!missing_ok)
+        ereport(ERROR,
+            (errcode(ERRCODE_UNDEFINED_OBJECT),
+             errmsg("vlabel object name \"%s\" does not exist in schema %s",
+                    rel->relname, schema_name)));
+      else
+        ereport(NOTICE,
+          (errcode(ERRCODE_UNDEFINED_OBJECT),
+           errmsg("vlabel object name \"%s\" does not exist in schema %s, skipping",
+                  rel->relname, schema_name),
+                     errOmitLocation(true)));
+      heap_close(skylon_vlabel_rel, NoLock);
+      return;
+    }
+    heap_close(skylon_vlabel_rel, RowExclusiveLock);
+  }
+  {
+    Relation  skylon_vlabel_attribute_rel;
+    cqContext cqc;
+
+    skylon_vlabel_attribute_rel = heap_open(VlabelAttrRelationId, RowExclusiveLock);
+
+    caql_getcount(
+              caql_addrel(cqclr(&cqc), skylon_vlabel_attribute_rel),
+              cql("DELETE FROM skylon_vlabel_attribute "
+                " WHERE vlabelname = :1 AND schemaname = :2",
+                CStringGetDatum(rel->relname), CStringGetDatum(schema_name)));
+    heap_close(skylon_vlabel_attribute_rel, NoLock);
+  }
+  {
+    RangeVar   *vlabel = makeRangeVar(NULL, NULL, NULL, -1);
+    vlabel->catalogname = database_name;
+    vlabel->schemaname = schema_name;
+    vlabel->relname = rel->relname;
+    Oid vid = RangeVarGetRelid(vlabel, true, false /*allowHcatalog*/);
+    DeleteRelationTuple(vid);
+    deleteDependencyRecordsFor(VlabelRelationId, vid);
+  }
+}
+
+void RemoveElabelByOid(Oid relid) {
+  RangeVar *rel = RelidGetRangeVar(relid);
+  RemoveElabel(rel, false);
+}
+
+void
+RemoveElabel(RangeVar *rel, bool missing_ok) {
+  // get database name for the relation
+  char *database_name = rel->catalogname ? rel->catalogname : get_database_name(MyDatabaseId);
+
+  // get schema name for the relation
+  char *schema_name = get_namespace_name(RangeVarGetCreationNamespace(rel));
+  {
+    Relation  skylon_graph_elabel_rel;
+    cqContext cqc;
+
+    skylon_graph_elabel_rel = heap_open(GraphElabelRelationId, RowExclusiveLock);
+
+    if (0 < caql_getcount(
+          caql_addrel(cqclr(&cqc), skylon_graph_elabel_rel),
+          cql("SELECT COUNT(*) FROM skylon_graph_elabel "
+            " WHERE elabelname = :1 AND schemaname = :2",
+            CStringGetDatum(rel->relname), CStringGetDatum(schema_name))))
+    {
+      ereport(ERROR,
+          (errcode(ERRCODE_UNDEFINED_OBJECT),
+           errmsg("elabel object name \"%s\" is still referenced to graphs",
+                  rel->relname)));
+    }
+    heap_close(skylon_graph_elabel_rel, RowExclusiveLock);
+  }
+  {
+    Relation  skylon_elabel_rel;
+    cqContext cqc;
+
+    skylon_elabel_rel = heap_open(ElabelRelationId, RowExclusiveLock);
+
+    if (0 == caql_getcount(
+          caql_addrel(cqclr(&cqc), skylon_elabel_rel),
+          cql("DELETE FROM skylon_elabel "
+            " WHERE elabelname = :1 AND schemaname = :2",
+            CStringGetDatum(rel->relname), CStringGetDatum(schema_name))))
+    {
+      if(!missing_ok)
+        ereport(ERROR,
+            (errcode(ERRCODE_UNDEFINED_OBJECT),
+             errmsg("elabel object name \"%s\" does not exist in schema %s",
+                    rel->relname, schema_name)));
+      else
+        ereport(NOTICE,
+          (errcode(ERRCODE_UNDEFINED_OBJECT),
+           errmsg("elabel object name \"%s\" does not exist in schema %s, skipping",
+                  rel->relname, schema_name),
+                     errOmitLocation(true)));
+      heap_close(skylon_elabel_rel, RowExclusiveLock);
+      return;
+    }
+    heap_close(skylon_elabel_rel, RowExclusiveLock);
+  }
+  {
+    Relation  skylon_elabel_attribute_rel;
+    cqContext cqc;
+
+    skylon_elabel_attribute_rel = heap_open(ElabelAttrRelationId, RowExclusiveLock);
+
+    caql_getcount(
+              caql_addrel(cqclr(&cqc), skylon_elabel_attribute_rel),
+              cql("DELETE FROM skylon_elabel_attribute "
+                " WHERE elabelName = :1 AND schemaname = :2",
+                CStringGetDatum(rel->relname), CStringGetDatum(schema_name)));
+    heap_close(skylon_elabel_attribute_rel, NoLock);
+  }
+  {
+    RangeVar   *elabel = makeRangeVar(NULL, NULL, NULL, -1);
+    elabel->catalogname = database_name;
+    elabel->schemaname = schema_name;
+    elabel->relname = rel->relname;
+    Oid eid = RangeVarGetRelid(elabel, true, false /*allowHcatalog*/);
+    DeleteRelationTuple(eid);
+    deleteDependencyRecordsFor(ElabelRelationId, eid);
+  }
+}
+
+void RemoveGraphByOid(Oid relid, bool ifRemoveTable) {
+  RangeVar *rel = RelidGetRangeVar(relid);
+  RemoveGraph(rel, false, ifRemoveTable);
+}
+
+void RemoveGraph(RangeVar *rel, bool missing_ok, bool ifRemoveTable) {
+  // get database name for the relation
+  char *database_name = rel->catalogname ? rel->catalogname : get_database_name(MyDatabaseId);
+
+  // get schema name for the relation
+  char *schema_name = get_namespace_name(RangeVarGetCreationNamespace(rel));
+
+  {
+    Relation  skylon_graph_rel;
+    cqContext cqc;
+
+    skylon_graph_rel = heap_open(GraphRelationId, RowExclusiveLock);
+
+    if (0 == caql_getcount(
+          caql_addrel(cqclr(&cqc), skylon_graph_rel),
+          cql("DELETE FROM skylon_graph "
+            " WHERE graphname = :1 AND schemaname = :2",
+            CStringGetDatum(rel->relname), CStringGetDatum(schema_name))))
+    {
+      if(!missing_ok)
+        ereport(ERROR,
+            (errcode(ERRCODE_UNDEFINED_OBJECT),
+             errmsg("graph object name \"%s\" does not exist in schema %s",
+                    rel->relname, schema_name)));
+      else
+        ereport(NOTICE,
+          (errcode(ERRCODE_UNDEFINED_OBJECT),
+           errmsg("graph object name \"%s\" does not exist in schema %s, skipping",
+                  rel->relname, schema_name),
+                     errOmitLocation(true)));
+      heap_close(skylon_graph_rel, RowExclusiveLock);
+      return;
+    }
+    heap_close(skylon_graph_rel, RowExclusiveLock);
+  }
+
+  if(ifRemoveTable) {
+    Relation  skylon_graph_vlabel_rel;
+    cqContext cqc;
+
+    skylon_graph_vlabel_rel = heap_open(GraphVlabelRelationId, RowExclusiveLock);
+    cqContext *pcqCtx = caql_beginscan(
+        caql_addrel(cqclr(&cqc), skylon_graph_vlabel_rel),
+        cql("SELECT * FROM skylon_graph_vlabel "
+                        " WHERE graphname = :1 AND schemaname = :2",
+                        CStringGetDatum(rel->relname), CStringGetDatum(schema_name)));
+    HeapTuple vlabelTuple = NULL;
+    while (HeapTupleIsValid(vlabelTuple = caql_getnext(pcqCtx))) {
+      Form_skylon_graph_vlabel tuple = (Form_skylon_graph_vlabel) GETSTRUCT(vlabelTuple);
+      char *vname = pstrdup(NameStr(tuple->vlabelname));
+      DropStmt *dropStmt = makeNode(DropStmt);
+      dropStmt->removeType = OBJECT_VLABEL;
+      dropStmt->missing_ok = TRUE;
+      dropStmt->objects = NIL;
+      dropStmt->behavior = DROP_RESTRICT;
+      RangeVar   *vlabel = makeRangeVar(NULL, NULL, NULL, -1);
+      vlabel->catalogname = database_name;
+      vlabel->schemaname = schema_name;
+      vlabel->relname = graphVertexTableName(rel->relname, vname);
+      if (OidIsValid(RangeVarGetRelid(vlabel, true, false)))
+      {
+        RemoveRelation(vlabel, dropStmt->behavior, dropStmt, RELKIND_RELATION);
+      }
+    }
+    caql_endscan(pcqCtx);
+    heap_close(skylon_graph_vlabel_rel, RowExclusiveLock);
+  }
+  if(ifRemoveTable) {
+    Relation  skylon_graph_elabel_rel;
+    cqContext cqc;
+
+    skylon_graph_elabel_rel = heap_open(GraphElabelRelationId, RowExclusiveLock);
+    cqContext *pcqCtx = caql_beginscan(
+        caql_addrel(cqclr(&cqc), skylon_graph_elabel_rel),
+        cql("SELECT * FROM skylon_graph_elabel "
+                        " WHERE graphname = :1 AND schemaname = :2",
+                        CStringGetDatum(rel->relname), CStringGetDatum(schema_name)));
+    HeapTuple elabelTuple = NULL;
+    while (HeapTupleIsValid(elabelTuple = caql_getnext(pcqCtx))) {
+      Form_skylon_graph_elabel tuple = (Form_skylon_graph_elabel) GETSTRUCT(elabelTuple);
+      char *ename = pstrdup(NameStr(tuple->elabelname));
+      DropStmt *dropStmt = makeNode(DropStmt);
+      dropStmt->removeType = OBJECT_VLABEL;
+      dropStmt->missing_ok = TRUE;
+      dropStmt->objects = NIL;
+      dropStmt->behavior = DROP_RESTRICT;
+      RangeVar   *elabel = makeRangeVar(NULL, NULL, NULL, -1);
+      elabel->catalogname = database_name;
+      elabel->schemaname = schema_name;
+      elabel->relname = graphEdgeTableName(rel->relname, ename);;
+      if (OidIsValid(RangeVarGetRelid(elabel, true, false)))
+      {
+        RemoveRelation(elabel, dropStmt->behavior, dropStmt, RELKIND_RELATION);
+      }
+    }
+    caql_endscan(pcqCtx);
+    heap_close(skylon_graph_elabel_rel, RowExclusiveLock);
+  }
+  {
+    Relation  skylon_graph_vlabel_rel;
+    cqContext cqc;
+
+    skylon_graph_vlabel_rel = heap_open(GraphVlabelRelationId, RowExclusiveLock);
+
+    caql_getcount(
+              caql_addrel(cqclr(&cqc), skylon_graph_vlabel_rel),
+              cql("DELETE FROM skylon_graph_vlabel "
+                " WHERE graphname = :1 AND schemaname = :2",
+                CStringGetDatum(rel->relname), CStringGetDatum(schema_name)));
+    heap_close(skylon_graph_vlabel_rel, RowExclusiveLock);
+  }
+  {
+    Relation  skylon_graph_elabel_rel;
+    cqContext cqc;
+
+    skylon_graph_elabel_rel = heap_open(GraphElabelRelationId, RowExclusiveLock);
+
+    caql_getcount(
+              caql_addrel(cqclr(&cqc), skylon_graph_elabel_rel),
+              cql("DELETE FROM skylon_graph_elabel "
+                " WHERE graphname = :1 AND schemaname = :2",
+                CStringGetDatum(rel->relname), CStringGetDatum(schema_name)));
+    heap_close(skylon_graph_elabel_rel, RowExclusiveLock);
+  }
+  {
+    RangeVar   *graph = makeRangeVar(NULL, NULL, NULL, -1);
+    graph->catalogname = database_name;
+    graph->schemaname = schema_name;
+    graph->relname = rel->relname;
+    Oid graphid = RangeVarGetRelid(graph, true, false /*allowHcatalog*/);
+    DeleteRelationTuple(graphid);
+    deleteDependencyRecordsFor(GraphRelationId, graphid);
+  }
+  {
+    Relation  skylon_index_rel;
+    cqContext cqc;
+    skylon_index_rel = heap_open(SkylonIndexRelationId, RowExclusiveLock);
+    caql_getcount(
+              caql_addrel(cqclr(&cqc), skylon_index_rel),
+              cql("DELETE FROM skylon_index "
+                " WHERE graphname = :1 AND schemaname = :2",
+                CStringGetDatum(rel->relname), CStringGetDatum(schema_name)));
+    heap_close(skylon_index_rel, RowExclusiveLock);
+  }
+}
+
 /*
  * RemoveRelation
  *		Deletes a relation.
@@ -2286,11 +3696,13 @@ ExecuteTruncate(TruncateStmt *stmt)
     int partcheck = 2;
 	List *partList = NIL;
 
+
 	/*
 	 * Open, exclusive-lock, and check all the explicitly-specified relations
 	 *
 	 * Check if table has partitions and add them too
 	 */
+	bool ifReturn = false;
 	while (partcheck)
 	{
 		foreach(cell, stmt->relations)
@@ -2299,6 +3711,19 @@ ExecuteTruncate(TruncateStmt *stmt)
 			Relation	rel;
 			PartitionNode *pNode;
 
+			List *labellist = transformAsGraphName(NULL, rv);
+			if(labellist) {
+			  TruncateStmt *truncate = makeNode(TruncateStmt);
+			  truncate->relations = labellist;
+			  truncate->behavior = stmt->behavior;
+			  ExecuteTruncate(truncate);
+			  ifReturn = true;
+			  continue;
+			}
+			else {
+			  parseAndTransformAsGraph(NULL, rv);
+			}
+
 		  rel = heap_openrv(rv, AccessExclusiveLock);
 			truncate_check_rel(rel);
 
@@ -2321,6 +3746,9 @@ ExecuteTruncate(TruncateStmt *stmt)
 			}
 			heap_close(rel, NoLock);
 		}
+		//if truncate a whole graph, return now,because the verticies and edges have truncated before
+		if(ifReturn)
+		  return;
 
 		partcheck--;
 
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 21a8618..a3023e2 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -264,6 +264,9 @@ static Relation open_relation_and_check_permission(VacuumStmt *vacstmt,
 												   char expected_relkind);
 static void vacuumStatement(VacuumStmt *vacstmt, List *relids);
 
+extern bool parseAndTransformAsGraph(ParseState *pstate, RangeVar *rangeVar);
+
+extern List *transformAsGraphName(ParseState *pstate, RangeVar *rangeVar);
 
 /****************************************************************************
  *																			*
@@ -288,6 +291,23 @@ void vacuum(VacuumStmt *vacstmt, List *relids, int preferred_seg_num)
 	
 	Assert(!(vacstmt != NULL && relids != NULL));
 	
+	List *labellist = transformAsGraphName(NULL, vacstmt->relation);
+	if(labellist) {
+	  ListCell *cell;
+	  foreach(cell, labellist) {
+	    RangeVar *labelrel = (RangeVar*)lfirst(cell);
+	    VacuumStmt *refactoredStmt = copyObject(vacstmt);
+	    refactoredStmt->relation = labelrel;
+	    vacuum(refactoredStmt, NIL, -1);
+	  }
+	  return;
+	}
+	else {
+	  parseAndTransformAsGraph(NULL, vacstmt->relation);
+	  analyzeStmt->relation = vacstmt->relation;
+	}
+
+
 	if (doVacuum)
 	{
 		if (vacstmt->rootonly)
diff --git a/src/backend/executor/execIndexscan.c b/src/backend/executor/execIndexscan.c
index 0e41c95..87b4453 100644
--- a/src/backend/executor/execIndexscan.c
+++ b/src/backend/executor/execIndexscan.c
@@ -24,6 +24,7 @@
  */
 #include "postgres.h"
 
+#include "catalog/pg_exttable.h"
 #include "access/genam.h"
 #include "access/nbtree.h"
 #include "executor/execIndexscan.h"
@@ -162,6 +163,9 @@ OpenIndexRelation(EState *estate, Oid indexOid, Index tableRtIndex)
  *
  * Caller may pass NULL for arrayKeys and numArrayKeys to indicate that
  * ScalarArrayOpExpr quals are not supported.
+ *
+ * TODO(hwy): This code is used for both external scan and index scan, so it
+ * should be placed in a common file.
  */
 
 void
@@ -232,6 +236,9 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 		Expr	   *leftop;		/* expr on lhs of operator */
 		Expr	   *rightop;	/* expr on rhs ... */
 		AttrNumber	varattno;	/* att number used in scan */
+		AttrNumber      varattnoold;
+		Oid             out_func_id = InvalidOid;
+		bool            typ_is_var_lena = InvalidOid;
 
 		/*
 		 * extract clause information from the qualification
@@ -243,6 +250,10 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 		subtype = lfirst_oid(subtype_cell);
 		subtype_cell = lnext(subtype_cell);
 
+		/*
+		 * So far, for a runTimeKey's expression, magma only supports OpExpr,
+		 * and must be (Var eq Var).
+		 */
 		if (IsA(clause, OpExpr))
 		{
 			/* indexkey op const or indexkey op expression */
@@ -266,6 +277,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 				insist_log(false,"indexqual doesn't have key on left side");
 
 			varattno = ((Var *) leftop)->varattno;
+			varattnoold = ((Var *) leftop)->varoattno;
 
 			/*
 			 * rightop is the constant or variable comparison value
@@ -286,6 +298,16 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 			}
 			else
 			{
+			        /* Only magma need do this logic. */
+			        if (IsA(planstate, ExternalScanState)
+			                && RelationIsMagmaTable2(((ExternalScanState *)planstate)->ss.ss_currentRelation->rd_id)
+			                /* We only need processing (Var op Var). */
+			                && IsA(rightop, Var))
+			        {
+			                Assert(((Var *) leftop)->vartype == ((Var *) rightop)->vartype);
+			                getTypeOutputInfo(((Var *) rightop)->vartype, &out_func_id, &typ_is_var_lena);
+			        }
+
 				/* Need to treat this one as a runtime key */
 				runtime_keys[n_runtime_keys].scan_key = this_scan_key;
 				runtime_keys[n_runtime_keys].key_expr =
@@ -303,7 +325,9 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 								   strategy,	/* op's strategy */
 								   subtype,		/* strategy subtype */
 								   opfuncid,	/* reg proc to use */
-								   scanvalue);	/* constant */
+								   scanvalue,   /* constant */
+								   varattnoold,
+								   out_func_id);
 		}
 		else if (IsA(clause, RowCompareExpr))
 		{
@@ -399,7 +423,9 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 									   op_strategy,		/* op's strategy */
 									   op_subtype,		/* strategy subtype */
 									   opfuncid,		/* reg proc to use */
-									   scanvalue);		/* constant */
+									   scanvalue,		/* constant */
+									   InvalidAttrNumber,
+				                                           InvalidOid);
 				extra_scan_keys++;
 			}
 
@@ -466,7 +492,9 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index,
 								   strategy,	/* op's strategy */
 								   subtype,		/* strategy subtype */
 								   opfuncid,	/* reg proc to use */
-								   (Datum) 0);	/* constant */
+								   (Datum) 0,	/* constant */
+								   InvalidAttrNumber,
+								   InvalidOid);
 		}
 		else
 			insist_log(false, "unsupported indexqual type: %d",
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 5de2981..12de33a 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -972,18 +972,10 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
                 }
                 CommonPlanContext ctx;
                 bool newPlanner = can_convert_common_plan(queryDesc, &ctx);
-                if (newPlanner && ctx.enforceNewScheduler && scheduler_plan_support_check(queryDesc)) {
-                  const char *queryId = palloc0(sizeof(int) + sizeof(int) + 5);
-                  sprintf(queryId, "QID%d_%d", gp_session_id, gp_command_count);
-                  scheduler_prepare_for_new_query(queryDesc, queryId, 0);
-                  pfree(queryId);
-                  scheduler_run(queryDesc->estate->scheduler_data, &ctx);
-                } else {
-                  estate->mainDispatchData = mainDispatchInit(queryDesc->resource);
-                  estate->dispatch_data = NULL;
-                  mainDispatchPrepare(estate->mainDispatchData, queryDesc, newPlanner);
-                  mainDispatchRun(estate->mainDispatchData, &ctx, newPlanner);
-                }
+                estate->mainDispatchData = mainDispatchInit(queryDesc->resource);
+                estate->dispatch_data = NULL;
+                mainDispatchPrepare(estate->mainDispatchData, queryDesc, newPlanner);
+                mainDispatchRun(estate->mainDispatchData, &ctx, newPlanner);
 
                 DropQueryContextInfo(queryDesc->plannedstmt->contextdisp);
                 queryDesc->plannedstmt->contextdisp = NULL;
@@ -1291,7 +1283,8 @@ ExecutorRun(QueryDesc *queryDesc,
         } while (!readCacheEof());
         result = NULL;
       } else if (queryDesc->newPlan) {
-        exec_mpp_query_new(queryDesc->newPlan->str,
+        exec_mpp_query_new(queryDesc->estate->mainDispatchData,
+                           queryDesc->newPlan->str,
                            queryDesc->newPlan->len, currentSliceId,
                            false, dest, queryDesc->planstate);
         result = NULL;
@@ -1867,6 +1860,13 @@ InitializeResultRelations(PlannedStmt *plannedstmt, EState *estate, CmdType oper
       estate->es_result_aosegnos = NIL;
 
       if (get_rel_relstorage(relid) == RELSTORAGE_ORC &&
+          !(eflags & EXEC_FLAG_EXPLAIN_ONLY) && rel_has_index(relid)) {
+        ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+            errmsg("cannot UPDATE/DELETE on table:%s because the table has indexes.",
+                   get_rel_name(relid))));
+          }
+
+      if (get_rel_relstorage(relid) == RELSTORAGE_ORC &&
           !(eflags & EXEC_FLAG_EXPLAIN_ONLY)) {
         ListCell *cell;
         foreach (cell, plannedstmt->resultRelations) {
@@ -1882,6 +1882,12 @@ InitializeResultRelations(PlannedStmt *plannedstmt, EState *estate, CmdType oper
         }
       }
     } else {
+      if (get_rel_relstorage(relid) == RELSTORAGE_ORC &&
+          !(eflags & EXEC_FLAG_EXPLAIN_ONLY) && rel_has_index(relid)) {
+        ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+            errmsg("cannot INSERT on table:%s because the table has indexes.",
+                   get_rel_name(relid))));
+          }
       List  *all_relids = NIL;
       all_relids = lappend_oid(all_relids, relid);
       if (rel_is_partitioned(relid))
@@ -2039,7 +2045,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
 	 */
 	if (Gp_role != GP_ROLE_EXECUTE)
 	{
-		ExecCheckRTPerms(plannedstmt->rtable);
+		  ExecCheckRTPerms(plannedstmt->rtable);
 	}
 
 	/*
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 87d8c17..6c05918 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -86,7 +86,6 @@
 #include "cdb/cdbmotion.h"
 #include "cdb/cdbsreh.h"
 #include "cdb/memquota.h"
-#include "cdb/scheduler.h"
 #include "cdb/cdbsrlz.h"
 #include "catalog/catalog.h" // isMasterOnly()
 #include "executor/spi.h"
@@ -331,7 +330,6 @@ InternalCreateExecutorState(MemoryContext qcontext, bool is_subquery)
 
 	estate->dispatch_data = NULL;
 	estate->mainDispatchData = NULL;
-	estate->scheduler_data = NULL;
 
 	estate->currentSliceIdInPlan = 0;
 	estate->currentExecutingSliceId = 0;
@@ -2196,6 +2194,8 @@ void mppExecutorFinishup(QueryDesc *queryDesc)
 		 */
 		TeardownInterconnect(estate->interconnect_context, estate->motionlayer_context, estate->cancelUnfinished);
 		estate->es_interconnect_is_setup = false;
+	} else if (queryDesc->newPlan) {
+	  teardownNewInterconnect();
 	}
 }
 
@@ -2259,12 +2259,7 @@ void mppExecutorCleanup(QueryDesc *queryDesc)
 		dispatch_catch_error(estate->dispatch_data);
 		estate->dispatch_data = NULL;
 	}
-	else if (estate->scheduler_data)
-	{
-	  scheduler_catch_error(estate->scheduler_data);
-	  scheduler_cleanup(estate->scheduler_data);
-	  estate->scheduler_data = NULL;
-	} else if (estate->mainDispatchData) {
+	else if (estate->mainDispatchData) {
 	  if (estate->es_interconnect_is_setup && !estate->es_got_eos)
 	    ExecSquelchNode(queryDesc->planstate);
 	  mainDispatchCatchError(&estate->mainDispatchData);
@@ -2275,6 +2270,8 @@ void mppExecutorCleanup(QueryDesc *queryDesc)
 	{
 		TeardownInterconnect(estate->interconnect_context, estate->motionlayer_context, true /* force EOS */);
 		estate->es_interconnect_is_setup = false;
+	} else if (queryDesc->newPlan) {
+	  teardownNewInterconnect();
 	}
 	
 	/**
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 8443877..452ca5b 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -539,13 +539,15 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
 				if (count == 0L) {
 					result = NULL;
 					exec_mpp_query_new(
+					    es->qd->estate->mainDispatchData,
 							es->qd->newPlan->str, es->qd->newPlan->len,
 							currentSliceId, false, NULL, NULL);
 				} else {
 					es->qd->newExecutorState =
 							makeMyNewExecutorTupState(es->qd->tupDesc);
 
-					beginMyNewExecutor(es->qd->newPlan->str,
+					beginMyNewExecutor(es->qd->estate->mainDispatchData,
+					                   es->qd->newPlan->str,
 														 es->qd->newPlan->len,
 														 currentSliceId, NULL);
 					execMyNewExecutor(es->qd->newExecutorState);
diff --git a/src/backend/executor/newExecutor.c b/src/backend/executor/newExecutor.c
index 706dc8a..6a5825d 100644
--- a/src/backend/executor/newExecutor.c
+++ b/src/backend/executor/newExecutor.c
@@ -55,7 +55,7 @@ void checkOushuDbExtensiveFunctionSupport(char functionString[]) {
 
 PlanState *newExecutorPlanStateReference = NULL;
 
-void exec_mpp_query_new(const char *plan, int len, int stageNo, bool setDisplay,
+void exec_mpp_query_new(void *dispatchData, const char *plan, int len, int stageNo, bool setDisplay,
                         DestReceiver *dest, PlanState *planstate) {
   checkOushuDbExtensiveFeatureSupport("New Executor");
   Assert(MyNewExecutor != NULL);
@@ -65,7 +65,7 @@ void exec_mpp_query_new(const char *plan, int len, int stageNo, bool setDisplay,
   sprintf(queryId, "QID%d_%d", gp_session_id, gp_command_count);
   int vsegNum = GetQEGangNum();
   int rangeNum = 0;
-  ExecutorNewWorkHorse(MyNewExecutor, plan, len, queryId, stageNo, GetQEIndex(),
+  ExecutorNewWorkHorse(MyNewExecutor, dispatchData, plan, len, queryId, stageNo, GetQEIndex(),
                        vsegNum, DateStyle, DateOrder, &rangeNum);
   MyExecutorSetJumpHashMap(MyNewExecutor, get_jump_hash_map(rangeNum),
                            JUMP_HASH_MAP_LENGTH);
@@ -97,6 +97,10 @@ void exec_mpp_query_new(const char *plan, int len, int stageNo, bool setDisplay,
   newExecutorPlanStateReference = NULL;
 }
 
+void teardownNewInterconnect() {
+  ExecutorTearDownInterconnect(MyNewExecutor);
+}
+
 MyNewExecutorTupState *makeMyNewExecutorTupState(TupleDesc tupdesc) {
   MyNewExecutorTupState *state =
       (MyNewExecutorTupState *)palloc(sizeof(MyNewExecutorTupState));
@@ -142,7 +146,7 @@ MyNewExecutorTupState *makeMyNewExecutorTupState(TupleDesc tupdesc) {
   return state;
 }
 
-void beginMyNewExecutor(const char *plan, int len, int stageNo,
+void beginMyNewExecutor(void *dispatchData, const char *plan, int len, int stageNo,
                         PlanState *planstate) {
   Assert(MyNewExecutor != NULL);
   newExecutorPlanStateReference = planstate;
@@ -151,7 +155,7 @@ void beginMyNewExecutor(const char *plan, int len, int stageNo,
   sprintf(queryId, "QID%d_%d", gp_session_id, gp_command_count);
   int vsegNum = GetQEGangNum();
   int rangeNum = 0;
-  ExecutorNewWorkHorse(MyNewExecutor, plan, len, queryId, stageNo, GetQEIndex(),
+  ExecutorNewWorkHorse(MyNewExecutor, dispatchData, plan, len, queryId, stageNo, GetQEIndex(),
                        vsegNum, DateStyle, DateOrder, &rangeNum);
   MyExecutorSetJumpHashMap(MyNewExecutor, get_jump_hash_map(rangeNum),
                            JUMP_HASH_MAP_LENGTH);
diff --git a/src/backend/executor/nodeExternalscan.c b/src/backend/executor/nodeExternalscan.c
index 2d203a7..0b5f423 100644
--- a/src/backend/executor/nodeExternalscan.c
+++ b/src/backend/executor/nodeExternalscan.c
@@ -36,6 +36,7 @@
 #include "postgres.h"
 #include "fmgr.h"
 
+#include "access/genam.h"
 #include "access/fileam.h"
 #include "access/filesplit.h"
 #include "access/heapam.h"
@@ -44,6 +45,8 @@
 #include "cdb/cdbvars.h"
 #include "cdb/cdbdatalocality.h"
 #include "executor/execdebug.h"
+#include "executor/execIndexscan.h"
+#include "executor/nodeIndexscan.h"
 #include "executor/nodeExternalscan.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
@@ -66,7 +69,6 @@ static TupleTableSlot *
 ExternalNext(ExternalScanState *node)
 {
 	FileScanDesc scandesc;
-	Index scanrelid;
 	EState *estate = NULL;
 	ScanDirection direction;
 	TupleTableSlot *slot = NULL;
@@ -78,7 +80,6 @@ ExternalNext(ExternalScanState *node)
 	 */
 	estate = node->ss.ps.state;
 	scandesc = node->ess_ScanDesc;
-	scanrelid = ((ExternalScan *) node->ss.ps.plan)->scan.scanrelid;
 	direction = estate->es_direction;
 	slot = node->ss.ss_ScanTupleSlot;
 
@@ -368,6 +369,53 @@ ExecInitExternalScan(ExternalScan *node, EState *estate, int eflags)
 
 	ExecAssignScanType(&externalstate->ss, RelationGetDescr(currentRelation));
 
+	if (IsA(node, MagmaIndexScan) || IsA(node, MagmaIndexOnlyScan))
+	{
+	        /*
+	         * Unlike ExecInitIndexScan(which is used by the heap table and is only executed on QD),
+	         * we can't call index_open to get iss_RelationDesc, because QE will also run here, and
+	         * index did not dispatch, so we set iss_RelationDesc to NULL.
+	         *
+	         * We have disabled the path that requires iss_RelationDesc, so there is no problem with doing so.
+	         * See also: best_inner_indexscan().
+	         */
+                externalstate->iss_RelationDesc = NULL;
+
+                /*
+                 * build the index scan keys from the index qualification
+                 */
+                ExecIndexBuildScanKeys((PlanState *) externalstate,
+                                       externalstate->iss_RelationDesc,
+                                       node->indexqual,
+                                       node->indexstrategy,
+                                       node->indexsubtype,
+                                       &externalstate->iss_ScanKeys,
+                                       &externalstate->iss_NumScanKeys,
+                                       &externalstate->iss_RuntimeKeys,
+                                       &externalstate->iss_NumRuntimeKeys,
+                                       NULL,        /* no ArrayKeys */
+                                       NULL);
+
+                /*
+                 * If we have runtime keys, we need an ExprContext to evaluate them. The
+                 * node's standard context won't do because we want to reset that context
+                 * for every tuple.  So, build another context just like the other one...
+                 * -tgl 7/11/00
+                 */
+                if (externalstate->iss_NumRuntimeKeys != 0)
+                {
+                	ExprContext *stdecontext = externalstate->ss.ps.ps_ExprContext;
+
+                	ExecAssignExprContext(estate, &externalstate->ss.ps);
+                	externalstate->iss_RuntimeContext = externalstate->ss.ps.ps_ExprContext;
+                	externalstate->ss.ps.ps_ExprContext = stdecontext;
+                }
+                else
+                {
+                	externalstate->iss_RuntimeContext = NULL;
+                }
+	}
+
 	/*
 	 * Initialize result tuple type and projection info.
 	 */
@@ -497,11 +545,48 @@ void
 ExecExternalReScan(ExternalScanState *node, ExprContext *exprCtxt)
 {
 	EState	   *estate;
+	ExprContext *econtext;
 	Index		scanrelid;
 	FileScanDesc fileScan;
+	TupleTableSlot *slot = NULL;
 
 	estate = node->ss.ps.state;
+	econtext = node->iss_RuntimeContext;		/* context for runtime keys */
 	scanrelid = ((SeqScan *) node->ss.ps.plan)->scanrelid;
+	slot = node->ss.ss_ScanTupleSlot;
+
+	if (econtext)
+	{
+		/*
+		 * If we are being passed an outer tuple, save it for runtime key
+		 * calc.  We also need to link it into the "regular" per-tuple
+		 * econtext, so it can be used during indexqualorig evaluations.
+		 */
+		if (exprCtxt != NULL)
+		{
+			ExprContext *stdecontext;
+
+			econtext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
+			stdecontext = node->ss.ps.ps_ExprContext;
+			stdecontext->ecxt_outertuple = exprCtxt->ecxt_outertuple;
+		}
+
+		/*
+		 * Reset the runtime-key context so we don't leak memory as each outer
+		 * tuple is scanned.  Note this assumes that we will recalculate *all*
+		 * runtime keys on each call.
+		 */
+		ResetExprContext(econtext);
+	}
+
+	/*
+	 * If we are doing runtime key calculations (ie, the index keys depend on
+	 * data from an outer scan), compute the new key values
+	 */
+	if (node->iss_NumRuntimeKeys != 0)
+		ExecIndexEvalRuntimeKeys(econtext,
+								 node->iss_RuntimeKeys,
+								 node->iss_NumRuntimeKeys);
 
 	/* If this is re-scanning of PlanQual ... */
 	if (estate->es_evTuple != NULL &&
@@ -529,16 +614,13 @@ ExecExternalReScan(ExternalScanState *node, ExprContext *exprCtxt)
 		Assert(fileScan->fs_formatter_name);
 
 		FmgrInfo *rescanFunc = fileScan->fs_ps_scan_funcs.rescan;
+		if (!rescanFunc)
+                        elog(ERROR, "%s_rescan function was not found",
+                               fileScan->fs_formatter_name);
 
-		if (rescanFunc)
-		{
-			InvokePlugStorageFormatReScan(rescanFunc, fileScan);
-		}
-		else
-		{
-			elog(ERROR, "%s_rescan function was not found",
-			            fileScan->fs_formatter_name);
-		}
+		InvokePlugStorageFormatReScan(rescanFunc, fileScan, &(node->ss),
+		    PlugStorageGetTransactionSnapshot(NULL),
+		    node->iss_RuntimeKeys, node->iss_NumRuntimeKeys, slot);
 	}
 }
 
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index beca1dc..98fcfe0 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -24,16 +24,20 @@
  */
 #include "postgres.h"
 
+#include "access/filesplit.h"
 #include "access/genam.h"
 #include "access/nbtree.h"
+#include "access/orcam.h"
 #include "cdb/cdbvars.h"
 #include "executor/execdebug.h"
 #include "executor/nodeIndexscan.h"
 #include "nodes/nodeFuncs.h"
+#include "nodes/nodes.h"
 #include "optimizer/clauses.h"
 #include "utils/array.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/debugutils.h"
 
 /*
  * Initialize the index scan descriptor if it is not initialized.
@@ -70,6 +74,22 @@ freeScanDesc(IndexScanState *indexstate)
 	}
 }
 
+/* native orc index */
+extern TupleTableSlot *OrcIndexNext(IndexScanState *node)
+{
+	if (node->scandesc == NULL)
+		orcBeginIndexOnlyScan(node, ((IndexScan*)(node->ss.ps.plan))->indexid,
+													((IndexScan*)(node->ss.ps.plan))->idxColummns);
+	TupleTableSlot *slot = orcIndexOnlyScanNext(node);
+
+	if (!TupIsNull(slot))
+	{
+		Gpmon_M_Incr_Rows_Out(GpmonPktFromIndexScanState(node));
+		CheckSendPlanStateGpmonPkt(&node->ss.ps);
+	}
+
+	return slot;
+}
 
 /* ----------------------------------------------------------------
  *		IndexNext
@@ -202,7 +222,10 @@ ExecIndexScan(IndexScanState *node)
 	/*
 	 * use IndexNext as access method
 	 */
-	return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
+	if (!(IsA(node->ss.ps.plan, OrcIndexOnlyScan) || IsA(node->ss.ps.plan, OrcIndexScan)))
+		return ExecScan(&node->ss, (ExecScanAccessMtd) IndexNext);
+	else
+		return ExecScan(&node->ss, (ExecScanAccessMtd) OrcIndexNext);
 }
 
 /* ----------------------------------------------------------------
@@ -222,7 +245,11 @@ ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
 	ExprContext *econtext;
 	Index		scanrelid;
 
-	initScanDesc(node);
+	if (!(IsA(node->ss.ps.plan, OrcIndexOnlyScan) || IsA(node->ss.ps.plan, OrcIndexScan)))
+		initScanDesc(node);
+	else
+		orcBeginIndexOnlyScan(node, ((IndexScan*)(node->ss.ps.plan))->indexid,
+													((IndexScan*)(node->ss.ps.plan))->idxColummns);
 
 	estate = node->ss.ps.state;
 	econtext = node->iss_RuntimeContext;		/* context for runtime keys */
@@ -273,7 +300,10 @@ ExecIndexReScan(IndexScanState *node, ExprContext *exprCtxt)
 	}
 
 	/* reset index scan */
-	index_rescan(node->iss_ScanDesc, node->iss_ScanKeys);
+	if (!(IsA(node->ss.ps.plan, OrcIndexOnlyScan) || IsA(node->ss.ps.plan, OrcIndexScan)))
+		index_rescan(node->iss_ScanDesc, node->iss_ScanKeys);
+	else
+		orcIndexOnlyReScan(node);
 
 	Gpmon_M_Incr(GpmonPktFromIndexScanState(node), GPMON_INDEXSCAN_RESCAN); 
 	CheckSendPlanStateGpmonPkt(&node->ss.ps);
@@ -481,7 +511,10 @@ ExecEndIndexScan(IndexScanState *node)
 	 * close the index relation
 	 */
 	ExecEagerFreeIndexScan(node);
-	index_close(indexRelationDesc, NoLock);
+	if (!(IsA(node->ss.ps.plan, OrcIndexOnlyScan) || IsA(node->ss.ps.plan, OrcIndexScan)))
+		index_close(indexRelationDesc, NoLock);
+	else
+		orcEndIndexOnlyScan(node);
 
 	/*
 	 * close the heap relation.
@@ -594,8 +627,13 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
 	 * taking another lock here.  Otherwise we need a normal reader's lock.
 	 */
 	relistarget = ExecRelationIsTargetRelation(estate, node->scan.scanrelid);
-	indexstate->iss_RelationDesc = index_open(node->indexid,
-									 relistarget ? NoLock : AccessShareLock);
+	if (!(IsA(&(node->scan.plan), OrcIndexOnlyScan) || IsA(&(node->scan.plan), OrcIndexScan)))
+		indexstate->iss_RelationDesc = index_open(node->indexid,relistarget ? NoLock : AccessShareLock);
+	else
+	{
+		indexstate->ss.splits = GetFileSplitsOfSegment(estate->es_plannedstmt->scantable_splits,
+																									 currentRelation->rd_id, GetQEIndex());
+	}
 
 	/*
 	 * build the index scan keys from the index qualification
diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c
index 3992c3a..b5be790 100644
--- a/src/backend/executor/nodeNestloop.c
+++ b/src/backend/executor/nodeNestloop.c
@@ -152,13 +152,13 @@ ExecNestLoop(NestLoopState *node)
 			 * iterations.
 			 */
 			node->nl_innerSideScanned = true;
-            /* CDB: Quit if empty inner implies no outer rows can match. */
+			/* CDB: Quit if empty inner implies no outer rows can match. */
 			/* See MPP-1146 and MPP-1694 */
 			if (node->nl_QuitIfEmptyInner)
-            {
-                ExecSquelchNode(outerPlan);
-                return NULL;
-            }
+			{
+			        ExecSquelchNode(outerPlan);
+			        return NULL;
+			}
 		}
 
 		if ((node->js.jointype == JOIN_LASJ_NOTIN) &&
@@ -200,10 +200,10 @@ ExecNestLoop(NestLoopState *node)
 		 */
 		if (node->nl_NeedNewOuter)
 		{
-            ENL1_printf("getting new outer tuple");
-            outerTupleSlot = ExecProcNode(outerPlan);
-            Gpmon_M_Incr(GpmonPktFromNLJState(node), GPMON_NLJ_OUTERTUPLE);
-            Gpmon_M_Incr(GpmonPktFromNLJState(node), GPMON_QEXEC_M_ROWSIN); 
+		        ENL1_printf("getting new outer tuple");
+		        outerTupleSlot = ExecProcNode(outerPlan);
+		        Gpmon_M_Incr(GpmonPktFromNLJState(node), GPMON_NLJ_OUTERTUPLE);
+		        Gpmon_M_Incr(GpmonPktFromNLJState(node), GPMON_QEXEC_M_ROWSIN);
 
 			/*
 			 * if there are no more outer tuples, then the join is complete..
@@ -308,18 +308,18 @@ ExecNestLoop(NestLoopState *node)
 					 */
 					ENL1_printf("qualification succeeded, projecting tuple");
 
-					Gpmon_M_Incr_Rows_Out(GpmonPktFromNLJState(node)); 
-                          	CheckSendPlanStateGpmonPkt(&node->js.ps);
+					Gpmon_M_Incr_Rows_Out(GpmonPktFromNLJState(node));
+					CheckSendPlanStateGpmonPkt(&node->js.ps);
 					return ExecProject(node->js.ps.ps_ProjInfo, NULL);
 				}
 			}
 
-            /* CDB: Quit if empty inner implies no outer rows can match. */
-            if (node->nl_QuitIfEmptyInner)
-            {
-                ExecSquelchNode(outerPlan);
-                return NULL;
-            }
+			/* CDB: Quit if empty inner implies no outer rows can match. */
+			if (node->nl_QuitIfEmptyInner)
+			{
+			        ExecSquelchNode(outerPlan);
+			        return NULL;
+			}
 
 			/*
 			 * Otherwise just return to top of loop for a new outer tuple.
@@ -327,7 +327,7 @@ ExecNestLoop(NestLoopState *node)
 			continue;
 		}
 
-        node->nl_QuitIfEmptyInner = false;  /*CDB*/
+		node->nl_QuitIfEmptyInner = false;  /*CDB*/
 
 		if ((node->js.jointype == JOIN_LASJ_NOTIN) &&
 				(!node->nl_innerSideScanned) &&
@@ -376,7 +376,7 @@ ExecNestLoop(NestLoopState *node)
 				ENL1_printf("qualification succeeded, projecting tuple");
 
 				Gpmon_M_Incr_Rows_Out(GpmonPktFromNLJState(node));
-                     	CheckSendPlanStateGpmonPkt(&node->js.ps);
+				CheckSendPlanStateGpmonPkt(&node->js.ps);
 				return ExecProject(node->js.ps.ps_ProjInfo, NULL);
 			}
 
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index 81c6792..92aa892 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -1129,18 +1129,10 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext, QueryDesc *gbl_query
 			 */
 		  CommonPlanContext ctx;
 		  bool newPlanner = can_convert_common_plan(queryDesc, &ctx);
-       if (newPlanner && ctx.enforceNewScheduler && scheduler_plan_support_check(queryDesc)) {
-		   	const char *queryId = palloc0(sizeof(int) + sizeof(int) + 5);
-		   	sprintf(queryId, "QID%d_%d", gp_session_id, gp_command_count);
-		   	scheduler_prepare_for_new_query(queryDesc, queryId, subplan->plan_id);
-		   	pfree(queryId);
-		   	scheduler_run(queryDesc->estate->scheduler_data, &ctx);
-		  } else {
-		    queryDesc->estate->mainDispatchData = mainDispatchInit(queryDesc->resource);
-		    queryDesc->estate->dispatch_data = NULL;
-		    mainDispatchPrepare(queryDesc->estate->mainDispatchData, queryDesc, newPlanner);
-		    mainDispatchRun(queryDesc->estate->mainDispatchData, &ctx, newPlanner);
-		  }
+      queryDesc->estate->mainDispatchData = mainDispatchInit(queryDesc->resource);
+      queryDesc->estate->dispatch_data = NULL;
+      mainDispatchPrepare(queryDesc->estate->mainDispatchData, queryDesc, newPlanner);
+      mainDispatchRun(queryDesc->estate->mainDispatchData, &ctx, newPlanner);
 
 			// decide if the query is supported by new executor
 			if (queryDesc && queryDesc->newPlan)
@@ -1179,7 +1171,8 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext, QueryDesc *gbl_query
 		  Plan *plan = exec_subplan_get_plan(gbl_queryDesc->plannedstmt, subplan);
 		  TupleDesc cleanTupDesc = ExecCleanTypeFromTL(plan->targetlist, false);
 		  queryDesc->newExecutorState = makeMyNewExecutorTupState(cleanTupDesc);
-		  beginMyNewExecutor(queryDesc->newPlan->str, queryDesc->newPlan->len,
+		  beginMyNewExecutor(queryDesc->estate->mainDispatchData,
+		                     queryDesc->newPlan->str, queryDesc->newPlan->len,
 		                     subplan->qDispSliceId, planstate);
 		}
 
@@ -1360,20 +1353,6 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext, QueryDesc *gbl_query
              * report it and exit to our error handler (below) via PG_THROW.
              */
             mainDispatchCleanUp(&queryDesc->estate->mainDispatchData);
-        } else if (shouldDispatch &&
-            queryDesc && queryDesc->estate &&
-            queryDesc->estate->scheduler_data) {
-          scheduler_wait(queryDesc->estate->scheduler_data);
-          queryDesc->estate->scheduler_data = NULL;
-          if (planstate->instrument && queryDesc->estate->scheduler_data &&
-              queryDesc->estate->scheduler_data->state != SS_ERROR) {
-            scheduler_receive_computenode_stats(
-                queryDesc->estate->scheduler_data, planstate);
-            cdbexplain_recvSchedulerExecStats(
-                planstate, queryDesc->estate->scheduler_data, 0,
-                econtext->ecxt_estate->showstatctx);
-          }
-          scheduler_cleanup(queryDesc->estate->scheduler_data);
         }
 
 		/* teardown the sequence server */
@@ -1387,6 +1366,8 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext, QueryDesc *gbl_query
 	        TeardownInterconnect(queryDesc->estate->interconnect_context, 
 								 queryDesc->estate->motionlayer_context,
 								 false); /* following success on QD */	
+		} else if (newExecutor) {
+		  teardownNewInterconnect();
 		}
 
     }
@@ -1410,12 +1391,6 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext, QueryDesc *gbl_query
                   econtext->ecxt_estate->showstatctx,
                   mainDispatchGetSegNum(queryDesc->estate->mainDispatchData));
             }
-          } else if (planstate->state->scheduler_data){
-            scheduler_receive_computenode_stats(
-                queryDesc->estate->scheduler_data, planstate);
-            cdbexplain_recvSchedulerExecStats(
-                planstate, queryDesc->estate->scheduler_data, 0,
-                econtext->ecxt_estate->showstatctx);
           }
         }
 
@@ -1429,24 +1404,23 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext, QueryDesc *gbl_query
 		 */
         if (shouldDispatch && queryDesc && queryDesc->estate && queryDesc->estate->mainDispatchData) {
           mainDispatchCatchError(&queryDesc->estate->mainDispatchData);
-        } else if (shouldDispatch && queryDesc && queryDesc->estate && queryDesc->estate->scheduler_data) {
-          scheduler_catch_error(queryDesc->estate->scheduler_data);
-          scheduler_cleanup(queryDesc->estate->scheduler_data);
-          queryDesc->estate->scheduler_data = NULL;
         }
 		
 		/* teardown the sequence server */
 		TeardownSequenceServer();
-		
-        /*
-         * Clean up the interconnect.
-         * CDB TODO: Is this needed following failure on QD?
-         */
-        if (shouldTeardownInterconnect)
-			TeardownInterconnect(queryDesc->estate->interconnect_context,
-								 queryDesc->estate->motionlayer_context,
-								 true);
-		PG_RE_THROW();
+
+    /*
+     * Clean up the interconnect.
+     * CDB TODO: Is this needed following failure on QD?
+     */
+    if (shouldTeardownInterconnect)
+      TeardownInterconnect(queryDesc->estate->interconnect_context,
+                           queryDesc->estate->motionlayer_context,
+                           true);
+    else if (newExecutor) {
+      teardownNewInterconnect();
+    }
+    PG_RE_THROW();
 	}
 	PG_END_TRY();
 
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 03cdda7..5190670 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -775,8 +775,6 @@ void Explain_udf_plan(QueryDesc *qdesc)
 
 	if (qdesc->estate->dispatch_data)
 		dispatcher_print_statistics(buf, qdesc->estate->dispatch_data);
-	else if (qdesc->estate->scheduler_data)
-		scheduler_print_stats(qdesc->estate->scheduler_data, buf);
 	appendStringInfo(buf, "Data locality statistics:\n");
 	if (qdesc->plannedstmt->datalocalityInfo ==NULL){
 		appendStringInfo(buf, "  no data locality information in this query\n");
@@ -2365,7 +2363,8 @@ _SPI_pquery(QueryDesc * queryDesc, bool fire_triggers, long tcount)
         {
           queryDesc->newExecutorState = makeMyNewExecutorTupState(
               queryDesc->tupDesc);
-          beginMyNewExecutor(queryDesc->newPlan->str,
+          beginMyNewExecutor(queryDesc->estate->mainDispatchData,
+                             queryDesc->newPlan->str,
                              queryDesc->newPlan->len, currentSliceId,
                              queryDesc->planstate);
           (*queryDesc->dest->rStartup)(queryDesc->dest,
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f68767d..f7dde09 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -238,6 +238,7 @@ _copyPlannedStmt(PlannedStmt *from)
 	COPY_SCALAR_FIELD(planner_segments);
 
 	COPY_LOCATION_FIELD(originNodeType);
+	COPY_NODE_FIELD(graphEntry);
 
 	return newnode;
 }
@@ -543,6 +544,8 @@ copyIndexScanFields(const IndexScan *from, IndexScan *newnode)
 	{
 		Assert(newnode->logicalIndexInfo == NULL);
 	}
+	COPY_SCALAR_FIELD(indexonly);
+	COPY_NODE_FIELD(idxColummns);
 }
 
 /*
@@ -602,8 +605,11 @@ _copyMagmaIndexScan(MagmaIndexScan *from)
 	COPY_SCALAR_FIELD(rejLimitInRows);
 	COPY_SCALAR_FIELD(fmterrtbl);
 	COPY_STRING_FIELD(indexname);
-	COPY_SCALAR_FIELD(indexorderdir);
+	COPY_NODE_FIELD(indexqual);
 	COPY_NODE_FIELD(indexqualorig);
+	COPY_NODE_FIELD(indexstrategy);
+	COPY_NODE_FIELD(indexsubtype);
+	COPY_SCALAR_FIELD(indexorderdir);
 	COPY_NODE_FIELD(errAosegnos);
 	COPY_NODE_FIELD(err_aosegfileinfos);
 	COPY_SCALAR_FIELD(encoding);
@@ -629,7 +635,10 @@ _copyMagmaIndexOnlyScan(MagmaIndexOnlyScan *from)
 	COPY_SCALAR_FIELD(rejLimitInRows);
 	COPY_SCALAR_FIELD(fmterrtbl);
 	COPY_STRING_FIELD(indexname);
+	COPY_NODE_FIELD(indexqual);
 	COPY_NODE_FIELD(indexqualorig);
+	COPY_NODE_FIELD(indexstrategy);
+	COPY_NODE_FIELD(indexsubtype);
 	COPY_SCALAR_FIELD(indexorderdir);
 	COPY_NODE_FIELD(errAosegnos);
 	COPY_NODE_FIELD(err_aosegfileinfos);
@@ -2160,6 +2169,7 @@ _copyRangeTblEntry(RangeTblEntry *from)
 	COPY_SCALAR_FIELD(forceDistRandom);
     COPY_NODE_FIELD(pseudocols);                /*CDB*/
 
+	COPY_STRING_FIELD(graphName);
 	return newnode;
 }
 
@@ -2723,6 +2733,7 @@ _copyQuery(Query *from)
 	}
 	else
 		newnode->intoPolicy = NULL;
+	COPY_NODE_FIELD(graphEntry);
 
 	return newnode;
 }
@@ -3379,7 +3390,15 @@ _copyIndexStmt(IndexStmt *from)
 	COPY_SCALAR_FIELD(concurrent);
 	COPY_NODE_FIELD(idxOids);
 	COPY_SCALAR_FIELD(do_part);
-
+	COPY_SCALAR_FIELD(magma);
+	COPY_SCALAR_FIELD(relationOid);
+	COPY_NODE_FIELD(allidxinfos);
+	COPY_NODE_FIELD(columnsToRead);
+	COPY_NODE_FIELD(contextdisp);
+	COPY_NODE_FIELD(graphele);
+	COPY_NODE_FIELD(graphIndexAttnum);
+	COPY_NODE_FIELD(graphIncludeAttnum);
+	COPY_SCALAR_FIELD(reverse);
 	return newnode;
 }
 
@@ -4401,6 +4420,15 @@ _copyVirtualSegmentNode(const VirtualSegmentNode *from)
 	return newnode;
 }
 
+static GraphEntry *
+_copyGraphEntry(const GraphEntry *from)
+{
+  GraphEntry *newnode = makeNode(GraphEntry);
+  newnode->relid = from->relid;
+  newnode->requiredPerms = from->requiredPerms;
+  return newnode;
+}
+
 /* ****************************************************************
  *					pg_list.h copy functions
  * ****************************************************************
@@ -5314,6 +5342,9 @@ copyObject(void *from)
 		case T_VirtualSegmentNode:
 			retval = _copyVirtualSegmentNode(from);
 			break;
+		case T_GraphEntry:
+		  retval = _copyGraphEntry(from);
+		  break;
 		default:
 			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
 			retval = from;		/* keep compiler quiet */
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index f04bb81..17e521c 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1268,6 +1268,15 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
 	COMPARE_SCALAR_FIELD(concurrent);
 	COMPARE_NODE_FIELD(idxOids);
 	COMPARE_SCALAR_FIELD(do_part);
+	COMPARE_SCALAR_FIELD(magma);
+	COMPARE_SCALAR_FIELD(relationOid);
+	COMPARE_NODE_FIELD(allidxinfos);
+	COMPARE_NODE_FIELD(columnsToRead);
+	COMPARE_NODE_FIELD(contextdisp);
+	COMPARE_NODE_FIELD(graphele);
+	COMPARE_NODE_FIELD(graphIndexAttnum);
+	COMPARE_NODE_FIELD(graphIncludeAttnum);
+	COMPARE_SCALAR_FIELD(reverse);
 
 	return true;
 }
diff --git a/src/backend/nodes/outfast.c b/src/backend/nodes/outfast.c
index 1409f38..3b63e85 100644
--- a/src/backend/nodes/outfast.c
+++ b/src/backend/nodes/outfast.c
@@ -483,6 +483,7 @@ _outPlannedStmt(StringInfo str, PlannedStmt *node)
 
 	WRITE_STRING_FIELD(hiveUrl);
 	WRITE_ENUM_FIELD(originNodeType, NodeTag);
+	WRITE_NODE_FIELD(graphEntry);
 }
 
 static void
@@ -612,7 +613,10 @@ _outMagmaIndexScan(StringInfo str, MagmaIndexScan *node)
 	WRITE_NODE_TYPE("MAGMAINDEXSCAN");
 	_outScanInfo(str, (Scan *) node);
 	WRITE_STRING_FIELD(indexname);
+	WRITE_LIST_FIELD(indexqual);
 	WRITE_LIST_FIELD(indexqualorig);
+	WRITE_LIST_FIELD(indexstrategy);
+	WRITE_LIST_FIELD(indexsubtype);
 	WRITE_ENUM_FIELD(indexorderdir, ScanDirection);
 	if (print_variable_fields) {
 	WRITE_NODE_FIELD(uriList);
@@ -640,7 +644,10 @@ _outMagmaIndexOnlyScan(StringInfo str, MagmaIndexOnlyScan *node)
 	WRITE_BOOL_FIELD(rejLimitInRows);
 	WRITE_OID_FIELD(fmterrtbl);
 	WRITE_STRING_FIELD(indexname);
+	WRITE_LIST_FIELD(indexqual);
 	WRITE_LIST_FIELD(indexqualorig);
+	WRITE_LIST_FIELD(indexstrategy);
+	WRITE_LIST_FIELD(indexsubtype);
 	WRITE_ENUM_FIELD(indexorderdir, ScanDirection);
 	WRITE_NODE_FIELD(errAosegnos);
 	WRITE_NODE_FIELD(err_aosegfileinfos);
@@ -706,6 +713,8 @@ outIndexScanFields(StringInfo str, IndexScan *node)
 	{
 		Assert(node->logicalIndexInfo == NULL);
 	}
+	WRITE_BOOL_FIELD(indexonly);
+	WRITE_LIST_FIELD(idxColummns);
 }
 
 static void
@@ -2362,6 +2371,7 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
 	WRITE_STRING_FIELD(accessMethod);
 	WRITE_STRING_FIELD(tableSpace);
 	WRITE_NODE_FIELD(indexParams);
+	WRITE_NODE_FIELD(indexIncludingParams);
 	WRITE_NODE_FIELD(options);
 
 	WRITE_NODE_FIELD(whereClause);
@@ -2374,10 +2384,16 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
 	WRITE_OID_FIELD(constrOid);
 	WRITE_BOOL_FIELD(concurrent);
 	WRITE_NODE_FIELD(idxOids);
+	WRITE_BOOL_FIELD(do_part);
+	WRITE_BOOL_FIELD(magma);
 	WRITE_OID_FIELD(relationOid);
 	WRITE_NODE_FIELD(allidxinfos);
 	WRITE_NODE_FIELD(columnsToRead);
 	WRITE_NODE_FIELD(contextdisp);
+	WRITE_NODE_FIELD(graphele);
+	WRITE_NODE_FIELD(graphIndexAttnum);
+	WRITE_NODE_FIELD(graphIncludeAttnum);
+	WRITE_BOOL_FIELD(reverse);
 }
 
 static void
@@ -3303,6 +3319,7 @@ _outQuery(StringInfo str, Query *node)
 	WRITE_NODE_FIELD(result_aosegnos);
 	WRITE_NODE_FIELD(returningLists);
 	WRITE_NODE_FIELD(contextdisp);
+	WRITE_NODE_FIELD(graphEntry);
 	/* Don't serialize policy */
 }
 
@@ -3519,6 +3536,7 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
 	WRITE_OID_FIELD(checkAsUser);
 
 	WRITE_BOOL_FIELD(forceDistRandom);
+	WRITE_STRING_FIELD(graphName);
 }
 
 static void
@@ -4011,6 +4029,14 @@ _outQueryResource(StringInfo str, QueryResource *node)
 	WRITE_INT64_FIELD(master_start_time);
 }
 
+static void
+_outGraphEntry(StringInfo str, GraphEntry *node)
+{
+  WRITE_NODE_TYPE("GraphEntry");
+  WRITE_OID_FIELD(relid);
+  WRITE_UINT_FIELD(requiredPerms);
+}
+
 /*
  * _outNode -
  *	  converts a Node into binary string and append it to 'str'
@@ -4868,6 +4894,10 @@ _outNode(StringInfo str, void *obj)
 				_outQueryResource(str, obj);
 				break;
 
+			case T_GraphEntry:
+        _outGraphEntry(str, obj);
+        break;
+
 			default:
 				elog(ERROR, "could not serialize unrecognized node type: %d",
 						 (int) nodeTag(obj));
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index c7ed4da..962b15c 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -663,6 +663,8 @@ outIndexScanFields(StringInfo str, IndexScan *node)
 	{
 		Assert(node->logicalIndexInfo == NULL);
 	}
+	WRITE_BOOL_FIELD(indexonly);
+	WRITE_NODE_FIELD(idxColummns);
 }
 
 static void
@@ -2292,10 +2294,16 @@ _outIndexStmt(StringInfo str, IndexStmt *node)
 	WRITE_OID_FIELD(constrOid);
 	WRITE_BOOL_FIELD(concurrent);
 	WRITE_NODE_FIELD(idxOids);
+	WRITE_BOOL_FIELD(do_part);
+	WRITE_BOOL_FIELD(magma);
 	WRITE_OID_FIELD(relationOid);
 	WRITE_NODE_FIELD(allidxinfos);
 	WRITE_NODE_FIELD(columnsToRead);
 	WRITE_NODE_FIELD(contextdisp);
+	WRITE_NODE_FIELD(graphele);
+	WRITE_NODE_FIELD(graphIndexAttnum);
+	WRITE_NODE_FIELD(graphIncludeAttnum);
+	WRITE_BOOL_FIELD(reverse);
 }
 
 static void
@@ -3711,6 +3719,7 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
 
 	WRITE_BOOL_FIELD(forceDistRandom);
     WRITE_NODE_FIELD(pseudocols);                                       /*CDB*/
+	WRITE_STRING_FIELD(graphName);
 }
 
 static void
diff --git a/src/backend/nodes/readfast.c b/src/backend/nodes/readfast.c
index 3371440..8547682 100644
--- a/src/backend/nodes/readfast.c
+++ b/src/backend/nodes/readfast.c
@@ -295,6 +295,7 @@ _readQuery(const char ** str)
 	READ_NODE_FIELD(result_aosegnos);
 	READ_NODE_FIELD(returningLists);
 	READ_NODE_FIELD(contextdisp);
+	READ_NODE_FIELD(graphEntry);
 	/* policy not serialized */
 
 	READ_DONE();
@@ -765,6 +766,7 @@ _readIndexStmt(const char ** str)
 	READ_STRING_FIELD(accessMethod);
 	READ_STRING_FIELD(tableSpace);
 	READ_NODE_FIELD(indexParams);
+	READ_NODE_FIELD(indexIncludingParams);
 	READ_NODE_FIELD(options);
 	READ_NODE_FIELD(whereClause);
 	READ_NODE_FIELD(rangetable);
@@ -776,11 +778,16 @@ _readIndexStmt(const char ** str)
 	READ_OID_FIELD(constrOid);
 	READ_BOOL_FIELD(concurrent);
 	READ_NODE_FIELD(idxOids);
+	READ_BOOL_FIELD(do_part);
+	READ_BOOL_FIELD(magma);
 	READ_OID_FIELD(relationOid);
 	READ_NODE_FIELD(allidxinfos);
 	READ_NODE_FIELD(columnsToRead);
 	READ_NODE_FIELD(contextdisp);
-
+	READ_NODE_FIELD(graphele);
+	READ_NODE_FIELD(graphIndexAttnum);
+	READ_NODE_FIELD(graphIncludeAttnum);
+	READ_BOOL_FIELD(reverse);
 	READ_DONE();
 }
 
@@ -2032,6 +2039,7 @@ _readRangeTblEntry(const char ** str)
 	READ_OID_FIELD(checkAsUser);
 
 	READ_BOOL_FIELD(forceDistRandom);
+	READ_STRING_FIELD(graphName);
 
 	READ_DONE();
 }
@@ -2975,6 +2983,7 @@ _readPlannedStmt(const char ** str)
 
 	READ_STRING_FIELD(hiveUrl);
 	READ_ENUM_FIELD(originNodeType, NodeTag);
+	READ_NODE_FIELD(graphEntry);
 
 	READ_DONE();
 }
@@ -3208,6 +3217,8 @@ readIndexScanFields(const char ** str, IndexScan *local_node)
 		ALLOCATE_LOCAL(local_node->logicalIndexInfo, LogicalIndexInfo, 1 /* single node allocation  */);
 		readLogicalIndexInfo(str, local_node->logicalIndexInfo);
 	}
+	READ_BOOL_FIELD(indexonly);
+	READ_NODE_FIELD(idxColummns);
 }
 
 /*
@@ -3289,7 +3300,10 @@ _readMagmaIndexScan(const char ** str)
 	READ_LOCALS(MagmaIndexScan);
 	readScanInfo(str, (Scan *)local_node);
 	READ_STRING_FIELD(indexname);
+	READ_NODE_FIELD(indexqual);
 	READ_NODE_FIELD(indexqualorig);
+	READ_NODE_FIELD(indexstrategy);
+	READ_NODE_FIELD(indexsubtype);
 	READ_ENUM_FIELD(indexorderdir, ScanDirection);
 	READ_NODE_FIELD(uriList);
 	READ_NODE_FIELD(fmtOpts);
@@ -3316,7 +3330,10 @@ _readMagmaIndexOnlyScan(const char ** str)
 	READ_BOOL_FIELD(rejLimitInRows);
 	READ_OID_FIELD(fmterrtbl);
 	READ_STRING_FIELD(indexname);
+	READ_NODE_FIELD(indexqual);
 	READ_NODE_FIELD(indexqualorig);
+	READ_NODE_FIELD(indexstrategy);
+	READ_NODE_FIELD(indexsubtype);
 	READ_ENUM_FIELD(indexorderdir, ScanDirection);
 	READ_NODE_FIELD(errAosegnos);
 	READ_NODE_FIELD(err_aosegfileinfos);
@@ -4247,6 +4264,16 @@ _readResultRelSegFileInfo(const char **str)
 	READ_DONE();
 }
 
+static GraphEntry *
+_readGraphEntry(const char **str) {
+  READ_LOCALS(GraphEntry);
+
+  READ_OID_FIELD(relid);
+  READ_UINT_FIELD(requiredPerms);
+
+  READ_DONE();
+}
+
 static QueryResource *
 _readQueryResource(const char **str)
 {
@@ -5053,6 +5080,10 @@ readNodeBinary(const char ** str)
 			return_value = _readQueryResource(str);
 			break;
 
+		case T_GraphEntry:
+      return_value = _readGraphEntry(str);
+      break;
+
 		default:
 			return_value = NULL; /* keep the compiler silent */
 			elog(ERROR, "could not deserialize unrecognized node type: %d",
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 6570406..55d6a24 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -909,6 +909,7 @@ _readIndexStmt(void)
 	READ_STRING_FIELD(accessMethod);
 	READ_STRING_FIELD(tableSpace);
 	READ_NODE_FIELD(indexParams);
+	READ_NODE_FIELD(indexIncludingParams);
 	READ_NODE_FIELD(options);
 	READ_NODE_FIELD(whereClause);
 	READ_NODE_FIELD(rangetable);
@@ -920,7 +921,16 @@ _readIndexStmt(void)
 	READ_OID_FIELD(constrOid);
 	READ_BOOL_FIELD(concurrent);
 	READ_NODE_FIELD(idxOids);
-
+	READ_BOOL_FIELD(do_part);
+	READ_BOOL_FIELD(magma);
+	READ_OID_FIELD(relationOid);
+	READ_NODE_FIELD(allidxinfos);
+	READ_NODE_FIELD(columnsToRead);
+	READ_NODE_FIELD(contextdisp);
+	READ_NODE_FIELD(graphele);
+	READ_NODE_FIELD(graphIndexAttnum);
+	READ_NODE_FIELD(graphIncludeAttnum);
+	READ_BOOL_FIELD(reverse);
 	READ_DONE();
 }
 
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index ae88f81..827a907 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -41,6 +41,7 @@
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_type.h"
+#include "catalog/pg_exttable.h"
 #include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
@@ -1662,6 +1663,8 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
 	List	   *indexpaths;
 	List	   *bitindexpaths;
 	ListCell   *l;
+	ListCell   *nextcell = NULL;
+	ListCell   *prevcell = NULL;
 	InnerIndexscanInfo *info;
 	MemoryContext oldcontext;
 	RangeTblEntry *rte;
@@ -1789,17 +1792,100 @@ best_inner_indexscan(PlannerInfo *root, RelOptInfo *rel,
 	relstorage = get_rel_relstorage(rte->relid);
 	Assert(relstorage != '\0');
 
-    /* Exclude plain index paths if user doesn't want them. */
-    if (!root->config->enable_indexscan && !root->config->mpp_trying_fallback_plan)
-        indexpaths = NIL;
-
-	/* Exclude plain index paths if the relation is an append-only relation. */
-	if (relstorage_is_ao(relstorage) ||
-		/* disable inner join index scan for magma
-		 * because magma index scan cant support dynamic filter
-		 */
-		relstorage == RELSTORAGE_EXTERNAL)
-		indexpaths = NIL;
+	if (RelationIsMagmaTable2(rte->relid))
+	{
+	        bool        del = false;
+	        Expr       *clause;
+	        Expr	   *leftop;	/* expr on lhs of operator */
+	        Expr	   *rightop;	/* expr on rhs ... */
+	        ListCell   *qual;
+	        Path       *path;
+
+	        /* Exclude plain index paths if user doesn't want them. */
+	        if ((!root->config->enable_magma_indexscan || !root->config->enable_magma_indexonlyscan)
+	                && !root->config->mpp_trying_fallback_plan)
+	        {
+	                for (l = list_head(indexpaths); l; l = nextcell)
+	                {
+	                        nextcell = lnext(l);
+	                        path = (Path *) lfirst(l);
+	                        if ((path->pathtype == T_MagmaIndexScan && !root->config->enable_magma_indexscan)
+	                                || (path->pathtype == T_MagmaIndexOnlyScan && !root->config->enable_magma_indexonlyscan))
+	                                indexpaths = list_delete_cell(indexpaths, l, prevcell);
+	                        else
+	                                prevcell = l;
+	                }
+	        }
+
+	        /*
+	         * Exclude plain index paths if there is an expression that magma deos not support.
+	         * So far, we only support (Var op Const), (Const op Var), (Var eq Var).
+	         */
+	        prevcell = NULL;
+	        for (l = list_head(indexpaths); l; l = nextcell)
+	        {
+	                nextcell = lnext(l);
+	                path = (Path *) lfirst(l);
+
+	                foreach(qual, ((IndexPath *) path)->indexquals)
+	                {
+	                        clause = ((RestrictInfo *) lfirst(qual))->clause;
+	                        /* e.g., RowCompareExpr */
+	                        if (!IsA(clause, OpExpr))
+	                        {
+	                                del = true;
+	                                break;
+	                        }
+
+	                        Assert(list_length(((OpExpr *) clause)->args) == 2);
+
+	                        leftop = (Expr *) get_leftop(clause);
+	                        if (leftop && IsA(leftop, RelabelType))
+	                                leftop = ((RelabelType *) leftop)->arg;
+	                        rightop = (Expr *) get_rightop(clause);
+	                        if (rightop && IsA(rightop, RelabelType))
+	                                rightop = ((RelabelType *) rightop)->arg;
+
+	                        /* e.g., (Var op FuncExpr), (FuncExpr op Var) */
+	                        if (!(IsA(leftop, Var) || IsA(leftop, Const))
+	                                || !(IsA(rightop, Var) || IsA(rightop, Const)))
+	                        {
+	                                del = true;
+	                                break;
+	                        }
+	                        if (IsA(leftop, Var) && IsA(rightop, Var))
+	                        {
+	                                if (((Var *) leftop)->vartype != ((Var *) rightop)->vartype
+	                                        /* If not satisfy (Var eq Var). */
+	                                        || pg_strcasecmp(get_opname(((OpExpr *) clause)->opno), "=") != 0)
+	                                {
+	                                        del = true;
+	                                        break;
+	                                }
+	                        }
+	                }
+
+	                if (del)
+	                {
+	                        indexpaths = list_delete_cell(indexpaths, l, prevcell);
+	                        del = false;
+	                }
+	                else
+	                        prevcell = l;
+	        }
+	}
+	else
+	{
+	        if (
+	                /* Exclude plain index paths if user doesn't want them. */
+	                (!root->config->enable_indexscan && !root->config->mpp_trying_fallback_plan)
+	                /* ... if the relation is an append-only relation. */
+	                || relstorage_is_ao(relstorage)
+	                /* ... if the relation is an external relation and not magma. */
+	                || relstorage_is_external(relstorage)
+	        )
+	                indexpaths = NIL;
+	}
 
 	/*
 	 * If we found anything usable, generate a BitmapHeapPath for the most
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 7e09615..b68c0ab 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -40,6 +40,7 @@
 #include "miscadmin.h" /* work_mem */
 
 #include "access/hd_work_mgr.h"
+#include "catalog/catquery.h"
 #include "catalog/pg_type.h"    /* INT8OID */
 #include "nodes/makefuncs.h"
 #include "executor/execHHashagg.h"
@@ -168,7 +169,10 @@ static MagmaIndexScan *make_magma_indexscan(List *qptlist,
 			   Index scanrelid,
 			   bool indexonly,
 			   Oid indexid,
+			   List *indexqual,
 			   List *indexqualorig,
+			   List *indexstrategy,
+			   List *indexsubtype,
 			   List *urilist,
 			   List *fmtopts,
 			   char fmttype,
@@ -352,8 +356,7 @@ create_scan_plan(CreatePlanContext *ctx, Path *best_path)
 	 */
 	if (use_physical_tlist(ctx, rel))
 	{
-		if (best_path->pathtype == T_MagmaIndexOnlyScan || best_path->pathtype == T_OrcIndexOnlyScan ||
-				best_path->pathtype == T_OrcIndexScan)
+		if (best_path->pathtype == T_MagmaIndexOnlyScan || best_path->pathtype == T_OrcIndexOnlyScan)
 		{
 			/* For index-only scan, the preferred tlist is the index's */
 			tlist = copyObject(((IndexPath *) best_path)->indexinfo->indextlist);
@@ -2279,7 +2282,10 @@ MagmaIndexScan *create_magma_indexscan_plan(
                     baserelid,
                     indexonly,
                     indexoid,
+                    fixed_indexquals,
                     stripped_indexquals,
+                    indexstrategy,
+                    indexsubtype,
                     rel->locationlist,
                     fmtopts,
                     rel->fmttype,
@@ -3834,6 +3840,19 @@ make_indexscan(List *qptlist,
 	IndexScan  *node = makeNode(IndexScan);
 	node->scan.plan.type = pathtype;
 	Plan	   *plan = &node->scan.plan;
+	/* native orc index scan need index columns */
+	if (pathtype == T_OrcIndexScan || pathtype == T_OrcIndexOnlyScan)
+	{
+		cqContext *idxcqCtx = caql_beginscan(NULL, cql("SELECT * FROM pg_index "
+				" WHERE indexrelid = :1 ", ObjectIdGetDatum(indexid)));
+		HeapTuple	ht_idx = caql_getnext(idxcqCtx);
+		Form_pg_index idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
+		for (int i = 0; i < idxrec->indnatts; i++)
+		{
+			node->idxColummns = lappend_oid(node->idxColummns, idxrec->indkey.values[i]);
+		}
+		caql_endscan(idxcqCtx);
+	}
 
 	/* cost should be inserted by caller */
 	plan->targetlist = qptlist;
@@ -3855,7 +3874,12 @@ make_indexscan(List *qptlist,
 
 static MagmaIndexScan *make_magma_indexscan(
 		List *qptlist, List *qpqual, Index scanrelid, bool indexonly,
-		Oid indexid, List *indexqualorig, List *urilist,
+		Oid indexid,
+		List *indexqual,
+		List *indexqualorig,
+		List *indexstrategy,
+		List *indexsubtype,
+		List *urilist,
 		List *fmtopts, char fmttype,
 		int rejectlimit, bool rejectlimitinrows,
 		Oid fmterrtableOid, int encoding, ScanDirection indexscandir)
@@ -3872,7 +3896,10 @@ static MagmaIndexScan *make_magma_indexscan(
 	plan->targetlist = qptlist;
 	plan->qual = qpqual;
 	node->indexname = getIndexNameByOid(indexid);
+	node->indexqual = indexqual;
 	node->indexqualorig = indexqualorig;
+	node->indexstrategy = indexstrategy;
+	node->indexsubtype = indexsubtype;
 	node->indexorderdir = indexscandir;
 	plan->lefttree = NULL;
 	plan->righttree = NULL;
diff --git a/src/backend/optimizer/plan/newPlanner.c b/src/backend/optimizer/plan/newPlanner.c
index 26be1c8..e15b7af 100644
--- a/src/backend/optimizer/plan/newPlanner.c
+++ b/src/backend/optimizer/plan/newPlanner.c
@@ -62,10 +62,6 @@ const char *new_executor_runtime_filter_mode;
 const char *new_executor_runtime_filter_mode_local = "local";
 const char *new_executor_runtime_filter_mode_global = "global";
 
-const char *new_scheduler_mode_on = "on";
-const char *new_scheduler_mode_off = "off";
-char *new_scheduler_mode;
-
 int new_interconnect_type;
 const char *show_new_interconnect_type() {
   switch (new_interconnect_type) {
@@ -90,6 +86,9 @@ static bool do_convert_targetlist_to_common_plan(Plan *node,
 static bool do_convert_quallist_to_common_plan(Plan *node,
                                                CommonPlanContext *ctx,
                                                bool isInsist);
+static bool do_convert_indexqualorig_to_common_plan(Plan *node,
+                                                    CommonPlanContext *ctx,
+                                                    bool isInsist);
 static bool do_convert_indexqual_to_common_plan(Plan *node,
                                                 CommonPlanContext *ctx,
                                                 bool isInsist);
@@ -369,6 +368,16 @@ void convert_extscan_to_common_plan(Plan *node, List *splits, Relation rel,
   }
 }
 
+void *convert_orcscan_indexqualorig_to_common_plan(Plan *node,
+                                                   CommonPlanContext *ctx,
+                                                   List *idxColumns) {
+  planner_init_common_plan_context(NULL, ctx);
+  ctx->idxColumns = idxColumns;
+  univPlanSeqScanNewInstance(ctx->univplan, -1);
+  do_convert_indexqualorig_to_common_plan(node, ctx, false);
+  return univPlanGetQualList(ctx->univplan);
+}
+
 void *convert_orcscan_qual_to_common_plan(Plan *node, CommonPlanContext *ctx) {
   planner_init_common_plan_context(NULL, ctx);
   univPlanSeqScanNewInstance(ctx->univplan, -1);
@@ -479,9 +488,6 @@ void planner_init_common_plan_context(PlannedStmt *stmt,
   ctx->convertible =
       pg_strcasecmp(new_executor_mode, new_executor_mode_off) != 0 ? true
                                                                    : false;
-  ctx->enforceNewScheduler =
-      pg_strcasecmp(new_scheduler_mode, new_scheduler_mode_on) == 0 ? true
-                                                                    : false;
   ctx->base.node = (Node *)stmt;
   ctx->querySelect = false;
   ctx->isMagma = false;
@@ -491,6 +497,8 @@ void planner_init_common_plan_context(PlannedStmt *stmt,
   ctx->parent = NULL;
   ctx->exprBufStack = NIL;
   ctx->rangeNum = 0;
+  ctx->isConvertingIndexQual = false;
+  ctx->idxColumns = NIL;
 }
 
 void planner_destroy_common_plan_context(CommonPlanContext *ctx, bool enforce) {
@@ -994,21 +1002,45 @@ bool do_convert_quallist_to_common_plan(Plan *node, CommonPlanContext *ctx,
   return true;
 }
 
+static bool do_convert_indexqualorig_to_common_plan(Plan *node,
+                                                    CommonPlanContext *ctx,
+                                                    bool isInsist) {
+  ListCell *lc;
+  foreach (lc, ((IndexScan *)node)->indexqualorig) {
+    Expr *expr = (Expr *)lfirst(lc);
+    univPlanNewExpr(ctx->univplan);
+    bool convert_ret = do_convert_expr_to_common_plan(-1, expr, ctx);
+    if (!convert_ret && isInsist)
+      return false;
+    else if (!convert_ret && !isInsist)
+      continue;
+    else if (convert_ret)
+      univPlanQualListAddExpr(ctx->univplan);
+  }
+  return true;
+}
+
 static bool do_convert_indexqual_to_common_plan(Plan *node,
                                                 CommonPlanContext *ctx,
                                                 bool isInsist) {
+  /* Must set to false when this function exit. */
+  ctx->isConvertingIndexQual = true;
+
   ListCell *lc;
   foreach (lc, ((ExternalScan *)node)->indexqualorig) {
     Expr *expr = (Expr *)lfirst(lc);
     univPlanNewExpr(ctx->univplan);
     bool convert_ret = do_convert_expr_to_common_plan(-1, expr, ctx);
-    if (!convert_ret && isInsist)
+    if (!convert_ret && isInsist) {
+      ctx->isConvertingIndexQual = false;
       return false;
-    else if (!convert_ret && !isInsist)
+    } else if (!convert_ret && !isInsist)
       continue;
     else if (convert_ret)
       univPlanIndexQualListAddExpr(ctx->univplan);
   }
+
+  ctx->isConvertingIndexQual = false;
   return true;
 }
 
@@ -1623,6 +1655,10 @@ bool do_convert_expr_to_common_plan(int32_t pid, Expr *expr,
 
     case T_Var: {
       Var *var = (Var *)expr;
+      // deal with orc index
+      if (ctx->idxColumns != NIL) {
+        var->varattno = list_find_oid(ctx->idxColumns, var->varattno) + 1;
+      }
       // TODO(chiyang): support system attribute
       if (var->varattno < 0 &&
           !(var->varattno == SelfItemPointerAttributeNumber ||
@@ -1686,6 +1722,22 @@ bool do_convert_expr_to_common_plan(int32_t pid, Expr *expr,
     case T_OpExpr: {
       OpExpr *opExpr = (OpExpr *)expr;
 
+      // Disable parameterized index qual, not supported yet.
+      // The reason we do not disable it on Segment is because the old executor
+      // will also run here(called by convert_extscan_to_common_plan() in
+      // magma_beginscan()/magma_rescan()), which supports parameterized index
+      // qual.
+      if (AmIMaster() && ctx->isMagma && ctx->isConvertingIndexQual) {
+        Expr *leftop = (Expr *)get_leftop(opExpr);
+        if (leftop && IsA(leftop, RelabelType))
+          leftop = ((RelabelType *)leftop)->arg;
+        Expr *rightop = (Expr *)get_rightop(opExpr);
+        if (rightop && IsA(rightop, RelabelType))
+          rightop = ((RelabelType *)rightop)->arg;
+
+        if (IsA(leftop, Var) && IsA(rightop, Var)) goto end;
+      }
+
       old = parentExprSwitchTo(expr, ctx);
 
       mappingFuncId = HAWQ_FUNCOID_MAPPING(opExpr->opfuncid);
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 9717a43..f82b5c0 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -874,7 +874,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
 	result->queryPartsMetadata = NIL;
 	result->numSelectorsPerScanId = NIL;
 	result->hiveUrl = NULL;
-	
+	result->graphEntry = parse->graphEntry;
 	Assert(result->utilityStmt == NULL || IsA(result->utilityStmt, DeclareCursorStmt));
 	
 	if (Gp_role == GP_ROLE_DISPATCH)
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index a3ca1b1..2bcaf77 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -528,6 +528,8 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, const int rtoffset)
 			fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset);
 			splan->scan.plan.qual =
 			fix_scan_list(glob, splan->scan.plan.qual, rtoffset);
+			splan->indexqual =
+			fix_scan_list(glob, splan->indexqual, rtoffset);
 			splan->indexqualorig =
 			fix_scan_list(glob, splan->indexqualorig, rtoffset);
 		}
@@ -1447,6 +1449,30 @@ set_inner_join_references(PlannerGlobal *glob, Plan *inner_plan,
 												 rtoffset);
 		}
 	}
+	else if (IsA(inner_plan, MagmaIndexOnlyScan) || IsA(inner_plan, MagmaIndexScan))
+	{
+		ExternalScan  *innerscan = (ExternalScan *) inner_plan;
+		List	   *indexqualorig = innerscan->indexqualorig;
+
+		/* No work needed if indexqual refers only to its own rel... */
+		if (NumRelids((Node *) indexqualorig) > 1)
+		{
+			Index		innerrel = innerscan->scan.scanrelid;
+
+			/* only refs to outer vars get changed in the inner qual */
+			innerscan->indexqualorig = fix_join_expr(
+			        glob, indexqualorig, outer_itlist, NULL,
+			        innerrel, rtoffset);
+			innerscan->indexqual = fix_join_expr(
+			        glob, innerscan->indexqual, outer_itlist, NULL,
+			        innerrel, rtoffset);
+
+			if (NumRelids((Node *) inner_plan->qual) > 1)
+				inner_plan->qual = fix_join_expr(
+						glob, inner_plan->qual, outer_itlist, NULL,
+						innerrel, rtoffset);
+		}
+	}
 	else if (IsA(inner_plan, BitmapIndexScan))
 	{
 		/*
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 15226b0..9a58069 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -67,6 +67,13 @@
 #include "cdb/cdbpartition.h"
 #include "cdb/cdbparquetstoragewrite.h"
 #include "cdb/cdbdatalocality.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph_elabel.h"
 #include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/prepare.h"
@@ -229,6 +236,18 @@ static Query *transformCreateExternalStmt(ParseState *pstate,
                                           CreateExternalStmt *stmt,
                                           List **extras_before,
                                           List **extras_after);
+static Query *transformCreateVlabelStmt(ParseState *pstate,
+                                          CreateVlabelStmt *stmt,
+                                          List **extras_before,
+                                          List **extras_after);
+static Query *transformCreateElabelStmt(ParseState *pstate,
+                                          CreateElabelStmt *stmt,
+                                          List **extras_before,
+                                          List **extras_after);
+static Query *transformCreateGraphStmt(ParseState *pstate,
+                                          CreateGraphStmt *stmt,
+                                          List **extras_before,
+                                          List **extras_after);
 static Query *transformCreateForeignStmt(ParseState *pstate,
                                          CreateForeignStmt *stmt,
                                          List **extras_before,
@@ -323,6 +342,12 @@ static Node *make_prule_rulestmt(ParseState *pstate, CreateStmtContext *cxt,
 static List *transformAttributeEncoding(List *stenc, CreateStmt *stmt,
                                         CreateStmtContext cxt);
 
+extern char *graphVertexTableName(char *gname,char *vname);
+
+extern char *graphEdgeTableName(char *gname,char *ename);
+
+extern bool parseAndTransformAsGraph(ParseState *pstate, RangeVar *rangeVar);
+
 char *getDefaultFilespace();
 
 /*
@@ -648,6 +673,21 @@ static Query *transformStmt(ParseState *pstate, Node *parseTree,
           pstate, (CreateExternalStmt *)parseTree, extras_before, extras_after);
       break;
 
+    case T_CreateVlabelStmt:
+      result = transformCreateVlabelStmt(
+          pstate, (CreateVlabelStmt *)parseTree, extras_before, extras_after);
+      break;
+
+    case T_CreateElabelStmt:
+      result = transformCreateElabelStmt(
+          pstate, (CreateElabelStmt *)parseTree, extras_before, extras_after);
+      break;
+
+    case T_CreateGraphStmt:
+      result = transformCreateGraphStmt(
+                pstate, (CreateGraphStmt *)parseTree, extras_before, extras_after);
+      break;
+
     case T_CreateForeignStmt:
       result = transformCreateForeignStmt(
           pstate, (CreateForeignStmt *)parseTree, extras_before, extras_after);
@@ -741,7 +781,8 @@ static Query *transformStmt(ParseState *pstate, Node *parseTree,
         result = transformSelectStmt(pstate, n);
       else
         result = transformSetOperationStmt(pstate, n);
-    } break;
+    }
+    break;
 
     case T_DeclareCursorStmt:
       result =
@@ -763,6 +804,7 @@ static Query *transformStmt(ParseState *pstate, Node *parseTree,
   /* Mark as original query until we learn differently */
   result->querySource = QSRC_ORIGINAL;
   result->canSetTag = true;
+  result->graphEntry = pstate->graphEntry;
 
   /*
    * Check that we did not produce too many resnos; at the very least we
@@ -885,6 +927,9 @@ static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) {
 
   /* setup database name for use of magma operations */
   MemoryContext oldContext = MemoryContextSwitchTo(MessageContext);
+
+  int isGraph = parseAndTransformAsGraph(pstate, stmt->relation);
+
   char *dbname = stmt->relation->catalogname;
   database =
       (dbname != NULL) ? pstrdup(dbname) : get_database_name(MyDatabaseId);
@@ -894,7 +939,9 @@ static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) {
   qry->resultRelation = setTargetTable(
       pstate, stmt->relation, interpretInhOption(stmt->relation->inhOpt), true,
       ACL_DELETE);
-
+if(isGraph)
+  pstate->p_target_rangetblentry->graphName = stmt->relation->schemaname ?
+      pstrdup(stmt->relation->schemaname) : NULL;
   qry->distinctClause = NIL;
 
   /*
@@ -937,7 +984,6 @@ static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) {
 
   return qry;
 }
-
 /*
  * transformInsertStmt -
  *	  transform an Insert Statement
@@ -958,6 +1004,7 @@ static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
   ListCell *icols;
   ListCell *attnos;
   ListCell *lc;
+  char *graphName;
 
   qry->commandType = CMD_INSERT;
   pstate->p_is_insert = true;
@@ -991,13 +1038,12 @@ static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
     sub_varnamespace = NIL;
   }
 
-  if (stmt->relation->catalogname != NULL) {
-    if (database != NULL) {
-      pfree(database);
-      database = NULL;
-    }
-    database = pstrdup(stmt->relation->catalogname);
-  }
+  graphName = stmt->relation->schemaname ? pstrdup(stmt->relation->schemaname) : NULL;
+  int isGraph = parseAndTransformAsGraph(pstate, stmt->relation);
+  MemoryContext oldContext = MemoryContextSwitchTo(MessageContext);
+  database =
+      (stmt->relation->catalogname != NULL) ? pstrdup(stmt->relation->catalogname) : get_database_name(MyDatabaseId);
+  MemoryContextSwitchTo(oldContext);
   /*
    * Must get write lock on INSERT target table before scanning SELECT, else
    * we will grab the wrong kind of initial lock if the target table is also
@@ -1006,7 +1052,8 @@ static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
    */
   qry->resultRelation =
       setTargetTable(pstate, stmt->relation, false, false, ACL_INSERT);
-
+  if(isGraph)
+    pstate->p_target_rangetblentry->graphName = graphName;
   /* Validate stmt->cols list, or build default list if no list given */
   icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos);
   Assert(list_length(icolumns) == list_length(attrnos));
@@ -1794,6 +1841,13 @@ static List *transformAttributeEncoding(List *stenc, CreateStmt *stmt,
   return newenc;
 }
 
+Query *transformCreateStmtImpl(ParseState *pstate,
+                               CreateStmt *stmt,
+                                          List **extras_before,
+                                          List **extras_after) {
+  return transformCreateStmt(pstate, stmt, extras_before, extras_after);
+}
+
 /*
  * transformCreateStmt -
  *	  transforms the "create table" statement
@@ -2376,6 +2430,196 @@ void recognizeExternalRelationFormatterOptions(
   createExtStmt->base.options = newOpts;
 }
 
+static Query *transformCreateVlabelStmt(ParseState *pstate,
+                                          CreateVlabelStmt *stmt,
+                                          List **extras_before,
+                                          List **extras_after) {
+  CreateStmtContext cxt;
+  Query *q;
+
+  cxt.stmtType = "CREATE VERTEX";
+  cxt.relation = stmt->relation;
+  cxt.hasoids = false;
+  cxt.isalter = false;
+  cxt.columns = NIL;
+  cxt.ckconstraints = NIL;
+  cxt.fkconstraints = NIL;
+  cxt.ixconstraints = NIL;
+  cxt.inh_indexes = NIL;
+  cxt.pkey = NULL;
+
+  cxt.blist = NIL;
+  cxt.alist = NIL;
+
+  ListCell *elements;
+  foreach (elements, stmt->tableElts) {
+    Node *element = lfirst(elements);
+
+    switch (nodeTag(element)) {
+      case T_ColumnDef:
+        transformColumnDefinition(pstate, &cxt, (ColumnDef *)element);
+        ColumnDef *column = (ColumnDef *)element;
+        Type type = typenameType(NULL, column->typname);
+        column->typname->typid = typeTypeId(type);
+        ReleaseType(type);
+        break;
+
+      case T_Constraint:
+        transformExtTableConstraint(pstate, &cxt, (Constraint *)element);
+        break;
+
+      case T_FkConstraint:
+        /* should never happen. If it does fix gram.y */
+        elog(ERROR, "node type %d not supported for vlabel",
+             (int)nodeTag(element));
+        break;
+
+      default:
+        elog(ERROR, "unrecognized node type: %d", (int)nodeTag(element));
+        break;
+    }
+  }
+
+  /*
+   * transformIndexConstraints wants cxt.alist to contain only index
+   * statements, so transfer anything we already have into extras_after
+   * immediately.
+   */
+  *extras_after = list_concat(cxt.alist, *extras_after);
+  cxt.alist = NIL;
+
+  /*
+   * Output results.
+   */
+  q = makeNode(Query);
+  q->commandType = CMD_UTILITY;
+  q->utilityStmt = (Node *)stmt;
+  stmt->tableElts = cxt.columns;
+  stmt->constraints = cxt.ixconstraints;
+  *extras_before = list_concat(*extras_before, cxt.blist);
+  *extras_after = list_concat(cxt.alist, *extras_after);
+  return q;
+}
+
+static Query *transformCreateElabelStmt(ParseState *pstate,
+                                          CreateElabelStmt *stmt,
+                                          List **extras_before,
+                                          List **extras_after) {
+  CreateStmtContext cxt;
+  Query *q;
+
+  cxt.stmtType = "CREATE EDGE";
+  cxt.relation = stmt->relation;
+  cxt.hasoids = false;
+  cxt.isalter = false;
+  cxt.columns = NIL;
+  cxt.ckconstraints = NIL;
+  cxt.fkconstraints = NIL;
+  cxt.ixconstraints = NIL;
+  cxt.inh_indexes = NIL;
+  cxt.pkey = NULL;
+
+  cxt.blist = NIL;
+  cxt.alist = NIL;
+
+  ListCell *elements;
+  foreach (elements, stmt->tableElts) {
+    Node *element = lfirst(elements);
+
+    switch (nodeTag(element)) {
+      case T_ColumnDef:
+        transformColumnDefinition(pstate, &cxt, (ColumnDef *)element);
+        ColumnDef *column = (ColumnDef *)element;
+        Type type = typenameType(NULL, column->typname);
+        column->typname->typid = typeTypeId(type);
+        ReleaseType(type);
+        break;
+
+      case T_Constraint:
+        transformExtTableConstraint(pstate, &cxt, (Constraint *)element);
+        break;
+
+      case T_FkConstraint:
+        /* should never happen. If it does fix gram.y */
+        elog(ERROR, "node type %d not supported for vlabel",
+             (int)nodeTag(element));
+        break;
+
+      default:
+        elog(ERROR, "unrecognized node type: %d", (int)nodeTag(element));
+        break;
+    }
+  }
+
+  /*
+   * transformIndexConstraints wants cxt.alist to contain only index
+   * statements, so transfer anything we already have into extras_after
+   * immediately.
+   */
+  *extras_after = list_concat(cxt.alist, *extras_after);
+  cxt.alist = NIL;
+
+  /*
+   * Output results.
+   */
+  q = makeNode(Query);
+  q->commandType = CMD_UTILITY;
+  q->utilityStmt = (Node *)stmt;
+  stmt->tableElts = cxt.columns;
+  stmt->constraints = cxt.ixconstraints;
+  *extras_before = list_concat(*extras_before, cxt.blist);
+  *extras_after = list_concat(cxt.alist, *extras_after);
+  return q;
+}
+
+static Query *transformCreateGraphStmt(ParseState *pstate,
+                                          CreateGraphStmt *stmt,
+                                          List **extras_before,
+                                          List **extras_after) {
+  CreateStmtContext cxt;
+  Query *q;
+
+  cxt.stmtType = "CREATE GRAPH";
+  cxt.relation = stmt->graph;
+  cxt.hasoids = false;
+  cxt.isalter = false;
+  cxt.columns = NIL;
+  cxt.ckconstraints = NIL;
+  cxt.fkconstraints = NIL;
+  cxt.ixconstraints = NIL;
+  cxt.inh_indexes = NIL;
+  cxt.pkey = NULL;
+
+  cxt.blist = NIL;
+  cxt.alist = NIL;
+
+
+  /*
+   * transformIndexConstraints wants cxt.alist to contain only index
+   * statements, so transfer anything we already have into extras_after
+   * immediately.
+   */
+  *extras_after = list_concat(cxt.alist, *extras_after);
+  cxt.alist = NIL;
+
+  /*
+   * Output results.
+   */
+  q = makeNode(Query);
+  q->commandType = CMD_UTILITY;
+  q->utilityStmt = (Node *)stmt;
+  *extras_before = list_concat(*extras_before, cxt.blist);
+  *extras_after = list_concat(cxt.alist, *extras_after);
+  return q;
+}
+
+Query *transformCreateExternalStmtImpl(ParseState *pstate,
+                                          CreateExternalStmt *stmt,
+                                          List **extras_before,
+                                          List **extras_after) {
+  return transformCreateExternalStmt(pstate, stmt, extras_before, extras_after);
+}
+
 static Query *transformCreateExternalStmt(ParseState *pstate,
                                           CreateExternalStmt *stmt,
                                           List **extras_before,
@@ -2591,6 +2835,9 @@ static Query *transformCreateExternalStmt(ParseState *pstate,
         }
       } break;
 
+      case T_String:
+        break;
+
       default:
         elog(ERROR, "unrecognized node type: %d", (int)nodeTag(element));
         break;
@@ -8084,6 +8331,181 @@ static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt,
   qry = makeNode(Query);
   qry->commandType = CMD_UTILITY;
 
+  char *graph = stmt->relation->schemaname ? pstrdup(stmt->relation->schemaname) : NULL;
+  char *ele = stmt->relation->relname;
+  int isGraph = parseAndTransformAsGraph(pstate, stmt->relation);
+  if(isGraph) {
+    stmt->graphele = makeRangeVar(stmt->relation->schemaname, graph, ele, -1);
+    Oid dboid = GetCatalogId(stmt->relation->catalogname);
+    Oid namespaceId = LookupNamespaceId(stmt->relation->schemaname, dboid);
+    if(isGraph == 2 /* as edge*/) {
+      Oid relid = caql_getoid(
+          NULL,
+          cql("SELECT oid FROM pg_class "
+            " WHERE relname = :1 "
+            " AND relnamespace = :2 ",
+            CStringGetDatum(stmt->relation->relname),
+            ObjectIdGetDatum(namespaceId)));
+
+      Relation attrelation = heap_open(AttributeRelationId, RowExclusiveLock);
+      cqContext cqc;
+      int colNum = caql_getcount(
+          NULL,
+                cql("SELECT COUNT(*) FROM pg_attribute "
+                  " WHERE attrelid = :1 AND attnum > :2",
+                  ObjectIdGetDatum(relid), Int32GetDatum(0)));
+
+      cqContext *pcqCtx = caql_beginscan(
+          caql_addrel(cqclr(&cqc), attrelation),
+          cql("SELECT * FROM pg_attribute "
+            " WHERE attrelid = :1 AND attnum > :2",
+            ObjectIdGetDatum(relid), Int32GetDatum(0)));
+      HeapTuple attributeTuple;
+      char **colnames = palloc0(colNum * sizeof(char*));
+      while (HeapTupleIsValid(attributeTuple = caql_getnext(pcqCtx))) {
+        Form_pg_attribute att = (Form_pg_attribute) GETSTRUCT(attributeTuple);
+        colnames[att->attnum - 1] = pstrdup(NameStr(att->attname));
+      }
+      caql_endscan(pcqCtx);
+      heap_close(attrelation, RowExclusiveLock);
+      Relation ElabelRelation = heap_open(ElabelRelationId, RowExclusiveLock);
+      HeapTuple elabelTuple= caql_getfirst(caql_addrel(cqclr(&cqc), ElabelRelation),
+                                           cql("SELECT * FROM skylon_elabel"
+          " WHERE elabelname = :1 AND schemaname = :2",
+          CStringGetDatum(ele), CStringGetDatum(stmt->relation->schemaname)));
+      Form_skylon_elabel elabel = (Form_skylon_elabel) GETSTRUCT(elabelTuple);
+      Relation VlabelAttRelation = heap_open(VlabelAttrRelationId, RowExclusiveLock);
+      int srcNum =
+          caql_getcount(
+          NULL,
+          cql("SELECT COUNT(*) FROM skylon_vlabel_attribute "
+             " WHERE vlabelname = :1 AND schemaname = :2 "
+             "AND primaryrank > :3",
+             CStringGetDatum(elabel->fromvlabel.data), CStringGetDatum(stmt->relation->schemaname), Int32GetDatum(0)));
+      int dstNum = caql_getcount(
+        NULL,
+        cql("SELECT COUNT(*) FROM skylon_vlabel_attribute "
+          " WHERE vlabelname = :1 AND schemaname = :2 "
+            "AND primaryrank > :3",
+          CStringGetDatum(elabel->tovlabel.data), CStringGetDatum(stmt->relation->schemaname), Int32GetDatum(0)));
+      int primaryNum = srcNum + dstNum;
+      heap_close(VlabelAttRelation, RowExclusiveLock);
+      heap_close(ElabelRelation, RowExclusiveLock);
+      Relation elabelAttRelation = heap_open(ElabelAttrRelationId, RowExclusiveLock);
+      int eattnum = caql_getcount(
+          NULL,
+              cql("SELECT COUNT(*) FROM skylon_elabel_attribute "
+                " WHERE elabelname = :1 AND schemaname = :2 "
+                  "AND rank > :3",
+                  CStringGetDatum(ele), CStringGetDatum(stmt->relation->schemaname), Int32GetDatum(0)));
+      char **attnames = palloc0(eattnum * sizeof(char*));
+      pcqCtx = caql_beginscan(
+          caql_addrel(cqclr(&cqc), elabelAttRelation),
+                        cql("SELECT * FROM skylon_elabel_attribute "
+                          " WHERE elabelname = :1 AND schemaname = :2 "
+                            "AND rank > :3",
+                            CStringGetDatum(ele), CStringGetDatum(stmt->relation->schemaname), Int32GetDatum(0)));
+      while (HeapTupleIsValid(attributeTuple = caql_getnext(pcqCtx))) {
+        Form_skylon_elabel_attribute att = (Form_skylon_elabel_attribute) GETSTRUCT(attributeTuple);
+        attnames[att->rank - 1] = pstrdup(NameStr(att->attrname));
+      }
+      caql_endscan(pcqCtx);
+      heap_close(elabelAttRelation, RowExclusiveLock);
+      ListCell *cell;
+      foreach(cell, stmt->indexParams) {
+        IndexElem *ele = (IndexElem *)lfirst(cell);
+        for(int i = 0; i < eattnum; i++) {
+          if(strcmp(attnames[i], ele->name) == 0) {
+            Value *attnum = makeInteger(0);
+            attnum->val.ival = i + 1;
+            stmt->graphIndexAttnum = lappend(stmt->graphIndexAttnum, attnum);
+            break;
+          }
+        }
+      }
+      foreach(cell, stmt->indexIncludingParams) {
+        IndexElem *ele = (IndexElem *)lfirst(cell);
+        for(int i = 0; i < eattnum; i++) {
+          if(strcmp(attnames[i], ele->name) == 0) {
+            Value *attnum = makeInteger(0);
+            attnum->val.ival = i + 1;
+            stmt->graphIncludeAttnum = lappend(stmt->graphIncludeAttnum, attnum);
+            break;
+          }
+        }
+      }
+      List *newIndexParams = NIL;
+      if(!stmt->reverse) {
+        for(int i = 0; i < primaryNum; i++) {
+          IndexElem *indexele = makeNode(IndexElem);
+          indexele->name = colnames[i];
+          newIndexParams = lappend(newIndexParams, indexele);
+        }
+      }
+      else {
+        for(int i = 0; i < dstNum; i++) {
+          IndexElem *indexele = makeNode(IndexElem);
+          indexele->name = colnames[srcNum + i];
+          newIndexParams = lappend(newIndexParams, indexele);
+        }
+        for(int i = 0; i < srcNum; i++) {
+          IndexElem *indexele = makeNode(IndexElem);
+          indexele->name = colnames[i];
+          newIndexParams = lappend(newIndexParams, indexele);
+        }
+      }
+    stmt->indexParams = list_concat(newIndexParams, stmt->indexParams);
+    }
+    else {
+      Relation vlabelAttRelation = heap_open(VlabelAttrRelationId, RowExclusiveLock);
+      cqContext cqc;
+      int vattnum = caql_getcount(
+              NULL,
+              cql("SELECT COUNT(*) FROM skylon_vlabel_attribute "
+                " WHERE vlabelname = :1 AND schemaname = :2 "
+                  "AND rank > :3",
+                  CStringGetDatum(ele), CStringGetDatum(stmt->relation->schemaname), Int32GetDatum(0)));
+      char **attnames = palloc0(vattnum * sizeof(char*));
+      cqContext *pcqCtx = caql_beginscan(
+          caql_addrel(cqclr(&cqc), vlabelAttRelation),
+                        cql("SELECT * FROM skylon_vlabel_attribute "
+                          " WHERE vlabelname = :1 AND schemaname = :2 "
+                            "AND rank > :3",
+                            CStringGetDatum(ele), CStringGetDatum(stmt->relation->schemaname), Int32GetDatum(0)));
+      HeapTuple attributeTuple;
+      while (HeapTupleIsValid(attributeTuple = caql_getnext(pcqCtx))) {
+        Form_skylon_vlabel_attribute att = (Form_skylon_vlabel_attribute) GETSTRUCT(attributeTuple);
+        attnames[att->rank - 1] = pstrdup(NameStr(att->attrname));
+      }
+      caql_endscan(pcqCtx);
+      heap_close(vlabelAttRelation, RowExclusiveLock);
+      ListCell *cell;
+      foreach(cell, stmt->indexParams) {
+        IndexElem *ele = (IndexElem *)lfirst(cell);
+        for(int i = 0; i < vattnum; i++) {
+          if(strcmp(attnames[i], ele->name) == 0) {
+            Value *attnum = makeInteger(0);
+            attnum->val.ival = i + 1;
+            stmt->graphIndexAttnum = lappend(stmt->graphIndexAttnum, attnum);
+            break;
+          }
+        }
+      }
+      foreach(cell, stmt->indexIncludingParams) {
+        IndexElem *ele = (IndexElem *)lfirst(cell);
+        for(int i = 0; i < vattnum; i++) {
+          if(strcmp(attnames[i], ele->name) == 0) {
+            Value *attnum = makeInteger(0);
+            attnum->val.ival = i + 1;
+            stmt->graphIncludeAttnum = lappend(stmt->graphIncludeAttnum, attnum);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
   /*
    * If the table already exists (i.e., this isn't a create table time
    * expansion of primary key() or unique()) and we're the ultimate parent
@@ -10133,6 +10555,9 @@ static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) {
 
   /* setup database name for use of magma operations */
   MemoryContext oldContext = MemoryContextSwitchTo(MessageContext);
+
+  int isGraph = parseAndTransformAsGraph(pstate, stmt->relation);
+
   char *dbname = stmt->relation->catalogname;
   database =
       (dbname != NULL) ? pstrdup(dbname) : get_database_name(MyDatabaseId);
@@ -10141,7 +10566,9 @@ static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) {
   qry->resultRelation = setTargetTable(
       pstate, stmt->relation, interpretInhOption(stmt->relation->inhOpt), true,
       ACL_UPDATE);
-
+  if(isGraph)
+    pstate->p_target_rangetblentry->graphName = stmt->relation->schemaname ?
+        pstrdup(stmt->relation->schemaname) : NULL;
   /*
    * the FROM clause is non-standard SQL syntax. We used to be able to do
    * this with REPLACE in POSTQUEL so we keep the feature.
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 17b3d29..ea4b0ce 100755
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -205,7 +205,7 @@ static Node *makeIsNotDistinctFromNode(Node *expr, int position);
 		CommentStmt ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
 		CreateDomainStmt CreateExternalStmt CreateFileSpaceStmt CreateGroupStmt
 		CreateOpClassStmt CreatePLangStmt
-		CreateQueueStmt CreateSchemaStmt CreateSeqStmt CreateStmt 
+		CreateQueueStmt CreateSchemaStmt CreateSeqStmt CreateStmt CreateGraphStmt
 		CreateTableSpaceStmt CreateFdwStmt CreateForeignServerStmt CreateForeignStmt 
 		CreateAssertStmt CreateTrigStmt 
 		CreateUserStmt CreateUserMappingStmt CreateRoleStmt
@@ -351,7 +351,7 @@ static Node *makeIsNotDistinctFromNode(Node *expr, int position);
 %type <node>	overlay_placing substr_from substr_for
 
 %type <boolean> opt_instead opt_analyze
-%type <boolean> index_opt_unique opt_verbose opt_full
+%type <boolean> index_opt_unique opt_verbose opt_full index_opt_reverse
 %type <boolean> opt_freeze opt_default opt_ordered opt_recheck
 %type <boolean> opt_rootonly_all
 %type <boolean> opt_dxl
@@ -373,7 +373,7 @@ static Node *makeIsNotDistinctFromNode(Node *expr, int position);
 
 %type <vsetstmt> set_rest
 %type <node>	TableElement ExtTableElement ConstraintElem ExtConstraintElem TableFuncElement
-%type <node>	columnDef ExtcolumnDef
+%type <node>	columnDef ExtcolumnDef fromVlabel toVlabel
 %type <node>	cdb_string
 %type <defelt>	def_elem old_aggr_elem keyvalue_pair
 %type <node>	def_arg columnElem where_clause where_or_current_clause
@@ -443,7 +443,7 @@ static Node *makeIsNotDistinctFromNode(Node *expr, int position);
 %type <node>	TableConstraint ExtTableConstraint TableLikeClause 
 %type <list>	TableLikeOptionList
 %type <ival>	TableLikeOption
-%type <list>	ColQualList
+%type <list>	ColQualList LabelList
 %type <node>	ColConstraint ColConstraintElem ConstraintAttr
 %type <ival>	key_actions key_delete key_match key_update key_action
 %type <ival>	ConstraintAttributeSpec ConstraintDeferrabilitySpec
@@ -517,15 +517,15 @@ static Node *makeIsNotDistinctFromNode(Node *expr, int position);
 
 	DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DECODE DEFAULT DEFAULTS
 	DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DENY
-	DESC DISABLE_P DISTINCT DISTRIBUTED DO DOMAIN_P DOUBLE_P DROP DXL
+	DESC DISABLE_P DISTINCT DISTRIBUTED DISCRIMINATOR DO DOMAIN_P DOUBLE_P DROP DXL
 
 	EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ERRORS ESCAPE EVERY EXCEPT 
-	EXCHANGE EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
+	EXCHANGE EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT EDGE
 
 	FALSE_P FETCH FIELDS FILESPACE FILESYSTEM FILL FILTER FIRST_P FLOAT_P FOLLOWING FOR 
     	FORCE FOREIGN FORMAT FORMATTER FORWARD FREEZE FROM FULL FUNCTION
 
-	GB GLOBAL GRANT GRANTED GREATEST GROUP_P GROUP_ID GROUPING
+	GB GLOBAL GRANT GRANTED GREATEST GROUP_P GROUP_ID GROUPING GRAPH
 
 	HANDLER HASH HAVING HEADER_P HOLD HOST HOUR_P
 
@@ -563,7 +563,7 @@ static Node *makeIsNotDistinctFromNode(Node *expr, int position);
 	RANDOMLY RANGE READ READABLE READS REAL REASSIGN RECHECK RECURSIVE 
     REFERENCES REINDEX REJECT_P RELATIVE_P 
 	RELEASE RENAME REPEATABLE REPLACE RESET RESOURCE RESTART RESTRICT 
-	RETURNING RETURNS REVOKE RIGHT
+	RETURNING RETURNS REVERSED REVOKE RIGHT
 	ROLE ROLLBACK ROLLUP ROOTPARTITION ROW ROWS RULE
 
 	SAVEPOINT SCATTER SCHEMA SCROLL SEARCH SECOND_P 
@@ -583,7 +583,7 @@ static Node *makeIsNotDistinctFromNode(Node *expr, int position);
 	UPDATE USER USING
 
 	VACUUM VALID VALIDATION VALIDATOR VALUE_P VALUES VARCHAR VARYING
-	VERBOSE VERSION_P VIEW VOLATILE VARIADIC
+	VERBOSE VERSION_P VIEW VOLATILE VARIADIC VERTEX
 
 	WEB WHEN WHERE WINDOW WITH WITHIN WITHOUT WORK WRAPPER WRITABLE WRITE
 
@@ -1050,6 +1050,7 @@ stmt :
 			| CreateSchemaStmt
 			| CreateSeqStmt
 			| CreateStmt
+			| CreateGraphStmt
 			| CreateTableSpaceStmt
 			| CreateTrigStmt
 			| CreateRoleStmt
@@ -3302,12 +3303,12 @@ opt_using:
 			USING									{}
 			| /*EMPTY*/								{}
 		;
-
-
+ 
+ 
 /*****************************************************************************
  *
  *		QUERY :
- *				CREATE TABLE relname
+ *				CREATE TABLE/VERTEX/EDGE relname
  *
  *****************************************************************************/
 
@@ -3542,8 +3543,89 @@ CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
 
 					$$ = (Node *)n;
 				}
+				| CREATE VERTEX qualified_name '(' OptTableElementList ')'
+		  		{
+		  			CreateVlabelStmt *n = makeNode(CreateVlabelStmt);
+		  			n->relation = $3;
+		  			n->tableElts = $5;
+		  			n->constraints = NULL;
+					$$ = (Node *)n;
+				}
+		| CREATE EDGE qualified_name '(' fromVlabel ',' toVlabel ',' OptTableElementList ')'
+		  		{
+		  			CreateElabelStmt *n = makeNode(CreateElabelStmt);
+		  			n->relation = $3;
+		  			n->tableElts = $9;
+		  			n->constraints = NULL;
+		  			n->fromVlabel = $5;
+		  			n->toVlabel = $7;
+					$$ = (Node *)n;
+				}
+		| CREATE EDGE qualified_name '(' fromVlabel ',' toVlabel ')'
+		  		{
+		  			CreateElabelStmt *n = makeNode(CreateElabelStmt);
+		  			n->relation = $3;
+		  			n->tableElts = NULL;
+		  			n->constraints = NULL;
+		  			n->fromVlabel = $5;
+		  			n->toVlabel = $7;
+					$$ = (Node *)n;
+				}
+		;
+		
+CreateGraphStmt: CREATE GRAPH qualified_name '(' VERTEX '(' LabelList ')' ',' EDGE '(' LabelList ')' ')' FORMAT Sconst format_opt OptWith
+				{
+					CreateGraphStmt *n = makeNode(CreateGraphStmt);
+					n->graph = $3;
+					n->vlabels = $7;
+					n->elabels = $12;
+					n->options = $18;
+					n->format = $16;
+					$$ = (Node *)n;
+				}
+				| CREATE GRAPH qualified_name '(' VERTEX '(' LabelList ')' ',' EDGE '(' LabelList ')' ')' OptWith
+				{
+					CreateGraphStmt *n = makeNode(CreateGraphStmt);
+					n->graph = $3;
+					n->vlabels = $7;
+					n->elabels = $12;
+					n->format = pstrdup("magmaap");
+					n->options = $15;
+					$$ = (Node *)n;
+				}
+				| CREATE GRAPH qualified_name '(' VERTEX '(' LabelList ')' ')' OptWith
+				{
+					CreateGraphStmt *n = makeNode(CreateGraphStmt);
+					n->graph = $3;
+					n->vlabels = $7;
+					n->elabels = NULL;
+					n->format = pstrdup("magmaap");
+					n->options = $10;
+					$$ = (Node *)n;
+				}
+				| CREATE GRAPH qualified_name '(' VERTEX '(' LabelList ')' ')' FORMAT Sconst format_opt OptWith
+				{
+					CreateGraphStmt *n = makeNode(CreateGraphStmt);
+					n->graph = $3;
+					n->vlabels = $7;
+					n->elabels = NULL;
+					n->format = $11;
+					n->options = $13;
+					$$ = (Node *)n;
+				}
 		;
 
+LabelList:
+			ColId
+				{
+					$$ = list_make1(makeString($1));
+				}
+			| LabelList ',' ColId
+				{
+					$$ = lappend($1, makeString($3));
+				}
+		;
+		
 /*
  * Redundancy here is needed to avoid shift/reduce conflicts,
  * since TEMP is not a reserved word.  See also OptTempTableName.
@@ -3617,6 +3699,20 @@ columnDef:	ColId Typename ColQualList opt_storage_encoding
 					$$ = (Node *)n;
 				}
 		;
+		
+fromVlabel:	FROM ColId
+				{
+					Value *n = makeString($2);					
+					$$ = (Node *)n;
+				}
+		;
+		
+toVlabel:	TO ColId
+				{
+					Value *n = makeString($2);					
+					$$ = (Node *)n;
+				}
+		;
 
 ColQualList:
 			ColQualList ColConstraint				{ $$ = lappend($1, $2); }
@@ -3899,6 +3995,18 @@ ConstraintElem:
 					n->indexspace = $8;
 					$$ = (Node *)n;
 				}
+			| DISCRIMINATOR '(' columnList ')' opt_definition OptConsTableSpace
+				{
+					Constraint *n = makeNode(Constraint);
+					n->contype = CONSTR_PRIMARY;
+					n->name = NULL;
+					n->raw_expr = NULL;
+					n->cooked_expr = NULL;
+					n->keys = $3;
+					n->options = $5;
+					n->indexspace = $6;
+					$$ = (Node *)n;
+				}
 			| FOREIGN KEY '(' columnList ')' REFERENCES qualified_name
 				opt_column_list key_match key_actions ConstraintAttributeSpec
 				{
@@ -4937,7 +5045,7 @@ format_opt:
 format_opt_list:
 			format_opt_item2
 			{
-				$$ = list_make1($1)
+				$$ = list_make1($1);
 			}
 			| format_opt_item2 '=' format_opt_item2
 			{
@@ -6327,7 +6435,9 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = $2;
 					n->missing_ok = TRUE;
-					n->objects = $5;
+					List *list = $5;
+					ListCell *cell;
+					n->objects = list;
 					n->behavior = $6;
 					$$ = (Node *)n;
 				}
@@ -6336,7 +6446,9 @@ DropStmt:	DROP drop_type IF_P EXISTS any_name_list opt_drop_behavior
 					DropStmt *n = makeNode(DropStmt);
 					n->removeType = $2;
 					n->missing_ok = FALSE;
-					n->objects = $3;
+					List *list = $3;
+					ListCell *cell;
+					n->objects = list;
 					n->behavior = $4;
 					$$ = (Node *)n;
 				}
@@ -6358,6 +6470,9 @@ drop_type:	TABLE									{ $$ = OBJECT_TABLE; }
 			| TABLESPACE							{ $$ = OBJECT_TABLESPACE; }
 			| FOREIGN TABLE							{ $$ = OBJECT_FOREIGNTABLE; }
 			| PROTOCOL								{ $$ = OBJECT_EXTPROTOCOL; }
+			| VERTEX									{ $$ = OBJECT_VLABEL; }
+			| EDGE									{ $$ = OBJECT_ELABEL; }
+			| GRAPH									{ $$ = OBJECT_GRAPH; }
 		;
 
 any_name_list:
@@ -6977,20 +7092,40 @@ opt_granted_by: GRANTED BY RoleId						{ $$ = $3; }
  *****************************************************************************/
 
 IndexStmt:	CREATE index_opt_unique INDEX index_name
-			ON qualified_name access_method_clause '(' index_params ')'
+			ON index_opt_reverse qualified_name access_method_clause '(' index_params ')'
+			opt_include opt_definition OptTableSpace where_clause
+				{
+					IndexStmt *n = makeNode(IndexStmt);
+					n->unique = $2;
+					n->concurrent = false;
+					n->idxname = $4;
+					n->reverse = $6;
+					n->relation = $7;
+					n->accessMethod = $8;
+					n->indexParams = $10;
+					n->indexIncludingParams = $12;
+					n->options = $13;
+					n->tableSpace = $14;
+					n->whereClause = $15;
+					n->idxOids = NULL;
+					$$ = (Node *)n;
+				}
+			| CREATE index_opt_unique INDEX index_name
+			ON index_opt_reverse qualified_name access_method_clause
 			opt_include opt_definition OptTableSpace where_clause
 				{
 					IndexStmt *n = makeNode(IndexStmt);
 					n->unique = $2;
 					n->concurrent = false;
 					n->idxname = $4;
-					n->relation = $6;
-					n->accessMethod = $7;
-					n->indexParams = $9;
-					n->indexIncludingParams = $11;
-					n->options = $12;
-					n->tableSpace = $13;
-					n->whereClause = $14;
+					n->reverse = $6;
+					n->relation = $7;
+					n->accessMethod = $8;
+					n->indexParams = NULL;
+					n->indexIncludingParams = $9;
+					n->options = $10;
+					n->tableSpace = $11;
+					n->whereClause = $12;
 					n->idxOids = NULL;
 					$$ = (Node *)n;
 				}
@@ -7023,6 +7158,10 @@ IndexStmt:	CREATE index_opt_unique INDEX index_name
 					$$ = (Node *)n;
 				}
 		;
+		
+index_opt_reverse:
+			REVERSED									{ $$ = TRUE; }
+			| /*EMPTY*/								{ $$ = FALSE; }
 
 index_opt_unique:
 			UNIQUE									{ $$ = TRUE; }
@@ -13513,6 +13652,7 @@ reserved_keyword:
 			| DEFAULT
 			| DEFERRABLE
 			| DESC
+			| DISCRIMINATOR
 			| DISTINCT
 			| DISTRIBUTED /* gp */
 			| DO
@@ -13520,6 +13660,7 @@ reserved_keyword:
 			| END_P
 			| EXCEPT
 			| EXCLUDE 
+			| EDGE
 			| FALSE_P
 			| FETCH
 			| FILTER
@@ -13528,6 +13669,7 @@ reserved_keyword:
 			| FOREIGN
 			| FROM
 			| GRANT
+			| GRAPH
 			| GROUP_P
 			| HAVING
 			| IN_P
@@ -13555,6 +13697,7 @@ reserved_keyword:
 			| RANGE
 			| REFERENCES
 			| RETURNING
+			| REVERSED
 			| ROWS
 			| SCATTER  /* gp */
 			| SELECT
@@ -13572,6 +13715,7 @@ reserved_keyword:
 			| USER
 			| USING
 			| VARIADIC
+			| VERTEX
 			| WINDOW
 			| WITH
 			| WHEN
@@ -14207,6 +14351,78 @@ makeIsNotDistinctFromNode(Node *expr, int position)
 	return n;
 }
 
+char *fromVlabelColName(char *vname)
+{
+	char extraname[] = "from_";
+	int len1 = strlen(vname);
+	int len2 = strlen(extraname);
+	char * newname = palloc0(len1+len2+1);
+	memcpy(newname,extraname,len2);
+	memcpy(newname+len2,vname,len1);
+	newname[len1 + len2] = '\0';
+	return newname;
+}
+
+char *toVlabelColName(char *vname)
+{
+	char extraname[] = "to_";
+	int len1 = strlen(vname);
+	int len2 = strlen(extraname);
+	char * newname = palloc0(len1+len2+1);
+	memcpy(newname,extraname,len2);
+	memcpy(newname+len2,vname,len1);
+	newname[len1 + len2] = '\0';
+	return newname;
+}
+
+char *vlabelName(char *vname)
+{
+	char extraname[] = "graph_vlabel_";
+	int len1 = strlen(vname);
+	int len2 = strlen(extraname);
+	char * newname = palloc0(len1+len2+1);
+	memcpy(newname,extraname,len2);
+	memcpy(newname+len2,vname,len1);
+	newname[len1 + len2] = '\0';
+	return newname;
+}
+
+char *elabelName(char *ename)
+{
+	char extraname[] = "graph_elabel_";
+	int len1 = strlen(ename);
+	int len2 = strlen(extraname);
+	char * newname = palloc0(len1+len2+1);
+	memcpy(newname,extraname,len2);
+	memcpy(newname+len2,ename,len1);
+	newname[len1 + len2] = '\0';
+	return newname;
+}
+
+char *graphVertexName(char *gname)
+{
+  char extraname[] = "graph_vertex_";
+  int len1 = strlen(gname);
+  int len2 = strlen(extraname);
+  char * newname = palloc0(len1+len2+1);
+  memcpy(newname,extraname,len2);
+  memcpy(newname+len2,gname,len1);
+  newname[len1 + len2] = '\0';
+  return newname;
+}
+
+char *graphEdgeName(char *gname)
+{
+  char extraname[] = "graph_edge_";
+  int len1 = strlen(gname);
+  int len2 = strlen(extraname);
+  char * newname = palloc0(len1+len2+1);
+  memcpy(newname,extraname,len2);
+  memcpy(newname+len2,gname,len1);
+  newname[len1 + len2] = '\0';
+  return newname;
+}
+
 /*
  * Must undefine base_yylex before including scan.c, since we want it
  * to create the function base_yylex not filtered_base_yylex.
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index dc08457..da7a2e1 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -49,6 +49,13 @@
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "catalog/pg_window.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph_elabel.h"
 #include "commands/defrem.h"
 #include "nodes/makefuncs.h"
 #include "nodes/print.h" /* XXX: remove after debugging !! */
@@ -86,6 +93,10 @@ static const char *clauseText[] = {
     "DISTINCT ON"
 };
 
+extern char *graphVertexTableName(char *gname,char *vname);
+
+extern char *graphEdgeTableName(char *gname,char *ename);
+
 static void extractRemainingColumns(List *common_colnames,
 						List *src_colnames, List *src_colvars,
 						List **res_colnames, List **res_colvars);
@@ -123,6 +134,8 @@ static List *transformRowExprToGroupClauses(ParseState *pstate, RowExpr *rowexpr
 											List *groupsets, List *targetList);
 static void freeGroupList(List *grouplist);
 
+extern char* findGraphSchema(char *graph);
+
 typedef struct grouping_rewrite_ctx
 {
 	List *grp_tles;
@@ -1410,7 +1423,170 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
 	return rte;
 }
 
+List *transformAsGraphName(ParseState *pstate, RangeVar *rangeVar) {
+  if(!rangeVar) return NULL;
+  char *catalog = rangeVar->catalogname;
+  char *schema = rangeVar->schemaname;
+  char *graph = rangeVar->relname;
+
+  if(schema) {
+    Relation skylon_graph_rel = heap_open(GraphRelationId, RowExclusiveLock);
+    cqContext cqc;
+    Oid dboid = GetCatalogId(catalog);
+    Oid namespaceId = LookupNamespaceId(schema, dboid);
+    if (0 == caql_getcount(
+          caql_addrel(cqclr(&cqc), skylon_graph_rel),
+          cql("SELECT COUNT(*) FROM skylon_graph "
+            " WHERE graphname = :1 AND schemaname = :2",
+            CStringGetDatum(graph), CStringGetDatum(schema)))){
+      heap_close(skylon_graph_rel, RowExclusiveLock);
+      return NULL;
+    }
+    heap_close(skylon_graph_rel, RowExclusiveLock);
+  }
+  else {
+    schema = findGraphSchema(graph);
+    if(!schema)
+      return NULL;
+  }
+  List *list = NIL;
+  {
+    Relation  skylon_graph_vlabel_rel;
+    cqContext cqc;
+
+    skylon_graph_vlabel_rel = heap_open(GraphVlabelRelationId, RowExclusiveLock);
+    cqContext *pcqCtx = caql_beginscan(
+        caql_addrel(cqclr(&cqc), skylon_graph_vlabel_rel),
+        cql("SELECT * FROM skylon_graph_vlabel "
+                        " WHERE graphname = :1 AND schemaname = :2",
+                        CStringGetDatum(graph), CStringGetDatum(schema)));
+    HeapTuple vlabelTuple = NULL;
+    while (HeapTupleIsValid(vlabelTuple = caql_getnext(pcqCtx))) {
+      Form_skylon_graph_vlabel tuple = (Form_skylon_graph_vlabel) GETSTRUCT(vlabelTuple);
+      RangeVar   *vlabel = makeRangeVar(NULL, NULL, NULL, -1);
+      char *vname = pstrdup(NameStr(tuple->vlabelname));
+      vlabel->catalogname = catalog;
+      vlabel->schemaname = schema;
+      vlabel->relname = graphVertexTableName(graph, vname);
+      list = lappend(list, vlabel);
+    }
+    caql_endscan(pcqCtx);
+    heap_close(skylon_graph_vlabel_rel, RowExclusiveLock);
+  }
+  {
+    Relation  skylon_graph_elabel_rel;
+    cqContext cqc;
+
+    skylon_graph_elabel_rel = heap_open(GraphElabelRelationId, RowExclusiveLock);
+    cqContext *pcqCtx = caql_beginscan(
+        caql_addrel(cqclr(&cqc), skylon_graph_elabel_rel),
+        cql("SELECT * FROM skylon_graph_elabel "
+                        " WHERE graphname = :1 AND schemaname = :2",
+                        CStringGetDatum(graph), CStringGetDatum(schema)));
+    HeapTuple elabelTuple = NULL;
+    while (HeapTupleIsValid(elabelTuple = caql_getnext(pcqCtx))) {
+      Form_skylon_graph_elabel tuple = (Form_skylon_graph_elabel) GETSTRUCT(elabelTuple);
+      RangeVar   *elabel = makeRangeVar(NULL, NULL, NULL, -1);
+      char *ename = pstrdup(NameStr(tuple->elabelname));
+      elabel->catalogname = catalog;
+      elabel->schemaname = schema;
+      elabel->relname = graphEdgeTableName(graph, ename);
+      list = lappend(list, elabel);
+    }
+    caql_endscan(pcqCtx);
+    heap_close(skylon_graph_elabel_rel, RowExclusiveLock);
+  }
+  return list;
+}
 
+int parseAndTransformAsGraph(ParseState *pstate, RangeVar *rangeVar) {
+  if(!rangeVar) return false;
+  if (rangeVar->schemaname == NULL)
+    return false;
+  char *catalog = NULL;
+  char *schema = rangeVar->catalogname;
+  char *graph = rangeVar->schemaname;
+  char *ele = rangeVar->relname;
+
+  Oid dboid = GetCatalogId(catalog);
+  Oid namespaceId = LookupNamespaceId(rangeVar->schemaname, dboid);
+  Oid relId=OidIsValid(namespaceId)
+      ? get_relname_relid(rangeVar->relname, namespaceId)
+      : InvalidOid;
+
+  int res = 0;
+  if(!OidIsValid(relId)){
+    RangeVar *tmpRel = makeNode(RangeVar);
+    tmpRel->schemaname = schema;
+    schema = get_namespace_name(RangeVarGetCreationNamespace(tmpRel));
+    cqContext cqc;
+    Relation VlabelRelation = heap_open(GraphVlabelRelationId, RowExclusiveLock);
+    HeapTuple vlabelTuple= caql_getfirst(caql_addrel(cqclr(&cqc), VlabelRelation),
+                                         cql("SELECT * FROM skylon_graph_vlabel"
+        " WHERE vlabelname = :1 "
+        "AND graphname = :2 AND schemaname = :3",
+        CStringGetDatum(ele),
+        CStringGetDatum(graph), CStringGetDatum(schema)));
+    if(HeapTupleIsValid(vlabelTuple)) {
+      rangeVar->catalogname = NULL;
+      rangeVar->schemaname = schema;
+      rangeVar->relname = graphVertexTableName(graph, ele);
+      res = 1;
+    }
+    else {
+      Relation ElabelRelation = heap_open(GraphElabelRelationId, RowExclusiveLock);
+      HeapTuple elabelTuple= caql_getfirst(caql_addrel(cqclr(&cqc), ElabelRelation),
+                                           cql("SELECT * FROM skylon_graph_elabel"
+          " WHERE elabelname = :1 "
+          "AND graphname = :2 AND schemaname = :3",
+          CStringGetDatum(ele),
+          CStringGetDatum(graph), CStringGetDatum(schema)));
+      if(!HeapTupleIsValid(elabelTuple)) {
+        heap_close(VlabelRelation, RowExclusiveLock);
+        heap_close(ElabelRelation, RowExclusiveLock);
+        return 0;
+      }
+      rangeVar->catalogname = NULL;
+      rangeVar->schemaname = schema;
+      rangeVar->relname = graphEdgeTableName(graph, ele);
+      res = 2;
+      heap_close(ElabelRelation, RowExclusiveLock);
+    }
+    heap_close(VlabelRelation, RowExclusiveLock);
+    Oid graphId = caql_getoid_only(
+        NULL,
+        NULL,
+        cql("SELECT oid FROM pg_class "
+          " WHERE relname = :1 and relnamespace = :2",
+          CStringGetDatum(graph),
+          ObjectIdGetDatum(LookupNamespaceId(schema, dboid))));
+    if(pstate) {
+      if(pstate->graphEntry) {
+        ListCell *cell;
+        bool hit = false;
+        foreach(cell, pstate->graphEntry)
+        {
+          GraphEntry *n = (GraphEntry*)lfirst(cell);
+          if(n->relid == graphId) {
+            hit = true;
+            break;
+          }
+        }
+        if(!hit) {
+          GraphEntry *node = makeNode(GraphEntry);
+          node->relid = graphId;
+          pstate->graphEntry = lappend(pstate->graphEntry, node);
+        }
+      }
+      else {
+        GraphEntry *node = makeNode(GraphEntry);
+        node->relid = graphId;
+        pstate->graphEntry = lappend(pstate->graphEntry, node);
+      }
+    }
+  }
+return res;
+}
 /*
  * transformFromClauseItem -
  *	  Transform a FROM-clause item, adding any required entries to the
@@ -1459,6 +1635,10 @@ transformFromClauseItem(ParseState *pstate, Node *n,
 		RangeTblEntry *rte = NULL;
 		int	rtindex;
 		RangeVar *rangeVar = (RangeVar *)n;
+		char *graph = rangeVar->schemaname ? pstrdup(rangeVar->schemaname) : NULL;
+
+//try to parse as graph
+		int isGraph = parseAndTransformAsGraph(pstate, rangeVar);
 
 		/*
 		 * If it is an unqualified name, it might be a CTE reference.
@@ -1480,7 +1660,8 @@ transformFromClauseItem(ParseState *pstate, Node *n,
 		{
 			rte = transformTableEntry(pstate, rangeVar);
 		}
-		
+		if(isGraph)
+		  rte->graphName = graph;
 		/* assume new rte is at end */
 		rtindex = list_length(pstate->p_rtable);
 		Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 923e75b..0f2958c 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -15,8 +15,16 @@
 
 #include "postgres.h"
 
+#include "catalog/catquery.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_type.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph_elabel.h"
 #include "commands/dbcommands.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
@@ -41,6 +49,10 @@
 
 bool		Transform_null_equals = false;
 
+extern char *graphVertexTableName(char *gname,char *vname);
+
+extern char *graphEdgeTableName(char *gname,char *ename);
+
 static Node *transformParamRef(ParseState *pstate, ParamRef *pref);
 static Node *transformAExprOp(ParseState *pstate, A_Expr *a);
 static Node *transformAExprAnd(ParseState *pstate, A_Expr *a);
@@ -173,6 +185,7 @@ transformExpr(ParseState *pstate, Node *expr)
 			{
 				A_Expr	   *a = (A_Expr *) expr;
 
+				a->lexpr;
 				switch (a->kind)
 				{
 					case AEXPR_OP:
@@ -643,6 +656,7 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
 
 	return result;
 }
+extern bool parseAndTransformAsGraph(ParseState *pstate, RangeVar *rangeVar);
 
 static Node *
 transformColumnRef(ParseState *pstate, ColumnRef *cref)
@@ -768,12 +782,29 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 				char	   *name1 = strVal(linitial(cref->fields));
 				char	   *name2 = strVal(lsecond(cref->fields));
 				char	   *name3 = strVal(lthird(cref->fields));
+				char     *graphName = name1 ? pstrdup(name1) : NULL;
+				RangeVar *rangeVar = makeNode(RangeVar);
+				rangeVar->catalogname = NULL;
+				rangeVar->schemaname = name1;
+				rangeVar->relname = name2;
+				int isGraph = parseAndTransformAsGraph(pstate, rangeVar);
+				if(isGraph) {
+				  name1 = rangeVar->schemaname;
+				  name2 = rangeVar->relname;
+				}
 
 				/* Whole-row reference? */
 				if (strcmp(name3, "*") == 0)
 				{
 					node = transformWholeRowRef(pstate, NULL /*catalogname*/, name1, name2,
 												cref->location);
+					if (node != NULL) {
+						RangeTblEntry *rte =  GetRTEByRangeTablePosn(pstate,
+								((Var*)node)->varno,
+								((Var*)node)->varlevelsup);
+						if(isGraph)
+						  rte->graphName = graphName;
+					}
 					break;
 				}
 
@@ -791,6 +822,13 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 											 NIL, false, false, false, true, NULL,
 											 cref->location, NULL);
 				}
+				if (node != NULL) {
+					RangeTblEntry *rte =  GetRTEByRangeTablePosn(pstate,
+									((Var*)node)->varno,
+									((Var*)node)->varlevelsup);
+					if(isGraph)
+					  rte->graphName = graphName;
+				}
 				break;
 			}
 		case 4:
@@ -799,7 +837,16 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
 				char	   *name2 = strVal(lsecond(cref->fields));
 				char	   *name3 = strVal(lthird(cref->fields));
 				char	   *name4 = strVal(lfourth(cref->fields));
-
+        RangeVar *rangeVar = makeNode(RangeVar);
+        rangeVar->catalogname = name1;
+        rangeVar->schemaname = name2;
+        rangeVar->relname = name3;
+        bool isGraph = parseAndTransformAsGraph(pstate, rangeVar);
+        if(isGraph) {
+          name1 = rangeVar->catalogname;
+          name2 = rangeVar->schemaname;
+          name3 = rangeVar->relname;
+        }
 				/* Whole-row reference? */
 				if (strcmp(name4, "*") == 0)
 				{
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 06c369b..e7227f5 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -2852,12 +2852,29 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
 	 */
 	if (pg_class_aclmask(relOid, userid, requiredPerms, ACLMASK_ALL)
 			!= requiredPerms) {
+		bool isgraph = false;
 		/*
 		 * If the table is a partition, return an error message that includes
 		 * the name of the parent table.
 		 */
 		const char *rel_name = get_rel_name_partition(relOid);
-		aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, rel_name);
+		if (0 != caql_getcount(NULL,
+							cql("SELECT COUNT(*) FROM skylon_graph "
+							" WHERE graphname = :1 ",
+							CStringGetDatum(rel_name)))) {
+			isgraph = true;
+		}
+		else if (NULL != rte->graphName) {
+			if (0 != caql_getcount(NULL,
+								cql("SELECT COUNT(*) FROM skylon_graph "
+								" WHERE graphname = :1 ",
+								CStringGetDatum(rte->graphName)))) {
+				isgraph = true;
+				rel_name = rte->graphName;
+			}
+		}
+		aclcheck_error(ACLCHECK_NO_PRIV,
+									 isgraph ? ACL_KIND_CLASS_GRAPH : ACL_KIND_CLASS, rel_name);
 	}
 }
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 03858a1..7b9f907 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -134,7 +134,6 @@
 #include "resourcemanager/resourceenforcer/resourceenforcer.h"
 
 #include "storage/cwrapper/hdfs-file-system-c.h"
-#include "scheduler/cwrapper/scheduler-c.h"
 #include "magma/cwrapper/magma-client-c.h"
 
 #include "pg_stat_activity_history_process.h"
@@ -3479,9 +3478,6 @@ die(SIGNAL_ARGS)
 		MagmaClientC_CancelMagmaClient();
 		MagmaFormatC_CancelMagmaClient();
 
-		if (MyScheduler != NULL)
-		  SchedulerCancelQuery(MyScheduler);
-
 		if (MyNewExecutor != NULL)
 			MyExecutorSetCancelQuery(MyNewExecutor);
 
@@ -3558,9 +3554,6 @@ StatementCancelHandler(SIGNAL_ARGS)
 		MagmaClientC_CancelMagmaClient();
 		MagmaFormatC_CancelMagmaClient();
 
-		if (MyScheduler != NULL)
-		  SchedulerCancelQuery(MyScheduler);
-
 		if (MyNewExecutor != NULL)
 			MyExecutorSetCancelQuery(MyNewExecutor);
 
@@ -5225,6 +5218,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 					else {
 						if (serializedCommonPlanLen > 0) {
 							exec_mpp_query_new(
+							    NULL,
 									serializedCommonPlan,
 									serializedCommonPlanLen,
 									localSlice, true, NULL, NULL);
@@ -5447,6 +5441,7 @@ PostgresMain(int argc, char *argv[], const char *username)
 
                     if (serializedCommonPlanLen > 0) {
                       exec_mpp_query_new(
+                          NULL,
                           serializedCommonPlan,
                           serializedCommonPlanLen,
                           currentSliceId, true, NULL, NULL);
@@ -5655,19 +5650,6 @@ PostgresMain(int argc, char *argv[], const char *username)
 					close_target = pq_getmsgstring(&input_message);
 					pq_getmsgend(&input_message);
 
-					// stop scheduler
-					if (MyScheduler) {
-					  SchedulerEnd(MyScheduler);
-					  SchedulerCatchedError *err = SchedulerGetLastError(MyScheduler);
-					  if (err->errCode != ERRCODE_SUCCESSFUL_COMPLETION) {
-					    int errCode = err->errCode;
-					    SchedulerCleanUp(MyScheduler);
-					    ereport(WARNING, (errcode(errCode),
-					        errmsg("failed to stop scheduler. %s (%d)",
-					               err->errMessage, errCode)));
-					  }
-					}
-
 					switch (close_type)
 					{
 						case 'S':
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 81d4635..586634b 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -14,6 +14,8 @@
  *
  *-------------------------------------------------------------------------
  */
+
+#include <string.h>
 #include "postgres.h"
 #include "port.h"
 
@@ -678,6 +680,21 @@ ProcessDropStatement(DropStmt *stmt)
 				ereport(ERROR,
 						(errcode(ERRCODE_CDB_FEATURE_NOT_YET), errmsg("Cannot support drop foreign table statement yet") ));
 
+			case OBJECT_VLABEL:
+			  rel = makeRangeVarFromNameList(names);
+			  RemoveVlabel(rel, stmt->missing_ok);
+			  break;
+
+			case OBJECT_ELABEL:
+        rel = makeRangeVarFromNameList(names);
+        RemoveElabel(rel, stmt->missing_ok);
+        break;
+
+      case OBJECT_GRAPH:
+        rel = makeRangeVarFromNameList(names);
+        RemoveGraph(rel, stmt->missing_ok, true);
+        break;
+
 			case OBJECT_TABLE:
 			case OBJECT_EXTTABLE:
 
@@ -1059,6 +1076,18 @@ ProcessUtility(Node *parsetree,
 			DefineExternalRelation((CreateExternalStmt *) parsetree);
 			break;
 
+		case T_CreateVlabelStmt:
+      DefineVlabel((CreateVlabelStmt *) parsetree);
+      break;
+
+		case T_CreateElabelStmt:
+      DefineElabel((CreateElabelStmt *) parsetree);
+      break;
+
+    case T_CreateGraphStmt:
+      DefineGraph((CreateGraphStmt *) parsetree);
+      break;
+
 		case T_CreateForeignStmt:
 			ereport(ERROR,
 							(errcode(ERRCODE_CDB_FEATURE_NOT_YET), errmsg("Cannot support create foreign statement yet") ));
@@ -1831,6 +1860,9 @@ ProcessUtility(Node *parsetree,
 					case OBJECT_INDEX:
 						ReindexIndex(stmt);
 						break;
+		      case OBJECT_VLABEL:
+		      case OBJECT_ELABEL:
+		      case OBJECT_GRAPH:
 					case OBJECT_TABLE:
 						ReindexTable(stmt);
 						break;
@@ -2157,6 +2189,18 @@ CreateCommandTag(Node *parsetree)
 			}
 			break;
 
+    case T_CreateVlabelStmt:
+      tag = "CREATE VERTEX";
+      break;
+
+    case T_CreateElabelStmt:
+      tag = "CREATE EDGE";
+      break;
+
+    case T_CreateGraphStmt:
+      tag = "CREATE GRAPH";
+      break;
+
 		case T_CreateForeignStmt:
 			tag = "CREATE FOREIGN TABLE";
 			break;
@@ -2208,6 +2252,15 @@ CreateCommandTag(Node *parsetree)
 		case T_DropStmt:
 			switch (((DropStmt *) parsetree)->removeType)
 			{
+			  case OBJECT_VLABEL:
+          tag = "DROP VERTEX";
+          break;
+			  case OBJECT_ELABEL:
+          tag = "DROP EDGE";
+          break;
+        case OBJECT_GRAPH:
+          tag = "DROP GRAPH";
+          break;
 				case OBJECT_TABLE:
 					tag = "DROP TABLE";
 					break;
@@ -2802,6 +2855,9 @@ GetCommandLogLevel(Node *parsetree)
 			lev = LOGSTMT_DDL;
 			break;
 
+		case T_CreateVlabelStmt:
+		case T_CreateElabelStmt:
+		case T_CreateGraphStmt:
 		case T_CreateExternalStmt:
 		case T_CreateForeignStmt:
 			lev = LOGSTMT_DDL;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 9cd07ad..9fbccad 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -1675,18 +1675,14 @@ get_relname_relid(const char *relname, Oid relnamespace)
 	Oid			result;
 	int			fetchCount;
 
-	result = caql_getoid_plus(
-			NULL,
-			&fetchCount,
-			NULL,
-			cql("SELECT oid FROM pg_class "
-				" WHERE relname = :1 "
-				" AND relnamespace = :2 ",
-				PointerGetDatum((char *) relname),
-				ObjectIdGetDatum(relnamespace)));
-
-	if (!fetchCount)
-		return InvalidOid;
+	result = caql_getoid_only(
+      NULL,
+      NULL,
+      cql("SELECT oid FROM pg_class "
+        " WHERE relname = :1 "
+        " AND relnamespace = :2 ",
+        CStringGetDatum(relname),
+        ObjectIdGetDatum(relnamespace)));
 
 	return result;
 }
@@ -3654,6 +3650,38 @@ get_relation_keys(Oid relid)
 }
 
 /*
+ * Is there a index with the given relid
+ */
+bool rel_has_index(Oid relid)
+{
+	if (!rel_is_partitioned(relid))
+		return (caql_getcount(
+				NULL, cql("SELECT COUNT(*) FROM pg_index "
+						" WHERE indrelid = :1 ",
+						ObjectIdGetDatum(relid))) > 0);
+	else
+	{
+		List *children = find_all_inheritors(relid);
+		ListCell *child;
+		foreach (child, children)
+		{
+			Oid myrelid = lfirst_oid(child);
+			bool hasidx = (caql_getcount(
+					NULL, cql("SELECT COUNT(*) FROM pg_index "
+							" WHERE indrelid = :1 ",
+							ObjectIdGetDatum(myrelid))) > 0);
+			if (hasidx)
+			{
+				list_free(children);
+				return true;
+			}
+		}
+		list_free(children);
+		return false;
+	}
+}
+
+/*
  * check_constraint_exists
  *	  Is there a check constraint with the given oid
  */
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 986eb68..9a44514 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -26,7 +26,6 @@
 #include "executor/cwrapper/executor-c.h"
 #include "executor/cwrapper/cached-result.h"
 #include "magma/cwrapper/magma-client-c.h"
-#include "scheduler/cwrapper/scheduler-c.h"
 
 ProtocolVersion FrontendProtocol = PG_PROTOCOL_LATEST;
 
@@ -167,5 +166,4 @@ const char *sql_text;
 bool is_qtype_sql = false;
 
 ExecutorC	*MyNewExecutor;
-SchedulerC *MyScheduler = NULL;
 CachedResultC *MyCachedResult = NULL;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 2cf0c8a..a56a59c 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -245,7 +245,6 @@ static const char *assign_timezone_abbreviations(const char *newval, bool doit,
 static const char *assign_new_interconnect_type(const char *newval, bool doit,GucSource source);
 static const char *assign_new_executor_mode(const char *newval, bool doit, GucSource source);
 static const char *assign_new_executor_runtime_filter_mode(const char *newval, bool doit, GucSource source);
-static const char *assign_new_scheduler_mode(const char *newval, bool doit, GucSource source);
 static const char *assign_switch_mode(const char *newval, bool doit, GucSource source);
 
 static bool assign_tcp_keepalives_idle(int newval, bool doit, GucSource source);
@@ -675,7 +674,7 @@ bool		enable_magma_seqscan = true;
 bool		enable_magma_bitmapscan = false;
 bool		enable_magma_indexonlyscan = false;
 bool		enable_orc_indexscan = false;
-bool		enable_orc_indexonlyscan = false;
+bool		enable_orc_indexonlyscan = true;
 bool		force_bitmap_table_scan = false;
 bool		enable_tidscan = true;
 bool		enable_sort = true;
@@ -1159,7 +1158,7 @@ static struct config_bool ConfigureNamesBool[] =
 			NULL
 		},
 		&enable_orc_indexonlyscan,
-		false, NULL, NULL
+		true, NULL, NULL
 	},
 	{
 		{"enable_orc_indexscan", PGC_USERSET, QUERY_TUNING_METHOD,
@@ -3741,7 +3740,7 @@ static struct config_bool ConfigureNamesBool[] =
 			GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE
 		},
 		&optimizer_enable_indexjoin,
-		true, NULL, NULL
+		false, NULL, NULL
 	},
 	{
 		{"optimizer_enable_motions_masteronly_queries", PGC_USERSET, DEVELOPER_OPTIONS,
@@ -7540,16 +7539,6 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"new_scheduler", PGC_USERSET, EXTERNAL_TABLES,
-			gettext_noop("Enable the new scheduler."),
-			gettext_noop("Valid values are \"OFF\" and \"ON\"."),
-			GUC_NOT_IN_SAMPLE | GUC_NO_SHOW_ALL
-		},
-		&new_scheduler_mode,
-		"OFF", assign_new_scheduler_mode, NULL
-	},
-
-	{
 		{"dispatch_udf", PGC_USERSET, EXTERNAL_TABLES,
 			gettext_noop("specified UDF to be dispatched."),
 			gettext_noop("Valid separator is \",\""),
@@ -14051,14 +14040,6 @@ static const char *assign_new_executor_runtime_filter_mode(const char *newval, b
 		return newval;				/* OK */
 }
 
-static const char *assign_new_scheduler_mode(const char *newval, bool doit, GucSource source) {
-		if (pg_strcasecmp(newval, new_scheduler_mode_on) != 0
-				&& pg_strcasecmp(newval, new_scheduler_mode_off) != 0) {
-			return NULL;			/* fail */
-		}
-		return newval;				/* OK */
-}
-
 static const char *assign_switch_mode(const char *newval, bool doit,
                                             GucSource source) {
   if (pg_strcasecmp(newval, "ON") != 0 && pg_strcasecmp(newval, "OFF") != 0) {
diff --git a/src/backend/utils/mmgr/Makefile b/src/backend/utils/mmgr/Makefile
index b117da9..5e8df67 100644
--- a/src/backend/utils/mmgr/Makefile
+++ b/src/backend/utils/mmgr/Makefile
@@ -11,6 +11,8 @@
 subdir = src/backend/utils/mmgr
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
+override CPPFLAGS := -I$(top_srcdir)/src/include/catalog $(CPPFLAGS)
+override CPPFLAGS := -I include $(CPPFLAGS)
 
 OBJS =  aset.o asetDirect.o mcxt.o memaccounting.o mpool.o portalmem.o memprot.o vmem_tracker.o redzone_handler.o runaway_cleaner.o idle_tracker.o event_version.o
 
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index af5f797..24cccce 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -322,6 +322,51 @@ static const SchemaQuery Query_for_list_of_tables = {
 	NULL
 };
 
+static const SchemaQuery Query_for_list_of_graphs = {
+  /* catname */
+  "pg_catalog.pg_class c",
+  /* selcondition */
+  "c.relname IN (SELECT graphname FROM skylon_graph)",  /* GPDB: x is obsolete, used only on very old GPDB systems */
+  /* viscondition */
+  "pg_catalog.pg_table_is_visible(c.oid)",
+  /* namespace */
+  "c.relnamespace",
+  /* result */
+  "pg_catalog.quote_ident(c.relname)",
+  /* qualresult */
+  NULL
+};
+
+static const SchemaQuery Query_for_list_of_vertices = {
+  /* catname */
+  "pg_catalog.pg_class c",
+  /* selcondition */
+  "c.relname IN (SELECT vlabelname FROM skylon_vlabel)",
+  /* viscondition */
+  "pg_catalog.pg_table_is_visible(c.oid)",
+  /* namespace */
+  "c.relnamespace",
+  /* result */
+  "pg_catalog.quote_ident(c.relname)",
+  /* qualresult */
+  NULL
+};
+
+static const SchemaQuery Query_for_list_of_edges = {
+  /* catname */
+  "pg_catalog.pg_class c",
+  /* selcondition */
+  "c.relname IN (SELECT elabelname FROM skylon_elabel)",
+  /* viscondition */
+  "pg_catalog.pg_table_is_visible(c.oid)",
+  /* namespace */
+  "c.relnamespace",
+  /* result */
+  "pg_catalog.quote_ident(c.relname)",
+  /* qualresult */
+  NULL
+};
+
 static const SchemaQuery Query_for_list_of_tisv = {
 	/* catname */
 	"pg_catalog.pg_class c",
@@ -557,8 +602,10 @@ static const pgsql_thing_t words_after_create[] = {
 	{"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, true},
 	{"DATABASE", Query_for_list_of_databases},
 	{"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, true},
+	{"EDGE", NULL, &Query_for_list_of_edges},
 	{"FOREIGN DATA WRAPPER", NULL, NULL},
 	{"FUNCTION", NULL, &Query_for_list_of_functions},
+	{"GRAPH", NULL, &Query_for_list_of_graphs},
 	{"GROUP", Query_for_list_of_roles},
 	{"LANGUAGE", Query_for_list_of_languages},
 	{"INDEX", NULL, &Query_for_list_of_indexes},
@@ -578,6 +625,7 @@ static const pgsql_thing_t words_after_create[] = {
 	{"UNIQUE", NULL, NULL},		/* for CREATE UNIQUE INDEX ... */
 	{"USER", Query_for_list_of_roles},
 	{"USER MAPPING FOR", NULL, NULL},
+	{"VERTEX", NULL, &Query_for_list_of_vertices},
 	{"VIEW", NULL, &Query_for_list_of_views},
 	{NULL, NULL, NULL, false}	/* end of list */
 };
@@ -2531,7 +2579,7 @@ _complete_from_query(int is_schema_query, const char *text, int state)
 			if (strcmp(completion_squery->catname,
 					   "pg_catalog.pg_class c") == 0 &&
 				strncmp(text, "pg_", 3) != 0 &&
-				strncmp(text, "gp_", 3) != 0)
+				strncmp(text, "gp_", 3) != 0 && strncmp(text, "skylon_", 3) != 0)
 			{
 				appendPQExpBuffer(&query_buffer,
 								  " AND c.relnamespace <> (SELECT oid FROM"
@@ -2554,6 +2602,43 @@ _complete_from_query(int is_schema_query, const char *text, int state)
 							  " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(nspname))+1)) > 1",
 							  string_length, e_text);
 
+      /*
+       * Add in matching graph names, but only if there is more than
+       * one potential match among graph names.
+       */
+
+      appendPQExpBuffer(&query_buffer, "\nUNION\n"
+               "SELECT pg_catalog.quote_ident(n.graphname) || '.' "
+                "FROM pg_catalog.skylon_graph n "
+                "WHERE substring(pg_catalog.quote_ident(n.graphname) || '.',1,%d)='%s'",
+                string_length, e_text);
+      appendPQExpBuffer(&query_buffer,
+                " AND (SELECT pg_catalog.count(*)"
+                " FROM pg_catalog.skylon_graph"
+      " WHERE substring(pg_catalog.quote_ident(graphname) || '.',1,%d) ="
+                " substring('%s',1,pg_catalog.length(pg_catalog.quote_ident(graphname))+1)) > 1",
+                string_length, e_text);
+
+      /*
+       * Add in matching qualified names, but only if there is exactly
+       * one graph matching the input-so-far.
+       */
+      appendPQExpBuffer(&query_buffer, "\nUNION\n"
+           "SELECT pg_catalog.quote_ident(n.graphname) || '.' || v.vlabelname "
+                "FROM pg_catalog.skylon_graph_vlabel v, pg_catalog.skylon_graph n "
+                "WHERE v.graphname = n.graphname AND v.schemaname = n.schemaname ",
+                qualresult,
+                completion_squery->catname,
+                completion_squery->namespace);
+
+      appendPQExpBuffer(&query_buffer, "\nUNION\n"
+           "SELECT pg_catalog.quote_ident(n.graphname) || '.' || e.elabelname "
+                "FROM pg_catalog.skylon_graph_elabel e, pg_catalog.skylon_graph n "
+                "WHERE e.graphname = n.graphname AND e.schemaname = n.schemaname ",
+                qualresult,
+                completion_squery->catname,
+                completion_squery->namespace);
+
 			/*
 			 * Add in matching qualified names, but only if there is exactly
 			 * one schema matching the input-so-far.
diff --git a/src/include/access/aomd.h b/src/include/access/aomd.h
index 42d8174..8eb4e0e 100644
--- a/src/include/access/aomd.h
+++ b/src/include/access/aomd.h
@@ -44,6 +44,16 @@ FormatAOSegmentFileName(
 							char *filepathname);
 
 extern void
+FormatAOSegmentIndexFileName(
+              char *basepath,
+              int segno,
+              int idxId,
+              int col,
+              int numCols,
+              int32 *fileSegNo,
+              char *filepathname);
+
+extern void
 MakeAOSegmentFileName(
 							Relation rel, 
 							int segno, 
diff --git a/src/include/access/orcam.h b/src/include/access/orcam.h
index f181a9c..47d24c2 100644
--- a/src/include/access/orcam.h
+++ b/src/include/access/orcam.h
@@ -79,17 +79,20 @@ extern Oid orcInsertValues(OrcInsertDescData *insertDesc, Datum *values,
 extern void orcEndInsert(OrcInsertDescData *insertDesc);
 
 // scan
-extern void orcBeginScan(struct ScanState *scanState);
-extern TupleTableSlot *orcScanNext(struct ScanState *scanState);
-extern void orcEndScan(struct ScanState *scanState);
-extern void orcReScan(struct ScanState *scanState);
-
-extern OrcScanDescData *orcBeginRead(Relation rel, Snapshot snapshot,
-                                     TupleDesc desc, List *fileSplits,
-                                     bool *colToReads, void *pushDown);
-extern void orcReadNext(OrcScanDescData *scanData, TupleTableSlot *slot);
-extern void orcEndRead(OrcScanDescData *scanData);
-extern void orcResetRead(OrcScanDescData *scanData);
+extern void orcBeginScan(struct ScanState* scanState);
+extern TupleTableSlot* orcScanNext(struct ScanState* scanState);
+extern void orcEndScan(struct ScanState* scanState);
+extern void orcReScan(struct ScanState* scanState);
+
+extern OrcScanDescData* orcBeginReadWithOptionsStr(
+    Relation rel, Snapshot snapshot, TupleDesc desc, List* fileSplits,
+    bool* colToReads, void* pushDown, const char*);
+extern OrcScanDescData* orcBeginRead(Relation rel, Snapshot snapshot,
+                                     TupleDesc desc, List* fileSplits,
+                                     bool* colToReads, void* pushDown);
+extern void orcReadNext(OrcScanDescData* scanData, TupleTableSlot* slot);
+extern void orcEndRead(OrcScanDescData* scanData);
+extern void orcResetRead(OrcScanDescData* scanData);
 
 // delete
 extern OrcDeleteDescData *orcBeginDelete(Relation rel, List *fileSplits,
@@ -110,8 +113,41 @@ extern uint64 orcEndUpdate(OrcUpdateDescData *updateDesc);
 // utils
 extern bool isDirectDispatch(Plan *plan);
 
+void checkOrcError(OrcFormatData* orcFormatData);
+
 // index
-extern int64_t* orcCreateIndex(Relation rel, int idxId, List* segno, int64* eof,
+extern int64_t* orcCreateIndex(Relation rel, Oid idxId, List* segno, int64* eof,
                                List* columnsToRead, int sortIdx);
+extern void orcBeginIndexOnlyScan(struct ScanState* scanState, Oid idxId,
+                                  List* columnsInIndex);
+extern void orcIndexReadNext(OrcScanDescData* scanData, TupleTableSlot* slot,
+                             List* columnsInIndex);
+
+extern TupleTableSlot* orcIndexOnlyScanNext(struct ScanState* scanState);
+
+extern void orcEndIndexOnlyScan(struct ScanState* scanState);
+
+extern void orcIndexOnlyReScan(struct ScanState* scanState);
+
+extern OrcScanDescData* orcBeginIndexOnlyRead(Relation rel, Oid idxId,
+                                              List* columnsInIndex,
+                                              Snapshot snapshot, TupleDesc desc,
+                                              List* fileSplits,
+                                              bool* colToReads, void* pushDown);
+
+extern void orcBeginIndexOnlyScan(struct ScanState* scanState, Oid idxId,
+                                  List* columnsInIndex);
+
+extern TupleTableSlot* orcIndexOnlyScanNext(struct ScanState* scanState);
+
+extern void orcEndIndexOnlyScan(struct ScanState* scanState);
+
+extern void orcIndexOnlyReScan(struct ScanState* scanState);
+
+extern OrcScanDescData* orcBeginIndexOnlyRead(Relation rel, Oid idxId,
+                                              List* columnsInIndex,
+                                              Snapshot snapshot, TupleDesc desc,
+                                              List* fileSplits,
+                                              bool* colToReads, void* pushDown);
 
 #endif /* ORCAM_H_ */
diff --git a/src/include/access/orcsegfiles.h b/src/include/access/orcsegfiles.h
index a23521b..2d6b5e4 100644
--- a/src/include/access/orcsegfiles.h
+++ b/src/include/access/orcsegfiles.h
@@ -46,7 +46,8 @@ extern void updateOrcFileSegInfo(Relation rel, AppendOnlyEntry *aoEntry,
 
 extern void insertInitialOrcIndexEntry(AppendOnlyEntry *aoEntry, int idxOid, int segNo);
 extern void updateOrcIndexFileInfo(AppendOnlyEntry *aoEntry, int idxOid, int segNo, int64 eof);
-extern void deleteOrcIndexFileInfo(AppendOnlyEntry *aoEntry, int idxOid);
+extern void deleteOrcIndexFileInfo(Relation rel, AppendOnlyEntry *aoEntry, int idxOid);
+extern void deleteOrcIndexHdfsFiles(Relation rel, int32 segmentFileNum, int32 idx);
 
 extern List *orcGetAllSegFileSplits(AppendOnlyEntry *aoEntry,
                                     Snapshot snapshot);
diff --git a/src/include/access/plugstorage.h b/src/include/access/plugstorage.h
index 7b20af8..9505fe7 100644
--- a/src/include/access/plugstorage.h
+++ b/src/include/access/plugstorage.h
@@ -130,7 +130,6 @@ typedef struct PlugStorageData
 	ScanState              *ps_scan_state;
 	ScanDirection           ps_scan_direction;
 	FileScanDesc            ps_file_scan_desc;
-	ExternalScanState      *ps_ext_scan_state;
 	ResultRelSegFileInfo   *ps_result_seg_file_info;
 	ExternalInsertDesc      ps_ext_insert_desc;
 	ExternalInsertDesc      ps_ext_delete_desc;
@@ -163,8 +162,11 @@ typedef struct PlugStorageData
 	char                   *ps_hive_url;
 	/* Add for magma index info */
 	MagmaIndex              magma_idx;
-	/* for beginTransaction */
+	/* For beginTransaction */
 	List*                   magma_talbe_full_names;
+	/* The following two fields are for parameterized index scan */
+	IndexRuntimeKeyInfo*    runtime_key_info;
+	int                     num_run_time_keys;
 } PlugStorageData;
 
 typedef PlugStorageData *PlugStorage;
@@ -238,7 +240,12 @@ bool InvokePlugStorageFormatGetNext(FmgrInfo *func,
                                     TupleTableSlot *tupTableSlot);
 
 void InvokePlugStorageFormatReScan(FmgrInfo *func,
-                                   FileScanDesc fileScanDesc);
+                                   FileScanDesc fileScanDesc,
+                                   ScanState* scanState,
+                                   MagmaSnapshot* snapshot,
+                                   IndexRuntimeKeyInfo* runtimeKeyInfo,
+                                   int numRuntimeKeys,
+                                   TupleTableSlot *tupTableSlot);
 
 void InvokePlugStorageFormatEndScan(FmgrInfo *func,
                                     FileScanDesc fileScanDesc);
diff --git a/src/include/access/relscan.h b/src/include/access/relscan.h
index 4becb73..0c573e3 100644
--- a/src/include/access/relscan.h
+++ b/src/include/access/relscan.h
@@ -137,11 +137,11 @@ typedef struct FileScanDescData
 	int    fs_serializeSchemaLen;
 
 	/* current scan information for pluggable format */
-	 PlugStorageScanFuncs fs_ps_scan_funcs;   /* scan functions */
-	 void *fs_ps_user_data;                   /* user data */
-	 struct ScanState *fs_ps_scan_state;      /* support rescan */
-	 Plan *fs_ps_plan;                        /* support rescan */
-
+	PlugStorageScanFuncs  fs_ps_scan_funcs;
+	void                 *fs_ps_user_data;
+	Plan                 *fs_ps_plan;
+	List                 *fs_ps_magma_splits;
+	bool                  fs_ps_magma_skip_tid;
 }	FileScanDescData;
 
 typedef FileScanDescData *FileScanDesc;
diff --git a/src/include/access/skey.h b/src/include/access/skey.h
index d295d3d..1882cac 100644
--- a/src/include/access/skey.h
+++ b/src/include/access/skey.h
@@ -62,15 +62,19 @@ typedef uint16 StrategyNumber;
  * for the invocation of an access method support procedure.  In this case
  * sk_strategy/sk_subtype are not meaningful, and sk_func may refer to a
  * function that returns something other than boolean.
+ *
+ * Fixme(hwy): Since the sk_attno may change, I added the sk_attnoold. Do we really need sk_attnoold?
  */
 typedef struct ScanKeyData
 {
-	int			sk_flags;		/* flags, see below */
-	AttrNumber	sk_attno;		/* table or index column number */
-	StrategyNumber sk_strategy; /* operator strategy number */
-	Oid			sk_subtype;		/* strategy subtype */
-	FmgrInfo	sk_func;		/* lookup info for function to call */
+	int	        sk_flags;	/* flags, see below */
+	AttrNumber	sk_attno;	/* table or index column number */
+	StrategyNumber  sk_strategy;    /* operator strategy number */
+	Oid		sk_subtype;     /* strategy subtype */
+	FmgrInfo	sk_func;	/* lookup info for function to call */
 	Datum		sk_argument;	/* data to compare */
+	AttrNumber      sk_attnoold;	/* original table or index column number */
+	FmgrInfo        sk_out_func;    /* for evaluating the runtime key in magma parameterized index scan */
 } ScanKeyData;
 
 typedef ScanKeyData *ScanKey;
@@ -133,8 +137,10 @@ extern void ScanKeyEntryInitialize(ScanKey entry,
 					   AttrNumber attributeNumber,
 					   StrategyNumber strategy,
 					   Oid subtype,
-					   RegProcedure procedure,
-					   Datum argument);
+					   RegProcedure opProcedure,
+					   Datum argument,
+					   AttrNumber attributeNumberOld,
+					   RegProcedure outputProcedure);
 extern void ScanKeyEntryInitializeWithInfo(ScanKey entry,
 							   int flags,
 							   AttrNumber attributeNumber,
diff --git a/src/include/catalog/calico.pl b/src/include/catalog/calico.pl
index de2e78d..82e6e17 100755
--- a/src/include/catalog/calico.pl
+++ b/src/include/catalog/calico.pl
@@ -3515,6 +3515,14 @@ sub more_header
 #include "catalog/pg_tidycat.h"
 
 #include "catalog/gp_configuration.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_index.h"
 #include "catalog/gp_segment_config.h"
 #include "catalog/gp_san_config.h"
 
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index abd79df..b17b0cb 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -144,6 +144,9 @@ typedef enum ObjectClass
 	OCLASS_USER_MAPPING,		/* pg_user_mapping */
 	OCLASS_EXTPROTOCOL,			/* pg_extprotocol */
 	OCLASS_COMPRESSION,			/* pg_compression */
+	OCLASS_GRAPH,     /* skylon_graph */
+	OCLASS_VLABEL,     /* skylon_vlabel */
+  OCLASS_ELABEL,     /* skylon_elabel */
 	MAX_OCLASS					/* MUST BE LAST */
 } ObjectClass;
 
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index f0d33e7..b36e07c 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -391,6 +391,27 @@ DECLARE_UNIQUE_INDEX(pg_resqueue_oid_index, 6027, on pg_resqueue using btree(oid
 DECLARE_UNIQUE_INDEX(pg_resqueue_rsqname_index, 6028, on pg_resqueue using btree(rsqname name_ops));
 #define ResQueueRsqnameIndexId	6028
 
+//DECLARE_UNIQUE_INDEX(pg_vlabel_name_index, 4860, on pg_vlabel using btree(vlabelname name_ops));
+//#define VlabelNameIndexId  4860
+//
+//DECLARE_UNIQUE_INDEX(pg_elabel_name_index, 4861, on pg_elabel using btree(elabelname name_ops));
+//#define ElabelNameIndexId  4861
+//
+//DECLARE_UNIQUE_INDEX(pg_vlabel_attribute_vname_attnam_index, 4862, on pg_vlabel_attribute using btree(vlabelname name_ops,attrname name_ops));
+//#define VlabelAttributeVnameAttnamIndexId  4862
+//
+//DECLARE_UNIQUE_INDEX(pg_elabel_attribute_ename_attnam_index, 4863, on pg_elabel_attribute using btree(elabelname name_ops,attrname name_ops));
+//#define ElabelAttributeEnameAttnamIndexId  4863
+//
+//DECLARE_UNIQUE_INDEX(pg_graph_vlabel_gnam_vnam_index, 4864, on pg_graph_vlabel using btree(graphname name_ops,vlabelname name_ops));
+//#define GraphVlabelGnameVnamIndexId  4864
+//
+//DECLARE_UNIQUE_INDEX(pg_graph_elabel_gnam_enam_index, 4865, on pg_graph_elabel using btree(graphname name_ops,elabelname name_ops));
+//#define GraphElabelGnameEnamIndexId  4865
+//
+//DECLARE_UNIQUE_INDEX(pg_graph_gnam_snam_index, 4866, on pg_graph using btree(graphname name_ops,schemaname name_ops));
+//#define GraphGnameSnamIndexId  4866
+
 /* TIDYCAT_END_CODEGEN */
 
 /* last step of initialization script: build the indexes declared above */
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
index 8dbf305..e2a4937 100644
--- a/src/include/catalog/namespace.h
+++ b/src/include/catalog/namespace.h
@@ -33,7 +33,8 @@ typedef struct _FuncCandidateList
 	Oid			args[1];		/* arg types --- VARIABLE LENGTH ARRAY */
 }	*FuncCandidateList;	/* VARIABLE LENGTH STRUCT */
 
-
+extern char *RelidGetName(Oid relid);
+extern RangeVar *RelidGetRangeVar(Oid relid);
 extern Oid GetCatalogId(const char *catalogname);
 extern Oid	RangeVarGetRelid(const RangeVar *relation, bool failOK, bool allowHcatalog);
 extern Oid	RangeVarGetCreationNamespace(const RangeVar *newRelation);
diff --git a/src/include/catalog/pg_tidycat.h b/src/include/catalog/pg_tidycat.h
index 49c7ff3..41d0aa3 100644
--- a/src/include/catalog/pg_tidycat.h
+++ b/src/include/catalog/pg_tidycat.h
@@ -26,6 +26,14 @@
  */
 
 
+#include "catalog/skylon_elabel.h"
+#include "catalog/skylon_elabel_attribute.h"
+#include "catalog/skylon_graph.h"
+#include "catalog/skylon_index.h"
+#include "catalog/skylon_graph_elabel.h"
+#include "catalog/skylon_graph_vlabel.h"
+#include "catalog/skylon_vlabel.h"
+#include "catalog/skylon_vlabel_attribute.h"
 #include "catalog/gp_configuration.h"
 #include "catalog/gp_global_sequence.h"
 #include "catalog/gp_master_mirroring.h"
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index b4b1029..26a2837 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -734,6 +734,29 @@ DATA(insert OID = 6995 ( gp_global_sequence	    PGNSP PGUID -1 f c t \054 5096 0
 /* relation id: 5006 - gp_configuration_history 20101104 */
 DATA(insert OID = 6434 ( gp_configuration_history	    PGNSP PGUID -1 f c t \054 5006 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));	
 #define GP_CONFIGURATION_HISTORY_RELTYPE_OID 6434
+/* relation id: 4850 - skylon_vlabel 20200224 */
+DATA(insert OID = 4870 ( skylon_vlabel     PGNSP PGUID -1 f c t \054 4850 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
+#define SKYLON_VLABEL_RELTYPE_OID 4870
+/* relation id: 4851 - skylon_elabel 20200224 */
+DATA(insert OID = 4871 ( skylon_elabel     PGNSP PGUID -1 f c t \054 4851 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
+#define SKYLON_ELABEL_RELTYPE_OID 4871
+/* relation id: 4852 - skylon_vlabel_attribute 20200224 */
+DATA(insert OID = 4872 ( skylon_vlabel_attribute     PGNSP PGUID -1 f c t \054 4852 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
+#define SKYLON_VLABEL_ATTRIBUTE_RELTYPE_OID 4872
+/* relation id: 4853 - skylon_elabel_attribute 20200224 */
+DATA(insert OID = 4873 ( skylon_elabel_attribute     PGNSP PGUID -1 f c t \054 4853 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
+#define SKYLON_ELABEL_ATTRIBUTE_RELTYPE_OID 4873
+/* relation id: 4854 - skylon_graph_vlabel 20200224 */
+DATA(insert OID = 4874 ( skylon_graph_vlabel     PGNSP PGUID -1 f c t \054 4854 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
+#define SKYLON_GRAPH_VLABEL_RELTYPE_OID 4874
+/* relation id: 4855 - skylon_graph_elabel 20200224 */
+DATA(insert OID = 4875 ( skylon_graph_elabel     PGNSP PGUID -1 f c t \054 4855 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
+#define SKYLON_GRAPH_ELABEL_RELTYPE_OID 4875
+/* relation id: 4856 - skylon_graph_elabel 20200224 */
+DATA(insert OID = 4876 ( skylon_graph     PGNSP PGUID -1 f c t \054 4856 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
+#define SKYLON_GRAPH_RELTYPE_OID 4876
+DATA(insert OID = 4877 ( skylon_index     PGNSP PGUID -1 f c t \054 4857 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
+#define SKYLON_INDEX_RELTYPE_OID 4877
 /* relation id: 5029 - gp_db_interfaces 20101104 */
 DATA(insert OID = 6436 ( gp_db_interfaces	    PGNSP PGUID -1 f c t \054 5029 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));	
 #define GP_DB_INTERFACES_RELTYPE_OID 6436
diff --git a/src/include/catalog/skylon_elabel.h b/src/include/catalog/skylon_elabel.h
new file mode 100644
index 0000000..d17f601
--- /dev/null
+++ b/src/include/catalog/skylon_elabel.h
@@ -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.
+ */
+/*-------------------------------------------------------------------------
+ *
+ * skylon_elabel.h
+ *    record sql execution information
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef SRC_INCLUDE_CATALOG_SKYLON_ELABEL_H_
+#define SRC_INCLUDE_CATALOG_SKYLON_ELABEL_H_
+
+#include "catalog/genbki.h"
+#include "c.h"
+
+/* TIDYCAT_BEGINDEF
+
+   CREATE TABLE skylon_elabel
+   with (camelcase=Elabel, shared=true, oid=false, relid=4851, reltype_oid=4871, content=MASTER_ONLY)
+   (
+   vlabelname                name,
+   schemaname              name
+   );
+
+   TIDYCAT_ENDDEF
+*/
+
+/* TIDYCAT_BEGIN_CODEGEN
+
+   WARNING: DO NOT MODIFY THE FOLLOWING SECTION:
+   Generated by tidycat.pl version 34
+   on Fri Feb 26 10:43:15 2016
+*/
+
+
+/*
+ TidyCat Comments for gp_configuration_history:
+  Table is shared, so catalog.c:IsSharedRelation is updated.
+  Table does not have an Oid column.
+  Table has static type (see pg_types.h).
+  Table has TOASTable columns, but NO TOAST table.
+  Table contents are only maintained on MASTER.
+  Table has weird hack for timestamp column.
+
+*/
+
+/*
+ * The CATALOG definition has to refer to the type of "time" as
+ * "timestamptz" (lower case) so that bootstrap mode recognizes it.  But
+ * the C header files define this type as TimestampTz.  Since the field is
+ * potentially-null and therefore cannot be accessed directly from C code,
+ * there is no particular need for the C struct definition to show the
+ * field type as TimestampTz --- instead we just make it Datum.
+ */
+
+
+/* ----------------
+ *    skylon_elabel definition.  cpp turns this into
+ *    typedef struct FormData_skylon_elabel
+ * ----------------
+ */
+
+#define ElabelRelationId 4851
+
+CATALOG(skylon_elabel,4851) BKI_WITHOUT_OIDS
+{
+  NameData elabelname;
+  NameData schemaname;
+  NameData fromvlabel;
+  NameData tovlabel;
+} FormData_skylon_elabel;
+
+
+/* ----------------
+ *    Form_skylon_elabel corresponds to a pointer to a tuple with
+ *    the format of skylon_elabel relation.
+ * ----------------
+ */
+
+typedef FormData_skylon_elabel *Form_skylon_elabel;
+
+/* ----------------
+ *    compiler constants for pg_database
+ * ----------------
+ */
+#define Natts_skylon_elabel 4
+#define Anum_skylon_elabel_elabelname 1
+#define Anum_skylon_elabel_schemaname 2
+#define Anum_skylon_elabel_fromvlabel 3
+#define Anum_skylon_elabel_tovlabel 4
+/* TIDYCAT_END_CODEGEN */
+
+extern void InsertElabelEntry(const char* elabelname, const char* schemaname,
+                       const char* fromvlabel, const char* tovlabel);
+
+#endif /* SRC_INCLUDE_CATALOG_SKYLON_ELABEL_H_ */
diff --git a/src/include/catalog/skylon_elabel_attribute.h b/src/include/catalog/skylon_elabel_attribute.h
new file mode 100644
index 0000000..2b28e6f
--- /dev/null
+++ b/src/include/catalog/skylon_elabel_attribute.h
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+/*-------------------------------------------------------------------------
+ *
+ * pg_elabel.h
+ *    record sql execution information
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef SRC_INCLUDE_CATALOG_SKYLON_ELABEL_ATTRIBUTE_H_
+#define SRC_INCLUDE_CATALOG_SKYLON_ELABEL_ATTRIBUTE_H_
+
+#include "catalog/genbki.h"
+#include "c.h"
+
+/* TIDYCAT_BEGINDEF
+
+   CREATE TABLE skylon_elabel_attribute
+   with (camelcase=ElabelAttr, shared=true, oid=false, relid=4853, reltype_oid=4873, content=MASTER_ONLY)
+   (
+   elabelname                name,
+   attrname              name,
+   attrtypid             oid
+   );
+
+   TIDYCAT_ENDDEF
+*/
+
+/* TIDYCAT_BEGIN_CODEGEN
+
+   WARNING: DO NOT MODIFY THE FOLLOWING SECTION:
+   Generated by tidycat.pl version 34
+   on Fri Feb 26 10:43:15 2016
+*/
+
+
+/*
+ TidyCat Comments for gp_configuration_history:
+  Table is shared, so catalog.c:IsSharedRelation is updated.
+  Table does not have an Oid column.
+  Table has static type (see pg_types.h).
+  Table has TOASTable columns, but NO TOAST table.
+  Table contents are only maintained on MASTER.
+  Table has weird hack for timestamp column.
+
+*/
+
+/*
+ * The CATALOG definition has to refer to the type of "time" as
+ * "timestamptz" (lower case) so that bootstrap mode recognizes it.  But
+ * the C header files define this type as TimestampTz.  Since the field is
+ * potentially-null and therefore cannot be accessed directly from C code,
+ * there is no particular need for the C struct definition to show the
+ * field type as TimestampTz --- instead we just make it Datum.
+ */
+
+
+/* ----------------
+ *    skylon_elabel definition.  cpp turns this into
+ *    typedef struct FormData_skylon_elabel
+ * ----------------
+ */
+
+#define ElabelAttrRelationId 4853
+
+CATALOG(skylon_elabel_attribute,4853) BKI_WITHOUT_OIDS
+{
+  NameData schemaname;
+  NameData elabelname;
+  NameData attrname;
+  Oid attrtypid;
+  int4 primaryrank;
+  int4 rank;
+} FormData_skylon_elabel_attribute;
+
+
+/* ----------------
+ *    Form_pg_elabel corresponds to a pointer to a tuple with
+ *    the format of pg_elabel relation.
+ * ----------------
+ */
+
+typedef FormData_skylon_elabel_attribute *Form_skylon_elabel_attribute;
+
+/* ----------------
+ *    compiler constants for pg_database
+ * ----------------
+ */
+#define Natts_skylon_elabel_attribute 6
+#define Anum_skylon_elabel_attribute_schemaname 1
+#define Anum_skylon_elabel_attribute_elabelname 2
+#define Anum_skylon_elabel_attribute_attrname 3
+#define Anum_skylon_elabel_attribute_attrtypid 4
+#define Anum_skylon_elabel_attribute_primaryrank 5
+#define Anum_skylon_elabel_attribute_rank 6
+/* TIDYCAT_END_CODEGEN */
+
+extern void InsertElabelAttrEntry(const char* schemaname, const char* elabelname, const char* attrname,
+                           Oid attrtypid, int4 primaryrank, int4 rank);
+
+#endif /* SRC_INCLUDE_CATALOG_SKYLON_ELABEL_ATTRIBUTE_H_ */
diff --git a/src/include/catalog/skylon_graph.h b/src/include/catalog/skylon_graph.h
new file mode 100644
index 0000000..6d1097c
--- /dev/null
+++ b/src/include/catalog/skylon_graph.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+/*-------------------------------------------------------------------------
+ *
+ * pg_elabel.h
+ *    record sql execution information
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef SRC_INCLUDE_CATALOG_SKYLON_GRAPH_H_
+#define SRC_INCLUDE_CATALOG_SKYLON_GRAPH_H_
+
+#include "catalog/genbki.h"
+#include "c.h"
+
+/* TIDYCAT_BEGINDEF
+
+   CREATE TABLE skylon_graph
+   with (camelcase=Graph, shared=true, oid=false, relid=4856, reltype_oid=4876, content=MASTER_ONLY)
+   (
+   graphName                name,
+   schemaName              name
+   );
+
+   TIDYCAT_ENDDEF
+*/
+
+/* TIDYCAT_BEGIN_CODEGEN
+
+   WARNING: DO NOT MODIFY THE FOLLOWING SECTION:
+   Generated by tidycat.pl version 34
+   on Fri Feb 26 10:43:15 2016
+*/
+
+
+/*
+ TidyCat Comments for gp_configuration_history:
+  Table is shared, so catalog.c:IsSharedRelation is updated.
+  Table does not have an Oid column.
+  Table has static type (see pg_types.h).
+  Table has TOASTable columns, but NO TOAST table.
+  Table contents are only maintained on MASTER.
+  Table has weird hack for timestamp column.
+
+*/
+
+/*
+ * The CATALOG definition has to refer to the type of "time" as
+ * "timestamptz" (lower case) so that bootstrap mode recognizes it.  But
+ * the C header files define this type as TimestampTz.  Since the field is
+ * potentially-null and therefore cannot be accessed directly from C code,
+ * there is no particular need for the C struct definition to show the
+ * field type as TimestampTz --- instead we just make it Datum.
+ */
+
+
+/* ----------------
+ *    skylon_graph definition.  cpp turns this into
+ *    typedef struct FormData_skylon_graph
+ * ----------------
+ */
+
+#define GraphRelationId 4856
+
+CATALOG(skylon_graph,4856) BKI_WITHOUT_OIDS
+{
+  NameData graphname;
+  NameData schemaname;
+} FormData_skylon_graph;
+
+
+/* ----------------
+ *    Form_skylon_graph corresponds to a pointer to a tuple with
+ *    the format of skylon_graph relation.
+ * ----------------
+ */
+
+typedef FormData_skylon_graph *Form_skylon_graph;
+
+/* ----------------
+ *    compiler constants for pg_database
+ * ----------------
+ */
+#define Natts_skylon_graph 2
+#define Anum_skylon_graph_graphname 1
+#define Anum_skylon_graph_schemaname 2
+/* TIDYCAT_END_CODEGEN */
+extern void InsertGraphEntry(const char* graphname, const char* schemaname);
+
+#endif /* SRC_INCLUDE_CATALOG_SKYLON_GRAPH_H_ */
diff --git a/src/include/catalog/skylon_graph_elabel.h b/src/include/catalog/skylon_graph_elabel.h
new file mode 100644
index 0000000..ab24904
--- /dev/null
+++ b/src/include/catalog/skylon_graph_elabel.h
@@ -0,0 +1,112 @@
+/*
+ * 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
... 23801 lines suppressed ...