You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by hu...@apache.org on 2019/03/24 07:53:12 UTC

[hawq] branch huor_univplan updated: HAWQ-1691. Add universal plan used by ORC format

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

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


The following commit(s) were added to refs/heads/huor_univplan by this push:
     new 52a3afa  HAWQ-1691. Add universal plan used by ORC format
52a3afa is described below

commit 52a3afa4ebd68f26e75aa59005f77912b7a69979
Author: Ruilong Huo <hu...@apache.org>
AuthorDate: Sun Mar 24 15:52:19 2019 +0800

    HAWQ-1691. Add universal plan used by ORC format
---
 depends/univplan/.gitignore                        |    8 +
 .../univplan/CMake/CMakeTestCompileInt64tType.cc   |   18 +
 depends/univplan/CMake/FindCogapp.cmake            |   50 +
 depends/univplan/CMake/FindGFlags.cmake            |   48 +
 depends/univplan/CMake/FindGlog.cmake              |   49 +
 depends/univplan/CMake/FindJSON.cmake              |   38 +
 depends/univplan/CMake/FindSnappy.cmake            |   30 +
 depends/univplan/CMake/Functions.cmake             |   46 +
 depends/univplan/CMake/Options.cmake               |   71 ++
 depends/univplan/CMake/Platform.cmake              |   47 +
 depends/univplan/CMakeLists.txt                    |   28 +
 depends/univplan/README.md                         |    2 +
 depends/univplan/bootstrap                         |   92 ++
 depends/univplan/src/CMakeLists.txt                |   77 ++
 depends/univplan/src/univplan/common/expression.cc |  730 ++++++++++++
 depends/univplan/src/univplan/common/expression.h  |  338 ++++++
 .../univplan/src/univplan/common/plannode-util.h   |  324 ++++++
 .../univplan/src/univplan/common/plannode-walker.h |  126 +++
 depends/univplan/src/univplan/common/stagize.cc    |  200 ++++
 depends/univplan/src/univplan/common/stagize.h     |   42 +
 depends/univplan/src/univplan/common/statistics.h  |   59 +
 .../univplan/src/univplan/common/subplan-util.cc   |  139 +++
 .../univplan/src/univplan/common/subplan-util.h    |   34 +
 .../univplan/src/univplan/common/univplan-type.h   |  133 +++
 depends/univplan/src/univplan/common/var-util.cc   |   99 ++
 depends/univplan/src/univplan/common/var-util.h    |   28 +
 .../univplan/src/univplan/cwrapper/univplan-c.cc   | 1160 ++++++++++++++++++++
 .../univplan/src/univplan/cwrapper/univplan-c.h    |  340 ++++++
 .../src/univplan/minmax/minmax-predicates.cc       |  583 ++++++++++
 .../src/univplan/minmax/minmax-predicates.h        |  592 ++++++++++
 .../univplan/proto/universal-plan-catalog.proto    |   49 +
 .../src/univplan/proto/universal-plan-expr.proto   |  203 ++++
 .../src/univplan/proto/universal-plan.proto        |  402 +++++++
 .../src/univplan/testutil/univplan-proto-util.cc   |  507 +++++++++
 .../src/univplan/testutil/univplan-proto-util.h    |  264 +++++
 .../univplanbuilder/univplanbuilder-agg.cc         |   45 +
 .../univplan/univplanbuilder/univplanbuilder-agg.h |   39 +
 .../univplanbuilder/univplanbuilder-append.cc      |   41 +
 .../univplanbuilder/univplanbuilder-append.h       |   36 +
 .../univplanbuilder/univplanbuilder-column.h       |   42 +
 .../univplanbuilder/univplanbuilder-connector.h    |   86 ++
 .../univplanbuilder/univplanbuilder-expr-node.h    |  724 ++++++++++++
 .../univplanbuilder/univplanbuilder-expr-poly.h    |   42 +
 .../univplanbuilder/univplanbuilder-expr-tree.h    |   93 ++
 .../univplanbuilder-ext-gs-filter.cc               |   43 +
 .../univplanbuilder-ext-gs-filter.h                |   39 +
 .../univplanbuilder/univplanbuilder-ext-gs-proj.cc |   45 +
 .../univplanbuilder/univplanbuilder-ext-gs-proj.h  |   39 +
 .../univplanbuilder/univplanbuilder-ext-gs-scan.cc |   91 ++
 .../univplanbuilder/univplanbuilder-ext-gs-scan.h  |   50 +
 .../univplanbuilder/univplanbuilder-hash.h         |   52 +
 .../univplanbuilder/univplanbuilder-hashjoin.h     |   67 ++
 .../univplanbuilder/univplanbuilder-insert.cc      |   38 +
 .../univplanbuilder/univplanbuilder-insert.h       |   36 +
 .../univplanbuilder/univplanbuilder-limit.cc       |   45 +
 .../univplanbuilder/univplanbuilder-limit.h        |   40 +
 .../univplanbuilder/univplanbuilder-listener.h     |   36 +
 .../univplanbuilder/univplanbuilder-material.h     |   82 ++
 .../univplanbuilder/univplanbuilder-mergejoin.h    |   62 ++
 .../univplanbuilder/univplanbuilder-nestloop.h     |   56 +
 .../univplanbuilder/univplanbuilder-node.cc        |   61 +
 .../univplanbuilder/univplanbuilder-node.h         |   59 +
 .../univplanbuilder/univplanbuilder-paraminfo.h    |   47 +
 .../univplanbuilder-plan-node-poly.h               |   48 +
 .../univplanbuilder/univplanbuilder-plan.cc        |  141 +++
 .../univplanbuilder/univplanbuilder-plan.h         |   74 ++
 .../univplanbuilder-range-tbl-entry.h              |   40 +
 .../univplanbuilder/univplanbuilder-receiver.h     |   39 +
 .../univplanbuilder/univplanbuilder-result.h       |   55 +
 .../univplanbuilder/univplanbuilder-scan-seq.cc    |   58 +
 .../univplanbuilder/univplanbuilder-scan-seq.h     |   44 +
 .../univplanbuilder/univplanbuilder-scan-task.h    |   82 ++
 .../univplanbuilder-shareinput-scan.h              |   58 +
 .../univplanbuilder/univplanbuilder-sink.h         |  240 ++++
 .../univplanbuilder/univplanbuilder-sort.cc        |   53 +
 .../univplanbuilder/univplanbuilder-sort.h         |   42 +
 .../univplanbuilder-subquery-scan.h                |   55 +
 .../univplanbuilder/univplanbuilder-table.h        |   55 +
 .../univplanbuilder/univplanbuilder-target-entry.h |   55 +
 .../univplanbuilder/univplanbuilder-unique.cc      |   45 +
 .../univplanbuilder/univplanbuilder-unique.h       |   39 +
 .../univplan/univplanbuilder/univplanbuilder.cc    |   80 ++
 .../src/univplan/univplanbuilder/univplanbuilder.h |   56 +
 depends/univplan/test/CMakeLists.txt               |   33 +
 depends/univplan/test/data/TestAgg                 |  260 +++++
 depends/univplan/test/data/TestCompletedPlanAfter  |  849 ++++++++++++++
 depends/univplan/test/data/TestCompletedPlanBefore |  628 +++++++++++
 depends/univplan/test/data/TestLimitCount          |  228 ++++
 depends/univplan/test/data/TestLimitCountOffset    |  246 +++++
 depends/univplan/test/data/TestLimitOffset         |  212 ++++
 depends/univplan/test/data/TestNullTest            |  136 +++
 depends/univplan/test/data/TestQualListAndExpr     |  259 +++++
 depends/univplan/test/data/TestSort                |   99 ++
 depends/univplan/test/data/TestStagizeAfter        |  167 +++
 depends/univplan/test/data/TestStagizeBefore       |  100 ++
 .../univplan/test/data/TestUnivPlanProtoGenerate   |  130 +++
 .../univplan/test/parallel/parallel-launcher.py    |  153 +++
 depends/univplan/test/unit/CMakeLists.txt          |   14 +
 depends/univplan/test/unit/test-basic-univplan.cc  |  247 +++++
 .../univplan/test/unit/test-minmax-cotasklist.cc   |  247 +++++
 .../univplan/test/unit/test-univplan-cwrapper.cc   |   78 ++
 depends/univplan/test/unit/test-univplan.h         |   55 +
 depends/univplan/test/unit/unit-test-main.cc       |   20 +
 103 files changed, 14612 insertions(+)

diff --git a/depends/univplan/.gitignore b/depends/univplan/.gitignore
new file mode 100644
index 0000000..a9b913a
--- /dev/null
+++ b/depends/univplan/.gitignore
@@ -0,0 +1,8 @@
+.DS_Store
+.cproject
+.project
+.settings
+.pydevproject
+*.pyc
+build/
+CodeCoverageReport/
diff --git a/depends/univplan/CMake/CMakeTestCompileInt64tType.cc b/depends/univplan/CMake/CMakeTestCompileInt64tType.cc
new file mode 100644
index 0000000..8b57439
--- /dev/null
+++ b/depends/univplan/CMake/CMakeTestCompileInt64tType.cc
@@ -0,0 +1,18 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include <cstdint>
+
+// test if int64_t is typedef to be long long
+
+void test(long long *i) {}  // NOLINT
+
+int main() {
+  int64_t i = 0;
+  test(&i);
+  return 0;
+}
diff --git a/depends/univplan/CMake/FindCogapp.cmake b/depends/univplan/CMake/FindCogapp.cmake
new file mode 100644
index 0000000..198c23b
--- /dev/null
+++ b/depends/univplan/CMake/FindCogapp.cmake
@@ -0,0 +1,50 @@
+# locate cogapp and generate source code from template
+# 
+# find_package(Cogapp REQUIRED)
+#
+# COGAPP_GENERATE (public function)
+#   GENERATED_CODE = Variable to define with generated source files.
+#   TEMPLATE  = Template used to generate source files.
+#
+# NOTE: The COGAPP_GENERATE macro & add_executable() or add_library()
+#       calls only work properly within the same directory.
+#
+
+find_package(PythonInterp REQUIRED)
+
+function(COGAPP_GENERATE GENERATED_CODE)
+  if(NOT ARGN)
+    message(SEND_ERROR "Error: COGAPP_GENERATE() called without any template files")
+    return()
+  endif()
+
+  set(${GENERATED_CODE})
+  foreach(FIL ${ARGN})
+    get_filename_component(ABS_FIL ${FIL} ABSOLUTE)
+    file(RELATIVE_PATH FIL_REL ${CMAKE_SOURCE_DIR} ${ABS_FIL})
+    
+    get_filename_component(FIL_DIR ${CMAKE_BINARY_DIR}/codegen/${FIL_REL} DIRECTORY)
+    file(MAKE_DIRECTORY ${FIL_DIR})
+    
+    get_filename_component(FIL_WE "${CMAKE_BINARY_DIR}/codegen/${FIL_REL}" NAME_WE)
+    get_filename_component(FIL_EXT "${CMAKE_BINARY_DIR}/codegen/${FIL_REL}" EXT)
+    
+    set(FIL_OUT "${FIL_DIR}/${FIL_WE}.cg${FIL_EXT}")
+    list(APPEND ${GENERATED_CODE} ${FIL_OUT})
+    
+    if(NOT EXISTS ${ABS_FIL})
+        MESSAGE(FATAL_ERROR "file ${ABS_FIL} does not exist")
+    endif()
+
+    add_custom_command(
+      OUTPUT ${FIL_OUT}
+      COMMAND  ${PYTHON_EXECUTABLE}
+      ARGS -m cogapp -d -o ${FIL_OUT} ${ABS_FIL}
+      DEPENDS ${ABS_FIL}
+      COMMENT "Running cog on ${FIL}"
+      VERBATIM )
+  endforeach()
+
+  set_source_files_properties(${${GENERATED_CODE}} PROPERTIES GENERATED TRUE)
+  set(${GENERATED_CODE} ${${GENERATED_CODE}} PARENT_SCOPE)
+endfunction()
\ No newline at end of file
diff --git a/depends/univplan/CMake/FindGFlags.cmake b/depends/univplan/CMake/FindGFlags.cmake
new file mode 100644
index 0000000..f93c571
--- /dev/null
+++ b/depends/univplan/CMake/FindGFlags.cmake
@@ -0,0 +1,48 @@
+# - Try to find GFLAGS
+#
+# The following variables are optionally searched for defaults
+#  GFLAGS_ROOT_DIR:            Base directory where all GFLAGS components are found
+#
+# The following are set after configuration is done:
+#  GFLAGS_FOUND
+#  GFLAGS_INCLUDE_DIRS
+#  GFLAGS_LIBRARIES
+#  GFLAGS_LIBRARYRARY_DIRS
+
+include(FindPackageHandleStandardArgs)
+
+set(GFLAGS_ROOT_DIR "" CACHE PATH "Folder contains Gflags")
+
+# We are testing only a couple of files in the include directories
+if(WIN32)
+    find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h
+        PATHS ${GFLAGS_ROOT_DIR}/src/windows)
+else()
+    find_path(GFLAGS_INCLUDE_DIR gflags/gflags.h
+        PATHS ${GFLAGS_ROOT_DIR})
+endif()
+
+if(MSVC)
+    find_library(GFLAGS_LIBRARY_RELEASE
+        NAMES libgflags
+        PATHS ${GFLAGS_ROOT_DIR}
+        PATH_SUFFIXES Release)
+
+    find_library(GFLAGS_LIBRARY_DEBUG
+        NAMES libgflags-debug
+        PATHS ${GFLAGS_ROOT_DIR}
+        PATH_SUFFIXES Debug)
+
+    set(GFLAGS_LIBRARY optimized ${GFLAGS_LIBRARY_RELEASE} debug ${GFLAGS_LIBRARY_DEBUG})
+else()
+    find_library(GFLAGS_LIBRARY gflags)
+endif()
+
+find_package_handle_standard_args(GFLAGS DEFAULT_MSG
+    GFLAGS_INCLUDE_DIR GFLAGS_LIBRARY)
+
+
+if(GFLAGS_FOUND)
+    set(GFLAGS_INCLUDE_DIRS ${GFLAGS_INCLUDE_DIR})
+    set(GFLAGS_LIBRARIES ${GFLAGS_LIBRARY})
+endif()
diff --git a/depends/univplan/CMake/FindGlog.cmake b/depends/univplan/CMake/FindGlog.cmake
new file mode 100644
index 0000000..d9f0ee0
--- /dev/null
+++ b/depends/univplan/CMake/FindGlog.cmake
@@ -0,0 +1,49 @@
+
+# - Try to find Glog
+#
+# The following variables are optionally searched for defaults
+#  GLOG_ROOT_DIR:            Base directory where all GLOG components are found
+#
+# The following are set after configuration is done: 
+#  GLOG_FOUND
+#  GLOG_INCLUDE_DIRS
+#  GLOG_LIBRARIES
+#  GLOG_LIBRARYRARY_DIRS
+
+include(FindPackageHandleStandardArgs)
+
+set(GLOG_ROOT_DIR "" CACHE PATH "Folder contains Google glog")
+
+if(WIN32)
+    find_path(GLOG_INCLUDE_DIR glog/logging.h
+        PATHS ${GLOG_ROOT_DIR}/src/windows)
+else()
+    find_path(GLOG_INCLUDE_DIR glog/logging.h
+        PATHS ${GLOG_ROOT_DIR})
+endif()
+
+if(MSVC)
+    find_library(GLOG_LIBRARY_RELEASE libglog_static
+        PATHS ${GLOG_ROOT_DIR}
+        PATH_SUFFIXES Release)
+
+    find_library(GLOG_LIBRARY_DEBUG libglog_static
+        PATHS ${GLOG_ROOT_DIR}
+        PATH_SUFFIXES Debug)
+
+    set(GLOG_LIBRARY optimized ${GLOG_LIBRARY_RELEASE} debug ${GLOG_LIBRARY_DEBUG})
+else()
+    find_library(GLOG_LIBRARY glog
+        PATHS ${GLOG_ROOT_DIR}
+        PATH_SUFFIXES
+            lib
+            lib64)
+endif()
+
+find_package_handle_standard_args(GLOG DEFAULT_MSG
+    GLOG_INCLUDE_DIR GLOG_LIBRARY)
+
+if(GLOG_FOUND)
+    set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR})
+    set(GLOG_LIBRARIES ${GLOG_LIBRARY})
+endif()
\ No newline at end of file
diff --git a/depends/univplan/CMake/FindJSON.cmake b/depends/univplan/CMake/FindJSON.cmake
new file mode 100644
index 0000000..a334948
--- /dev/null
+++ b/depends/univplan/CMake/FindJSON.cmake
@@ -0,0 +1,38 @@
+# - Find json
+# Find the native JSON headers and libraries.
+#
+#  JSON_INCLUDE_DIRS   - where to find json/json.h, etc.
+#  JSON_LIBRARIES      - List of libraries when using json.
+#  JSON_FOUND          - True if json found.
+
+#=============================================================================
+# Copyright 2006-2009 Kitware, Inc.
+# Copyright 2012 Rolf Eike Beer <ei...@sf-mail.de>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# Look for the header file.
+find_path(JSON_INCLUDE_DIR NAMES json/json.h)
+mark_as_advanced(JSON_INCLUDE_DIR)
+
+# Look for the library (sorted from most current/relevant entry to least).
+find_library(JSON_LIBRARY NAMES jsoncpp
+)
+mark_as_advanced(JSON_LIBRARY)
+
+# handle the QUIETLY and REQUIRED arguments and set JSON_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(JSON DEFAULT_MSG JSON_INCLUDE_DIR JSON_LIBRARY)
+
+if(JSON_FOUND)
+  set(JSON_LIBRARIES ${JSON_LIBRARY})
+  set(JSON_INCLUDE_DIRS ${JSON_INCLUDE_DIR})
+endif()
diff --git a/depends/univplan/CMake/FindSnappy.cmake b/depends/univplan/CMake/FindSnappy.cmake
new file mode 100644
index 0000000..623d2d7
--- /dev/null
+++ b/depends/univplan/CMake/FindSnappy.cmake
@@ -0,0 +1,30 @@
+# Variables used by this module, they can change the default behaviour and need
+# to be set before calling find_package:
+#
+#  SNAPPY_ROOT_DIR  Set this variable to the root installation of
+#                    Snappy if the module has problems finding
+#                    the proper installation path.
+#
+# Variables defined by this module:
+#
+#  SNAPPY_FOUND              System has Snappy libs/headers
+#  SNAPPY_LIBRARIES          The Snappy libraries
+#  SNAPPY_INCLUDE_DIR        The location of Snappy headers
+
+find_path(SNAPPY_INCLUDE_DIR
+    NAMES snappy.h
+    HINTS ${SNAPPY_ROOT_DIR}/include)
+
+find_library(SNAPPY_LIBRARIES
+    NAMES snappy
+    HINTS ${SNAPPY_ROOT_DIR}/lib)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Snappy DEFAULT_MSG
+    SNAPPY_LIBRARIES
+    SNAPPY_INCLUDE_DIR)
+
+mark_as_advanced(
+    SNAPPY_ROOT_DIR
+    SNAPPY_LIBRARIES
+    SNAPPY_INCLUDE_DIR)
diff --git a/depends/univplan/CMake/Functions.cmake b/depends/univplan/CMake/Functions.cmake
new file mode 100644
index 0000000..a771b60
--- /dev/null
+++ b/depends/univplan/CMake/Functions.cmake
@@ -0,0 +1,46 @@
+FUNCTION(AUTO_SOURCES RETURN_VALUE PATTERN SOURCE_SUBDIRS)
+
+	IF ("${SOURCE_SUBDIRS}" STREQUAL "RECURSE")
+		SET(PATH ".")
+		IF (${ARGC} EQUAL 4)
+			LIST(GET ARGV 3 PATH)
+		ENDIF ()
+	ENDIF()
+
+	IF ("${SOURCE_SUBDIRS}" STREQUAL "RECURSE")
+		UNSET(${RETURN_VALUE})
+		FILE(GLOB SUBDIR_FILES "${PATH}/${PATTERN}")
+		LIST(APPEND ${RETURN_VALUE} ${SUBDIR_FILES})
+
+		FILE(GLOB SUBDIRS RELATIVE ${PATH} ${PATH}/*)
+
+		FOREACH(DIR ${SUBDIRS})
+			IF (IS_DIRECTORY ${PATH}/${DIR})
+				IF (NOT "${DIR}" STREQUAL "CMAKEFILES")
+					FILE(GLOB_RECURSE SUBDIR_FILES "${PATH}/${DIR}/${PATTERN}")
+					LIST(APPEND ${RETURN_VALUE} ${SUBDIR_FILES})
+				ENDIF()
+			ENDIF()
+		ENDFOREACH()
+	ELSE ()
+		FILE(GLOB ${RETURN_VALUE} "${PATTERN}")
+
+		FOREACH (PATH ${SOURCE_SUBDIRS})
+			FILE(GLOB SUBDIR_FILES "${PATH}/${PATTERN}")
+			LIST(APPEND ${RETURN_VALUE} ${SUBDIR_FILES})
+		ENDFOREACH(PATH ${SOURCE_SUBDIRS})
+	ENDIF ()
+
+	IF (${FILTER_OUT})
+		LIST(REMOVE_ITEM ${RETURN_VALUE} ${FILTER_OUT})
+	ENDIF()
+
+	SET(${RETURN_VALUE} ${${RETURN_VALUE}} PARENT_SCOPE)
+ENDFUNCTION(AUTO_SOURCES)
+
+FUNCTION(CONTAINS_STRING FILE SEARCH RETURN_VALUE)
+	FILE(STRINGS ${FILE} FILE_CONTENTS REGEX ".*${SEARCH}.*")
+	IF (FILE_CONTENTS)
+		SET(${RETURN_VALUE} TRUE PARENT_SCOPE)
+	ENDIF()
+ENDFUNCTION(CONTAINS_STRING)
diff --git a/depends/univplan/CMake/Options.cmake b/depends/univplan/CMake/Options.cmake
new file mode 100644
index 0000000..36841ea
--- /dev/null
+++ b/depends/univplan/CMake/Options.cmake
@@ -0,0 +1,71 @@
+##############################################################################
+# In this file we handle all env and customer's settings
+##############################################################################
+
+##############################################################################
+# Setup build and dependencies information 
+##############################################################################
+SET(DEPENDENCY_INSTALL_PREFIX "/opt/dependency")
+IF($ENV{DEPENDENCY_INSTALL_PREFIX})
+	SET(DEPENDENCY_INSTALL_PREFIX $ENV{DEPENDENCY_INSTALL_PREFIX})
+ENDIF()
+
+SET(DEPENDENCY_DIST_PACKAGE_NAME "dependency-dist-package.tar.gz")
+IF($ENV{DEPENDENCY_DIST_PACKAGE_NAME})
+	SET(DEPENDENCY_DIST_PACKAGE_NAME $ENV{DEPENDENCY_DIST_PACKAGE_NAME})
+ENDIF()
+
+SET(CMAKE_PREFIX_PATH "${DEPENDENCY_INSTALL_PREFIX}" ${CMAKE_PREFIX_PATH})
+SET(CMAKE_PREFIX_PATH "${DEPENDENCY_INSTALL_PREFIX}/package" ${CMAKE_PREFIX_PATH})
+SET(CMAKE_PREFIX_PATH "${DEPENDENCY_INSTALL_PREFIX}/tools" ${CMAKE_PREFIX_PATH})
+
+SET(DEPENDENCY_LIBRARY_PATH "${DEPENDENCY_INSTALL_PREFIX}/package/lib:${DEPENDENCY_LIBRARY_PATH}")
+SET(DEPENDENCY_LIBRARY_PATH "${DEPENDENCY_INSTALL_PREFIX}/package/lib64:${DEPENDENCY_LIBRARY_PATH}")
+
+##############################################################################
+# Setup build flags
+##############################################################################
+OPTION(ENABLE_COVERAGE "enable code coverage." OFF)
+
+IF(NOT CMAKE_BUILD_TYPE)
+    SET(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE)
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+IF(ENABLE_COVERAGE STREQUAL ON)
+    INCLUDE(CodeCoverage)
+ENDIF(ENABLE_COVERAGE STREQUAL ON)
+
+IF(CMAKE_BUILD_TYPE MATCHES Debug)
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0")    
+ENDIF()
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fno-omit-frame-pointer -fno-strict-aliasing")
+
+IF(ENABLE_AVX STREQUAL ON)
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx -mno-avx2")
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DAVX_OPT")
+ELSE()
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mno-avx -mno-avx2")
+ENDIF()
+
+#c++11 is needed to provide thread saft singleton implementation. 
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-deprecated-register")
+#-Rpass-missed=loop-vectorize  -Wall -Wconversion
+
+IF(CMAKE_COMPILER_IS_CLANG)
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-limit-debug-info -stdlib=libc++ -DUSE_CLANG")
+    IF(OS_LINUX)
+        SET(CLANG_LDFLAGS "-lc++abi -lc++" ${CLANG_LDFLAGS})
+    ENDIF(OS_LINUX)
+ENDIF(CMAKE_COMPILER_IS_CLANG)
+
+TRY_COMPILE(INT64T_EQUAL_LONGLONG
+    ${CMAKE_BINARY_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CMakeTestCompileInt64tType.cc
+    OUTPUT_VARIABLE OUTPUT)
+
+IF(INT64T_EQUAL_LONGLONG)
+    MESSAGE(STATUS "Checking whether int64_t is typedef to long long -- yes")
+ELSE(INT64T_EQUAL_LONGLONG)
+    MESSAGE(STATUS "Checking whether int64_t is typedef to long long -- no")
+ENDIF(INT64T_EQUAL_LONGLONG)
diff --git a/depends/univplan/CMake/Platform.cmake b/depends/univplan/CMake/Platform.cmake
new file mode 100644
index 0000000..1ee0238
--- /dev/null
+++ b/depends/univplan/CMake/Platform.cmake
@@ -0,0 +1,47 @@
+IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    SET(OS_LINUX true CACHE INTERNAL "Linux operating system")
+ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+    SET(OS_MACOSX true CACHE INTERNAL "Mac Darwin operating system")
+ELSE(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    MESSAGE(FATAL_ERROR "Unsupported OS: \"${CMAKE_SYSTEM_NAME}\"")
+ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+
+IF(CMAKE_COMPILER_IS_GNUCXX)
+    EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} --version  OUTPUT_VARIABLE COMPILER_OUTPUT)
+    
+    STRING(REGEX MATCH "[0-9]\\.[0-9]\\.[0-9]" GCC_COMPILER_VERSION ${COMPILER_OUTPUT})
+    STRING(REGEX MATCHALL "[0-9]" GCC_COMPILER_VERSION ${GCC_COMPILER_VERSION})
+    
+    LIST(LENGTH GCC_COMPILER_VERSION GCC_COMPILER_VERSION_LEN)
+    IF (NOT 3 EQUAL ${GCC_COMPILER_VERSION_LEN})
+        MESSAGE(FATAL_ERROR "Cannot get gcc version from \"${COMPILER_OUTPUT}\"")
+    ENDIF(NOT 3 EQUAL ${GCC_COMPILER_VERSION_LEN})
+    
+    LIST(GET GCC_COMPILER_VERSION 0 GCC_COMPILER_VERSION_MAJOR)
+    LIST(GET GCC_COMPILER_VERSION 1 GCC_COMPILER_VERSION_MINOR)
+    LIST(GET GCC_COMPILER_VERSION 2 GCC_COMPILER_VERSION_PATCH)
+    
+    SET(GCC_COMPILER_VERSION_MAJOR ${GCC_COMPILER_VERSION_MAJOR} CACHE INTERNAL "gcc major version")
+    SET(GCC_COMPILER_VERSION_MINOR ${GCC_COMPILER_VERSION_MINOR} CACHE INTERNAL "gcc minor version")
+    SET(GCC_COMPILER_VERSION_PATCH ${GCC_COMPILER_VERSION_PATCH} CACHE INTERNAL "gcc patch version")
+    
+    MESSAGE(STATUS "checking compiler: GCC (${GCC_COMPILER_VERSION_MAJOR}.${GCC_COMPILER_VERSION_MINOR}.${GCC_COMPILER_VERSION_PATCH})")
+ELSE(CMAKE_COMPILER_IS_GNUCXX)
+    EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} --version  OUTPUT_VARIABLE COMPILER_OUTPUT)
+    IF(COMPILER_OUTPUT MATCHES "clang")
+        SET(CMAKE_COMPILER_IS_CLANG true CACHE INTERNAL "using clang as compiler")
+        MESSAGE(STATUS "checking compiler: CLANG")
+    ELSE(COMPILER_OUTPUT MATCHES "clang")
+        MESSAGE(FATAL_ERROR "Unsupported compiler: \"${CMAKE_CXX_COMPILER}\"")
+    ENDIF(COMPILER_OUTPUT MATCHES "clang")
+ENDIF(CMAKE_COMPILER_IS_GNUCXX)
+
+INCLUDE (TestBigEndian)
+TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
+if(IS_BIG_ENDIAN)
+ message(STATUS "BIG_ENDIAN")
+ ADD_DEFINITIONS(-DIS_BIG_ENDIAN)
+else()
+ message(STATUS "LITTLE_ENDIAN")
+ ADD_DEFINITIONS(-DIS_LITTLE_ENDIAN)
+endif()
diff --git a/depends/univplan/CMakeLists.txt b/depends/univplan/CMakeLists.txt
new file mode 100644
index 0000000..f25ad2c
--- /dev/null
+++ b/depends/univplan/CMakeLists.txt
@@ -0,0 +1,28 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(univplan)
+
+##############################################################################
+# General CMake initialization
+##############################################################################
+SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
+SET(CMAKE_VERBOSE_MAKEFILE OFF CACHE STRING "Verbose build." FORCE)
+
+IF(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
+    MESSAGE(FATAL_ERROR "cannot build the project in the source directory! Out-of-source build is enforced!")
+ENDIF()
+
+##############################################################################
+# Import env, customer settings and utilities
+##############################################################################
+INCLUDE(Functions)
+INCLUDE(Platform)
+INCLUDE(Options)
+
+ADD_SUBDIRECTORY(src)
+ADD_SUBDIRECTORY(test)
+
+ADD_CUSTOM_TARGET(coverage
+    COMMAND make resetcoverage
+    COMMAND make -j8 unittest
+    COMMAND make ucoverage
+    COMMENT "Run all unit tests and get coverage...")
diff --git a/depends/univplan/README.md b/depends/univplan/README.md
new file mode 100644
index 0000000..9167b24
--- /dev/null
+++ b/depends/univplan/README.md
@@ -0,0 +1,2 @@
+# univplan
+Universal plan
diff --git a/depends/univplan/bootstrap b/depends/univplan/bootstrap
new file mode 100755
index 0000000..1554c7b
--- /dev/null
+++ b/depends/univplan/bootstrap
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+die() {
+    echo "$@" 1>&2 ; exit 1
+}
+
+arg ()
+{
+    echo "$1" | sed "s/^${2-[^=]*=}//"
+}
+
+# Detect directory information.
+source_dir=`cd "\`dirname \"$0\"\`";pwd`
+binary_dir=`pwd`
+
+# Choose the default install prefix.
+default_prefix="/opt/dependency/package"
+
+# Display bootstrap usage
+usage() {
+echo '
+Usage: '"$0"' [<options>]
+Options: [defaults in brackets after descriptions]
+Configuration:
+    --help                          print this message
+    --prefix=PREFIX                 install files in tree rooted at PREFIX
+                                    ['"${default_prefix}"']
+    --enable-coverage               enable code coverage, must be used together with --enable-debug
+    --enable-debug                  enable debug build
+    --enable-avx                    enable avx for vector instruction optimization
+'
+    exit 10
+}
+
+# Parse arguments
+prefix_dir="${default_prefix}"
+build_type="Release"
+enable_coverage="OFF"
+enable_avx="ON"
+while test $# != 0; do
+    case "$1" in
+    --prefix=*) dir=`arg "$1"`
+                prefix_dir="$dir";;
+	--enable-coverage) enable_coverage="ON"
+                       build_type="Debug";;
+    --enable-debug) build_type="Debug";;
+    --enable-avx=*) avx=`arg "$1"`
+                    enable_avx="$avx";;
+    --help) usage ;;
+    *) die "Unknown option: $1" ;;
+    esac
+    shift
+done
+
+if [ ${source_dir} = ${binary_dir} ]; then
+	die "cannot build the project in the source directory! Out-of-source build is enforced!"
+fi
+
+enable_avx_upper=`echo "${enable_avx}" | tr [a-z] [A-Z]`
+if [ ${enable_avx_upper} != "ON" ] && [ ${enable_avx_upper} != "OFF" ]; then
+    die "unknown value for option enable-avx: ${enable_avx}, valid options are: on and off"
+fi
+
+# Check clang compiler
+if [[ x"${CC}" = x"" ]]; then
+    CC=gcc
+fi
+
+if [[ x"${CXX}" = x"" ]]; then
+    CXX=g++
+fi
+
+c_compiler=`which ${CC}`
+cxx_compiler=`which ${CXX}`
+cmake=`which cmake`
+
+if [ ! -x ${c_compiler} ]; then
+    die "cannot found c compiler"
+fi
+
+if [ ! -x ${cxx_compiler} ]; then
+    die "cannot found c++ compiler"
+fi
+
+if [ ! -x ${cmake} ]; then
+    die "cannot found cmake"
+fi
+
+# Configure 
+${cmake} -DCMAKE_BUILD_TYPE=${build_type} -DCMAKE_INSTALL_PREFIX=${prefix_dir} -DCMAKE_C_COMPILER=${c_compiler} -DCMAKE_CXX_COMPILER=${cxx_compiler} -DENABLE_COVERAGE=${enable_coverage} -DENABLE_AVX=${enable_avx_upper} ${source_dir} || die "failed to configure the project"
+
+echo 'bootstrap success. Run "make" to build.'
diff --git a/depends/univplan/src/CMakeLists.txt b/depends/univplan/src/CMakeLists.txt
new file mode 100644
index 0000000..f53e3a7
--- /dev/null
+++ b/depends/univplan/src/CMakeLists.txt
@@ -0,0 +1,77 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(univplan)
+
+FIND_PACKAGE(Protobuf REQUIRED)
+
+SET(univplan_VERSION_MAJOR 0)
+SET(univplan_VERSION_MINOR 1)
+SET(univplan_VERSION_PATCH 0)
+SET(univplan_VERSION_API 1)
+set(CMAKE_MACOSX_RPATH 1)
+
+SET(univplan_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+SET(univplan_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/univplan)
+SET(univplan_proto_DIR ${univplan_SRC_DIR}/proto)
+
+file(GLOB proto_files "${univplan_SRC_DIR}/proto/*.proto")
+set(proto_SRC_DIR ${CMAKE_BINARY_DIR}/src/univplan/proto)
+set(UNIVPLAN_PROTO_HDRS
+       ${proto_SRC_DIR}/universal-plan.pb.h
+       ${proto_SRC_DIR}/universal-plan-catalog.pb.h
+       ${proto_SRC_DIR}/universal-plan-expr.pb.h
+)
+set(UNIVPLAN_PROTO_SRCS
+       ${proto_SRC_DIR}/universal-plan.pb.cc
+       ${proto_SRC_DIR}/universal-plan-catalog.pb.cc
+       ${proto_SRC_DIR}/universal-plan-expr.pb.cc
+)
+file(MAKE_DIRECTORY ${proto_SRC_DIR})
+add_custom_command(
+       OUTPUT ${UNIVPLAN_PROTO_SRCS} ${UNIVPLAN_PROTO_HDRS}
+       COMMAND ${Protobuf_PROTOC_EXECUTABLE}
+       ARGS --cpp_out ${CMAKE_BINARY_DIR}/src -I ${CMAKE_CURRENT_SOURCE_DIR} ${proto_files}
+       DEPENDS "${proto_files}"
+       )
+
+AUTO_SOURCES(univplan_files "*.cc" "RECURSE" "${univplan_SRC_DIR}")
+LIST(APPEND univplan_SOURCES ${univplan_files})
+
+AUTO_SOURCES(univplanbuilder_HEADER "*.h" "${univplan_SRC_DIR}/univplanbuilder")
+AUTO_SOURCES(common_HEADER "*.h" "${univplan_SRC_DIR}/common")
+AUTO_SOURCES(cwrapper_HEADER "*.h" "${univplan_SRC_DIR}/cwrapper")
+AUTO_SOURCES(minmax_HEADER "*.h" "${univplan_SRC_DIR}/minmax")
+AUTO_SOURCES(testutil_HEADER "*.h" "${univplan_SRC_DIR}/testutil")
+
+INCLUDE_DIRECTORIES(${univplan_ROOT_DIR})
+INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/src)
+INCLUDE_DIRECTORIES(${DEPENDENCY_INSTALL_PREFIX}/package/include)
+
+LINK_DIRECTORIES(${DEPENDENCY_INSTALL_PREFIX}/package/lib)
+
+
+ADD_LIBRARY(univplan-shared SHARED
+            ${UNIVPLAN_PROTO_HDRS}
+            ${UNIVPLAN_PROTO_SRCS}
+            ${univplan_SOURCES}
+            )
+# ADD_LIBRARY(univplan-static STATIC ${univplan_SOURCES} ${UNIVPLAN_PROTO_SRCS} ${UNIVPLAN_PROTO_HDRS})
+
+SET_TARGET_PROPERTIES(univplan-shared PROPERTIES OUTPUT_NAME "univplan")
+# SET_TARGET_PROPERTIES(univplan-static PROPERTIES OUTPUT_NAME "univplan")
+
+target_link_libraries(univplan-shared ${CLANG_LDFLAGS} dbcommon glog protobuf pthread)
+# target_link_libraries(univplan-static ${CLANG_LDFLAGS} dbcommon glog protobuf pthread)
+
+INSTALL(TARGETS univplan-shared
+     RUNTIME DESTINATION bin
+     LIBRARY DESTINATION lib
+     ARCHIVE DESTINATION lib)
+
+INSTALL(FILES ${univplanbuilder_HEADER} DESTINATION include/univplan/univplanbuilder)
+INSTALL(FILES ${common_HEADER} DESTINATION include/univplan/common)
+INSTALL(FILES ${cwrapper_HEADER} DESTINATION include/univplan/cwrapper)
+INSTALL(FILES ${minmax_HEADER} DESTINATION include/univplan/minmax)
+INSTALL(FILES ${testutil_HEADER} DESTINATION include/univplan/testutil)
+INSTALL(FILES ${UNIVPLAN_PROTO_HDRS} DESTINATION include/univplan/proto)
+
+SET(univplan_ROOT_DIR ${univplan_ROOT_DIR} PARENT_SCOPE)
diff --git a/depends/univplan/src/univplan/common/expression.cc b/depends/univplan/src/univplan/common/expression.cc
new file mode 100644
index 0000000..afe6fbc
--- /dev/null
+++ b/depends/univplan/src/univplan/common/expression.cc
@@ -0,0 +1,730 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/common/expression.h"
+
+#include <algorithm>
+
+#include "dbcommon/common/tuple-batch.h"
+#include "dbcommon/common/vector/fixed-length-vector.h"
+#include "dbcommon/common/vector/list-vector.h"
+#include "dbcommon/common/vector/struct-vector.h"
+#include "dbcommon/common/vector/variable-length-vector.h"
+#include "dbcommon/function/func-kind.cg.h"
+#include "dbcommon/log/logger.h"
+#include "dbcommon/type/array.h"
+#include "dbcommon/type/type-util.h"
+
+namespace univplan {
+
+dbcommon::SelectList *ExprState::convertSelectList(const dbcommon::Datum &d,
+                                                   ExprContext *context) {
+  dbcommon::Object *obj = dbcommon::DatumGetValue<dbcommon::Object *>(d);
+  dbcommon::SelectList *sel = nullptr;
+  dbcommon::BooleanVector *vec = nullptr;
+  dbcommon::Scalar *val = nullptr;
+
+  if ((sel = dynamic_cast<dbcommon::SelectList *>(obj)) == nullptr) {
+    if (convertedSelectlist == nullptr)
+      convertedSelectlist.reset(new dbcommon::SelectList);
+    sel = convertedSelectlist.get();
+    if ((vec = dynamic_cast<dbcommon::BooleanVector *>(obj)) != nullptr) {
+      sel->fromVector(vec);
+    } else if ((val = dynamic_cast<dbcommon::Scalar *>(obj)) != nullptr) {
+      sel->clear();
+      if (val->getBoolValue()) {
+        auto size = context->getNumOfRows();
+        sel->resize(size);
+        for (auto i = 0; i < size; i++) (*sel)[i] = i;
+      }
+    } else {
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "Supposed to be SelectList or BooleanVector or Const");
+    }
+  }
+  return sel;
+}
+
+ListExprState::ListExprState(const univplan::UnivPlanExprPolyList *exprs) {
+  for (int i = 0; i < exprs->size(); ++i) {
+    args.push_back(InitExpr(&exprs->Get(i)));
+  }
+}
+
+dbcommon::Datum ListExprState::calc(ExprContext *context) {
+  dbcommon::SelectList *result = nullptr;
+
+  for (ExprState::uptr &e : args) {
+    dbcommon::Datum d = e->calc(context);
+    dbcommon::SelectList *sel = convertSelectList(d, context);
+
+    if (result) {
+      retval.resize(result->size() + sel->size());
+      auto end =
+          std::set_intersection(result->begin(), result->end(), sel->begin(),
+                                sel->end(), retval.begin());
+      retval.resize(end - retval.begin());
+      result->swap(retval);
+    } else {
+      result = sel;
+    }
+  }
+
+  return dbcommon::CreateDatum(result);
+}
+
+dbcommon::Datum VarExprState::calc(ExprContext *context) {
+  int32_t columnIndex = var->varattno() - 1;
+
+  dbcommon::TupleBatch *batch = nullptr;
+  if (var->varno() == INNER_VAR) {
+    batch = context->innerBatch;
+  } else if (var->varno() == OUTER_VAR) {
+    batch = context->outerBatch;
+  } else {
+    batch = context->scanBatch;
+  }
+
+  if (context->tupleIterValid() && !batch->isScalarTupleBatch()) {
+    batch->getColumn(columnIndex)->readPlainScalar(context->tupleIdx, &scalar);
+    return dbcommon::CreateDatum<dbcommon::Scalar *>(&scalar);
+  }
+
+  dbcommon::Vector *ret;
+
+  if (columnIndex >= 0) {
+    // Case 1. Relation attribute
+    ret = batch->getColumn(columnIndex);
+  } else {
+    // Case 2. System attribute
+    LOG_ERROR(
+        ERRCODE_FEATURE_NOT_SUPPORTED,
+        "System attribute is not supported in univplan::VarExprState::calc");
+  }
+
+  return CreateDatum(ret);
+}
+
+ConstExprState::ConstExprState(const univplan::UnivPlanConst *val)
+    : scalar(dbcommon::Datum()) {
+  retType = univplan::PlanNodeUtil::typeKindMapping(val->type());
+  retTypeMod = val->typemod();
+  if (val->isnull()) {
+    scalar.isnull = true;
+  } else if (univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::TIMESTAMPID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::TIMESTAMPTZID) {
+    scalar.value = dbcommon::CreateDatum(
+        val->value().c_str(), &ts,
+        univplan::PlanNodeUtil::typeKindMapping(val->type()));
+  } else if (univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::DECIMALID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::DECIMALNEWID) {
+    dbcommon::DecimalType t;
+    decimalReg = t.fromString(val->value().c_str());
+    scalar.value = dbcommon::CreateDatum(&decimalReg);
+  } else if (univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+             dbcommon::TypeKind::INTERVALID) {
+    intervalReg = dbcommon::IntervalType::fromString(val->value().c_str());
+    scalar.value = dbcommon::CreateDatum(&intervalReg);
+  } else if (univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::BINARYID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::IOBASETYPEID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::STRUCTEXID) {
+    auto srcStr = val->value().c_str();
+    auto srcLen = val->value().size();
+    uint32_t dstLen = 0;
+    binary.resize(srcLen + sizeof(dstLen));
+    for (auto i = 0; i < srcLen;) {
+      if (srcStr[i] != '\\') {
+        binary[dstLen++] = srcStr[i];
+        i += 1;
+      } else if (srcStr[i + 1] == '\\') {
+        binary[dstLen++] = '\\';
+        i += 2;
+      } else {
+        binary[dstLen++] = (srcStr[i + 1] - '0') * 64 +
+                           (srcStr[i + 2] - '0') * 8 + (srcStr[i + 3] - '0');
+        i += 4;
+      }
+    }
+    scalar.value = dbcommon::CreateDatum<char *>(&binary[0]);
+    scalar.length = dstLen;
+  } else if (univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::SMALLINTARRAYID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::INTARRAYID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::BIGINTARRAYID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::FLOATARRAYID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::DOUBLEARRAYID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::STRINGARRAYID ||
+             univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+                 dbcommon::TypeKind::BPCHARARRAYID) {
+    auto typeEnt = reinterpret_cast<dbcommon::ArrayType *>(
+        dbcommon::TypeUtil::instance()
+            ->getTypeEntryById(
+                univplan::PlanNodeUtil::typeKindMapping(val->type()))
+            ->type.get());
+    array = std::move(typeEnt->getScalarFromString(val->value()));
+    scalar.value = dbcommon::CreateDatum(array.get());
+  } else {
+    scalar.value = dbcommon::CreateDatum(
+        val->value().c_str(),
+        univplan::PlanNodeUtil::typeKindMapping(val->type()));
+  }
+
+  if (univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+          dbcommon::TypeKind::STRINGID ||
+      univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+          dbcommon::TypeKind::VARCHARID ||
+      univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+          dbcommon::TypeKind::CHARID ||
+      univplan::PlanNodeUtil::typeKindMapping(val->type()) ==
+          dbcommon::TypeKind::DECIMALNEWID) {
+    scalar.length = val->value().length();
+  }
+}
+
+dbcommon::Datum ConstExprState::calc(ExprContext *context) {
+  return dbcommon::CreateDatum(&scalar);
+}
+
+OpExprState::OpExprState(const univplan::UnivPlanOpExpr *op)
+    : invoker(univplan::PlanNodeUtil::funcKindMapping(op->funcid())) {
+  const dbcommon::FuncEntry *entry =
+      dbcommon::Func::instance()->getFuncEntryById(
+          univplan::PlanNodeUtil::funcKindMapping(op->funcid()));
+  retType = entry->retType;
+}
+
+OpExprState::OpExprState(dbcommon::FuncKind funcId) : invoker(funcId) {
+  const dbcommon::FuncEntry *entry =
+      dbcommon::Func::instance()->getFuncEntryById(
+          univplan::PlanNodeUtil::funcKindMapping(funcId));
+  retType = entry->retType;
+}
+
+dbcommon::Datum OpExprState::calc(ExprContext *context) {
+  invoker.resetPrarmeter();
+  invoker.addParam(dbcommon::CreateDatum(0));
+
+  assert(args.size() == 2 || args.size() == 1);
+  for (ExprState::uptr &arg : args) {
+    invoker.addParam(arg->calc(context));
+  }
+  if (retval) {
+    retval->clear();
+  } else {
+    bool isRetvalVector = true;
+    if (args.size() == 2) {
+      dbcommon::Object *paraL =
+          dbcommon::DatumGetValue<dbcommon::Object *>(invoker.getParam(1));
+      dbcommon::Vector *vecL = dynamic_cast<dbcommon::Vector *>(paraL);
+      dbcommon::Object *paraR =
+          dbcommon::DatumGetValue<dbcommon::Object *>(invoker.getParam(2));
+      dbcommon::Vector *vecR = dynamic_cast<dbcommon::Vector *>(paraR);
+      isRetvalVector = vecL || vecR;
+    } else if (args.size() == 1) {
+      dbcommon::Object *para =
+          dbcommon::DatumGetValue<dbcommon::Object *>(invoker.getParam(1));
+      isRetvalVector = dynamic_cast<dbcommon::Vector *>(para);
+    }
+
+    if (isRetvalVector) {
+      if (retType == dbcommon::TypeKind::BOOLEANID)
+        retval = std::unique_ptr<dbcommon::Object>(new dbcommon::SelectList);
+      else
+        retval = dbcommon::Vector::BuildVector(retType, true, retTypeMod);
+    } else {
+      retval = std::unique_ptr<dbcommon::Object>(new dbcommon::Scalar);
+    }
+  }
+  invoker.setParam(0, dbcommon::CreateDatum<dbcommon::Object *>(retval.get()));
+
+  return invoker.invoke();
+}
+
+dbcommon::Datum FuncExprState::calc(ExprContext *context) {
+  invoker.resetPrarmeter();
+  invoker.addParam(dbcommon::CreateDatum(0));
+
+  for (ExprState::uptr &arg : args) {
+    invoker.addParam(arg->calc(context));
+  }
+
+  if (retval) {
+    retval->clear();
+  } else {
+    bool isVecFunc = false;
+    for (size_t i = 1; i <= args.size(); i++) {
+      dbcommon::Object *para =
+          dbcommon::DatumGetValue<dbcommon::Object *>(invoker.getParam(i));
+      dbcommon::Vector *vec = dynamic_cast<dbcommon::Vector *>(para);
+      if (vec) {
+        isVecFunc = true;
+        break;
+      }
+    }
+    if (func->funcid() == dbcommon::FuncKind::RANDOMF) isVecFunc = true;
+    if (!isVecFunc) {
+      retval = std::unique_ptr<dbcommon::Object>(new dbcommon::Scalar);
+    } else {
+      dbcommon::TypeKind rettype =
+          univplan::PlanNodeUtil::typeKindMapping(func->rettype());
+      if (rettype == dbcommon::TypeKind::BOOLEANID)
+        retval = std::unique_ptr<dbcommon::Object>(new dbcommon::SelectList);
+      else
+        retval = dbcommon::Vector::BuildVector(rettype, true);
+    }
+  }
+  invoker.setParam(0, dbcommon::CreateDatum<dbcommon::Object *>(retval.get()));
+  if (func->funcid() == dbcommon::FuncKind::RANDOMF) {
+    invoker.addParam(dbcommon::CreateDatum(context->outerBatch != nullptr
+                                               ? context->outerBatch
+                                               : context->scanBatch));
+  }
+
+  return invoker.invoke();
+}
+
+dbcommon::Datum NullTestState::calc(ExprContext *context) {
+  assert(args.size() == 1);
+
+  auto obj =
+      dbcommon::DatumGetValue<dbcommon::Object *>(args[0]->calc(context));
+
+  if (auto scalar = dynamic_cast<dbcommon::Scalar *>(obj)) {
+    scalarResult_.value = dbcommon::CreateDatum<bool>(scalar->isnull == isNull);
+    return dbcommon::CreateDatum(&scalarResult_);
+  } else {
+    auto vec = reinterpret_cast<dbcommon::Vector *>(obj);
+    size_t size = vec->getNumOfRows();
+    result.resize(0);
+
+    for (size_t i = 0; i < size; ++i) {
+      bool null = vec->isNull(i);
+
+      if (null == isNull) {
+        result.push_back(vec->getPlainIndex(i));
+      }
+    }
+  }
+
+  return dbcommon::CreateDatum(&result);
+}
+
+dbcommon::Datum BooleanTestState::calc(ExprContext *context) {
+  assert(args.size() == 1);
+  for (ExprState::uptr &arg : args) {
+    dbcommon::Vector *vec =
+        dbcommon::DatumGetValue<dbcommon::Vector *>(arg->calc(context));
+
+    size_t size = vec->getNumOfRows();
+    result.reset(new dbcommon::SelectList);
+    result->reserve(size);
+
+    const bool *val = reinterpret_cast<const bool *>(vec->getValue());
+    for (size_t i = 0; i < size; ++i) {
+      uint64_t index = vec->getPlainIndex(i);
+      bool null = vec->isNullPlain(index);
+      if (op->type() == univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_TRUE) {
+        if (!null && val[index]) result->push_back(index);
+      } else if (op->type() ==
+                 univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_NOT_TRUE) {
+        if (null || !val[index]) result->push_back(index);
+      } else if (op->type() == univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_FALSE) {
+        if (!null && !val[index]) result->push_back(index);
+      } else if (op->type() ==
+                 univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_NOT_FALSE) {
+        if (null || val[index]) result->push_back(index);
+      } else if (op->type() ==
+                 univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_UNKNOWN) {
+        if (null) result->push_back(index);
+      } else {
+        assert(op->type() ==
+               univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_NOT_UNKNOWN);
+        if (!null) result->push_back(index);
+      }
+    }
+  }
+
+  return dbcommon::CreateDatum(result.get());
+}
+
+dbcommon::Datum BoolExprState::calc(ExprContext *context) {
+  if (op == univplan::BOOLEXPRTYPE::BOOLEXPRTYPE_OR_EXPR) {
+    return calcOr(context);
+  } else if (op == univplan::BOOLEXPRTYPE::BOOLEXPRTYPE_NOT_EXPR) {
+    return calcNot(context);
+  } else {
+    assert(op == univplan::BOOLEXPRTYPE::BOOLEXPRTYPE_AND_EXPR);
+    return calcAnd(context);
+  }
+}
+
+dbcommon::Datum BoolExprState::calcAnd(ExprContext *context) {
+  assert(args.size() >= 2);
+  backupSel_ = context->releaseSelected();
+  dbcommon::SelectList *backupSel = context->getSelectList();
+
+  dbcommon::Object *para0 = args[0]->calc(context);
+  if (dynamic_cast<dbcommon::Scalar *>(para0))
+    LOG_ERROR(ERRCODE_FEATURE_NOT_SUPPORTED, "Feature not supported");
+
+  if (dynamic_cast<dbcommon::SelectList *>(para0)) {
+    if (retval == nullptr)
+      retval =
+          dbcommon::Vector::BuildVector(dbcommon::TypeKind::BOOLEANID, true);
+    reinterpret_cast<dbcommon::SelectList *>(para0)->toVector(
+        reinterpret_cast<dbcommon::Vector *>(retval.get()));
+  } else {
+    retval =
+        reinterpret_cast<dbcommon::Vector *>(para0)->cloneSelected(nullptr);
+  }
+
+  dbcommon::Vector *retVector =
+      reinterpret_cast<dbcommon::Vector *>(retval.get());
+
+  std::unique_ptr<dbcommon::Vector> tmpVectorBackup;
+
+  for (auto i = 1; i < args.size(); i++) {
+    auto &it = args[i];
+    dbcommon::Object *para = it->calc(context);
+
+    auto lhsVector = retVector->cloneSelected(nullptr);
+    dbcommon::Vector *rhsVector = reinterpret_cast<dbcommon::Vector *>(para);
+
+    if (dynamic_cast<dbcommon::Scalar *>(para))
+      LOG_ERROR(ERRCODE_FEATURE_NOT_SUPPORTED, "Feature not supported");
+
+    if (auto sel = dynamic_cast<dbcommon::SelectList *>(para)) {
+      if (tmpVectorBackup == nullptr)
+        tmpVectorBackup =
+            dbcommon::Vector::BuildVector(dbcommon::TypeKind::BOOLEANID, true);
+      rhsVector = tmpVectorBackup.get();
+      sel->toVector(rhsVector);
+    }
+
+    dbcommon::FixedSizeTypeVectorRawData<bool> lhs(lhsVector.get());
+    dbcommon::FixedSizeTypeVectorRawData<bool> rhs(rhsVector);
+    retVector->resize(context->getNumOfRowsPlain(), nullptr, lhs.nulls,
+                      rhs.nulls);
+    dbcommon::FixedSizeTypeVectorRawData<bool> ret(retVector);
+    auto setBoolean = [&](uint64_t plainIdx) {
+      ret.values[plainIdx] = lhs.values[plainIdx] & rhs.values[plainIdx];
+    };
+    dbcommon::transformVector(ret.plainSize, nullptr, nullptr, setBoolean);
+
+    if (ret.nulls) {
+      auto setNullFromLhs = [&](uint64_t plainIdx) {
+        if (lhs.values[plainIdx] == false)
+          const_cast<bool *>(ret.nulls)[plainIdx] = false;
+      };
+      dbcommon::transformVector(ret.plainSize, nullptr, lhs.nulls,
+                                setNullFromLhs);
+
+      auto setNullFromRhs = [&](uint64_t plainIdx) {
+        if (rhs.values[plainIdx] == false)
+          const_cast<bool *>(ret.nulls)[plainIdx] = false;
+      };
+      dbcommon::transformVector(ret.plainSize, nullptr, rhs.nulls,
+                                setNullFromRhs);
+    }
+  }
+
+  context->setSelected(backupSel);
+  auto retsel = convertSelectList(dbcommon::CreateDatum(retVector), context);
+  return dbcommon::CreateDatum(retsel);
+}
+
+dbcommon::Datum BoolExprState::calcOr(ExprContext *context) {
+  assert(args.size() >= 2);
+  backupSel_ = context->releaseSelected();
+  dbcommon::SelectList *backupSel = context->getSelectList();
+  if (retval == nullptr) retval.reset(new dbcommon::SelectList);
+  retval->clear();
+  dbcommon::SelectList *retsel =
+      static_cast<dbcommon::SelectList *>(retval.get());
+  retsel->setPlainSize(0);
+
+  dbcommon::Datum d = args[0]->calc(context);
+  dbcommon::SelectList *sel = convertSelectList(d, context);
+  *retsel = *sel;
+
+  for (auto i = 1; i < args.size(); i++) {
+    auto &it = args[i];
+    dbcommon::Datum d = it->calc(context);
+    dbcommon::SelectList *sel = convertSelectList(d, context);
+
+    dbcommon::SelectList tmp = *retsel;
+
+    retsel->resize(tmp.size() + sel->size());
+    auto end = std::set_union(tmp.begin(), tmp.end(), sel->begin(), sel->end(),
+                              retsel->begin());
+    retsel->resize(end - retsel->begin());
+    retsel->setNulls(context->getNumOfRowsPlain(), nullptr, tmp.getNulls(),
+                     sel->getNulls());
+  }
+  retsel->setNulls(context->getNumOfRowsPlain(), retsel, false);
+
+  context->setSelected(backupSel);
+  return dbcommon::CreateDatum(retval.get());
+}
+
+dbcommon::Datum BoolExprState::calcNot(ExprContext *context) {
+  assert(args.size() == 1);
+  backupSel_ = context->releaseSelected();
+  dbcommon::SelectList *backupSel = context->getSelectList();
+  dbcommon::Datum d = args.front()->calc(context);
+
+  if (auto sel = dynamic_cast<dbcommon::SelectList *>(
+          dbcommon::DatumGetValue<dbcommon::Object *>(d))) {
+    if (retval == nullptr) retval.reset(new dbcommon::SelectList);
+    auto retsel = reinterpret_cast<dbcommon::SelectList *>(retval.get());
+    *retsel = sel->getComplement(context->getNumOfRowsPlain());
+    retsel->setNulls(context->getNumOfRowsPlain(), nullptr, sel->getNulls());
+
+    if (backupSel) {
+      auto end = std::set_intersection(retsel->begin(), retsel->end(),
+                                       backupSel->begin(), backupSel->end(),
+                                       retsel->begin());
+      retsel->resize(end - retsel->begin());
+    }
+  } else if (dbcommon::BooleanVector *vec =
+                 dynamic_cast<dbcommon::BooleanVector *>(
+                     dbcommon::DatumGetValue<dbcommon::Object *>(d))) {
+    if (retval == nullptr) retval.reset(new dbcommon::SelectList);
+    auto retsel = reinterpret_cast<dbcommon::SelectList *>(retval.get());
+    dbcommon::SelectList tmp;
+    tmp.fromVector(vec);
+    *retsel = tmp.getComplement(context->getNumOfRowsPlain());
+    retsel->setNulls(context->getNumOfRowsPlain(), nullptr, tmp.getNulls());
+
+    if (backupSel) {
+      auto end = std::set_intersection(retsel->begin(), retsel->end(),
+                                       backupSel->begin(), backupSel->end(),
+                                       retsel->begin());
+      retsel->resize(end - retsel->begin());
+    }
+  } else {
+    dbcommon::Scalar *scalar = static_cast<dbcommon::Scalar *>(
+        dbcommon::DatumGetValue<dbcommon::Object *>(d));
+    if (scalar->value.value.i8)
+      scalar->value.value.i8 = 0;
+    else
+      scalar->value.value.i8 = 1;
+    retval.reset(new dbcommon::Scalar(*scalar));
+  }
+
+  context->setSelected(backupSel);
+  return dbcommon::CreateDatum(retval.get());
+}
+
+ExprState::uptr InitExpr(const univplan::UnivPlanExprPolyList *exprs) {
+  return ExprState::uptr(new ListExprState(exprs));
+}
+
+ExprState::uptr InitExpr(const univplan::UnivPlanExprPoly *expr) {
+  switch (expr->type()) {
+    case univplan::UNIVPLAN_EXPR_VAR:
+      return ExprState::uptr(new VarExprState(&expr->var()));
+    case univplan::UNIVPLAN_EXPR_CONST:
+      return ExprState::uptr(new ConstExprState(&expr->val()));
+    case univplan::UNIVPLAN_EXPR_TARGETENTRY:
+      return InitExpr(&expr->targetentry().expression());
+    case univplan::UNIVPLAN_EXPR_OPEXPR: {
+      const univplan::UnivPlanOpExpr &op = expr->opexpr();
+      bool predictable =
+          dbcommon::Func::instance()
+              ->getFuncEntryById(static_cast<dbcommon::FuncKind>(op.funcid()))
+              ->predictable;
+      if (!predictable)
+        LOG_ERROR(ERRCODE_INTERNAL_ERROR, "FuncExpr %d is not predictable",
+                  op.funcid());
+      OpExprState::uptr retval(new OpExprState(&op));
+      for (int i = 0; i < op.args_size(); ++i)
+        retval->addArg(InitExpr(&op.args(i)));
+      return std::move(retval);
+    }
+    case univplan::UNIVPLAN_EXPR_FUNCEXPR: {
+      const univplan::UnivPlanFuncExpr &func = expr->funcexpr();
+      bool predictable =
+          dbcommon::Func::instance()
+              ->getFuncEntryById(static_cast<dbcommon::FuncKind>(func.funcid()))
+              ->predictable;
+      if (!predictable)
+        LOG_ERROR(ERRCODE_INTERNAL_ERROR, "FuncExpr %d is not predictable",
+                  func.funcid());
+      FuncExprState::uptr retval(new FuncExprState(&func));
+      for (int i = 0; i < func.args_size(); ++i)
+        retval->addArg(InitExpr(&func.args(i)));
+      return std::move(retval);
+    }
+    case univplan::UNIVPLAN_EXPR_NULLTEST: {
+      const univplan::UnivPlanNullTest &op = expr->nulltest();
+      NullTestState::uptr retval(new NullTestState(&op));
+      retval->addArg(InitExpr(&op.arg()));
+      return std::move(retval);
+    }
+    case univplan::UNIVPLAN_EXPR_BOOLEANTEST: {
+      const univplan::UnivPlanBooleanTest &op = expr->booltest();
+      BooleanTestState::uptr retval(new BooleanTestState(&op));
+      retval->addArg(InitExpr(&op.arg()));
+      return std::move(retval);
+    }
+    case univplan::UNIVPLAN_EXPR_BOOLEXPR: {
+      const univplan::UnivPlanBoolExpr &op = expr->boolexpr();
+      BoolExprState::uptr retval(new BoolExprState(&op));
+      for (int i = 0; i < op.args_size(); ++i)
+        retval->addArg(InitExpr(&op.args(i)));
+      return std::move(retval);
+    }
+    default:
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR, "expr type %d is not predictable",
+                expr->type());
+  }
+  return nullptr;
+}
+
+bool do_opexpr2(int col, const univplan::UnivPlanOpExpr &op,
+                std::vector<std::unique_ptr<IndexExpr> > &allExpr,    // NOLINT
+                std::vector<std::unique_ptr<IndexExpr> > &equalExpr,  // NOLINT
+                int *equal) {
+  std::unique_ptr<IndexExpr> idx(new IndexExpr());
+  const univplan::UnivPlanVar &var = op.args(0).var();
+  int att = var.varattno();
+  int typeId = var.typeid_();
+  if (typeId == dbcommon::TypeKind::DECIMALID ||
+      typeId == dbcommon::TypeKind::BOOLEANID) {
+    return false;
+  }
+  int modify = var.typemod();
+  std::string funcName =
+      dbcommon::Func::instance()
+          ->getFuncEntryById(static_cast<dbcommon::FuncKind>(op.funcid()))
+          ->funcName;
+  if (att - 1 == col &&
+      (!(dbcommon::StringUtil::countReplicates(funcName, "not_equal") == 1))) {
+    const univplan::UnivPlanConst &con = op.args(1).val();
+    idx->colidx = att;
+    idx->typeId = typeId;
+    idx->oper = funcName;
+    idx->constVal = con.value();
+    idx->typeModify = modify;
+    if (!(dbcommon::StringUtil::countReplicates(funcName, "equal") == 1)) {
+      allExpr.push_back(std::move(idx));
+      *equal = 0;
+    } else {
+      equalExpr.push_back(std::move(idx));
+      *equal = 1;
+    }
+    return true;
+  }
+  return false;
+}
+
+bool do_boolexpr2(
+    int pk, const univplan::UnivPlanBoolExpr &expr,
+    std::vector<std::unique_ptr<IndexExpr> > &allExpr,    // NOLINT
+    std::vector<std::unique_ptr<IndexExpr> > &equalExpr,  // NOLINT
+    int *equal) {
+  int args_size = expr.args_size();
+  bool hasExpr = false;
+  for (int i = 0; i < args_size; ++i) {
+    const univplan::UnivPlanExprPoly &op = expr.args(i);
+    switch (op.type()) {
+      case univplan::UNIVPLAN_EXPR_OPEXPR: {
+        const univplan::UnivPlanOpExpr &opex = op.opexpr();
+        bool has = do_opexpr2(pk, opex, allExpr, equalExpr, equal);
+        if (*equal == 1) return true;
+        if (has) hasExpr = true;
+        break;
+      }
+      case univplan::UNIVPLAN_EXPR_BOOLEXPR: {
+        const univplan::UnivPlanBoolExpr &opex = op.boolexpr();
+        bool has = do_boolexpr2(pk, opex, allExpr, equalExpr, equal);
+        if (*equal == 1) return true;
+        if (has) hasExpr = true;
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  return hasExpr;
+}
+
+bool loopContinue(
+    int pkCol, const univplan::UnivPlanExprPolyList *filterExprs,
+    std::vector<std::unique_ptr<IndexExpr> > &allExpr,      // NOLINT
+    std::vector<std::unique_ptr<IndexExpr> > &equalExpr) {  // NOLINT
+  int filterSize = filterExprs->size();
+  assert(filterSize > 0);
+  bool hasExpr = false;
+  for (int i = 0; i < filterSize; ++i) {
+    const univplan::UnivPlanExprPoly &ep = filterExprs->Get(i);
+    switch (ep.type()) {
+      case univplan::UNIVPLAN_EXPR_OPEXPR: {
+        const univplan::UnivPlanOpExpr &op = ep.opexpr();
+        int equal = 0;
+        bool has = do_opexpr2(pkCol, op, allExpr, equalExpr, &equal);
+        if (equal == 1) return true;
+        if (has) hasExpr = true;
+        break;
+      }
+      case univplan::UNIVPLAN_EXPR_BOOLEXPR: {
+        const univplan::UnivPlanBoolExpr &op = ep.boolexpr();
+        if (op.type() == univplan::BOOLEXPRTYPE::BOOLEXPRTYPE_AND_EXPR) {
+          int equal = 0;
+          bool has = do_boolexpr2(pkCol, op, allExpr, equalExpr, &equal);
+          if (equal == 1) return true;
+          if (has) hasExpr = true;
+        }
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  return hasExpr;
+}
+
+std::vector<std::vector<std::unique_ptr<IndexExpr> > > getIndexExpr2(
+    const std::vector<int> &index,
+    const univplan::UnivPlanExprPolyList *filterExprs) {
+  std::vector<std::vector<std::unique_ptr<IndexExpr> > > indexExprVec;
+  int indexSize = index.size();
+  assert(indexSize > 0);
+  for (int i = 0; i < indexSize; ++i) {
+    int col = index[i];
+    std::vector<std::unique_ptr<IndexExpr> > allExpr;
+    std::vector<std::unique_ptr<IndexExpr> > equalExpr;
+    bool loop = loopContinue(col, filterExprs, allExpr, equalExpr);
+    if (!loop) return indexExprVec;
+    int equalSize = equalExpr.size();
+    int allSize = allExpr.size();
+    if (equalSize > 0) {
+      indexExprVec.push_back(std::move(equalExpr));
+      continue;
+    } else {
+      if (allSize > 0) {
+        indexExprVec.push_back(std::move(allExpr));
+        return indexExprVec;
+      }
+    }
+  }
+  return indexExprVec;
+}
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/common/expression.h b/depends/univplan/src/univplan/common/expression.h
new file mode 100644
index 0000000..a27db06
--- /dev/null
+++ b/depends/univplan/src/univplan/common/expression.h
@@ -0,0 +1,338 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_COMMON_EXPRESSION_H_
+#define UNIVPLAN_SRC_UNIVPLAN_COMMON_EXPRESSION_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "dbcommon/function/invoker.h"
+#include "dbcommon/type/decimal.h"
+#include "dbcommon/type/interval.h"
+#include "dbcommon/utils/string-util.h"
+
+#include "univplan/common/plannode-util.h"
+
+namespace dbcommon {
+class TupleBatch;
+}
+
+namespace univplan {
+
+class ExprContext {
+ public:
+  ExprContext()
+      : innerBatch(nullptr), outerBatch(nullptr), scanBatch(nullptr) {}
+  ExprContext(dbcommon::TupleBatch *outerBatch,
+              dbcommon::TupleBatch *innerBatch, dbcommon::TupleBatch *scanBatch)
+      : outerBatch(outerBatch), innerBatch(innerBatch), scanBatch(scanBatch) {
+    assert((scanBatch && !innerBatch && !outerBatch) ||
+           (outerBatch && !innerBatch && !scanBatch) ||
+           (innerBatch && outerBatch && !scanBatch));
+  }
+
+  dbcommon::TupleBatch *innerBatch;
+  dbcommon::TupleBatch *outerBatch;
+  dbcommon::TupleBatch *scanBatch;
+
+  // Iterator of plain index for processing input tuple by tuple rather than TB
+  // by TB
+  uint64_t tupleIdx = -1;
+  bool tupleIterValid() { return tupleIdx != -1; }
+  void setTupleIter(uint64_t tupleIdx) { this->tupleIdx = tupleIdx; }
+  void disableTupleIter() { tupleIdx = -1; }
+
+ public:
+  void setSelected(dbcommon::SelectList *selected) {
+    if (innerBatch) innerBatch->setSelected(selected);
+    if (outerBatch) outerBatch->setSelected(selected);
+    if (scanBatch) scanBatch->setSelected(selected);
+  }
+
+  std::unique_ptr<dbcommon::SelectList> releaseSelected() {
+    if (innerBatch) return innerBatch->releaseSelected();
+    if (outerBatch) return outerBatch->releaseSelected();
+    if (scanBatch) return scanBatch->releaseSelected();
+    return nullptr;
+  }
+
+  size_t getNumOfRows() {
+    if (innerBatch) return innerBatch->getNumOfRows();
+    if (outerBatch) return outerBatch->getNumOfRows();
+    if (scanBatch) return scanBatch->getNumOfRows();
+
+    // tupleCount=1 special for constant select
+    return 1;
+  }
+
+  size_t getNumOfRowsPlain() {
+    if (innerBatch) return innerBatch->getNumOfRowsPlain();
+    if (outerBatch) return outerBatch->getNumOfRowsPlain();
+    if (scanBatch) return scanBatch->getNumOfRowsPlain();
+
+    // tupleCount=1 special for constant select
+    return 1;
+  }
+
+  dbcommon::SelectList *getSelectList() {
+    if (innerBatch && innerBatch->getSelected())
+      return innerBatch->getSelected();
+    if (outerBatch && outerBatch->getSelected())
+      return outerBatch->getSelected();
+    if (scanBatch && scanBatch->getSelected()) return scanBatch->getSelected();
+    return nullptr;
+  }
+};
+
+class ExprState {
+ public:
+  ExprState() {}
+  virtual ~ExprState() {}
+
+  typedef std::unique_ptr<ExprState> uptr;
+
+  virtual dbcommon::Datum calc(ExprContext *context) = 0;
+
+  dbcommon::SelectList *convertSelectList(const dbcommon::Datum &d,
+                                          ExprContext *context);
+
+  dbcommon::TypeKind getRetType() { return retType; }
+
+  int64_t getRetTypeModifier() { return retTypeMod; }
+
+  void addArg(ExprState::uptr arg) { args.push_back(std::move(arg)); }
+
+  ExprState *getArg(size_t idx) { return args[idx].get(); }
+
+ protected:
+  dbcommon::TypeKind retType = dbcommon::TypeKind::UNKNOWNID;
+  int64_t retTypeMod = -1;
+  std::vector<ExprState::uptr> args;
+
+  // When relying on current ExprContext's SelectList content, ExprState should
+  // backup the SelectList.
+  std::unique_ptr<dbcommon::SelectList> backupSel_;
+
+ private:
+  std::unique_ptr<dbcommon::SelectList> convertedSelectlist;
+};
+
+class ListExprState : public ExprState {
+ public:
+  explicit ListExprState(const univplan::UnivPlanExprPolyList *exprs);
+  ~ListExprState() {}
+
+  typedef std::unique_ptr<ListExprState> uptr;
+
+  dbcommon::Datum calc(ExprContext *context) override;
+
+ private:
+  dbcommon::SelectList retval;
+};
+
+class VarExprState : public ExprState {
+ public:
+  explicit VarExprState(const univplan::UnivPlanVar *var) : var(var) {
+    retType = univplan::PlanNodeUtil::typeKindMapping(var->typeid_());
+    retTypeMod = var->typemod();
+  }
+  ~VarExprState() {}
+
+  typedef std::unique_ptr<VarExprState> uptr;
+
+  dbcommon::Datum calc(ExprContext *context) override;
+
+  int32_t getAttributeNumber() const { return var->varattno(); }
+
+  uint32_t getVarNo() const { return var->varno(); }
+
+ private:
+  const univplan::UnivPlanVar *var;
+  // iterator for processing input tuple by tuple
+  dbcommon::Scalar scalar;
+};
+
+class ConstExprState : public ExprState {
+ public:
+  explicit ConstExprState(const univplan::UnivPlanConst *val);
+  ~ConstExprState() {}
+
+  typedef std::unique_ptr<ConstExprState> uptr;
+
+  dbcommon::Datum calc(ExprContext *context) override;
+
+ private:
+  dbcommon::Scalar scalar;
+  dbcommon::Timestamp ts;
+  dbcommon::DecimalVar decimalReg;
+  dbcommon::IntervalVar intervalReg;
+  std::vector<char> binary;
+  dbcommon::Vector::uptr array;
+};
+
+class OpExprState : public ExprState {
+ public:
+  explicit OpExprState(const univplan::UnivPlanOpExpr *op);
+  explicit OpExprState(dbcommon::FuncKind funcId);
+  ~OpExprState() {}
+
+  typedef std::unique_ptr<OpExprState> uptr;
+
+  dbcommon::Datum calc(ExprContext *context) override;
+
+ private:
+  dbcommon::Invoker invoker;
+  std::unique_ptr<dbcommon::Object> retval;
+};
+
+class FuncExprState : public ExprState {
+ public:
+  explicit FuncExprState(const univplan::UnivPlanFuncExpr *func)
+      : func(func),
+        invoker(univplan::PlanNodeUtil::funcKindMapping(func->funcid())) {}
+  ~FuncExprState() {}
+
+  typedef std::unique_ptr<FuncExprState> uptr;
+
+  dbcommon::Datum calc(ExprContext *context) override;
+
+ private:
+  const univplan::UnivPlanFuncExpr *func;
+  dbcommon::Invoker invoker;
+  std::unique_ptr<dbcommon::Object> retval;
+};
+
+class NullTestState : public ExprState {
+ public:
+  explicit NullTestState(const univplan::UnivPlanNullTest *op)
+      : op(op),
+        isNull(op->type() == univplan::NULLTESTTYPE::NULLTESTTYPE_IS_NULL) {}
+
+  explicit NullTestState(bool isNull) : op(nullptr), isNull(isNull) {}
+
+  ~NullTestState() {}
+
+  typedef std::unique_ptr<NullTestState> uptr;
+
+  dbcommon::Datum calc(ExprContext *context) override;
+
+ private:
+  const univplan::UnivPlanNullTest *op;
+  bool isNull;
+  dbcommon::SelectList result;
+  dbcommon::Scalar scalarResult_;
+};
+
+class BooleanTestState : public ExprState {
+ public:
+  explicit BooleanTestState(const univplan::UnivPlanBooleanTest *op) : op(op) {}
+  ~BooleanTestState() {}
+
+  typedef std::unique_ptr<BooleanTestState> uptr;
+
+  dbcommon::Datum calc(ExprContext *context) override;
+
+ private:
+  const univplan::UnivPlanBooleanTest *op;
+  std::unique_ptr<dbcommon::SelectList> result;
+};
+
+class BoolExprState : public ExprState {
+ public:
+  explicit BoolExprState(const univplan::UnivPlanBoolExpr *expr)
+      : op(expr->type()) {}
+  ~BoolExprState() {}
+
+  typedef std::unique_ptr<BoolExprState> uptr;
+
+  dbcommon::Datum calc(ExprContext *context) override;
+  dbcommon::Datum calcAnd(ExprContext *context);
+  dbcommon::Datum calcOr(ExprContext *context);
+  dbcommon::Datum calcNot(ExprContext *context);
+
+ private:
+  const univplan::BOOLEXPRTYPE op;
+  std::unique_ptr<dbcommon::Object> retval;
+};
+
+ExprState::uptr InitExpr(const univplan::UnivPlanExprPoly *expr);
+ExprState::uptr InitExpr(const univplan::UnivPlanExprPolyList *exprs);
+
+/* those interface only for magma index */
+struct IndexExpr {
+  IndexExpr() : colidx(-1), typeId(-1), typeModify(-1) {}
+
+  IndexExpr(const IndexExpr &idx) {
+    colidx = idx.colidx;
+    typeId = idx.typeId;
+    oper = idx.oper;
+    constVal = idx.constVal;
+    typeModify = idx.typeModify;
+  }
+
+  IndexExpr &operator=(const IndexExpr &idx) {
+    colidx = idx.colidx;
+    typeId = idx.typeId;
+    oper = idx.oper;
+    constVal = idx.constVal;
+    typeModify = idx.typeModify;
+    return *this;
+  }
+
+  bool isEqual() {
+    return dbcommon::StringUtil::countReplicates(oper, "equal");
+  }
+
+  bool isGreater() {
+    return dbcommon::StringUtil::countReplicates(oper, "greater");
+  }
+
+  bool isLessthan() {
+    return dbcommon::StringUtil::countReplicates(oper, "less");
+  }
+
+  ~IndexExpr() {}
+  int colidx;
+  int typeId;
+  int typeModify;
+  std::string oper;
+  std::string constVal;
+};
+
+bool do_opexpr(const univplan::UnivPlanOpExpr &op, IndexExpr *index, int pk,
+               int *equal);
+
+bool do_boolexpr(const univplan::UnivPlanBoolExpr &expr, IndexExpr *index,
+                 int pk, int *equal);
+
+std::vector<std::unique_ptr<IndexExpr> > getIndexExpr(
+    const std::vector<int> &index,
+    const univplan::UnivPlanExprPolyList *filterExprs);
+
+bool do_opexpr2(int pk, const univplan::UnivPlanOpExpr &op,
+                std::vector<std::unique_ptr<IndexExpr> > &allExpr,    // NOLINT
+                std::vector<std::unique_ptr<IndexExpr> > &equalExpr,  // NOLINT
+                int *equal);
+bool do_boolexpr2(
+    int pk, const univplan::UnivPlanBoolExpr &expr,
+    std::vector<std::unique_ptr<IndexExpr> > &allExpr,    // NOLINT
+    std::vector<std::unique_ptr<IndexExpr> > &equalExpr,  // NOLINT
+    int *equal);
+bool loopContinue(
+    int pkCol, const univplan::UnivPlanExprPolyList *filterExprs,
+    std::vector<std::unique_ptr<IndexExpr> > &allExpr,     // NOLINT
+    std::vector<std::unique_ptr<IndexExpr> > &equalExpr);  // NOLINT
+
+std::vector<std::vector<std::unique_ptr<IndexExpr> > > getIndexExpr2(
+    const std::vector<int> &index,
+    const univplan::UnivPlanExprPolyList *filterExprs);
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_COMMON_EXPRESSION_H_
diff --git a/depends/univplan/src/univplan/common/plannode-util.h b/depends/univplan/src/univplan/common/plannode-util.h
new file mode 100644
index 0000000..46743a3
--- /dev/null
+++ b/depends/univplan/src/univplan/common/plannode-util.h
@@ -0,0 +1,324 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_COMMON_PLANNODE_UTIL_H_
+#define UNIVPLAN_SRC_UNIVPLAN_COMMON_PLANNODE_UTIL_H_
+
+#include <algorithm>
+#include <utility>
+
+#include "dbcommon/log/logger.h"
+#include "dbcommon/type/type-kind.h"
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-agg.h"
+#include "univplan/univplanbuilder/univplanbuilder-append.h"
+#include "univplan/univplanbuilder/univplanbuilder-connector.h"
+#include "univplan/univplanbuilder/univplanbuilder-ext-gs-scan.h"
+#include "univplan/univplanbuilder/univplanbuilder-hash.h"
+#include "univplan/univplanbuilder/univplanbuilder-hashjoin.h"
+#include "univplan/univplanbuilder/univplanbuilder-insert.h"
+#include "univplan/univplanbuilder/univplanbuilder-limit.h"
+#include "univplan/univplanbuilder/univplanbuilder-material.h"
+#include "univplan/univplanbuilder/univplanbuilder-mergejoin.h"
+#include "univplan/univplanbuilder/univplanbuilder-nestloop.h"
+#include "univplan/univplanbuilder/univplanbuilder-result.h"
+#include "univplan/univplanbuilder/univplanbuilder-scan-seq.h"
+#include "univplan/univplanbuilder/univplanbuilder-shareinput-scan.h"
+#include "univplan/univplanbuilder/univplanbuilder-sink.h"
+#include "univplan/univplanbuilder/univplanbuilder-sort.h"
+#include "univplan/univplanbuilder/univplanbuilder-subquery-scan.h"
+#include "univplan/univplanbuilder/univplanbuilder-unique.h"
+
+namespace dbcommon {
+enum FuncKind : uint32_t;
+};
+
+namespace univplan {
+
+class PlanNodeUtil {
+ public:
+  PlanNodeUtil() {}
+  ~PlanNodeUtil() {}
+
+  static UnivPlanBuilderNode::uptr createPlanBuilderNode(
+      UNIVPLANNODETYPE ntype) {
+    UnivPlanBuilderNode::uptr res;
+    switch (ntype) {
+      case UNIVPLAN_AGG:
+        res.reset(new UnivPlanBuilderAgg());
+        break;
+      case UNIVPLAN_SCAN_SEQ:
+        res.reset(new UnivPlanBuilderScanSeq());
+        break;
+      case UNIVPLAN_CONNECTOR:
+        res.reset(new UnivPlanBuilderConnector());
+        break;
+      case UNIVPLAN_SORT:
+        res.reset(new UnivPlanBuilderSort());
+        break;
+      case UNIVPLAN_EXT_GS_SCAN:
+        res.reset(new UnivPlanBuilderExtGSScan());
+        break;
+      case UNIVPLAN_LIMIT:
+        res.reset(new UnivPlanBuilderLimit());
+        break;
+      case UNIVPLAN_APPEND:
+        res.reset(new UnivPlanBuilderAppend());
+        break;
+      case UNIVPLAN_NESTLOOP:
+        res.reset(new UnivPlanBuilderNestLoop());
+        break;
+      case UNIVPLAN_HASHJOIN:
+        res.reset(new UnivPlanBuilderHashJoin());
+        break;
+      case UNIVPLAN_MERGEJOIN:
+        res.reset(new UnivPlanBuilderMergeJoin());
+        break;
+      case UNIVPLAN_MATERIAL:
+        res.reset(new UnivPlanBuilderMaterial());
+        break;
+      case UNIVPLAN_RESULT:
+        res.reset(new UnivPlanBuilderResult());
+        break;
+      case UNIVPLAN_HASH:
+        res.reset(new UnivPlanBuilderHash());
+        break;
+      case UNIVPLAN_SUBQUERYSCAN:
+        res.reset(new UnivPlanBuilderSubqueryScan());
+        break;
+      case UNIVPLAN_UNIQUE:
+        res.reset(new UnivPlanBuilderUnique());
+        break;
+      case UNIVPLAN_INSERT:
+        res.reset(new UnivPlanBuilderInsert());
+        break;
+      case UNIVPLAN_SHAREINPUTSCAN:
+        res.reset(new UnivPlanBuilderShareInputScan());
+        break;
+      default:
+        LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                  "PlanNodeUtil::createPlanBuilderNode can't handle "
+                  "UNIVPLANNODETYPE %d",
+                  ntype);
+    }
+    return std::move(res);
+  }
+
+  static const UnivPlanPlanNode &getPlanNode(const UnivPlanPlanNodePoly &node) {
+    if (node.has_connector()) {
+      return node.connector().super();
+    } else if (node.has_scanseq()) {
+      return node.scanseq().super();
+    } else if (node.has_converge()) {
+      return node.converge().super();
+    } else if (node.has_shuffle()) {
+      return node.shuffle().super();
+    } else if (node.has_broadcast()) {
+      return node.broadcast().super();
+    } else if (node.has_sink()) {
+      return node.sink().super();
+    } else if (node.has_agg()) {
+      return node.agg().super();
+    } else if (node.has_sort()) {
+      return node.sort().super();
+    } else if (node.has_extgsscan()) {
+      return node.extgsscan().super();
+    } else if (node.has_extgsfilter()) {
+      return node.extgsfilter().super();
+    } else if (node.has_extgsproject()) {
+      return node.extgsproject().super();
+    } else if (node.has_limit()) {
+      return node.limit().super();
+    } else if (node.has_append()) {
+      return node.append().super();
+    } else if (node.has_nestloop()) {
+      return node.nestloop().super();
+    } else if (node.has_hashjoin()) {
+      return node.hashjoin().super();
+    } else if (node.has_mergejoin()) {
+      return node.mergejoin().super();
+    } else if (node.has_material()) {
+      return node.material().super();
+    } else if (node.has_result()) {
+      return node.result().super();
+    } else if (node.has_hash()) {
+      return node.hash().super();
+    } else if (node.has_subqueryscan()) {
+      return node.subqueryscan().super();
+    } else if (node.has_unique()) {
+      return node.unique().super();
+    } else if (node.has_insert()) {
+      return node.insert().super();
+    } else if (node.has_shareinputscan()) {
+      return node.shareinputscan().super();
+    } else {
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "PlanNodeUtil::getPlanNode type %d not supported", node.type());
+    }
+  }
+
+  static UnivPlanPlanNode *getMutablePlanNode(UnivPlanPlanNodePoly *node) {
+    if (node->has_connector()) {
+      return node->mutable_connector()->mutable_super();
+    } else if (node->has_scanseq()) {
+      return node->mutable_scanseq()->mutable_super();
+    } else if (node->has_converge()) {
+      return node->mutable_converge()->mutable_super();
+    } else if (node->has_shuffle()) {
+      return node->mutable_shuffle()->mutable_super();
+    } else if (node->has_broadcast()) {
+      return node->mutable_broadcast()->mutable_super();
+    } else if (node->has_sink()) {
+      return node->mutable_sink()->mutable_super();
+    } else if (node->has_agg()) {
+      return node->mutable_agg()->mutable_super();
+    } else if (node->has_sort()) {
+      return node->mutable_sort()->mutable_super();
+    } else if (node->has_limit()) {
+      return node->mutable_limit()->mutable_super();
+    } else if (node->has_append()) {
+      return node->mutable_append()->mutable_super();
+    } else if (node->has_nestloop()) {
+      return node->mutable_nestloop()->mutable_super();
+    } else if (node->has_hashjoin()) {
+      return node->mutable_hashjoin()->mutable_super();
+    } else if (node->has_mergejoin()) {
+      return node->mutable_mergejoin()->mutable_super();
+    } else if (node->has_material()) {
+      return node->mutable_material()->mutable_super();
+    } else if (node->has_result()) {
+      return node->mutable_result()->mutable_super();
+    } else if (node->has_hash()) {
+      return node->mutable_hash()->mutable_super();
+    } else if (node->has_subqueryscan()) {
+      return node->mutable_subqueryscan()->mutable_super();
+    } else if (node->has_extgsscan()) {
+      return node->mutable_extgsscan()->mutable_super();
+    } else if (node->has_extgsfilter()) {
+      return node->mutable_extgsfilter()->mutable_super();
+    } else if (node->has_extgsproject()) {
+      return node->mutable_extgsproject()->mutable_super();
+    } else if (node->has_unique()) {
+      return node->mutable_unique()->mutable_super();
+    } else if (node->has_insert()) {
+      return node->mutable_insert()->mutable_super();
+    } else if (node->has_shareinputscan()) {
+      return node->mutable_shareinputscan()->mutable_super();
+    } else {
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "PlanNodeUtil::getPlanNode type %d not supported",
+                node->type());
+    }
+  }
+
+  static const UnivPlanPlan *getPlan(const UnivPlanPlan &cur, int32_t stageNo) {
+    if (cur.stageno() == stageNo) return &cur;
+    for (int i = 0; i < cur.childstages_size(); i++) {
+      const UnivPlanPlan *ret = getPlan(cur.childstages(i), stageNo);
+      if (ret != nullptr) return ret;
+    }
+    return nullptr;
+  }
+
+  static dbcommon::TypeKind exprType(const UnivPlanExprPoly &expr) {
+    if (expr.has_opexpr()) {
+      return typeKindMapping(expr.opexpr().rettype());
+    } else if (expr.has_val()) {
+      return typeKindMapping(expr.val().type());
+    } else if (expr.has_targetentry()) {
+      return exprType(expr.targetentry().expression());
+    } else if (expr.has_aggref()) {
+      return typeKindMapping(expr.aggref().rettype());
+    } else if (expr.has_var()) {
+      return typeKindMapping(expr.var().typeid_());
+    } else if (expr.has_funcexpr()) {
+      return typeKindMapping(expr.funcexpr().rettype());
+    } else if (expr.has_nulltest() || expr.has_boolexpr() ||
+               expr.has_booltest()) {
+      return dbcommon::TypeKind::BOOLEANID;
+    } else if (expr.has_caseexpr()) {
+      return typeKindMapping(expr.caseexpr().casetype());
+    } else if (expr.has_param()) {
+      return typeKindMapping(expr.param().typeid_());
+    } else if (expr.has_subplan()) {
+      if (expr.subplan().sublinktype() == univplan::SUBLINKTYPE::EXPR_SUBLINK)
+        return typeKindMapping(expr.subplan().typeid_());
+      else
+        return dbcommon::TypeKind::BOOLEANID;
+    } else if (expr.has_coalesceexpr()) {
+      return typeKindMapping(expr.coalesceexpr().coalescetype());
+    } else if (expr.has_nullifexpr()) {
+      return typeKindMapping(expr.nullifexpr().rettype());
+    } else if (expr.has_distinctexpr()) {
+      return typeKindMapping(expr.distinctexpr().rettype());
+    } else {
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "PlanNodeUtil::exprType expr %d not supported", expr.type());
+    }
+  }
+
+  static int64_t exprTypeMod(const UnivPlanExprPoly &expr) {
+    if (expr.has_val()) {
+      return (expr.val().typemod());
+    } else if (expr.has_var()) {
+      return (expr.var().typemod());
+    } else if (expr.has_targetentry()) {
+      return exprType(expr.targetentry().expression());
+    } else if (expr.has_param()) {
+      return (expr.param().typemod());
+    } else if (expr.has_subplan()) {
+      return (expr.subplan().typemod());
+    } else if (expr.has_coalesceexpr()) {
+      return expr.coalesceexpr().coalescetypemod();
+    } else if (expr.has_nullifexpr()) {
+      return expr.nullifexpr().typemod();
+    }
+
+    int64_t ret = -1;
+    if (expr.has_opexpr()) {
+      for (auto arg : expr.opexpr().args())
+        ret = std::max(exprTypeMod(arg), ret);
+      return ret;
+    } else if (expr.has_aggref()) {
+      for (auto arg : expr.aggref().args())
+        ret = std::max(exprTypeMod(arg), ret);
+      return ret;
+    } else if (expr.has_funcexpr()) {
+      for (auto arg : expr.funcexpr().args())
+        ret = std::max(exprTypeMod(arg), ret);
+      return ret;
+    } else if (expr.has_distinctexpr()) {
+      for (auto arg : expr.funcexpr().args())
+        ret = std::max(exprTypeMod(arg), ret);
+      return ret;
+    }
+
+    if (expr.has_nulltest() || expr.has_boolexpr() || expr.has_booltest() ||
+        expr.has_caseexpr()) {
+      return -1;
+    } else {
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "PlanNodeUtil::exprTypeMod expr %d not supported", expr.type());
+    }
+  }
+
+  static dbcommon::TypeKind typeKindMapping(int32_t type) {
+    dbcommon::TypeKind typeKind = static_cast<dbcommon::TypeKind>(type);
+    if (typeKind == dbcommon::TypeKind::DECIMALID)
+      typeKind = dbcommon::TypeKind::DECIMALNEWID;
+    return typeKind;
+  }
+
+  static dbcommon::FuncKind funcKindMapping(int32_t funcType) {
+    return static_cast<dbcommon::FuncKind>(funcType);
+  }
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_COMMON_PLANNODE_UTIL_H_
diff --git a/depends/univplan/src/univplan/common/plannode-walker.h b/depends/univplan/src/univplan/common/plannode-walker.h
new file mode 100644
index 0000000..ab79745
--- /dev/null
+++ b/depends/univplan/src/univplan/common/plannode-walker.h
@@ -0,0 +1,126 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_COMMON_PLANNODE_WALKER_H_
+#define UNIVPLAN_SRC_UNIVPLAN_COMMON_PLANNODE_WALKER_H_
+
+#include "univplan/proto/universal-plan.pb.h"
+
+#include "dbcommon/log/logger.h"
+
+namespace univplan {
+
+class PlanNodeWalkerContext {
+ public:
+  PlanNodeWalkerContext() {}
+  virtual ~PlanNodeWalkerContext() {}
+};
+
+class PlanNodeWalker {
+ public:
+  PlanNodeWalker() {}
+  virtual ~PlanNodeWalker() {}
+
+  virtual void walk(UnivPlanExprPoly *expr, PlanNodeWalkerContext *ctx) = 0;
+
+  // Walk all dependent expressions.
+  // @param expr Root expr
+  // @param walker Apply walker->walk() for checking each expression
+  // @param ctx Context for checking list
+  static void walkExpressionTree(UnivPlanExprPoly *expr, PlanNodeWalker *walker,
+                                 PlanNodeWalkerContext *ctx) {
+    // Call walkExpressionTree to check all containing "UnivPlanExprPoly".
+    // Pay attention to check the "optional UnivPlanExprPoly" exist before
+    // calling walkExpressionTree.
+    if (expr->has_var() || expr->has_val() || expr->has_param()) {
+      // do nothing
+    } else if (expr->has_aggref()) {
+      UnivPlanAggref *aggref = expr->mutable_aggref();
+      walkExpressionTree(aggref->mutable_args(), walker, ctx);
+    } else if (expr->has_funcexpr()) {
+      UnivPlanFuncExpr *funcExpr = expr->mutable_funcexpr();
+      walkExpressionTree(funcExpr->mutable_args(), walker, ctx);
+    } else if (expr->has_opexpr()) {
+      UnivPlanOpExpr *opExpr = expr->mutable_opexpr();
+      walkExpressionTree(opExpr->mutable_args(), walker, ctx);
+    } else if (expr->has_boolexpr()) {
+      UnivPlanBoolExpr *boolExpr = expr->mutable_boolexpr();
+      walkExpressionTree(boolExpr->mutable_args(), walker, ctx);
+    } else if (expr->has_nulltest()) {
+      UnivPlanNullTest *nullTest = expr->mutable_nulltest();
+      walkExpressionTree(nullTest->mutable_arg(), walker, ctx);
+    } else if (expr->has_booltest()) {
+      UnivPlanBooleanTest *boolTest = expr->mutable_booltest();
+      walkExpressionTree(boolTest->mutable_arg(), walker, ctx);
+    } else if (expr->has_targetentry()) {
+      UnivPlanTargetEntry *targetEntry = expr->mutable_targetentry();
+      walkExpressionTree(targetEntry->mutable_expression(), walker, ctx);
+    } else if (expr->has_caseexpr()) {
+      UnivPlanCaseExpr *caseexpr = expr->mutable_caseexpr();
+      walkExpressionTree(caseexpr->mutable_args(), walker, ctx);
+      walkExpressionTree(caseexpr->mutable_defresult(), walker, ctx);
+    } else if (expr->has_casewhen()) {
+      UnivPlanCaseWhen *casewhen = expr->mutable_casewhen();
+      walkExpressionTree(casewhen->mutable_expr(), walker, ctx);
+      walkExpressionTree(casewhen->mutable_result(), walker, ctx);
+    } else if (expr->has_subplan()) {
+      UnivPlanSubPlan *subplan = expr->mutable_subplan();
+      walkExpressionTree(subplan->mutable_args(), walker, ctx);
+      if (subplan->has_testexpr())
+        walkExpressionTree(subplan->mutable_testexpr(), walker, ctx);
+    } else if (expr->has_scalararrayopexpr()) {
+      UnivPlanScalarArrayOpExpr *scalarArrayOpExpr =
+          expr->mutable_scalararrayopexpr();
+      walkExpressionTree(scalarArrayOpExpr->mutable_args(), walker, ctx);
+    } else if (expr->has_coalesceexpr()) {
+      UnivPlanCoalesceExpr *coalesceExpr = expr->mutable_coalesceexpr();
+      walkExpressionTree(coalesceExpr->mutable_args(), walker, ctx);
+    } else if (expr->has_nullifexpr()) {
+      UnivPlanNullIfExpr *nullIfExpr = expr->mutable_nullifexpr();
+      walkExpressionTree(nullIfExpr->mutable_args(), walker, ctx);
+    } else if (expr->has_distinctexpr()) {
+      UnivPlanDistinctExpr *distinctExpr = expr->mutable_distinctexpr();
+      walkExpressionTree(distinctExpr->mutable_args(), walker, ctx);
+    } else {
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "PlanNodeUtil::expressionTreeWalker expr %d not supported",
+                expr->type());
+    }
+    walker->walk(expr, ctx);
+  }
+
+  static void walkExpressionTree(UnivPlanExprPolyList *exprs,
+                                 PlanNodeWalker *walker,
+                                 PlanNodeWalkerContext *ctx) {
+    for (int i = 0; i < exprs->size(); ++i) {
+      walkExpressionTree(exprs->Mutable(i), walker, ctx);
+    }
+  }
+
+  virtual void walk(UnivPlanPlanNodePoly *planNodePoly, PlanNodeWalker *walker,
+                    PlanNodeWalkerContext *ctx) {}
+
+  static void walkPlanTree(UnivPlanPlanNodePoly *planNodePoly,
+                           PlanNodeWalker *walker, PlanNodeWalkerContext *ctx) {
+    auto planNode = PlanNodeUtil::getMutablePlanNode(planNodePoly);
+    if (planNode->has_leftplan())
+      walkPlanTree(planNode->mutable_leftplan(), walker, ctx);
+    if (planNode->has_rightplan())
+      walkPlanTree(planNode->mutable_rightplan(), walker, ctx);
+    if (planNodePoly->has_append()) {
+      auto append = planNodePoly->mutable_append();
+      for (auto i = 0; i < append->appendplans_size(); i++)
+        walkPlanTree(append->mutable_appendplans(i), walker, ctx);
+    }
+
+    walker->walk(planNodePoly, walker, ctx);
+  }
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_COMMON_PLANNODE_WALKER_H_
diff --git a/depends/univplan/src/univplan/common/stagize.cc b/depends/univplan/src/univplan/common/stagize.cc
new file mode 100644
index 0000000..d13273d
--- /dev/null
+++ b/depends/univplan/src/univplan/common/stagize.cc
@@ -0,0 +1,200 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/common/stagize.h"
+
+#include <utility>
+
+#include "dbcommon/log/logger.h"
+#include "univplan/common/plannode-util.h"
+#include "univplan/common/subplan-util.h"
+
+namespace univplan {
+
+// return a totally new Plan inside ctx->upb
+void PlanStagizer::stagize(const UnivPlanPlan *plan, StagizerContext *ctx) {
+  ctx->upb.reset(new UnivPlanBuilder);
+  ctx->upb->getPlanBuilderPlan()->from(*plan);
+
+  // stage main plan
+  ctx->pid = -1;
+  ctx->isleft = true;
+  stageNo = 0;
+  // -1 is a mark for the root stage, the stageNo of the plan tree's stage
+  // is a postorder traversal except that the stageNo of root stage is zero
+  ctx->upb->getPlanBuilderPlan()->setStageNo(-1);
+  stagize(plan->plan(), ctx, 0);
+  ctx->upb->getPlanBuilderPlan()->setStageNo(0);
+
+  // stage subplan
+  for (auto i = 0; i < plan->subplans_size(); i++) {
+    ctx->pid = -1;
+    ctx->isleft = true;
+    if (ctx->subplanStageNo[i + 1] <= ctx->totalStageNo) {
+      // retrieve stageNo for SubPlan
+      stagize(plan->subplans(i), ctx, ctx->subplanStageNo[i + 1]);
+    } else {
+      // allocate new stage for InitPlan
+      auto newStage =
+          ctx->upb->getPlanBuilderPlan()->addChildStageAndGetBuilder();
+      newStage->from(*(ctx->upb->getPlanBuilderPlan()->getPlan()));
+      newStage->setStageNo(ctx->subplanStageNo[i + 1]);
+      auto backupStage = ctx->upb->swapBuilder(std::move(newStage));
+      stagize(plan->subplans(i), ctx, ctx->subplanStageNo[i + 1]);
+      ctx->upb->swapBuilder(std::move(backupStage));
+      ctx->upb->getPlanBuilderPlan()->getPlan()->add_subplans();  // placeholder
+    }
+  }
+  assert(ctx->subplanStageNo.size() == plan->subplans_size());
+
+  // link subplan to correlated stage
+  auto rootPlan = ctx->upb->getPlanBuilderPlan()->getPlan();
+  assert(rootPlan->subplans_size() == plan->subplans_size());
+  auto rootStage = rootPlan;
+  UnivPlanPlan backup;  // store stagized subplans
+  backup.mutable_subplans()->Swap(rootPlan->mutable_subplans());
+  SubplanUtil::linkSubplan(&backup, rootStage);
+}
+
+// FIXME(chiyang): To support subplan with correct stageNo(i.e. the
+// corresponding sliceID/MotionID in HAWQ), we copy the motionID from HAWQ.
+// However, motionID is not set in previous unittest, as a result of which we
+// keep the old stageNo allocate strategy when needed(i.e. when the
+// connector.stageno() == -1).
+void PlanStagizer::stagize(const UnivPlanPlanNodePoly &originalNode,
+                           StagizerContext *ctx, int32_t currentStageNo) {
+  // ctx->upb->getPlanBuilderPlan referred to the current stage
+  // ctx->pid referred to the pid of the new plan tree
+  // ctx->isleft determine whether the current plannode is the left child of its
+  // parent
+  if (!originalNode.IsInitialized()) {
+    LOG_ERROR(ERRCODE_INTERNAL_ERROR, "stagize node is empty");
+  }
+  const UnivPlanPlan *currentStage = ctx->upb->getPlanBuilderPlan()->getPlan();
+  if (originalNode.has_connector()) {
+    const UnivPlanConnector &connector = originalNode.connector();
+
+    UnivPlanBuilderSinkInput::uptr builderSinkInput;
+    switch (connector.type()) {
+      case CONNECTORTYPE_CONVERGE:
+        builderSinkInput.reset(new UnivPlanBuilderConverge());
+        break;
+      case CONNECTORTYPE_SHUFFLE:
+        builderSinkInput.reset(new UnivPlanBuilderShuffle());
+        break;
+      case CONNECTORTYPE_BROADCAST:
+        builderSinkInput.reset(new UnivPlanBuilderBroadcast());
+        break;
+      default:
+        LOG_ERROR(ERRCODE_INTERNAL_ERROR, "unexpected connector node type %d",
+                  connector.type());
+    }
+    // build sink
+    UnivPlanBuilderSink::uptr builderSink(new UnivPlanBuilderSink());
+    builderSink->from(connector);
+    builderSink->setSourceStageNo(stageNo);
+    builderSink->setCurrentStageNo(currentStage->stageno());
+    builderSink->setConnectorType(connector.type());
+    builderSink->uid = nodeId++;
+    builderSink->pid = ctx->pid;
+    UnivPlanBuilderSink *backupBuilderSink = builderSink.get();
+    ctx->upb->addPlanNode(ctx->isleft, std::move(builderSink));
+
+    // build new stage, need to be done before add sinkinput
+    UnivPlanBuilderPlan::uptr builderNewStage =
+        ctx->upb->getPlanBuilderPlan()->addChildStageAndGetBuilder();
+    builderNewStage->from(*(ctx->upb->getPlanBuilderPlan()->getPlan()));
+    builderNewStage->setStageNo(connector.stageno() != -1 ? connector.stageno()
+                                                          : stageNo);
+
+    UnivPlanBuilderPlan::uptr backupStage =
+        ctx->upb->swapBuilder(std::move(builderNewStage));
+
+    // sinkInput info
+    builderSinkInput->from(connector);
+    builderSinkInput->setTargetStageNo(currentStage->stageno());
+    builderSinkInput->setCurrentStageNo(stageNo);
+    builderSinkInput->uid = nodeId++;
+    builderSinkInput->pid = -1;
+    UnivPlanBuilderSinkInput *backupBuilderSinkInput = builderSinkInput.get();
+    ctx->upb->addPlanNode(ctx->isleft, std::move(builderSinkInput));
+
+    // sinkinput's left child comes from connector,
+    // and there will be only one child
+    const UnivPlanPlanNodePoly &originalNodeLeft =
+        PlanNodeUtil::getPlanNode(originalNode).leftplan();
+    ctx->pid = nodeId - 1;  // the nodeId of sinkinput
+    ctx->isleft = true;
+    stageNo++;
+    stagize(originalNodeLeft, ctx, connector.stageno());
+
+    builderNewStage = ctx->upb->swapBuilder(std::move(backupStage));
+
+    // the old stageNo assign strategy, a post-order traversal
+    int32_t childStageNo =
+        ctx->totalStageNo - builderNewStage->getPlan()->stageno();
+    if (currentStageNo == -1)
+      currentStageNo =
+          (backupBuilderSinkInput->getTargetStageNo() != -1)
+              ? (ctx->totalStageNo - backupBuilderSinkInput->getTargetStageNo())
+              : 0;
+    // to bypass the old stageNo assign strategy when possible
+    if (connector.stageno() != -1) {
+      childStageNo = connector.stageno();
+      if (currentStageNo == -1) currentStageNo = currentStage->stageno();
+      if (currentStageNo == -1) currentStageNo = 0;
+    }
+
+    builderNewStage->setStageNo(childStageNo);
+    backupBuilderSink->setCurrentStageNo(currentStageNo);
+    backupBuilderSink->setSourceStageNo(childStageNo);
+    backupBuilderSinkInput->setCurrentStageNo(childStageNo);
+    backupBuilderSinkInput->setTargetStageNo(currentStageNo);
+  } else {
+    UnivPlanBuilderNode::uptr builderNodeNew =
+        PlanNodeUtil::createPlanBuilderNode(originalNode.type());
+    builderNodeNew->from(originalNode);
+    int32_t builderNodeNewId = nodeId++;
+    builderNodeNew->uid = builderNodeNewId;
+    builderNodeNew->pid = ctx->pid;
+    ctx->upb->addPlanNode(ctx->isleft, std::move(builderNodeNew));
+
+    const UnivPlanPlanNode &originalNodePlanNode =
+        PlanNodeUtil::getPlanNode(originalNode);
+
+    auto relatedSubplans = SubplanUtil::getRelatedSubplanIds(originalNode);
+    for (auto subplanId : relatedSubplans) {
+      ctx->subplanStageNo[subplanId] = currentStageNo;
+    }
+
+    if (originalNodePlanNode.has_rightplan()) {
+      ctx->pid = builderNodeNewId;
+      ctx->isleft = false;
+      const UnivPlanPlanNodePoly &originalNodeRight =
+          originalNodePlanNode.rightplan();
+      stagize(originalNodeRight, ctx, currentStageNo);
+    }
+
+    if (originalNodePlanNode.has_leftplan()) {
+      ctx->pid = builderNodeNewId;
+      ctx->isleft = true;
+      const UnivPlanPlanNodePoly &originalNodeLeft =
+          originalNodePlanNode.leftplan();
+      stagize(originalNodeLeft, ctx, currentStageNo);
+    }
+
+    if (originalNode.has_subqueryscan()) {
+      ctx->pid = builderNodeNewId;
+      ctx->isleft = true;
+      const UnivPlanPlanNodePoly &subplan =
+          originalNode.subqueryscan().subplan();
+      stagize(subplan, ctx, currentStageNo);
+    }
+  }
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/common/stagize.h b/depends/univplan/src/univplan/common/stagize.h
new file mode 100644
index 0000000..1b64d96
--- /dev/null
+++ b/depends/univplan/src/univplan/common/stagize.h
@@ -0,0 +1,42 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_COMMON_STAGIZE_H_
+#define UNIVPLAN_SRC_UNIVPLAN_COMMON_STAGIZE_H_
+
+#include <map>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder.h"
+
+namespace univplan {
+
+typedef struct StagizerContext {
+  UnivPlanBuilder::uptr upb;
+  int32_t pid;
+  bool isleft;
+  uint32_t totalStageNo;
+  std::map<int32_t, int32_t> subplanStageNo;
+} StagizerContext;
+
+class PlanStagizer {
+ public:
+  PlanStagizer() {}
+  ~PlanStagizer() {}
+
+  void stagize(const UnivPlanPlan *plan, StagizerContext *ctx);
+
+ private:
+  void stagize(const UnivPlanPlanNodePoly &node, StagizerContext *ctx,
+               int32_t currentStageNo);
+  int32_t nodeId = 0;
+  int32_t stageNo = 0;  // stageNo start from 0
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_COMMON_STAGIZE_H_
diff --git a/depends/univplan/src/univplan/common/statistics.h b/depends/univplan/src/univplan/common/statistics.h
new file mode 100644
index 0000000..011f1b9
--- /dev/null
+++ b/depends/univplan/src/univplan/common/statistics.h
@@ -0,0 +1,59 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_COMMON_STATISTICS_H_
+#define UNIVPLAN_SRC_UNIVPLAN_COMMON_STATISTICS_H_
+
+namespace univplan {
+// Statistics that are available for all types of columns.
+class ColumnStatistics {
+ public:
+  virtual ~ColumnStatistics() {}
+
+  // Get the number of values in this column. It will differ from the number
+  // of rows because of NULL values and repeated values.
+  // @return the number of values
+  uint64_t getNumberOfValues() const { return valueCount; }
+
+  // Returns true if there are nulls in the scope of column statistics
+  bool hasNull() const { return hasNullValue; }
+
+  virtual void reset() {
+    valueCount = 0;
+    hasNullValue = true;
+  }
+
+  void increment(uint64_t count) { valueCount += count; }
+
+  void unsetNull() { hasNullValue = false; }
+
+  virtual void merge(const ColumnStatistics& stats) {
+    valueCount += stats.getNumberOfValues();
+    hasNullValue |= stats.hasNull();
+  }
+
+ protected:
+  uint64_t valueCount;
+  bool hasNullValue;
+};
+
+class Statistics {
+ public:
+  virtual ~Statistics() {}
+
+  // Get the statistics of colId column.
+  // @return one column's statistics
+  virtual const ColumnStatistics* getColumnStatistics(uint32_t colId) const = 0;
+
+  // Get the number of columns
+  // @return the number of columns
+  virtual uint32_t getNumberOfColumns() const = 0;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_COMMON_STATISTICS_H_
diff --git a/depends/univplan/src/univplan/common/subplan-util.cc b/depends/univplan/src/univplan/common/subplan-util.cc
new file mode 100644
index 0000000..cbf0a1d
--- /dev/null
+++ b/depends/univplan/src/univplan/common/subplan-util.cc
@@ -0,0 +1,139 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author: Chiyang Wan
+////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/common/subplan-util.h"
+#include "univplan/common/plannode-util.h"
+#include "univplan/common/plannode-walker.h"
+
+namespace univplan {
+
+class SubplanWalker : public PlanNodeWalker {
+ public:
+  void walk(UnivPlanPlanNodePoly* planNodePoly, PlanNodeWalker* walker,
+            PlanNodeWalkerContext* ctx) override {
+    auto planNode = PlanNodeUtil::getMutablePlanNode(planNodePoly);
+
+    // Basic check
+    PlanNodeWalker::walkExpressionTree(planNode->mutable_targetlist(), walker,
+                                       ctx);
+    PlanNodeWalker::walkExpressionTree(planNode->mutable_quallist(), walker,
+                                       ctx);
+    PlanNodeWalker::walkExpressionTree(planNode->mutable_initplan(), walker,
+                                       ctx);
+
+    // Special check for shuffle
+    if (planNodePoly->has_shuffle()) {
+      auto sf = planNodePoly->mutable_shuffle();
+      PlanNodeWalker::walkExpressionTree(sf->mutable_hashexpr(), walker, ctx);
+    }
+
+    // Special check for joinQual
+    if (planNodePoly->has_nestloop()) {
+      auto nl = planNodePoly->mutable_nestloop();
+      PlanNodeWalker::walkExpressionTree(nl->mutable_joinqual(), walker, ctx);
+    }
+    if (planNodePoly->has_hashjoin()) {
+      auto hj = planNodePoly->mutable_hashjoin();
+      PlanNodeWalker::walkExpressionTree(hj->mutable_joinqual(), walker, ctx);
+      PlanNodeWalker::walkExpressionTree(hj->mutable_hashclauses(), walker,
+                                         ctx);
+      PlanNodeWalker::walkExpressionTree(hj->mutable_hashqualclauses(), walker,
+                                         ctx);
+    }
+    if (planNodePoly->has_mergejoin()) {
+      auto mj = planNodePoly->mutable_mergejoin();
+      PlanNodeWalker::walkExpressionTree(mj->mutable_joinqual(), walker, ctx);
+      PlanNodeWalker::walkExpressionTree(mj->mutable_mergeclauses(), walker,
+                                         ctx);
+    }
+
+    // Special check for limit
+    if (planNodePoly->has_limit()) {
+      auto limit = planNodePoly->mutable_limit();
+      if (limit->has_limitoffset())
+        PlanNodeWalker::walkExpressionTree(limit->mutable_limitoffset(), walker,
+                                           ctx);
+      if (limit->has_limitcount())
+        PlanNodeWalker::walkExpressionTree(limit->mutable_limitcount(), walker,
+                                           ctx);
+    }
+    if (planNodePoly->has_sort()) {
+      auto sort = planNodePoly->mutable_sort();
+      if (sort->has_limitoffset())
+        PlanNodeWalker::walkExpressionTree(sort->mutable_limitoffset(), walker,
+                                           ctx);
+      if (sort->has_limitcount())
+        PlanNodeWalker::walkExpressionTree(sort->mutable_limitcount(), walker,
+                                           ctx);
+    }
+
+    // Special check from result
+    if (planNodePoly->has_result()) {
+      auto result = planNodePoly->mutable_result();
+      PlanNodeWalker::walkExpressionTree(result->mutable_resconstantqual(),
+                                         walker, ctx);
+    }
+  }
+};
+
+class SubplanPlanidWalkerContext : public PlanNodeWalkerContext {
+ public:
+  std::vector<int32_t> planids;
+};
+
+class SubplanPlanidWalker : public SubplanWalker {
+ public:
+  void walk(UnivPlanExprPoly* expr, PlanNodeWalkerContext* ctx) override {
+    if (expr->has_subplan() && !expr->subplan().initplan()) {
+      SubplanPlanidWalkerContext* context =
+          reinterpret_cast<SubplanPlanidWalkerContext*>(ctx);
+      context->planids.push_back(expr->subplan().planid());
+    }
+  }
+};
+
+std::vector<int32_t> SubplanUtil::getRelatedSubplanIds(
+    const UnivPlanPlanNodePoly& planNodePolyInput) {
+  SubplanPlanidWalkerContext ctx;
+  SubplanPlanidWalker walker;
+  walker.SubplanWalker::walk(
+      &(const_cast<UnivPlanPlanNodePoly&>(planNodePolyInput)), &walker, &ctx);
+  return ctx.planids;
+}
+
+class SubplanAttachWalkerContext : public PlanNodeWalkerContext {
+ public:
+  const UnivPlanPlan* rootPlan;
+  UnivPlanPlan* currStage;
+};
+
+class SubplanAttachWalker : public SubplanWalker {
+ public:
+  void walk(UnivPlanExprPoly* expr, PlanNodeWalkerContext* ctx) override {
+    if (expr->has_subplan() && !expr->subplan().initplan()) {
+      auto context = reinterpret_cast<SubplanAttachWalkerContext*>(ctx);
+      // count plan ID from 1
+      auto oldPlanId = expr->subplan().planid();
+      context->currStage->add_subplans()->CopyFrom(
+          context->rootPlan->subplans(oldPlanId - 1));
+      expr->mutable_subplan()->set_planid(context->currStage->subplans_size());
+    }
+  }
+};
+
+void SubplanUtil::linkSubplan(UnivPlanPlan* rootPlan, UnivPlanPlan* currStage) {
+  SubplanAttachWalker walker;
+  SubplanAttachWalkerContext ctx;
+  ctx.rootPlan = rootPlan;
+  ctx.currStage = currStage;
+  PlanNodeWalker::walkPlanTree(currStage->mutable_plan(), &walker, &ctx);
+  for (auto i = 0; i < currStage->childstages_size(); i++) {
+    linkSubplan(rootPlan, currStage->mutable_childstages(i));
+  }
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/common/subplan-util.h b/depends/univplan/src/univplan/common/subplan-util.h
new file mode 100644
index 0000000..c06317c
--- /dev/null
+++ b/depends/univplan/src/univplan/common/subplan-util.h
@@ -0,0 +1,34 @@
+////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author: Chiyang Wan
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_COMMON_SUBPLAN_UTIL_H_
+#define UNIVPLAN_SRC_UNIVPLAN_COMMON_SUBPLAN_UTIL_H_
+
+#include <vector>
+
+#include "univplan/common/univplan-type.h"
+#include "univplan/proto/universal-plan.pb.h"
+
+namespace univplan {
+
+class SubplanUtil {
+ public:
+  // @return Return related subplan IDs.
+  static std::vector<int32_t> getRelatedSubplanIds(
+      const UnivPlanPlanNodePoly& planNodePolyInput);
+
+  // Link subplan to its correlated plan stage.
+  // Inside stage, each subplan expression will change its planId to a
+  // new number according to the order of attaching subplans.
+  //
+  // @param rootPlan The plan that contains fully stagized subplans.
+  static void linkSubplan(UnivPlanPlan* rootPlan, UnivPlanPlan* currStage);
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_COMMON_SUBPLAN_UTIL_H_
diff --git a/depends/univplan/src/univplan/common/univplan-type.h b/depends/univplan/src/univplan/common/univplan-type.h
new file mode 100644
index 0000000..4c48c84
--- /dev/null
+++ b/depends/univplan/src/univplan/common/univplan-type.h
@@ -0,0 +1,133 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_COMMON_UNIVPLAN_TYPE_H_
+#define UNIVPLAN_SRC_UNIVPLAN_COMMON_UNIVPLAN_TYPE_H_
+
+#include <list>
+#include <string>
+
+#include "dbcommon/common/tuple-batch.h"
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-scan-task.h"
+
+namespace univplan {
+typedef google::protobuf::RepeatedPtrField<univplan::UnivPlanExprPoly>
+    UnivPlanExprPolyList;
+
+typedef google::protobuf::RepeatedPtrField<univplan::UnivPlanScanTask>
+    UnivPlanScanTaskList;
+
+// this class provides interface of accessing scan task and its splits
+class UnivPlanScanFileSplitList {
+ public:
+  UnivPlanScanFileSplitList() : splitsTb_(nullptr) {}
+  explicit UnivPlanScanFileSplitList(dbcommon::TupleBatch *tb)
+      : splitsTb_(tb) {}
+
+  void setSplitsTb(dbcommon::TupleBatch *tb) { splitsTb_ = tb; }
+  uint32_t splits_size() const {
+    return splitsTb_ == nullptr ? 0 : splitsTb_->getNumOfRows();
+  }
+
+  // methods of getting split properties indexed in tb
+  void splits_filename(int index, std::string *filename) {
+    const dbcommon::TupleBatchReader &readers =
+        splitsTb_->getTupleBatchReader();
+    uint64_t len = 0;
+    bool isNull = false;
+    const char *res =
+        readers[TBSPLITS_COL_INDEX_FILENAME]->read(index, &len, &isNull);
+    filename->assign(res, len);
+  }
+
+  int64_t splits_start(int index) const {
+    const dbcommon::TupleBatchReader &readers =
+        splitsTb_->getTupleBatchReader();
+    uint64_t len = 0;
+    bool isNull = false;
+    const char *res =
+        readers[TBSPLITS_COL_INDEX_START]->read(index, &len, &isNull);
+    return *(reinterpret_cast<const int64_t *>(res));
+  }
+
+  int64_t splits_len(int index) const {
+    const dbcommon::TupleBatchReader &readers =
+        splitsTb_->getTupleBatchReader();
+    uint64_t len = 0;
+    bool isNull = false;
+    const char *res =
+        readers[TBSPLITS_COL_INDEX_LEN]->read(index, &len, &isNull);
+    return *(reinterpret_cast<const int64_t *>(res));
+  }
+
+  int64_t splits_rangeid(int index) const {
+    const dbcommon::TupleBatchReader &readers =
+        splitsTb_->getTupleBatchReader();
+    uint64_t len = 0;
+    bool isNull = false;
+    const char *res =
+        readers[TBSPLITS_COL_INDEX_RANGEID]->read(index, &len, &isNull);
+    return *(reinterpret_cast<const int64_t *>(res));
+  }
+
+  int32_t splits_rgid(int index) const {
+    const dbcommon::TupleBatchReader &readers =
+        splitsTb_->getTupleBatchReader();
+    uint64_t len = 0;
+    bool isNull = false;
+    const char *res =
+        readers[TBSPLITS_COL_INDEX_RGID]->read(index, &len, &isNull);
+    return *(reinterpret_cast<const int32_t *>(res));
+  }
+
+  void debugOuput() {
+    if (splitsTb_ == nullptr) {
+      LOG_INFO("no rows in splits tb");
+      return;
+    }
+    for (int i = 0; i < splitsTb_->getNumOfRows(); ++i) {
+      std::string filename;
+      splits_filename(i, &filename);
+      int64_t start = splits_start(i);
+      int64_t len = splits_len(i);
+      int64_t rangeid = splits_rangeid(i);
+      int32_t rgid = splits_rgid(i);
+      LOG_INFO("[%d] %s,%lld,%lld,%lld,%d", i, filename.c_str(), start, len,
+               rangeid, rgid);
+    }
+  }
+
+ protected:
+  dbcommon::TupleBatch *splitsTb_;
+};
+
+// this subclass owns deserialized tb
+class UnivPlanScanFileSplitListTb : public UnivPlanScanFileSplitList {
+ public:
+  UnivPlanScanFileSplitListTb() : UnivPlanScanFileSplitList(nullptr) {}
+  explicit UnivPlanScanFileSplitListTb(dbcommon::TupleBatch::uptr tb)
+      : UnivPlanScanFileSplitList(tb.get()) {
+    splitsTbInst_ = std::move(tb);
+  }
+  void deserialize(const std::string &serializedTb) {
+    splitsTbInst_.reset(new dbcommon::TupleBatch());
+    splitsTbInst_->deserialize(serializedTb);
+    setSplitsTb(splitsTbInst_.get());
+  }
+
+ protected:
+  std::unique_ptr<dbcommon::TupleBatch> splitsTbInst_;
+};
+
+typedef std::list<std::unique_ptr<univplan::UnivPlanScanFileSplitList>>
+    UnivPlanScanFileSplitListList;
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_COMMON_UNIVPLAN_TYPE_H_
diff --git a/depends/univplan/src/univplan/common/var-util.cc b/depends/univplan/src/univplan/common/var-util.cc
new file mode 100644
index 0000000..0f707e5
--- /dev/null
+++ b/depends/univplan/src/univplan/common/var-util.cc
@@ -0,0 +1,99 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/common/var-util.h"
+
+#include <utility>
+
+#include "dbcommon/log/logger.h"
+#include "dbcommon/utils/macro.h"
+
+#include "univplan/common/plannode-util.h"
+#include "univplan/common/plannode-walker.h"
+
+namespace univplan {
+
+class FixVarTypeContext : public PlanNodeWalkerContext {
+ public:
+  FixVarTypeContext() {}
+  virtual ~FixVarTypeContext() {}
+
+ public:
+  UnivPlanPlanNode* planNode = nullptr;
+};
+
+class FixVarTypeWalker : public PlanNodeWalker {
+ public:
+  void walk(UnivPlanExprPoly* expr, PlanNodeWalkerContext* ctx) override {
+    if (expr->has_var()) {
+      FixVarTypeContext* context = reinterpret_cast<FixVarTypeContext*>(ctx);
+      UnivPlanPlanNode* planNode = context->planNode;
+      UnivPlanVar* var = expr->mutable_var();
+      if (var->varno() == OUTER_VAR && planNode->has_leftplan()) {
+        UnivPlanPlanNode* leftPlanNode =
+            PlanNodeUtil::getMutablePlanNode(planNode->mutable_leftplan());
+        UnivPlanExprPoly* refTargetEntry =
+            leftPlanNode->mutable_targetlist(var->varattno() - 1);
+        var->set_typeid_(
+            static_cast<int32_t>(PlanNodeUtil::exprType(*refTargetEntry)));
+      } else if (var->varno() == INNER_VAR && planNode->has_rightplan()) {
+        UnivPlanPlanNode* rightPlanNode =
+            PlanNodeUtil::getMutablePlanNode(planNode->mutable_rightplan());
+        UnivPlanExprPoly* refTargetEntry =
+            rightPlanNode->mutable_targetlist(var->varattno() - 1);
+        var->set_typeid_(
+            static_cast<int32_t>(PlanNodeUtil::exprType(*refTargetEntry)));
+      }
+    }
+  }
+};
+
+void VarUtil::fixVarType(UnivPlanPlanNodePoly* plantree) {
+  UnivPlanPlanNode* planNode = PlanNodeUtil::getMutablePlanNode(plantree);
+
+  // workaround here
+  if (plantree->type() == UNIVPLAN_APPEND) return;
+
+  if (planNode->has_leftplan()) fixVarType(planNode->mutable_leftplan());
+  if (planNode->has_rightplan()) fixVarType(planNode->mutable_rightplan());
+  FixVarTypeContext walkerContext;
+  walkerContext.planNode = planNode;
+  FixVarTypeWalker walker;
+
+  PlanNodeWalker::walkExpressionTree(planNode->mutable_targetlist(), &walker,
+                                     &walkerContext);
+}
+
+class CollectVarTypeContext : public PlanNodeWalkerContext {
+ public:
+  CollectVarTypeContext() {}
+  virtual ~CollectVarTypeContext() {}
+
+ public:
+  std::vector<int32_t> varAttNoVec;
+};
+
+class CollectVarTypeWalker : public PlanNodeWalker {
+ public:
+  void walk(UnivPlanExprPoly* expr, PlanNodeWalkerContext* ctx) override {
+    if (expr->has_var()) {
+      CollectVarTypeContext* context =
+          reinterpret_cast<CollectVarTypeContext*>(ctx);
+      context->varAttNoVec.push_back(expr->var().varattno());
+    }
+  }
+};
+
+std::vector<int32_t> VarUtil::collectVarAttNo(UnivPlanExprPoly* expr) {
+  CollectVarTypeContext walkerContext;
+  CollectVarTypeWalker walker;
+
+  PlanNodeWalker::walkExpressionTree(expr, &walker, &walkerContext);
+  return std::move(walkerContext.varAttNoVec);
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/common/var-util.h b/depends/univplan/src/univplan/common/var-util.h
new file mode 100644
index 0000000..32a0797
--- /dev/null
+++ b/depends/univplan/src/univplan/common/var-util.h
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_COMMON_VAR_UTIL_H_
+#define UNIVPLAN_SRC_UNIVPLAN_COMMON_VAR_UTIL_H_
+
+#include <vector>
+
+#include "univplan/proto/universal-plan.pb.h"
+
+namespace univplan {
+
+class VarUtil {
+ public:
+  VarUtil() {}
+  ~VarUtil() {}
+
+  void fixVarType(UnivPlanPlanNodePoly* plantree);
+  std::vector<int32_t> collectVarAttNo(UnivPlanExprPoly* expr);
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_COMMON_VAR_UTIL_H_
diff --git a/depends/univplan/src/univplan/cwrapper/univplan-c.cc b/depends/univplan/src/univplan/cwrapper/univplan-c.cc
new file mode 100644
index 0000000..4697068
--- /dev/null
+++ b/depends/univplan/src/univplan/cwrapper/univplan-c.cc
@@ -0,0 +1,1160 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/cwrapper/univplan-c.h"
+
+#include <cassert>
+#include <map>
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "dbcommon/function/func-kind.cg.h"
+#include "dbcommon/function/func.h"
+#include "dbcommon/log/logger.h"
+#include "dbcommon/utils/comp/lz4-compressor.h"
+#include "dbcommon/utils/macro.h"
+
+#include "univplan/common/plannode-util.h"
+#include "univplan/common/stagize.h"
+#include "univplan/common/var-util.h"
+#include "univplan/univplanbuilder/univplanbuilder-expr-tree.h"
+#include "univplan/univplanbuilder/univplanbuilder-plan.h"
+#include "univplan/univplanbuilder/univplanbuilder-table.h"
+#include "univplan/univplanbuilder/univplanbuilder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static void univPlanSetError(UnivPlanCatchedError *ce, int errCode,
+                             const char *errMsg);
+
+struct UnivPlanC {
+  univplan::UnivPlanBuilder::uptr upb;
+  std::stack<univplan::UnivPlanBuilder::uptr> upbBak;
+  univplan::UnivPlanBuilderNode::uptr curNode;
+  std::stack<univplan::UnivPlanBuilderNode::uptr> curNodeBak;
+  univplan::UnivPlanBuilderExprTree::uptr curExpr;
+  std::string serializedPlan;
+  UnivPlanCatchedError error;
+  std::string debugString;
+  uint16_t totalStageNo;
+  std::map<int32_t, int32_t> subplanStageNo;
+};
+
+UnivPlanC *univPlanNewInstance() {
+  UnivPlanC *instance = new UnivPlanC();
+  instance->upb.reset(new univplan::UnivPlanBuilder);
+  instance->error.errCode = ERRCODE_SUCCESSFUL_COMPLETION;
+  instance->totalStageNo = 0;
+  return instance;
+}
+
+void univPlanFreeInstance(UnivPlanC **up) {
+  assert(up != nullptr);
+  if (*up == nullptr) return;
+  delete *up;
+  *up = nullptr;
+}
+
+void univPlanNewSubPlanNode(UnivPlanC *up) {
+  up->upbBak.push(std::move(up->upb));
+  up->curNodeBak.push(std::move(up->curNode));
+  up->upb.reset(new univplan::UnivPlanBuilder);
+}
+
+void univPlanFreeSubPlanNode(UnivPlanC *up) {
+  up->upb = std::move(up->upbBak.top());
+  up->upbBak.pop();
+  up->curNode = std::move(up->curNodeBak.top());
+  up->curNodeBak.pop();
+}
+
+void univPlanRangeTblEntryAddTable(UnivPlanC *up, uint64_t tid,
+                                   FormatType format, const char *location,
+                                   const char *optStrInJson, uint32_t columnNum,
+                                   const char **columnName,
+                                   int32_t *columnDataType,
+                                   int64_t *columnDataTypeMod) {
+  univplan::UnivPlanBuilderPlan *bld = up->upb->getPlanBuilderPlan();
+  univplan::UnivPlanBuilderRangeTblEntry::uptr rte =
+      bld->addRangeTblEntryAndGetBuilder();
+  univplan::UnivPlanBuilderTable::uptr table(
+      new univplan::UnivPlanBuilderTable);
+  table->setTableId(tid);
+  univplan::UNIVPLANFORMATTYPE fmtType;
+  switch (format) {
+    case FormatType::UnivPlanCsvFormat:
+      fmtType = univplan::CSV_FORMAT;
+      break;
+    case FormatType::UnivPlanTextFormat:
+      fmtType = univplan::TEXT_FORMAT;
+      break;
+    case FormatType::UnivPlanOrcFormat:
+      fmtType = univplan::ORC_FORMAT;
+      break;
+    case FormatType::UnivPlanMagmaFormat:
+      fmtType = univplan::MAGMA_FORMAT;
+      break;
+    default:
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "univPlanRangeTblEntryAddTable can't handle FormatType %d",
+                format);
+  }
+  table->setTableFormat(fmtType);
+  table->setTableLocation(location);
+
+  std::string cvKey = "TableOptionsInJson_" + std::to_string(tid);
+  std::string nCvKey;
+  bld->addCommonValue(cvKey, optStrInJson, &nCvKey);
+  table->setTableOptionsInJson(nCvKey);
+  for (int i = 0; i < columnNum; ++i) {
+    univplan::UnivPlanBuilderColumn::uptr column =
+        table->addPlanColumnAndGetBuilder();
+    column->setColumnName(columnName[i]);
+    column->setTypeId(columnDataType[i]);
+    column->setTypeMod(columnDataTypeMod[i]);
+  }
+
+  rte->setTable(std::move(table->ownTable()));
+}
+
+void univPlanRangeTblEntryAddDummy(UnivPlanC *up) {
+  univplan::UnivPlanBuilderPlan *bld = up->upb->getPlanBuilderPlan();
+  univplan::UnivPlanBuilderRangeTblEntry::uptr rte =
+      bld->addRangeTblEntryAndGetBuilder();
+  univplan::UnivPlanBuilderTable::uptr table(
+      new univplan::UnivPlanBuilderTable);
+  table->setTableId(0);
+  univplan::UNIVPLANFORMATTYPE fmtType = univplan::INVALID_FORMAT;
+  table->setTableFormat(fmtType);
+  table->setTableLocation("");
+  table->setTableOptionsInJson("");
+  rte->setTable(std::move(table->ownTable()));
+}
+
+void univPlanReceiverAddListeners(UnivPlanC *up, uint32_t listenerNum,
+                                  const char **addr, int32_t *port) {
+  univplan::UnivPlanBuilderPlan *bld = up->upb->getPlanBuilderPlan();
+  univplan::UnivPlanBuilderReceiver::uptr rev = bld->addReceiverAndGetBuilder();
+  for (int i = 0; i < listenerNum; ++i) {
+    univplan::UnivPlanBuilderListener::uptr listener =
+        rev->addPlanListenerAndGetBuilder();
+    listener->setAddress(addr[i]);
+    listener->setPort(port[i]);
+  }
+}
+
+void univPlanAddParamInfo(UnivPlanC *up, int32_t type, bool isNull,
+                          const char *buffer) {
+  univplan::UnivPlanBuilderPlan *bld = up->upb->getPlanBuilderPlan();
+  univplan::UnivPlanBuilderParamInfo::uptr paramInfo =
+      bld->addParamInfoAndGetBuilder();
+  paramInfo->setType(type).setIsNull(isNull);
+  if (!isNull && buffer) paramInfo->setValue(buffer);
+}
+
+void univPlanSetDoInstrument(UnivPlanC *up, bool doInstrument) {
+  univplan::UnivPlanBuilderPlan *bld = up->upb->getPlanBuilderPlan();
+  bld->setDoInstrument(doInstrument);
+}
+
+void univPlanSetNCrossLevelParams(UnivPlanC *up, int32_t nCrossLevelParams) {
+  univplan::UnivPlanBuilderPlan *bld = up->upb->getPlanBuilderPlan();
+  bld->setNCrossLevelParams(nCrossLevelParams);
+}
+
+void univPlanSetCmdType(UnivPlanC *up, UnivPlanCCmdType type) {
+  univplan::UnivPlanBuilderPlan *bld = up->upb->getPlanBuilderPlan();
+  univplan::UNIVPLANCMDTYPE cmdType;
+  switch (type) {
+    case UnivPlanCCmdType::UNIVPLAN_CMD_SELECT:
+      cmdType = univplan::UNIVPLANCMDTYPE::CMD_SELECT;
+      break;
+    case UnivPlanCCmdType::UNIVPLAN_CMD_INSERT:
+      cmdType = univplan::UNIVPLANCMDTYPE::CMD_INSERT;
+      break;
+    default:
+      LOG_ERROR(ERRCODE_FEATURE_NOT_SUPPORTED, "CmdType(%d) not supported yet",
+                type);
+  }
+
+  bld->setCmdType(cmdType);
+}
+
+void univPlanSetPlanNodeInfo(UnivPlanC *up, double planRows,
+                             int32_t planRowWidth, uint64_t operatorMemKB) {
+  up->curNode->setNodePlanRows(planRows);
+  up->curNode->setNodePlanRowWidth(planRowWidth);
+  up->curNode->setNodePlanOperatorMemKB(operatorMemKB);
+}
+
+int32_t univPlanConnectorNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode = univplan::PlanNodeUtil::createPlanBuilderNode(
+      univplan::UNIVPLAN_CONNECTOR);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  up->totalStageNo += 1;
+  return up->curNode->uid;
+}
+
+void univPlanConnectorSetType(UnivPlanC *up, ConnectorType type) {
+  switch (type) {
+    case ConnectorType::UnivPlanShuffle:
+      dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get())
+          ->setConnectorType(univplan::CONNECTORTYPE_SHUFFLE);
+      break;
+    case ConnectorType::UnivPlanBroadcast:
+      dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get())
+          ->setConnectorType(univplan::CONNECTORTYPE_BROADCAST);
+      break;
+    case ConnectorType::UnivPlanConverge:
+      dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get())
+          ->setConnectorType(univplan::CONNECTORTYPE_CONVERGE);
+      break;
+    default:
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "univPlanConnectorSetType can't handle ConnectorType %d", type);
+  }
+}
+
+void univPlanConnectorSetStageNo(UnivPlanC *up, int32_t stageNo) {
+  dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get())
+      ->setStageNo(stageNo);
+}
+
+void univPlanConnectorSetRangeVsegMap(UnivPlanC *up, int *map,
+                                      bool magmaTable) {
+  dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get())
+      ->setMagmaMap(map);
+  dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get())
+      ->setMagmaTable(magmaTable);
+}
+
+void univPlanSetRangeNum(UnivPlanC *up, int rangeNum) {
+  dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get())
+      ->setRangeNum(rangeNum);
+}
+
+void univPlanConnectorSetColIdx(UnivPlanC *up, int64_t numCols,
+                                const int32_t *colIdx) {
+  univplan::UnivPlanBuilderConnector *conn =
+      dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get());
+  std::vector<int32_t> nArray(colIdx, colIdx + numCols);
+  conn->setColIdx(nArray);
+}
+
+void univPlanConnectorSetSortFuncId(UnivPlanC *up, int64_t numCols,
+                                    const int32_t *sortFuncId) {
+  univplan::UnivPlanBuilderConnector *conn =
+      dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get());
+  std::vector<int32_t> nArray(sortFuncId, sortFuncId + numCols);
+  conn->setSortFuncId(nArray);
+}
+
+int32_t univPlanExtScanNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode = univplan::PlanNodeUtil::createPlanBuilderNode(
+      univplan::UNIVPLAN_EXT_GS_SCAN);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+void univPlanExtScanSetRelId(UnivPlanC *up, uint32_t relId) {
+  dynamic_cast<univplan::UnivPlanBuilderExtGSScan *>(up->curNode.get())
+      ->setScanRelId(relId);
+}
+
+void univPlanExtScanSetIndex(UnivPlanC *up, bool index) {
+  dynamic_cast<univplan::UnivPlanBuilderExtGSScan *>(up->curNode.get())
+      ->setScanIndex(index);
+}
+
+void univPlanExtScanSetScanType(UnivPlanC *up, int type) {
+  dynamic_cast<univplan::UnivPlanBuilderExtGSScan *>(up->curNode.get())
+      ->setIndexScanType(univplan::ExternalScanType(type));
+}
+
+void univPlanExtScanDirection(UnivPlanC *up, int direction) {
+  dynamic_cast<univplan::UnivPlanBuilderExtGSScan *>(up->curNode.get())
+      ->setDirectionType(univplan::ExternalScanDirection(direction));
+}
+
+void univPlanExtScanSetIndexName(UnivPlanC *up, const char *indexName) {
+  dynamic_cast<univplan::UnivPlanBuilderExtGSScan *>(up->curNode.get())
+      ->setIndexName(indexName);
+}
+
+void univPlanIndexQualListAddExpr(UnivPlanC *up) {
+  dynamic_cast<univplan::UnivPlanBuilderExtGSScan *>(up->curNode.get())
+      ->addIndexQual(std::move(up->curExpr));
+}
+
+void univPlanExtScanSetColumnsToRead(UnivPlanC *up, int64_t numCols,
+                                     const int32_t *columnsToRead) {
+  std::vector<int32_t> nArray(columnsToRead, columnsToRead + numCols);
+  dynamic_cast<univplan::UnivPlanBuilderExtGSScan *>(up->curNode.get())
+      ->setColumnsToRead(nArray);
+}
+
+int32_t univPlanSeqScanNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode = univplan::PlanNodeUtil::createPlanBuilderNode(
+      univplan::UNIVPLAN_SCAN_SEQ);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+void univPlanSeqScanSetRelId(UnivPlanC *up, uint32_t relId) {
+  dynamic_cast<univplan::UnivPlanBuilderScanSeq *>(up->curNode.get())
+      ->setScanRelId(relId);
+}
+
+void univPlanSeqScanSetColumnsToRead(UnivPlanC *up, int64_t numCols,
+                                     const int32_t *columnsToRead) {
+  std::vector<int32_t> nArray(columnsToRead, columnsToRead + numCols);
+  dynamic_cast<univplan::UnivPlanBuilderScanSeq *>(up->curNode.get())
+      ->setColumnsToRead(nArray);
+}
+
+void univPlanSeqScanSetReadStatsOnly(UnivPlanC *up, bool readStatsOnly) {
+  dynamic_cast<univplan::UnivPlanBuilderScanSeq *>(up->curNode.get())
+      ->setReadStatsOnly(readStatsOnly);
+}
+
+void univPlanSeqScanAddTaskWithFileSplits(bool isMagma, UnivPlanC *up,
+                                          uint32_t fileSplitNum,
+                                          const char **fileName, int64_t *start,
+                                          int64_t *len, int32_t *rangeid,
+                                          int32_t *rgid) {
+  univplan::UnivPlanBuilderScanTask::uptr task;
+  if (isMagma) {
+    task = dynamic_cast<univplan::UnivPlanBuilderExtGSScan *>(up->curNode.get())
+               ->addScanTaskAndGetBuilder();
+  } else {
+    task = dynamic_cast<univplan::UnivPlanBuilderScanSeq *>(up->curNode.get())
+               ->addScanTaskAndGetBuilder();
+  }
+  for (int i = 0; i < fileSplitNum; ++i) {
+    task->addScanFileSplit(fileName[i], start[i], len[i],
+                           (rangeid == nullptr ? -1 : rangeid[i]),
+                           (rgid == nullptr ? -1 : rgid[i]));
+  }
+  task->generate();
+}
+
+int32_t univPlanAggNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode =
+      univplan::PlanNodeUtil::createPlanBuilderNode(univplan::UNIVPLAN_AGG);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+void univPlanAggSetNumGroupsAndGroupColIndexes(UnivPlanC *up, int64_t numGroups,
+                                               int64_t numCols,
+                                               const int32_t *grpColIdx) {
+  univplan::UnivPlanBuilderAgg *agg =
+      dynamic_cast<univplan::UnivPlanBuilderAgg *>(up->curNode.get());
+  agg->setNumGroups(numGroups);
+  std::vector<int32_t> nArray(grpColIdx, grpColIdx + numCols);
+  agg->setGroupColIndexes(nArray);
+}
+
+int32_t univPlanSortNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode =
+      univplan::PlanNodeUtil::createPlanBuilderNode(univplan::UNIVPLAN_SORT);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+void univPlanSortSetColIdx(UnivPlanC *up, int64_t numCols,
+                           const int32_t *colIdx) {
+  univplan::UnivPlanBuilderSort *sort =
+      dynamic_cast<univplan::UnivPlanBuilderSort *>(up->curNode.get());
+  std::vector<int32_t> nArray(colIdx, colIdx + numCols);
+  sort->setColIdx(nArray);
+}
+
+void univPlanSortSetSortFuncId(UnivPlanC *up, int64_t numCols,
+                               const int32_t *sortFuncId) {
+  univplan::UnivPlanBuilderSort *sort =
+      dynamic_cast<univplan::UnivPlanBuilderSort *>(up->curNode.get());
+  std::vector<int32_t> nArray(sortFuncId, sortFuncId + numCols);
+  sort->setSortFuncId(nArray);
+}
+
+void univPlanSortAddLimitOffset(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderSort *>(up->curNode.get())
+      ->setLimitOffset(std::move(up->curExpr));
+}
+
+void univPlanSortAddLimitCount(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderSort *>(up->curNode.get())
+      ->setLimitCount(std::move(up->curExpr));
+}
+
+int32_t univPlanLimitNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode =
+      univplan::PlanNodeUtil::createPlanBuilderNode(univplan::UNIVPLAN_LIMIT);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+int32_t univPlanAppendNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode =
+      univplan::PlanNodeUtil::createPlanBuilderNode(univplan::UNIVPLAN_APPEND);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+void univPlanAppendAddAppendPlan(UnivPlanC *up) {
+  const univplan::UnivPlanPlanNodePoly &poly =
+      up->upb->getPlanBuilderPlan()->getPlan()->plan();
+  dynamic_cast<univplan::UnivPlanBuilderAppend *>(up->curNodeBak.top().get())
+      ->addAppendPlan(poly);
+}
+
+static univplan::UNIVPLANJOINTYPE joinTypeMapping(UnivPlanCJoinType type) {
+  switch (type) {
+    case UnivPlanCJoinType::UNIVPLAN_JOIN_INNER:
+      return univplan::UNIVPLANJOINTYPE::JOIN_INNER;
+    case UnivPlanCJoinType::UNIVPLAN_JOIN_LEFT:
+      return univplan::UNIVPLANJOINTYPE::JOIN_LEFT;
+    case UnivPlanCJoinType::UNIVPLAN_JOIN_RIGHT:
+      return univplan::UNIVPLANJOINTYPE::JOIN_RIGHT;
+    case UnivPlanCJoinType::UNIVPLAN_JOIN_FULL:
+      return univplan::UNIVPLANJOINTYPE::JOIN_FULL;
+    default:
+      LOG_INFO("JoinType(%d) not supported yet", type);
+      return univplan::UNIVPLANJOINTYPE::JOIN_NOT_SUPPORTED;
+  }
+}
+
+int32_t univPlanNestLoopNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode = univplan::PlanNodeUtil::createPlanBuilderNode(
+      univplan::UNIVPLAN_NESTLOOP);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+bool univPlanNestLoopSetType(UnivPlanC *up, UnivPlanCJoinType type) {
+  univplan::UNIVPLANJOINTYPE univplanType = joinTypeMapping(type);
+  if (univplanType == univplan::UNIVPLANJOINTYPE::JOIN_NOT_SUPPORTED)
+    return false;
+  dynamic_cast<univplan::UnivPlanBuilderNestLoop *>(up->curNode.get())
+      ->setJoinType(univplanType);
+  return true;
+}
+
+void univPlanNestLoopAddJoinQual(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderNestLoop *>(up->curNode.get())
+      ->addJoinQual(std::move(up->curExpr));
+}
+
+int32_t univPlanHashJoinNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode = univplan::PlanNodeUtil::createPlanBuilderNode(
+      univplan::UNIVPLAN_HASHJOIN);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+bool univPlanHashJoinSetType(UnivPlanC *up, UnivPlanCJoinType type) {
+  switch (type) {
+    case UnivPlanCJoinType::UNIVPLAN_JOIN_INNER:
+    case UnivPlanCJoinType::UNIVPLAN_JOIN_LEFT:
+    case UnivPlanCJoinType::UNIVPLAN_JOIN_IN:
+    case UnivPlanCJoinType::UNIVPLAN_JOIN_LASJ:
+    case UnivPlanCJoinType::UNIVPLAN_JOIN_LASJ_NOTIN:
+      break;
+    default:
+      return false;
+  }
+  dynamic_cast<univplan::UnivPlanBuilderHashJoin *>(up->curNode.get())
+      ->setJoinType(static_cast<univplan::UNIVPLANJOINTYPE>(type));
+  return true;
+}
+
+void univPlanHashJoinAddJoinQual(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderHashJoin *>(up->curNode.get())
+      ->addJoinQual(std::move(up->curExpr));
+}
+
+void univPlanHashJoinAddHashClause(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderHashJoin *>(up->curNode.get())
+      ->addHashClause(std::move(up->curExpr));
+}
+
+void univPlanHashJoinAddHashQualClause(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderHashJoin *>(up->curNode.get())
+      ->addHashQualClause(std::move(up->curExpr));
+}
+
+int32_t univPlanMergeJoinNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode = univplan::PlanNodeUtil::createPlanBuilderNode(
+      univplan::UNIVPLAN_MERGEJOIN);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+bool univPlanMergeJoinSetType(UnivPlanC *up, UnivPlanCJoinType type) {
+  univplan::UNIVPLANJOINTYPE univplanType = joinTypeMapping(type);
+  if (univplanType == univplan::UNIVPLANJOINTYPE::JOIN_NOT_SUPPORTED)
+    return false;
+  dynamic_cast<univplan::UnivPlanBuilderMergeJoin *>(up->curNode.get())
+      ->setJoinType(joinTypeMapping(type));
+  return true;
+}
+
+void univPlanMergeJoinAddJoinQual(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderMergeJoin *>(up->curNode.get())
+      ->addJoinQual(std::move(up->curExpr));
+}
+
+void univPlanMergeJoinAddMergeClause(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderMergeJoin *>(up->curNode.get())
+      ->addMergeClause(std::move(up->curExpr));
+}
+
+int32_t univPlanHashNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode =
+      univplan::PlanNodeUtil::createPlanBuilderNode(univplan::UNIVPLAN_HASH);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+static univplan::UNIVPLANSHARETYPE shareTypeMapping(UnivPlanCShareType type) {
+  switch (type) {
+    case UnivPlanCShareType::UNIVPLAN_SHARE_NOTSHARED:
+      return univplan::UNIVPLANSHARETYPE::SHARE_NOTSHARED;
+    case UnivPlanCShareType::UNIVPLAN_SHARE_MATERIAL_XSLICE:
+      return univplan::UNIVPLANSHARETYPE::SHARE_MATERIAL_XSLICE;
+    default:
+      LOG_INFO("ShareType(%d) not supported yet", type);
+      return univplan::UNIVPLANSHARETYPE::SHARE_NOT_SUPPORTED;
+  }
+}
+
+int32_t univPlanMaterialNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode = univplan::PlanNodeUtil::createPlanBuilderNode(
+      univplan::UNIVPLAN_MATERIAL);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+bool univPlanMaterialSetAttr(UnivPlanC *up, UnivPlanCShareType type,
+                             bool cdbStrict, int32_t shareId,
+                             int32_t driverSlice, int32_t nsharer,
+                             int32_t xslice) {
+  univplan::UNIVPLANSHARETYPE univplanType = shareTypeMapping(type);
+  if (univplanType == univplan::UNIVPLANSHARETYPE::SHARE_NOT_SUPPORTED)
+    return false;
+  dynamic_cast<univplan::UnivPlanBuilderMaterial *>(up->curNode.get())
+      ->setShareType(univplanType)
+      .setCdbStrict(cdbStrict)
+      .setShareId(shareId)
+      .setDriverSlice(driverSlice)
+      .setNSharer(nsharer)
+      .setNSharerXSlice(xslice);
+  return true;
+}
+
+int32_t univPlanShareInputScanNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode = univplan::PlanNodeUtil::createPlanBuilderNode(
+      univplan::UNIVPLAN_SHAREINPUTSCAN);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+bool univPlanShareInputScanSetAttr(UnivPlanC *up, UnivPlanCShareType type,
+                                   int32_t shareId, int32_t driverSlice) {
+  univplan::UNIVPLANSHARETYPE univplanType = shareTypeMapping(type);
+  if (univplanType == univplan::UNIVPLANSHARETYPE::SHARE_NOT_SUPPORTED)
+    return false;
+  univplan::UnivPlanBuilderShareInputScan *bld =
+      dynamic_cast<univplan::UnivPlanBuilderShareInputScan *>(
+          up->curNode.get());
+  bld->setShareType(univplanType);
+  bld->setShareId(shareId);
+  bld->setDriverSlice(driverSlice);
+  return true;
+}
+
+int32_t univPlanResultNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode =
+      univplan::PlanNodeUtil::createPlanBuilderNode(univplan::UNIVPLAN_RESULT);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+void univPlanResultAddResConstantQual(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderResult *>(up->curNode.get())
+      ->addResConstantQual(std::move(up->curExpr));
+}
+
+int32_t univPlanSubqueryScanNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode = univplan::PlanNodeUtil::createPlanBuilderNode(
+      univplan::UNIVPLAN_SUBQUERYSCAN);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+
+void univPlanSubqueryScanAddSubPlan(UnivPlanC *up) {
+  const univplan::UnivPlanPlanNodePoly &poly =
+      up->upb->getPlanBuilderPlan()->getPlan()->plan();
+  dynamic_cast<univplan::UnivPlanBuilderSubqueryScan *>(
+      up->curNodeBak.top().get())
+      ->setSubPlan(poly);
+}
+
+int32_t univPlanUniqueNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode =
+      univplan::PlanNodeUtil::createPlanBuilderNode(univplan::UNIVPLAN_UNIQUE);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  return up->curNode->uid;
+}
+void univPlanUniqueSetNumGroupsAndUniqColIdxs(UnivPlanC *up, int64_t numCols,
+                                              const int32_t *uniqColIdxs) {
+  auto uniq =
+      dynamic_cast<univplan::UnivPlanBuilderUnique *>(up->curNode.get());
+  uniq->setUniqColIdxs(numCols, uniqColIdxs);
+}
+
+int32_t univPlanInsertNewInstance(UnivPlanC *up, int32_t pid) {
+  up->curNode =
+      univplan::PlanNodeUtil::createPlanBuilderNode(univplan::UNIVPLAN_INSERT);
+  up->curNode->pid = pid;
+  up->curNode->uid = up->upb->getUid();
+  up->totalStageNo += 1;
+  return up->curNode->uid;
+}
+
+void univPlanInsertSetRelId(UnivPlanC *up, uint32_t relId) {
+  dynamic_cast<univplan::UnivPlanBuilderInsert *>(up->curNode.get())
+      ->setInsertRelId(relId);
+}
+
+void univPlanAddToPlanNode(UnivPlanC *up, bool isLeft) {
+  up->upb->addPlanNode(isLeft, std::move(up->curNode));
+}
+
+UnivPlanCatchedError *univPlanGetLastError(UnivPlanC *up) {
+  return &(up->error);
+}
+
+void univPlanFixVarType(UnivPlanC *up) {
+  univplan::VarUtil varUtil;
+  varUtil.fixVarType(up->upb->getPlanBuilderPlan()->getPlan()->mutable_plan());
+}
+
+void univPlanStagize(UnivPlanC *up) {
+  univplan::PlanStagizer stagizer;
+  univplan::StagizerContext ctx;
+  ctx.totalStageNo = up->totalStageNo;
+  ctx.subplanStageNo = up->subplanStageNo;
+  stagizer.stagize(up->upb->getPlanBuilderPlan()->getPlan(), &ctx);
+  up->upb = std::move(ctx.upb);
+}
+
+void univPlanAddGuc(UnivPlanC *up, const char *name, const char *value) {
+  up->upb->getPlanBuilderPlan()->addGuc(name, value);
+}
+
+const char *univPlanSerialize(UnivPlanC *up, int32_t *size, bool compress) {
+  // compress
+  if (compress) {
+    std::string serializedPlan = up->upb->serialize();
+    dbcommon::LZ4Compressor comp;
+    comp.compress(serializedPlan.c_str(), serializedPlan.size(),
+                  &up->serializedPlan);
+
+  } else {
+    up->serializedPlan = up->upb->serialize();
+  }
+  *size = up->serializedPlan.size();
+  return up->serializedPlan.data();
+}
+
+const char *univPlanGetJsonFormatedPlan(UnivPlanC *up) {
+  up->debugString = up->upb->getJsonFormatedPlan();
+  return up->debugString.c_str();
+}
+
+void univPlanSetError(UnivPlanCatchedError *ce, int errCode,
+                      const char *errMsg) {
+  assert(ce != nullptr);
+  ce->errCode = errCode;
+  snprintf(ce->errMessage, strlen(errMsg) + 1, "%s", errMsg);
+}
+
+void univPlanNewExpr(UnivPlanC *up) {
+  up->curExpr.reset(new univplan::UnivPlanBuilderExprTree);
+}
+
+void univPlanQualListAddExpr(UnivPlanC *up) {
+  assert(up->curExpr);
+  up->curNode->addQualList(std::move(up->curExpr));
+}
+
+void univPlanInitplanAddExpr(UnivPlanC *up) {
+  assert(up->curExpr);
+  up->curNode->addInitplan(std::move(up->curExpr));
+}
+
+void univPlanTargetListAddTargetEntry(UnivPlanC *up, bool resJunk) {
+  assert(up->curExpr);
+  univplan::UnivPlanBuilderTargetEntry::uptr te =
+      up->curNode->addTargetEntryAndGetBuilder();
+  te->setResJunk(resJunk);
+  te->setExpr(std::move(up->curExpr));
+}
+
+void univPlanConnectorAddHashExpr(UnivPlanC *up) {
+  assert(up->curExpr);
+  // todo assert curNode is connector
+  dynamic_cast<univplan::UnivPlanBuilderConnector *>(up->curNode.get())
+      ->addHashExpr(std::move(up->curExpr));
+}
+
+void univPlanLimitAddLimitOffset(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderLimit *>(up->curNode.get())
+      ->setLimitOffset(std::move(up->curExpr));
+}
+
+void univPlanLimitAddLimitCount(UnivPlanC *up) {
+  assert(up->curExpr);
+  dynamic_cast<univplan::UnivPlanBuilderLimit *>(up->curNode.get())
+      ->setLimitCount(std::move(up->curExpr));
+}
+
+int32_t univPlanExprAddConst(UnivPlanC *up, int32_t pid, int32_t type,
+                             bool isNull, const char *buffer, int64_t typeMod) {
+  assert(up->curExpr);
+  auto constVal =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderConst>(pid);
+  constVal->setType(type).setTypeMod(typeMod).setIsNull(isNull);
+  if (!isNull) constVal->setValue(buffer);
+
+  int32_t uid = constVal->uid;
+  up->curExpr->addExprNode(std::move(constVal));
+  return uid;
+}
+
+int32_t univPlanExprAddVar(UnivPlanC *up, int32_t pid, uint32_t varNo,
+                           int32_t varAttNo, int32_t typeId, int64_t typeMod) {
+  assert(up->curExpr);
+  auto var = up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderVar>(pid);
+  var->setVarNo(varNo).setVarAttNo(varAttNo).setTypeId(typeId).setTypeMod(
+      typeMod);
+
+  int32_t uid = var->uid;
+  up->curExpr->addExprNode(std::move(var));
+  return uid;
+}
+
+int32_t univPlanExprAddOpExpr(UnivPlanC *up, int32_t pid, int32_t funcId) {
+  assert(up->curExpr);
+  auto opExpr =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderOpExpr>(pid);
+  opExpr->setFuncId(funcId);
+  opExpr->setRetType(
+      dbcommon::Func::instance()
+          ->getFuncEntryById(static_cast<dbcommon::FuncKind>(funcId))
+          ->retType);
+
+  int32_t uid = opExpr->uid;
+  up->curExpr->addExprNode(std::move(opExpr));
+  return uid;
+}
+
+int32_t univPlanExprAddFuncExpr(UnivPlanC *up, int32_t pid, int32_t funcId) {
+  assert(up->curExpr);
+  auto funcExpr =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderFuncExpr>(pid);
+  funcExpr->setFuncId(funcId);
+  funcExpr->setRetType(
+      dbcommon::Func::instance()
+          ->getFuncEntryById(static_cast<dbcommon::FuncKind>(funcId))
+          ->retType);
+
+  int32_t uid = funcExpr->uid;
+  up->curExpr->addExprNode(std::move(funcExpr));
+  return uid;
+}
+
+// Add type cast for final stage AGG function, in order to keep compatible with
+// HAWQ's optimizer and executor
+static int32_t univPlanAggrefAddFinalStageTypeCast(
+    UnivPlanC *up, int32_t pid, const dbcommon::AggEntry *aggEnt) {
+  if (aggEnt->aggFnId == dbcommon::FuncKind::AVG_SMALLINT ||
+      aggEnt->aggFnId == dbcommon::FuncKind::AVG_INT ||
+      aggEnt->aggFnId == dbcommon::FuncKind::AVG_BIGINT)
+    return univPlanExprAddFuncExpr(up, pid,
+                                   dbcommon::FuncKind::DOUBLE_TO_DECIMAL);
+  if (aggEnt->aggFnId == dbcommon::FuncKind::SUM_BIGINT)
+    return univPlanExprAddFuncExpr(up, pid,
+                                   dbcommon::FuncKind::BIGINT_TO_DECIMAL);
+  if (aggEnt->aggFnId == dbcommon::FuncKind::SUM_FLOAT)
+    return univPlanExprAddFuncExpr(up, pid,
+                                   dbcommon::FuncKind::DOUBLE_TO_FLOAT);
+  return pid;
+}
+
+int32_t univPlanAggrefAddPartialStage(UnivPlanC *up, int32_t pid,
+                                      int32_t funcId) {
+  assert(up->curExpr);
+  auto aggref =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderAggref>(pid);
+  const dbcommon::AggEntry *aggEntry =
+      dbcommon::Func::instance()->getAggEntryById(
+          static_cast<dbcommon::FuncKind>(funcId));
+  dbcommon::TypeKind retType = dbcommon::Func::instance()
+                                   ->getFuncEntryById(aggEntry->aggTransFnId)
+                                   ->retType;
+  aggref->setFuncId(funcId)
+      .setTransFuncId(aggEntry->aggTransFnId)
+      .setRetType(retType)
+      .setTransInitVal(aggEntry->aggInitVal);
+
+  int32_t uid = aggref->uid;
+  up->curExpr->addExprNode(std::move(aggref));
+  return uid;
+}
+
+int32_t univPlanAggrefAddIntermediateStage(UnivPlanC *up, int32_t pid,
+                                           int32_t funcId) {
+  assert(up->curExpr);
+  auto aggref =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderAggref>(pid);
+  const dbcommon::AggEntry *aggEntry =
+      dbcommon::Func::instance()->getAggEntryById(
+          static_cast<dbcommon::FuncKind>(funcId));
+  dbcommon::TypeKind retType = dbcommon::Func::instance()
+                                   ->getFuncEntryById(aggEntry->aggPrelimFnId)
+                                   ->retType;
+  aggref->setFuncId(funcId)
+      .setTransFuncId(aggEntry->aggPrelimFnId)
+      .setFinalFuncId(dbcommon::FuncKind::FUNCINVALID)
+      .setRetType(retType)
+      .setTransInitVal(aggEntry->aggInitVal);
+
+  int32_t uid = aggref->uid;
+  up->curExpr->addExprNode(std::move(aggref));
+  return uid;
+}
+
+int32_t univPlanAggrefAddFinalStage(UnivPlanC *up, int32_t pid,
+                                    int32_t funcId) {
+  assert(up->curExpr);
+  auto aggref =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderAggref>(pid);
+  const dbcommon::AggEntry *aggEntry =
+      dbcommon::Func::instance()->getAggEntryById(
+          static_cast<dbcommon::FuncKind>(funcId));
+  dbcommon::TypeKind retType =
+      dbcommon::Func::instance()
+          ->getFuncEntryById(aggEntry->aggFinalFn ==
+                                     dbcommon::FuncKind::FUNCINVALID
+                                 ? aggEntry->aggTransFnId
+                                 : aggEntry->aggFinalFn)
+          ->retType;
+  aggref->setFuncId(funcId)
+      .setTransFuncId(aggEntry->aggPrelimFnId)
+      .setFinalFuncId(aggEntry->aggFinalFn)
+      .setRetType(retType)
+      .setTransInitVal(aggEntry->aggInitVal);
+  if (aggEntry->aggFinalFn != dbcommon::FuncKind::FUNCINVALID)
+    aggref->setRetType(dbcommon::Func::instance()
+                           ->getFuncEntryById(aggEntry->aggFinalFn)
+                           ->retType);
+
+  int32_t uid = aggref->uid;
+  aggref->pid = univPlanAggrefAddFinalStageTypeCast(up, pid, aggEntry);
+  up->curExpr->addExprNode(std::move(aggref));
+  return uid;
+}
+
+int32_t univPlanAggrefAddOneStage(UnivPlanC *up, int32_t pid, int32_t funcId) {
+  assert(up->curExpr);
+  auto aggref =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderAggref>(pid);
+  const dbcommon::AggEntry *aggEntry =
+      dbcommon::Func::instance()->getAggEntryById(
+          static_cast<dbcommon::FuncKind>(funcId));
+  dbcommon::TypeKind retType =
+      dbcommon::Func::instance()
+          ->getFuncEntryById(aggEntry->aggFinalFn ==
+                                     dbcommon::FuncKind::FUNCINVALID
+                                 ? aggEntry->aggTransFnId
+                                 : aggEntry->aggFinalFn)
+          ->retType;
+  aggref->setFuncId(funcId)
+      .setTransFuncId(aggEntry->aggTransFnId)
+      .setFinalFuncId(aggEntry->aggFinalFn)
+      .setRetType(retType)
+      .setTransInitVal(aggEntry->aggInitVal);
+
+  int32_t uid = aggref->uid;
+  aggref->pid = univPlanAggrefAddFinalStageTypeCast(up, pid, aggEntry);
+  up->curExpr->addExprNode(std::move(aggref));
+  return uid;
+}
+
+int32_t univPlanAggrefAddProxyVar(UnivPlanC *up, int32_t pid, int32_t varAttNo,
+                                  int32_t funcId, int64_t typeMod) {
+  assert(up->curExpr);
+  auto var = up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderVar>(pid);
+  const dbcommon::AggEntry *aggEntry =
+      dbcommon::Func::instance()->getAggEntryById(
+          static_cast<dbcommon::FuncKind>(funcId));
+  dbcommon::TypeKind retType = dbcommon::Func::instance()
+                                   ->getFuncEntryById(aggEntry->aggTransFnId)
+                                   ->retType;
+  var->setVarNo(OUTER_VAR).setVarAttNo(varAttNo).setTypeId(retType).setTypeMod(
+      typeMod);
+
+  int32_t uid = var->uid;
+  up->curExpr->addExprNode(std::move(var));
+  return uid;
+}
+
+int32_t univPlanExprAddParam(UnivPlanC *up, int32_t pid,
+                             UnivplanParamKind paramKind, int32_t paramId,
+                             int32_t typeId, int64_t typeMod) {
+  assert(up->curExpr);
+  auto param =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderParam>(pid);
+  param->setParamKind(static_cast<univplan::PARAMKIND>(paramKind))
+      .setParamId(paramId)
+      .setTypeId(typeId)
+      .setTypeMod(typeMod);
+
+  int32_t uid = param->uid;
+  up->curExpr->addExprNode(std::move(param));
+  return uid;
+}
+
+int32_t univPlanExprAddSubPlan(UnivPlanC *up, int32_t pid,
+                               UnivplanSubLinkType sublinkType, int32_t planId,
+                               int32_t stageNo, int32_t typeId, int64_t typeMod,
+                               bool useHashTable, bool initPlan) {
+  assert(up->curExpr);
+  auto subplan =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderSubPlan>(pid);
+  subplan->setSubLinkType(static_cast<univplan::SUBLINKTYPE>(sublinkType))
+      .setPlanId(planId)
+      .setTypeId(typeId)
+      .setTypeMod(typeMod)
+      .setUseHashTable(useHashTable)
+      .setInitPlan(initPlan);
+
+  int32_t uid = subplan->uid;
+  up->curExpr->addExprNode(std::move(subplan));
+  if (initPlan) up->subplanStageNo[planId] = stageNo;
+  return uid;
+}
+void univPlanExprAddSubPlanTestexpr(UnivPlanC *up, int32_t subplanId) {
+  reinterpret_cast<univplan::UnivPlanBuilderSubPlan *>(
+      up->curExpr->getExprNode(subplanId))
+      ->setAddingTestexpr();
+}
+
+void univPlanAddTokenEntry(UnivPlanC *up, FileSystemCredentialCPtr tokenEntry) {
+  std::string protocol(tokenEntry->key.protocol);
+  std::string host(tokenEntry->key.host);
+  int port = tokenEntry->key.port;
+  std::string token(tokenEntry->credential);
+  up->upb->getPlanBuilderPlan()->setTokenEntry(protocol, host, port, token);
+}
+
+void univPlanAddSnapshot(UnivPlanC *up, char *snapshot, int32_t snapshot_len) {
+  std::string Snapshot(snapshot, snapshot_len);
+  up->upb->getPlanBuilderPlan()->setSnapshot(Snapshot);
+  // LOG_DEBUG("univplan c add snapshot: %s, size: %d", Snapshot.c_str(),
+  //          snapshot_len);
+}
+
+void univPlanSubPlanAddSetParam(UnivPlanC *up, int32_t subplanId, int32_t num,
+                                int32_t *setParam) {
+  univplan::UnivPlanBuilderSubPlan *builder =
+      reinterpret_cast<univplan::UnivPlanBuilderSubPlan *>(
+          up->curExpr->getExprNode(subplanId));
+  for (int32_t i = 0; i < num; ++i) {
+    builder->addSetParam(setParam[i]);
+  }
+}
+
+void univPlanSubPlanAddParParam(UnivPlanC *up, int32_t subplanId, int32_t num,
+                                int32_t *parParam) {
+  univplan::UnivPlanBuilderSubPlan *builder =
+      reinterpret_cast<univplan::UnivPlanBuilderSubPlan *>(
+          up->curExpr->getExprNode(subplanId));
+  for (int32_t i = 0; i < num; ++i) {
+    builder->addParParam(parParam[i]);
+  }
+}
+
+void univPlanSubPlanAddTestexprParam(UnivPlanC *up, int32_t subplanId,
+                                     int32_t num, int32_t *testexprParam) {
+  univplan::UnivPlanBuilderSubPlan *builder =
+      reinterpret_cast<univplan::UnivPlanBuilderSubPlan *>(
+          up->curExpr->getExprNode(subplanId));
+  for (int32_t i = 0; i < num; ++i) {
+    builder->addTestexprParam(testexprParam[i]);
+  }
+}
+
+int32_t univPlanExprAddBoolExpr(UnivPlanC *up, int32_t pid,
+                                UnivplanBoolExprType boolExprType) {
+  assert(up->curExpr);
+  auto boolExpr =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderBoolExpr>(pid);
+  boolExpr->setType(static_cast<univplan::BOOLEXPRTYPE>(boolExprType));
+
+  int32_t uid = boolExpr->uid;
+  up->curExpr->addExprNode(std::move(boolExpr));
+  return uid;
+}
+int32_t univPlanExprAddNullTestExpr(UnivPlanC *up, int32_t pid,
+                                    UnivplanNullTestType nullTestType) {
+  assert(up->curExpr);
+  auto nullTest =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderNullTest>(pid);
+  nullTest->setType(static_cast<univplan::NULLTESTTYPE>(nullTestType));
+
+  int32_t uid = nullTest->uid;
+  up->curExpr->addExprNode(std::move(nullTest));
+  return uid;
+}
+
+int32_t univPlanExprAddBoolTestExpr(UnivPlanC *up, int32_t pid,
+                                    UnivplanBooleanTestType boolTestType) {
+  assert(up->curExpr);
+  auto boolTest =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderBooleanTest>(pid);
+  boolTest->setType(static_cast<univplan::BOOLTESTTYPE>(boolTestType));
+
+  int32_t uid = boolTest->uid;
+  up->curExpr->addExprNode(std::move(boolTest));
+  return uid;
+}
+
+int32_t univPlanExprAddCaseExpr(UnivPlanC *up, int32_t pid, int32_t casetype) {
+  auto caseexpr =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderCaseExpr>(pid);
+  caseexpr->setCasetype(casetype);
+
+  int32_t uid = caseexpr->uid;
+  up->curExpr->addExprNode(std::move(caseexpr));
+  return uid;
+}
+
+void univPlanExprAddCaseExprDefresult(UnivPlanC *up, int32_t caseexpr_id) {
+  reinterpret_cast<univplan::UnivPlanBuilderCaseExpr *>(
+      up->curExpr->getExprNode(caseexpr_id))
+      ->setAddingDefresult();
+}
+
+int32_t univPlanExprAddCaseWhen(UnivPlanC *up, int32_t pid) {
+  auto casewhen =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderCaseWhen>(pid);
+
+  int32_t uid = casewhen->uid;
+  up->curExpr->addExprNode(std::move(casewhen));
+  return uid;
+}
+
+void univPlanExprAddCaseWhenExpr(UnivPlanC *up, int32_t casewhen_id) {}
+
+void univPlanExprAddCaseWhenResult(UnivPlanC *up, int32_t casewhen_id) {
+  reinterpret_cast<univplan::UnivPlanBuilderCaseWhen *>(
+      up->curExpr->getExprNode(casewhen_id))
+      ->setAddingResult();
+}
+
+int32_t univPlanExprAddScalarArrayOpExpr(UnivPlanC *up, int32_t pid,
+                                         int32_t funcId, bool useOr) {
+  assert(up->curExpr);
+  auto opExpr =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderScalarArrayOpExpr>(
+          pid);
+  opExpr->setFuncId(funcId).setUseOr(useOr);
+
+  int32_t uid = opExpr->uid;
+  up->curExpr->addExprNode(std::move(opExpr));
+  return uid;
+}
+
+int32_t univPlanExprAddCoalesceExpr(UnivPlanC *up, int32_t pid,
+                                    int32_t coalesceType,
+                                    int32_t coalesceTypeMod) {
+  auto coalesceExpr =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderCoalesceExpr>(pid);
+  coalesceExpr->setCoalesceType(coalesceType)
+      .setCoalesceTypeMod(coalesceTypeMod);
+  int32_t uid = coalesceExpr->uid;
+  up->curExpr->addExprNode(std::move(coalesceExpr));
+  return uid;
+}
+
+int32_t univPlanExprAddNullIfExpr(UnivPlanC *up, int32_t pid, int32_t funcId,
+                                  int32_t retType, int32_t typeMod) {
+  assert(up->curExpr);
+  auto nullIfExpr =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderNullIfExpr>(pid);
+  nullIfExpr->setFuncId(funcId);
+  nullIfExpr->setRetType(retType);
+  nullIfExpr->setTypeMod(typeMod);
+
+  int32_t uid = nullIfExpr->uid;
+  up->curExpr->addExprNode(std::move(nullIfExpr));
+  return uid;
+}
+
+int32_t univPlanExprAddDistinctExpr(UnivPlanC *up, int32_t pid,
+                                    int32_t funcId) {
+  assert(up->curExpr);
+  auto distinctExpr =
+      up->curExpr->ExprNodeFactory<univplan::UnivPlanBuilderDistinctExpr>(pid);
+  distinctExpr->setFuncId(funcId);
+  distinctExpr->setRetType(
+      dbcommon::Func::instance()
+          ->getFuncEntryById(static_cast<dbcommon::FuncKind>(funcId))
+          ->retType);
+
+  int32_t uid = distinctExpr->uid;
+  up->curExpr->addExprNode(std::move(distinctExpr));
+  return uid;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/depends/univplan/src/univplan/cwrapper/univplan-c.h b/depends/univplan/src/univplan/cwrapper/univplan-c.h
new file mode 100644
index 0000000..57aa839
--- /dev/null
+++ b/depends/univplan/src/univplan/cwrapper/univplan-c.h
@@ -0,0 +1,340 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_CWRAPPER_UNIVPLAN_C_H_
+#define UNIVPLAN_SRC_UNIVPLAN_CWRAPPER_UNIVPLAN_C_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef ERROR_MESSAGE_BUFFER_SIZE
+#define ERROR_MESSAGE_BUFFER_SIZE 4096
+#endif
+
+struct UnivPlanC;
+
+typedef struct UnivPlanC UnivPlanC;
+
+typedef struct FileSystemCredentialKeyC {
+  char *protocol;
+  char *host;
+  int port;
+} FileSystemCredentialKeyC;
+
+typedef struct FileSystemCredentialC {
+  struct FileSystemCredentialKeyC key;
+  char *credential;
+} FileSystemCredentialC;
+
+typedef struct FileSystemCredentialC *FileSystemCredentialCPtr;
+
+typedef struct UnivPlanCatchedError {
+  int errCode;
+  char errMessage[ERROR_MESSAGE_BUFFER_SIZE];
+} UnivPlanCatchedError;
+
+UnivPlanC *univPlanNewInstance();
+void univPlanFreeInstance(UnivPlanC **up);
+
+void univPlanNewSubPlanNode(UnivPlanC *up);
+void univPlanFreeSubPlanNode(UnivPlanC *up);
+
+// fill RangeTblEntry
+typedef enum FormatType {
+  UnivPlanTextFormat,
+  UnivPlanCsvFormat,
+  UnivPlanOrcFormat,
+  UnivPlanMagmaFormat
+} FormatType;
+void univPlanRangeTblEntryAddTable(UnivPlanC *up, uint64_t tid,
+                                   FormatType format, const char *location,
+                                   const char *optStrInJson, uint32_t columnNum,
+                                   const char **columnName,
+                                   int32_t *columnDataType,
+                                   int64_t *columnDataTypeMod);
+void univPlanRangeTblEntryAddDummy(UnivPlanC *up);
+
+// construct interconnect info
+void univPlanReceiverAddListeners(UnivPlanC *up, uint32_t listenerNum,
+                                  const char **addr, int32_t *port);
+
+// add param info
+void univPlanAddParamInfo(UnivPlanC *up, int32_t type, bool isNull,
+                          const char *buffer);
+
+void univPlanSetDoInstrument(UnivPlanC *up, bool doInstrument);
+
+void univPlanSetNCrossLevelParams(UnivPlanC *up, int32_t nCrossLevelParams);
+
+typedef enum UnivPlanCCmdType {
+  UNIVPLAN_CMD_UNKNOWN,
+  UNIVPLAN_CMD_SELECT,
+  UNIVPLAN_CMD_UPDATE,
+  UNIVPLAN_CMD_INSERT,
+  UNIVPLAN_CMD_DELETE,
+  UNIVPLAN_CMD_UTILITY,
+  UNIVPLAN_CMD_NOTHING
+} UnivPlanCCmdType;
+void univPlanSetCmdType(UnivPlanC *up, UnivPlanCCmdType type);
+
+void univPlanSetPlanNodeInfo(UnivPlanC *up, double planRows,
+                             int32_t planRowWidth, uint64_t operatorMemKB);
+
+/*
+ * the expr tree must be built before adding targetlist/qualist
+ */
+void univPlanQualListAddExpr(UnivPlanC *up);
+void univPlanInitplanAddExpr(UnivPlanC *up);
+void univPlanTargetListAddTargetEntry(UnivPlanC *up, bool resJunk);
+void univPlanConnectorAddHashExpr(UnivPlanC *up);
+void univPlanConnectorSetRangeVsegMap(UnivPlanC *up, int *map, bool magmaTable);
+// set magma range num
+void univPlanSetRangeNum(UnivPlanC *up, int rangeNum);
+
+// construct Connector
+typedef enum ConnectorType {
+  UnivPlanShuffle,
+  UnivPlanBroadcast,
+  UnivPlanConverge
+} ConnectorType;
+int32_t univPlanConnectorNewInstance(UnivPlanC *up, int32_t);
+void univPlanConnectorSetType(UnivPlanC *up, ConnectorType type);
+void univPlanConnectorSetStageNo(UnivPlanC *up, int32_t stageNo);
+void univPlanConnectorSetColIdx(UnivPlanC *up, int64_t numCols,
+                                const int32_t *colIdx);
+void univPlanConnectorSetSortFuncId(UnivPlanC *up, int64_t numCols,
+                                    const int32_t *sortFuncId);
+
+// construct ExtScan
+int32_t univPlanExtScanNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanExtScanSetRelId(UnivPlanC *up, uint32_t relId);
+void univPlanExtScanSetColumnsToRead(UnivPlanC *up, int64_t numCols,
+                                     const int32_t *columnsToRead);
+// construct magma index info
+void univPlanExtScanSetIndex(UnivPlanC *up, bool index);
+void univPlanExtScanSetScanType(UnivPlanC *up, int type);
+void univPlanExtScanDirection(UnivPlanC *up, int direction);
+void univPlanExtScanSetIndexName(UnivPlanC *up, const char *indexName);
+void univPlanIndexQualListAddExpr(UnivPlanC *up);
+
+/*void univPlanExtScanAddTaskWithFileSplits(UnivPlanC *up, uint32_t
+   fileSplitNum, int64_t *lbLen, int64_t *ubLen, const char **lowerBound, const
+   char **upperBound);
+*/
+// construct SeqScan
+int32_t univPlanSeqScanNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanSeqScanSetRelId(UnivPlanC *up, uint32_t relId);
+void univPlanSeqScanSetReadStatsOnly(UnivPlanC *up, bool readStatsOnly);
+void univPlanSeqScanSetColumnsToRead(UnivPlanC *up, int64_t numCols,
+                                     const int32_t *columnsToRead);
+void univPlanSeqScanAddTaskWithFileSplits(bool isMagma, UnivPlanC *up,
+                                          uint32_t fileSplitNum,
+                                          const char **fileName, int64_t *start,
+                                          int64_t *len, int32_t *rangeid,
+                                          int32_t *rgid);
+
+// construct Agg
+int32_t univPlanAggNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanAggSetNumGroupsAndGroupColIndexes(UnivPlanC *up, int64_t numGroups,
+                                               int64_t numCols,
+                                               const int32_t *grpColIdx);
+
+// construct Sort
+int32_t univPlanSortNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanSortSetColIdx(UnivPlanC *up, int64_t numCols,
+                           const int32_t *colIdx);
+void univPlanSortSetSortFuncId(UnivPlanC *up, int64_t numCols,
+                               const int32_t *sortFuncId);
+void univPlanSortAddLimitOffset(UnivPlanC *up);
+void univPlanSortAddLimitCount(UnivPlanC *up);
+
+// construct Limit
+int32_t univPlanLimitNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanLimitAddLimitOffset(UnivPlanC *up);
+void univPlanLimitAddLimitCount(UnivPlanC *up);
+
+// construct append
+int32_t univPlanAppendNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanAppendAddAppendPlan(UnivPlanC *up);
+
+typedef enum UnivPlanCJoinType {
+  UNIVPLAN_JOIN_INNER,
+  UNIVPLAN_JOIN_LEFT,
+  UNIVPLAN_JOIN_RIGHT,
+  UNIVPLAN_JOIN_FULL,
+  UNIVPLAN_JOIN_IN,
+  UNIVPLAN_JOIN_LASJ = 8,
+  UNIVPLAN_JOIN_LASJ_NOTIN = 9
+} UnivPlanCJoinType;
+// construct nestloop
+int32_t univPlanNestLoopNewInstance(UnivPlanC *up, int32_t pid);
+bool univPlanNestLoopSetType(UnivPlanC *up, UnivPlanCJoinType type);
+void univPlanNestLoopAddJoinQual(UnivPlanC *up);
+// construct hashjoin
+int32_t univPlanHashJoinNewInstance(UnivPlanC *up, int32_t pid);
+bool univPlanHashJoinSetType(UnivPlanC *up, UnivPlanCJoinType type);
+void univPlanHashJoinAddJoinQual(UnivPlanC *up);
+void univPlanHashJoinAddHashClause(UnivPlanC *up);
+void univPlanHashJoinAddHashQualClause(UnivPlanC *up);
+// construct mergejoin
+int32_t univPlanMergeJoinNewInstance(UnivPlanC *up, int32_t pid);
+bool univPlanMergeJoinSetType(UnivPlanC *up, UnivPlanCJoinType type);
+void univPlanMergeJoinAddJoinQual(UnivPlanC *up);
+void univPlanMergeJoinAddMergeClause(UnivPlanC *up);
+
+// construct hash
+int32_t univPlanHashNewInstance(UnivPlanC *up, int32_t pid);
+
+typedef enum UnivPlanCShareType {
+  UNIVPLAN_SHARE_NOTSHARED,
+  UNIVPLAN_SHARE_MATERIAL,
+  UNIVPLAN_SHARE_MATERIAL_XSLICE,
+  UNIVPLAN_SHARE_SORT,
+  UNIVPLAN_SHARE_SORT_XSLICE
+} UnivPlanCShareType;
+// construct material
+int32_t univPlanMaterialNewInstance(UnivPlanC *up, int32_t pid);
+bool univPlanMaterialSetAttr(UnivPlanC *up, UnivPlanCShareType type,
+                             bool cdbStrict, int32_t shareId,
+                             int32_t driverSlice, int32_t nsharer,
+                             int32_t xslice);
+
+// construct shareinputscan
+int32_t univPlanShareInputScanNewInstance(UnivPlanC *up, int32_t pid);
+bool univPlanShareInputScanSetAttr(UnivPlanC *up, UnivPlanCShareType type,
+                                   int32_t shareId, int32_t driverSlice);
+
+// construct result
+int32_t univPlanResultNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanResultAddResConstantQual(UnivPlanC *up);
+
+// construct subqueryscan
+int32_t univPlanSubqueryScanNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanSubqueryScanAddSubPlan(UnivPlanC *up);
+
+// construct Unique
+int32_t univPlanUniqueNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanUniqueSetNumGroupsAndUniqColIdxs(UnivPlanC *up, int64_t numCols,
+                                              const int32_t *uniqColIdxs);
+
+// construct Insert
+int32_t univPlanInsertNewInstance(UnivPlanC *up, int32_t pid);
+void univPlanInsertSetRelId(UnivPlanC *up, uint32_t relId);
+
+void univPlanAddToPlanNode(UnivPlanC *up, bool isLeft);
+
+void univPlanFixVarType(UnivPlanC *up);
+
+void univPlanStagize(UnivPlanC *up);
+
+void univPlanAddGuc(UnivPlanC *up, const char *name, const char *value);
+
+const char *univPlanSerialize(UnivPlanC *up, int32_t *size, bool compress);
+
+UnivPlanCatchedError *univPlanGetLastError(UnivPlanC *up);
+
+// call before add expr node
+void univPlanNewExpr(UnivPlanC *up);
+
+// following functions return the id of the new expr node in the expr tree
+// which will be used as the pid for adding its argument in the expr tree
+int32_t univPlanExprAddConst(UnivPlanC *up, int32_t pid, int32_t type,
+                             bool isNull, const char *buffer, int64_t typeMod);
+int32_t univPlanExprAddVar(UnivPlanC *up, int32_t pid, uint32_t varNo,
+                           int32_t varAttNo, int32_t typeId, int64_t typeMod);
+int32_t univPlanExprAddOpExpr(UnivPlanC *up, int32_t pid, int32_t funcId);
+int32_t univPlanExprAddFuncExpr(UnivPlanC *up, int32_t pid, int32_t funcId);
+int32_t univPlanAggrefAddPartialStage(UnivPlanC *up, int32_t pid,
+                                      int32_t funcId);
+int32_t univPlanAggrefAddIntermediateStage(UnivPlanC *up, int32_t pid,
+                                           int32_t funcId);
+int32_t univPlanAggrefAddFinalStage(UnivPlanC *up, int32_t pid, int32_t funcId);
+int32_t univPlanAggrefAddOneStage(UnivPlanC *up, int32_t pid, int32_t funcId);
+int32_t univPlanAggrefAddProxyVar(UnivPlanC *up, int32_t pid, int32_t varAttNo,
+                                  int32_t funcId, int64_t typeMod);
+typedef enum { UNIVPLAN_PARAM_EXTERN, UNIVPLAN_PARAM_EXEC } UnivplanParamKind;
+int32_t univPlanExprAddParam(UnivPlanC *up, int32_t pid,
+                             UnivplanParamKind paramKind, int32_t paramId,
+                             int32_t typeId, int64_t typeMod);
+typedef enum {
+  UNIVPLAN_EXISTS_SUBLINK = 0,
+  UNIVPLAN_ALL_SUBLINK = 1,
+  UNIVPLAN_ANY_SUBLINK = 2,
+  UNIVPLAN_ROWCOMPARE_SUBLINK = 3,
+  UNIVPLAN_EXPR_SUBLINK = 4,
+  UNIVPLAN_ARRAY_SUBLINK = 5,
+  UNIVPLAN_NOT_EXISTS_SUBLINK = 6
+} UnivplanSubLinkType;
+int32_t univPlanExprAddSubPlan(UnivPlanC *up, int32_t pid,
+                               UnivplanSubLinkType sublinkType, int32_t planId,
+                               int32_t stageNo, int32_t typeId, int64_t typeMod,
+                               bool useHashTable, bool initPlan);
+void univPlanExprAddSubPlanTestexpr(UnivPlanC *up, int32_t subplanId);
+
+void univPlanAddTokenEntry(UnivPlanC *up, FileSystemCredentialCPtr tokenEntry);
+void univPlanAddSnapshot(UnivPlanC *up, char *snapshot, int32_t snapshot_len);
+void univPlanSubPlanAddSetParam(UnivPlanC *up, int32_t subplanId, int32_t num,
+                                int32_t *setParam);
+void univPlanSubPlanAddParParam(UnivPlanC *up, int32_t subplanId, int32_t num,
+                                int32_t *parParam);
+void univPlanSubPlanAddTestexprParam(UnivPlanC *up, int32_t subplanId,
+                                     int32_t num, int32_t *testexprParam);
+
+typedef enum {
+  UNIVPLAN_BOOLEXPRTYPE_AND_EXPR,
+  UNIVPLAN_BOOLEXPRTYPE_OR_EXPR,
+  UNIVPLAN_BOOLEXPRTYPE_NOT_EXPR
+} UnivplanBoolExprType;
+int32_t univPlanExprAddBoolExpr(UnivPlanC *up, int32_t pid,
+                                UnivplanBoolExprType boolExprType);
+typedef enum {
+  UNIVPLAN_NULLTESTTYPE_IS_NULL,
+  UNIVPLAN_NULLTESTTYPE_IS_NOT_NULL
+} UnivplanNullTestType;
+int32_t univPlanExprAddNullTestExpr(UnivPlanC *up, int32_t pid,
+                                    UnivplanNullTestType nullTestType);
+
+typedef enum {
+  UNIVPLAN_BOOLEANTESTTYPE_IS_TRUE,
+  UNIVPLAN_BOOLEANTESTTYPE_IS_NOT_TRUE,
+  UNIVPLAN_BOOLEANTESTTYPE_IS_FALSE,
+  UNIVPLAN_BOOLEANTESTTYPE_IS_NOT_FALSE,
+  UNIVPLAN_BOOLEANTESTTYPE_IS_UNKNOWN,
+  UNIVPLAN_BOOLEANTESTTYPE_IS_NOT_UNKNOWN
+} UnivplanBooleanTestType;
+int32_t univPlanExprAddBoolTestExpr(UnivPlanC *up, int32_t pid,
+                                    UnivplanBooleanTestType boolTestType);
+
+int32_t univPlanExprAddCaseExpr(UnivPlanC *up, int32_t pid, int32_t casetype);
+void univPlanExprAddCaseExprDefresult(UnivPlanC *up, int32_t caseexpr_id);
+int32_t univPlanExprAddCaseWhen(UnivPlanC *up, int32_t pid);
+void univPlanExprAddCaseWhenExpr(UnivPlanC *up, int32_t casewhen_id);
+void univPlanExprAddCaseWhenResult(UnivPlanC *up, int32_t casewhen_id);
+
+int32_t univPlanExprAddScalarArrayOpExpr(UnivPlanC *up, int32_t pid,
+                                         int32_t funcId, bool useOr);
+
+int32_t univPlanExprAddCoalesceExpr(UnivPlanC *up, int32_t pid,
+                                    int32_t coalesceType,
+                                    int32_t coalesceTypeMod);
+
+int32_t univPlanExprAddNullIfExpr(UnivPlanC *up, int32_t pid, int32_t funcId,
+                                  int32_t retType, int32_t typeMod);
+
+int32_t univPlanExprAddDistinctExpr(UnivPlanC *up, int32_t pid, int32_t funcId);
+
+// debug
+const char *univPlanGetJsonFormatedPlan(UnivPlanC *up);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_CWRAPPER_UNIVPLAN_C_H_
diff --git a/depends/univplan/src/univplan/minmax/minmax-predicates.cc b/depends/univplan/src/univplan/minmax/minmax-predicates.cc
new file mode 100644
index 0000000..0fb26aa
--- /dev/null
+++ b/depends/univplan/src/univplan/minmax/minmax-predicates.cc
@@ -0,0 +1,583 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+#include "univplan/minmax/minmax-predicates.h"
+
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include "dbcommon/log/logger.h"
+#include "dbcommon/type/type-util.h"
+#include "dbcommon/utils/string-util.h"
+
+#include "univplan/common/plannode-walker.h"
+
+namespace univplan {
+
+ListPredicate::ListPredicate(const univplan::UnivPlanExprPolyList* exprs,
+                             const MinMaxPredicatesAbstract* pred)
+    : PredicateOper(pred) {
+  for (int i = 0; i < exprs->size(); ++i) {
+    children.push_back(
+        MinMaxPredicatesAbstract::buildPredicateOper(&exprs->Get(i), pred));
+  }
+}
+
+bool ListPredicate::canDrop() {
+  // behave as And
+  for (PredicateOper::uptr& child : children) {
+    if (child->canDrop()) return true;
+  }
+  return false;
+}
+
+BooleanPredicate::BooleanPredicate(const MinMaxPredicatesAbstract* pred,
+                                   const univplan::UnivPlanBoolExpr* op)
+    : PredicateOper(pred) {
+  for (int i = 0; i < op->args_size(); ++i) {
+    children.push_back(
+        MinMaxPredicatesAbstract::buildPredicateOper(&op->args(i), pred));
+  }
+}
+
+bool VarPredicate::canDrop() {
+  if (PREDPAGE(pred)->hasAllNull(var->varattno())) return true;
+  PredicateStats s = PREDPAGE(pred)->getMinMax(var->varattno());
+  if (s.hasMinMax && !dbcommon::DatumGetValue<bool>(s.maxValue.value))
+    return true;
+  return false;
+}
+
+bool IsTrueBooleanTestPredicate::canDrop() {
+  if (PREDPAGE(pred)->hasAllNull(var->varattno())) return true;
+  PredicateStats s = PREDPAGE(pred)->getMinMax(var->varattno());
+  if (s.hasMinMax && !dbcommon::DatumGetValue<bool>(s.maxValue.value))
+    return true;
+  return false;
+}
+
+bool IsNotTrueBooleanTestPredicate::canDrop() {
+  if (!PREDPAGE(pred)->hasNull(var->varattno())) {
+    PredicateStats s = PREDPAGE(pred)->getMinMax(var->varattno());
+    if (s.hasMinMax && dbcommon::DatumGetValue<bool>(s.minValue.value))
+      return true;
+  }
+  return false;
+}
+
+bool IsFalseBooleanTestPredicate::canDrop() {
+  if (PREDPAGE(pred)->hasAllNull(var->varattno())) return true;
+  PredicateStats s = PREDPAGE(pred)->getMinMax(var->varattno());
+  if (s.hasMinMax && dbcommon::DatumGetValue<bool>(s.minValue.value))
+    return true;
+  return false;
+}
+
+bool IsNotFalseBooleanTestPredicate::canDrop() {
+  if (!PREDPAGE(pred)->hasNull(var->varattno())) {
+    PredicateStats s = PREDPAGE(pred)->getMinMax(var->varattno());
+    if (s.hasMinMax && !dbcommon::DatumGetValue<bool>(s.maxValue.value))
+      return true;
+  }
+  return false;
+}
+
+bool IsUnknownBooleanTestPredicate::canDrop() {
+  if (!PREDPAGE(pred)->hasNull(var->varattno())) return true;
+  return false;
+}
+
+bool IsNotUnknownBooleanTestPredicate::canDrop() {
+  if (PREDPAGE(pred)->hasAllNull(var->varattno())) return true;
+  return false;
+}
+
+bool AndPredicate::canDrop() {
+  // as long as one branch is OK to drop, we can drop it.
+  for (PredicateOper::uptr& child : children) {
+    if (child->canDrop()) return true;
+  }
+  return false;
+}
+
+bool OrPredicate::canDrop() {
+  // as long as one branch is NOT ok to drop, we can NOT drop it.
+  for (PredicateOper::uptr& child : children) {
+    if (!child->canDrop()) return false;
+  }
+  return true;
+}
+
+bool IsNullPredicate::canDrop() {
+  // as long as one var has null, we can't drop it
+  for (auto index : varAttrNo) {
+    if (PREDPAGE(pred)->hasNull(index)) return false;
+  }
+  return true;
+}
+
+bool IsNotNullPredicate::canDrop() {
+  // if one var has all null, we can drop it
+  for (auto index : varAttrNo) {
+    if (PREDPAGE(pred)->hasAllNull(index)) return true;
+  }
+  return false;
+}
+
+dbcommon::TupleBatch::uptr CompPredicate::buildTupleBatch(int32_t argIndex) {
+  dbcommon::TupleBatch::uptr batch(
+      new dbcommon::TupleBatch(*PREDPAGE(pred)->getTupleDesc(), true));
+  dbcommon::TupleBatchWriter& writer = batch->getTupleBatchWriter();
+  for (uint32_t i = 0; i < batch->getNumOfColumns(); ++i) {
+    if (varAttNo[argIndex].size() == 1 && i == varAttNo[argIndex][0] - 1) {
+      PredicateStats s =
+          PREDPAGE(pred)->getMinMax(i + 1, &minTimestamp, &maxTimestamp);
+      if (!s.hasMinMax) return nullptr;
+      writer[i]->append(&s.minValue);
+      writer[i]->append(&s.maxValue);
+    }
+  }
+  batch->incNumOfRows(2);
+  return std::move(batch);
+}
+
+PredicateStats::uptr CompPredicate::calcLeft() { return doCalc(0); }
+
+PredicateStats::uptr CompPredicate::calcRight() { return doCalc(1); }
+
+PredicateStats::uptr CompPredicate::doCalc(int32_t argIndex) {
+  PredicateStats::uptr stats(new PredicateStats);
+
+  if (varAttNo[argIndex].size() == 1 &&
+      PREDPAGE(pred)->hasAllNull(varAttNo[argIndex][0])) {
+    stats->hasAllNull = true;
+    return std::move(stats);
+  }
+
+  tbVec_.push_back(buildTupleBatch(argIndex));
+  if (!tbVec_[argIndex]) return nullptr;
+  ExprContext context;
+  context.scanBatch = tbVec_[argIndex].get();
+  dbcommon::Object* obj = dbcommon::DatumGetValue<dbcommon::Object*>(
+      args[argIndex]->calc(&context));
+  dbcommon::Vector* vec = dynamic_cast<dbcommon::Vector*>(obj);
+  if (!vec) {
+    dbcommon::Scalar* scalar = dynamic_cast<dbcommon::Scalar*>(obj);
+    stats->maxValue = *scalar;
+    stats->minValue = *scalar;
+  } else {
+    dbcommon::Scalar s1;
+    dbcommon::Scalar s2;
+    vec->readPlainScalar(0, &s1);
+    vec->readPlainScalar(1, &s2);
+    int32_t comRes =
+        compareTo(s1, typeKinds[argIndex], s2, typeKinds[argIndex]);
+    stats->maxValue = comRes >= 0 ? s1 : s2;
+    stats->minValue = comRes <= 0 ? s1 : s2;
+  }
+  return std::move(stats);
+}
+
+bool CompPredicate::isValidToPredicate() const {
+  // for arg1 op arg2, currently we only allow at most one variable
+  // exists in each side, and the two vars can't be the same one
+  if (varAttNo[0].size() > 1 || varAttNo[1].size() > 1) return false;
+
+  if (varAttNo[0].size() == 1 && varAttNo[1].size() == 1 &&
+      varAttNo[0][0] == varAttNo[1][0])
+    return false;
+
+  return true;
+}
+
+std::string CompPredicate::covertPredicateTypeStr(std::string typeName) {
+  if (typeName == "date")
+    return "int32";
+  else if (typeName == "time")
+    return "int64";
+  else if (typeName == "bpchar" || typeName == "varchar")
+    return "string";
+  return typeName;
+}
+
+int32_t CompPredicate::compareTo(const dbcommon::Scalar& s1,
+                                 dbcommon::TypeKind t1,
+                                 const dbcommon::Scalar& s2,
+                                 dbcommon::TypeKind t2) {
+  std::string type1 =
+      covertPredicateTypeStr(dbcommon::TypeUtil::getTypeNameById(t1));
+  std::string type2 =
+      covertPredicateTypeStr(dbcommon::TypeUtil::getTypeNameById(t2));
+  std::string funcName = type1 + "_less_than_" + type2;
+  const dbcommon::FuncEntry* funcEntry =
+      dbcommon::Func::instance()->getFuncEntryByName(funcName);
+  if (!funcEntry)
+    LOG_ERROR(ERRCODE_INTERNAL_ERROR, "func name %s not found in func system",
+              funcName.c_str());
+  std::unique_ptr<dbcommon::Object> retval(new dbcommon::Scalar);
+  std::unique_ptr<dbcommon::Invoker> invoker(
+      new dbcommon::Invoker(funcEntry->funcId));
+  invoker->resetPrarmeter();
+  invoker->addParam(dbcommon::CreateDatum<dbcommon::Object*>(retval.get()));
+  invoker->addParam(dbcommon::CreateDatum<const dbcommon::Object*>(&s1));
+  invoker->addParam(dbcommon::CreateDatum<const dbcommon::Object*>(&s2));
+  invoker->invoke();
+  if (dbcommon::DatumGetValue<bool>(
+          dynamic_cast<dbcommon::Scalar*>(retval.get())->value))
+    return -1;
+
+  funcName = type1 + "_equal_" + type2;
+  funcEntry = dbcommon::Func::instance()->getFuncEntryByName(funcName);
+  if (!funcEntry)
+    LOG_ERROR(ERRCODE_INTERNAL_ERROR, "func name %s not found in func system",
+              funcName.c_str());
+  invoker.reset(new dbcommon::Invoker(funcEntry->funcId));
+  invoker->resetPrarmeter();
+  invoker->addParam(dbcommon::CreateDatum<dbcommon::Object*>(retval.get()));
+  invoker->addParam(dbcommon::CreateDatum<const dbcommon::Object*>(&s1));
+  invoker->addParam(dbcommon::CreateDatum<const dbcommon::Object*>(&s2));
+  invoker->invoke();
+  if (dbcommon::DatumGetValue<bool>(
+          dynamic_cast<dbcommon::Scalar*>(retval.get())->value))
+    return 0;
+
+  return 1;
+}
+
+bool EqualPredicate::canDrop() {
+  if (!isValidToPredicate()) return false;
+
+  PredicateStats::uptr leftStat = this->calcLeft();
+  PredicateStats::uptr rightStat = this->calcRight();
+
+  // left or right has no statistics
+  if (leftStat == nullptr || rightStat == nullptr) return false;
+
+  // if either side is ALL null, can drop
+  if (leftStat->hasAllNull || rightStat->hasAllNull) return true;
+
+  // can drop when left's max < right's min, or right's max < left's min
+  if (compareTo(leftStat->maxValue, typeKinds[0], rightStat->minValue,
+                typeKinds[1]) < 0 ||
+      compareTo(rightStat->maxValue, typeKinds[1], leftStat->minValue,
+                typeKinds[0]) < 0)
+    return true;
+
+  // now check bloom filter
+  int32_t columnId;
+  PredicateStats* stat;
+  dbcommon::TypeKind type;
+  if (expr->args(0).has_var() && expr->args(1).has_val()) {
+    columnId = expr->args(0).var().varattno();
+    stat = rightStat.get();
+    type = typeKinds[1];
+  } else if (expr->args(1).has_var() && expr->args(0).has_val()) {
+    columnId = expr->args(1).var().varattno();
+    stat = leftStat.get();
+    type = typeKinds[0];
+  } else {
+    return false;
+  }
+
+  if (PREDPAGE(pred)->canDropByBloomFilter(columnId, stat, type)) return true;
+
+  return false;
+}
+
+bool NEPredicate::canDrop() {
+  if (!isValidToPredicate()) return false;
+
+  PredicateStats::uptr leftStat = this->calcLeft();
+  PredicateStats::uptr rightStat = this->calcRight();
+
+  // left or right has no statistics
+  if (leftStat == nullptr || rightStat == nullptr) return false;
+
+  // if either side is ALL null, can drop
+  if (leftStat->hasAllNull || rightStat->hasAllNull) return true;
+
+  // can drop when there is only one unique value.
+  if (compareTo(leftStat->minValue, typeKinds[0], leftStat->maxValue,
+                typeKinds[0]) == 0 &&
+      compareTo(rightStat->minValue, typeKinds[1], rightStat->maxValue,
+                typeKinds[1]) == 0 &&
+      compareTo(leftStat->maxValue, typeKinds[0], rightStat->maxValue,
+                typeKinds[1]) == 0)
+    return true;
+  else
+    return false;
+}
+
+bool GTPredicate::canDrop() {
+  if (!isValidToPredicate()) return false;
+
+  PredicateStats::uptr leftStat = this->calcLeft();
+  PredicateStats::uptr rightStat = this->calcRight();
+
+  // left or right has no statistics
+  if (leftStat == nullptr || rightStat == nullptr) return false;
+
+  // if either side is ALL null, can drop
+  if (leftStat->hasAllNull || rightStat->hasAllNull) return true;
+
+  // can drop when left's max <= right's min.
+  if (compareTo(leftStat->maxValue, typeKinds[0], rightStat->minValue,
+                typeKinds[1]) <= 0)
+    return true;
+  else
+    return false;
+}
+
+bool GEPredicate::canDrop() {
+  if (!isValidToPredicate()) return false;
+
+  PredicateStats::uptr leftStat = this->calcLeft();
+  PredicateStats::uptr rightStat = this->calcRight();
+
+  // left or right has no statistics
+  if (leftStat == nullptr || rightStat == nullptr) return false;
+
+  // if either side is ALL null, can drop
+  if (leftStat->hasAllNull || rightStat->hasAllNull) return true;
+
+  // can drop when left's max < right's min.
+  if (compareTo(leftStat->maxValue, typeKinds[0], rightStat->minValue,
+                typeKinds[1]) < 0) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool LTPredicate::canDrop() {
+  if (!isValidToPredicate()) return false;
+
+  PredicateStats::uptr leftStat = this->calcLeft();
+  PredicateStats::uptr rightStat = this->calcRight();
+
+  // left or right has no statistics
+  if (leftStat == nullptr || rightStat == nullptr) return false;
+
+  // if either side is ALL null, can drop
+  if (leftStat->hasAllNull || rightStat->hasAllNull) return true;
+
+  // can drop when right's max <= left's min.
+  if (compareTo(rightStat->maxValue, typeKinds[1], leftStat->minValue,
+                typeKinds[0]) <= 0)
+    return true;
+  else
+    return false;
+}
+
+bool LEPredicate::canDrop() {
+  if (!isValidToPredicate()) return false;
+
+  PredicateStats::uptr leftStat = this->calcLeft();
+  PredicateStats::uptr rightStat = this->calcRight();
+
+  // left or right has no statistics
+  if (leftStat == nullptr || rightStat == nullptr) return false;
+
+  // if either side is ALL null, can drop
+  if (leftStat->hasAllNull || rightStat->hasAllNull) return true;
+
+  // can drop when right's max < left's min.
+  if (compareTo(rightStat->maxValue, typeKinds[1], leftStat->minValue,
+                typeKinds[0]) < 0)
+    return true;
+  else
+    return false;
+}
+
+PredicateOper::uptr MinMaxPredicatesAbstract::buildPredicateOper(
+    const univplan::UnivPlanExprPolyList* exprs,
+    const MinMaxPredicatesAbstract* owner) {
+  return PredicateOper::uptr(new ListPredicate(exprs, owner));
+}
+
+PredicateOper::uptr MinMaxPredicatesAbstract::buildPredicateOper(
+    const univplan::UnivPlanExprPoly* expr,
+    const MinMaxPredicatesAbstract* owner) {
+  switch (expr->type()) {
+    case univplan::UNIVPLAN_EXPR_OPEXPR: {
+      const univplan::UnivPlanOpExpr& op = expr->opexpr();
+      CompPredicate::uptr ret;
+      std::string funcName =
+          dbcommon::Func::instance()
+              ->getFuncEntryById(static_cast<dbcommon::FuncKind>(op.funcid()))
+              ->funcName;
+      if (dbcommon::StringUtil::countReplicates(funcName, "less_than") == 1)
+        ret.reset(new LTPredicate(owner, &op));
+      else if (dbcommon::StringUtil::countReplicates(funcName, "less_eq") == 1)
+        ret.reset(new LEPredicate(owner, &op));
+      else if (dbcommon::StringUtil::countReplicates(funcName, "not_equal") ==
+               1)
+        ret.reset(new NEPredicate(owner, &op));
+      else if (dbcommon::StringUtil::countReplicates(funcName, "equal") == 1)
+        ret.reset(new EqualPredicate(owner, &op));
+      else if (dbcommon::StringUtil::countReplicates(funcName,
+                                                     "greater_than") == 1)
+        ret.reset(new GTPredicate(owner, &op));
+      else if (dbcommon::StringUtil::countReplicates(funcName, "greater_eq") ==
+               1)
+        ret.reset(new GEPredicate(owner, &op));
+      else
+        goto end;
+      for (int i = 0; i < op.args_size(); ++i)
+        ret->addArg(InitExpr(&op.args(i)));
+      return std::move(ret);
+    }
+    case univplan::UNIVPLAN_EXPR_BOOLEXPR: {
+      const univplan::UnivPlanBoolExpr& op = expr->boolexpr();
+      BooleanPredicate::uptr ret;
+      if (op.type() == univplan::BOOLEXPRTYPE::BOOLEXPRTYPE_AND_EXPR)
+        ret.reset(new AndPredicate(owner, &op));
+      else if (op.type() == univplan::BOOLEXPRTYPE::BOOLEXPRTYPE_OR_EXPR)
+        ret.reset(new OrPredicate(owner, &op));
+      else
+        goto end;
+      return std::move(ret);
+    }
+    case univplan::UNIVPLAN_EXPR_NULLTEST: {
+      const univplan::UnivPlanNullTest& op = expr->nulltest();
+      NullTestPredicate::uptr ret;
+      if (op.type() == univplan::NULLTESTTYPE::NULLTESTTYPE_IS_NULL) {
+        ret.reset(new IsNullPredicate(owner, &op));
+      } else {
+        assert(op.type() == univplan::NULLTESTTYPE::NULLTESTTYPE_IS_NOT_NULL);
+        ret.reset(new IsNotNullPredicate(owner, &op));
+      }
+      return std::move(ret);
+    }
+    case univplan::UNIVPLAN_EXPR_VAR: {
+      const univplan::UnivPlanVar& var = expr->var();
+      VarPredicate::uptr ret(new VarPredicate(owner, &var));
+      return std::move(ret);
+    }
+    case univplan::UNIVPLAN_EXPR_BOOLEANTEST: {
+      const univplan::UnivPlanBooleanTest& op = expr->booltest();
+      BooleanTestPredicate::uptr ret;
+      if (op.type() == univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_TRUE) {
+        ret.reset(new IsTrueBooleanTestPredicate(owner, &op));
+      } else if (op.type() ==
+                 univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_NOT_TRUE) {
+        ret.reset(new IsNotTrueBooleanTestPredicate(owner, &op));
+      } else if (op.type() == univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_FALSE) {
+        ret.reset(new IsFalseBooleanTestPredicate(owner, &op));
+      } else if (op.type() ==
+                 univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_NOT_FALSE) {
+        ret.reset(new IsNotFalseBooleanTestPredicate(owner, &op));
+      } else if (op.type() == univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_UNKNOWN) {
+        ret.reset(new IsUnknownBooleanTestPredicate(owner, &op));
+      } else {
+        assert(op.type() ==
+               univplan::BOOLTESTTYPE::BOOLTESTTYPE_IS_NOT_UNKNOWN);
+        ret.reset(new IsNotUnknownBooleanTestPredicate(owner, &op));
+      }
+      return std::move(ret);
+    }
+    default: {
+      // do nothing
+      break;
+    }
+  }
+end:
+  LOG_INFO("Predicate warning: expr is not predicated: %s",
+           expr->DebugString().c_str());
+  PredicateOper::uptr ret(new PredicateOper(owner));
+  return std::move(ret);
+}
+
+bool MinMaxPredicatesPage::canDrop() {
+  if (nullptr == exprs) {
+    return false;
+  }
+
+  try {
+    predicate = MinMaxPredicatesAbstract::buildPredicateOper(exprs, this);
+    return predicate->canDrop();
+  } catch (...) {
+    return false;
+  }
+}
+
+COBlockTaskList::COBlockTaskList() {}
+
+void COBlockTaskList::intersect(const COBlockTaskList& source) {
+  auto selfIter = taskList.begin();
+  auto srcIter = source.taskList.begin();
+  if (selfIter != taskList.end()) {
+    selfIter->second->resetIntersection();
+    return;  // no task to process
+  }
+  while (srcIter != source.taskList.end() && selfIter != taskList.end()) {
+    COBlockTask* selfTask = selfIter->second.get();
+    COBlockTask* srcTask = srcIter->second.get();
+    if (selfTask->taskBeginRowId > srcTask->getTaskEndRowId()) {
+      srcIter++;  // try next source task
+    } else if (srcTask->taskBeginRowId > selfTask->getTaskEndRowId()) {
+      selfIter++;
+      if (selfIter != taskList.end()) {
+        selfIter->second->resetIntersection();
+      }
+    } else {
+      selfIter->second->intersect(*srcTask);
+      srcIter++;  // try next source task
+    }
+  }
+}
+
+void COBlockTaskList::unionAll(const COBlockTaskList& source) {
+  auto selfIter = taskList.begin();
+  auto srcIter = source.taskList.begin();
+  if (selfIter != taskList.end()) {
+    selfIter->second->resetUnionAll();
+    return;  // no task to process
+  }
+  while (srcIter != source.taskList.end() && selfIter != taskList.end()) {
+    COBlockTask* selfTask = selfIter->second.get();
+    COBlockTask* srcTask = srcIter->second.get();
+    if (selfTask->beginRowId > srcTask->getTaskEndRowId()) {
+      srcIter++;  // try next source task
+    } else if (srcTask->taskBeginRowId > selfTask->getEndRowId()) {
+      selfIter++;
+      if (selfIter != taskList.end()) {
+        selfIter->second->resetUnionAll();
+      }
+    } else {
+      selfIter->second->unionAll(*srcTask);
+      srcIter++;  // try next source task
+    }
+  }
+}
+
+void MinMaxPredicatesCO::preparePredicates() {
+  predicate.reset(new ListPredicate(exprs, this));
+}
+
+void MinMaxPredicatesCO::calculate(
+    std::unordered_map<int, COBlockTaskList::uptr>* res) {
+  // prepare res
+  for (int i = 0; i < this->td->getNumOfColumns(); ++i) {
+    (*res)[i + 1].reset(new COBlockTaskList());
+  }
+
+  while (true) {
+    predicatesForPages.reset();
+    preparePredicatesForStrip();
+    if (predicatesForPages == nullptr) {
+      break;  // no more to work with
+    }
+    if (!predicatesForPages->canDrop()) {
+      for (auto iter = res->begin(); iter != res->end(); ++iter) {
+        iter->second->add(std::move(buildCOTaskFromCurrentStrip(iter->first)));
+      }
+    }
+  }
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/minmax/minmax-predicates.h b/depends/univplan/src/univplan/minmax/minmax-predicates.h
new file mode 100644
index 0000000..f3e1b2c
--- /dev/null
+++ b/depends/univplan/src/univplan/minmax/minmax-predicates.h
@@ -0,0 +1,592 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_MINMAX_MINMAX_PREDICATES_H_
+#define UNIVPLAN_SRC_UNIVPLAN_MINMAX_MINMAX_PREDICATES_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "dbcommon/common/tuple-batch.h"
+#include "dbcommon/common/tuple-desc.h"
+#include "dbcommon/nodes/datum.h"
+
+#include "univplan/common/expression.h"
+#include "univplan/common/statistics.h"
+#include "univplan/common/univplan-type.h"
+#include "univplan/common/var-util.h"
+
+namespace univplan {
+
+class PredicateStats {
+ public:
+  PredicateStats() {}
+  virtual ~PredicateStats() {}
+  typedef std::unique_ptr<PredicateStats> uptr;
+
+  dbcommon::Scalar maxValue;
+  dbcommon::Scalar minValue;
+  bool hasAllNull = false;
+  bool hasMinMax = false;
+};
+
+class MinMaxPredicatesAbstract;
+class MinMaxPredicatesPage;
+class MinMaxPredicatesCO;
+
+#define PREDPAGE(pred) (dynamic_cast<const MinMaxPredicatesPage*>(pred))
+#define PREDCO(pred) (dynamic_cast<const MinMaxPredicatesCO*>(pred))
+
+class PredicateOper {
+ public:
+  explicit PredicateOper(const MinMaxPredicatesAbstract* pred) : pred(pred) {}
+  virtual ~PredicateOper() {}
+
+  typedef std::unique_ptr<PredicateOper> uptr;
+
+  virtual bool canDrop() { return false; }
+
+ protected:
+  const MinMaxPredicatesAbstract* pred = nullptr;
+};
+
+class ListPredicate : public PredicateOper {
+ public:
+  ListPredicate(const univplan::UnivPlanExprPolyList* exprs,
+                const MinMaxPredicatesAbstract* pred);
+  ~ListPredicate() {}
+
+  typedef std::unique_ptr<ListPredicate> uptr;
+
+  bool canDrop() override;
+
+ private:
+  std::vector<PredicateOper::uptr> children;
+};
+
+class BooleanPredicate : public PredicateOper {
+ public:
+  BooleanPredicate(const MinMaxPredicatesAbstract* pred,
+                   const univplan::UnivPlanBoolExpr* op);
+  ~BooleanPredicate() {}
+
+  typedef std::unique_ptr<BooleanPredicate> uptr;
+
+ protected:
+  std::vector<PredicateOper::uptr> children;
+};
+
+class VarPredicate : public PredicateOper {
+ public:
+  VarPredicate(const MinMaxPredicatesAbstract* pred,
+               const univplan::UnivPlanVar* var)
+      : PredicateOper(pred), var(var) {}
+  ~VarPredicate() {}
+
+  typedef std::unique_ptr<VarPredicate> uptr;
+
+  bool canDrop() override;
+
+ private:
+  const univplan::UnivPlanVar* var;
+};
+
+class BooleanTestPredicate : public PredicateOper {
+ public:
+  BooleanTestPredicate(const MinMaxPredicatesAbstract* pred,
+                       const univplan::UnivPlanBooleanTest* op)
+      : PredicateOper(pred), var(&op->arg().var()) {}
+  ~BooleanTestPredicate() {}
+
+  typedef std::unique_ptr<BooleanTestPredicate> uptr;
+
+ protected:
+  const univplan::UnivPlanVar* var;
+};
+
+class IsTrueBooleanTestPredicate : public BooleanTestPredicate {
+ public:
+  IsTrueBooleanTestPredicate(const MinMaxPredicatesAbstract* pred,
+                             const univplan::UnivPlanBooleanTest* op)
+      : BooleanTestPredicate(pred, op) {}
+  ~IsTrueBooleanTestPredicate() {}
+
+  typedef std::unique_ptr<IsTrueBooleanTestPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class IsNotTrueBooleanTestPredicate : public BooleanTestPredicate {
+ public:
+  IsNotTrueBooleanTestPredicate(const MinMaxPredicatesAbstract* pred,
+                                const univplan::UnivPlanBooleanTest* op)
+      : BooleanTestPredicate(pred, op) {}
+  ~IsNotTrueBooleanTestPredicate() {}
+
+  typedef std::unique_ptr<IsNotTrueBooleanTestPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class IsFalseBooleanTestPredicate : public BooleanTestPredicate {
+ public:
+  IsFalseBooleanTestPredicate(const MinMaxPredicatesAbstract* pred,
+                              const univplan::UnivPlanBooleanTest* op)
+      : BooleanTestPredicate(pred, op) {}
+  ~IsFalseBooleanTestPredicate() {}
+
+  typedef std::unique_ptr<IsFalseBooleanTestPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class IsNotFalseBooleanTestPredicate : public BooleanTestPredicate {
+ public:
+  IsNotFalseBooleanTestPredicate(const MinMaxPredicatesAbstract* pred,
+                                 const univplan::UnivPlanBooleanTest* op)
+      : BooleanTestPredicate(pred, op) {}
+  ~IsNotFalseBooleanTestPredicate() {}
+
+  typedef std::unique_ptr<IsNotFalseBooleanTestPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class IsUnknownBooleanTestPredicate : public BooleanTestPredicate {
+ public:
+  IsUnknownBooleanTestPredicate(const MinMaxPredicatesAbstract* pred,
+                                const univplan::UnivPlanBooleanTest* op)
+      : BooleanTestPredicate(pred, op) {}
+  ~IsUnknownBooleanTestPredicate() {}
+
+  typedef std::unique_ptr<IsUnknownBooleanTestPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class IsNotUnknownBooleanTestPredicate : public BooleanTestPredicate {
+ public:
+  IsNotUnknownBooleanTestPredicate(const MinMaxPredicatesAbstract* pred,
+                                   const univplan::UnivPlanBooleanTest* op)
+      : BooleanTestPredicate(pred, op) {}
+  ~IsNotUnknownBooleanTestPredicate() {}
+
+  typedef std::unique_ptr<IsNotUnknownBooleanTestPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class AndPredicate : public BooleanPredicate {
+ public:
+  AndPredicate(const MinMaxPredicatesAbstract* pred,
+               const univplan::UnivPlanBoolExpr* op)
+      : BooleanPredicate(pred, op) {}
+  ~AndPredicate() {}
+
+  typedef std::unique_ptr<AndPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class OrPredicate : public BooleanPredicate {
+ public:
+  OrPredicate(const MinMaxPredicatesAbstract* pred,
+              const univplan::UnivPlanBoolExpr* op)
+      : BooleanPredicate(pred, op) {}
+  ~OrPredicate() {}
+
+  typedef std::unique_ptr<OrPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class NullTestPredicate : public PredicateOper {
+ public:
+  NullTestPredicate(const MinMaxPredicatesAbstract* pred,
+                    const univplan::UnivPlanNullTest* op)
+      : PredicateOper(pred) {
+    if (!op->arg().has_var())
+      LOG_ERROR(ERRCODE_FEATURE_NOT_SUPPORTED,
+                "NullTestPredicate only work for simple expression");
+    univplan::VarUtil varUtil;
+    varAttrNo = varUtil.collectVarAttNo(
+        const_cast<univplan::UnivPlanExprPoly*>(&op->arg()));
+  }
+  ~NullTestPredicate() {}
+
+  typedef std::unique_ptr<NullTestPredicate> uptr;
+
+ protected:
+  std::vector<int32_t> varAttrNo;
+};
+
+class IsNullPredicate : public NullTestPredicate {
+ public:
+  IsNullPredicate(const MinMaxPredicatesAbstract* pred,
+                  const univplan::UnivPlanNullTest* op)
+      : NullTestPredicate(pred, op) {}
+  ~IsNullPredicate() {}
+
+  typedef std::unique_ptr<IsNullPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class IsNotNullPredicate : public NullTestPredicate {
+ public:
+  IsNotNullPredicate(const MinMaxPredicatesAbstract* pred,
+                     const univplan::UnivPlanNullTest* op)
+      : NullTestPredicate(pred, op) {}
+  ~IsNotNullPredicate() {}
+
+  typedef std::unique_ptr<IsNotNullPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class CompPredicate : public PredicateOper {
+ public:
+  CompPredicate(const MinMaxPredicatesAbstract* pred,
+                const univplan::UnivPlanOpExpr* op)
+      : PredicateOper(pred), expr(op) {
+    assert(op->args_size() == 2);
+    typeKinds.push_back(univplan::PlanNodeUtil::exprType(op->args(0)));
+    typeKinds.push_back(univplan::PlanNodeUtil::exprType(op->args(1)));
+    univplan::VarUtil varUtil;
+    varAttNo.push_back(varUtil.collectVarAttNo(
+        const_cast<univplan::UnivPlanExprPoly*>(&op->args(0))));
+    varAttNo.push_back(varUtil.collectVarAttNo(
+        const_cast<univplan::UnivPlanExprPoly*>(&op->args(1))));
+  }
+  ~CompPredicate() {}
+
+  typedef std::unique_ptr<CompPredicate> uptr;
+
+  void addArg(ExprState::uptr arg) { args.push_back(std::move(arg)); }
+
+  bool isValidToPredicate() const;
+
+ protected:
+  PredicateStats::uptr calcLeft();
+  PredicateStats::uptr calcRight();
+  int32_t compareTo(const dbcommon::Scalar& s1, dbcommon::TypeKind t1,
+                    const dbcommon::Scalar& s2, dbcommon::TypeKind t2);
+
+ private:
+  dbcommon::TupleBatch::uptr buildTupleBatch(int32_t argIndex);
+  PredicateStats::uptr doCalc(int32_t argIndex);
+  std::string covertPredicateTypeStr(std::string typeName);
+
+ protected:
+  std::vector<dbcommon::TypeKind> typeKinds;
+  const univplan::UnivPlanOpExpr* expr;
+
+ private:
+  std::vector<ExprState::uptr> args;
+  std::vector<std::vector<int32_t>> varAttNo;
+  dbcommon::Timestamp minTimestamp;
+  dbcommon::Timestamp maxTimestamp;
+  std::vector<dbcommon::TupleBatch::uptr> tbVec_;
+};
+
+class EqualPredicate : public CompPredicate {
+ public:
+  EqualPredicate(const MinMaxPredicatesAbstract* pred,
+                 const univplan::UnivPlanOpExpr* op)
+      : CompPredicate(pred, op) {}
+  ~EqualPredicate() {}
+
+  typedef std::unique_ptr<EqualPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class NEPredicate : public CompPredicate {
+ public:
+  NEPredicate(const MinMaxPredicatesAbstract* pred,
+              const univplan::UnivPlanOpExpr* op)
+      : CompPredicate(pred, op) {}
+  ~NEPredicate() {}
+
+  typedef std::unique_ptr<NEPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class GTPredicate : public CompPredicate {
+ public:
+  GTPredicate(const MinMaxPredicatesAbstract* pred,
+              const univplan::UnivPlanOpExpr* op)
+      : CompPredicate(pred, op) {}
+  ~GTPredicate() {}
+
+  typedef std::unique_ptr<GTPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class GEPredicate : public CompPredicate {
+ public:
+  GEPredicate(const MinMaxPredicatesAbstract* pred,
+              const univplan::UnivPlanOpExpr* op)
+      : CompPredicate(pred, op) {}
+  ~GEPredicate() {}
+
+  typedef std::unique_ptr<GEPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class LTPredicate : public CompPredicate {
+ public:
+  LTPredicate(const MinMaxPredicatesAbstract* pred,
+              const univplan::UnivPlanOpExpr* op)
+      : CompPredicate(pred, op) {}
+  ~LTPredicate() {}
+
+  typedef std::unique_ptr<LTPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class LEPredicate : public CompPredicate {
+ public:
+  LEPredicate(const MinMaxPredicatesAbstract* pred,
+              const univplan::UnivPlanOpExpr* op)
+      : CompPredicate(pred, op) {}
+  ~LEPredicate() {}
+
+  typedef std::unique_ptr<LEPredicate> uptr;
+
+  bool canDrop() override;
+};
+
+class MinMaxPredicatesAbstract {
+ public:
+  MinMaxPredicatesAbstract(const univplan::UnivPlanExprPolyList* predicateExprs,
+                           const dbcommon::TupleDesc* tupleDesc)
+      : exprs(predicateExprs), td(tupleDesc) {}
+  virtual ~MinMaxPredicatesAbstract() {}
+
+  // facility for building general purpose predicate tree
+  static PredicateOper::uptr buildPredicateOper(
+      const univplan::UnivPlanExprPolyList* exprs,
+      const MinMaxPredicatesAbstract* owner);
+
+  static PredicateOper::uptr buildPredicateOper(
+      const univplan::UnivPlanExprPoly* expr,
+      const MinMaxPredicatesAbstract* owner);
+
+  const dbcommon::TupleDesc* getTupleDesc() const { return td; }
+
+ protected:
+  const univplan::UnivPlanExprPolyList* exprs;  // original pushed filter
+  const dbcommon::TupleDesc* td;                // full tuple desc
+  PredicateOper::uptr predicate;                // generated predicate
+};
+
+class MinMaxPredicatesPage : public MinMaxPredicatesAbstract {
+ public:
+  MinMaxPredicatesPage(const Statistics* s,
+                       const univplan::UnivPlanExprPolyList* predicateExprs,
+                       const dbcommon::TupleDesc* tupleDesc)
+      : MinMaxPredicatesAbstract(predicateExprs, tupleDesc), stripeStats(s) {}
+  virtual ~MinMaxPredicatesPage() {}
+
+  typedef std::unique_ptr<MinMaxPredicatesPage> uptr;
+
+  virtual bool canDrop();  // page level min-max calculation interface
+
+ public:
+  virtual bool hasNull(int32_t colId) const = 0;
+  virtual bool hasAllNull(int32_t colId) const = 0;
+  virtual bool canDropByBloomFilter(int32_t colId, PredicateStats* stat,
+                                    dbcommon::TypeKind type) const = 0;
+  virtual PredicateStats getMinMax(int32_t colId) const = 0;
+  virtual PredicateStats getMinMax(int32_t colId,
+                                   dbcommon::Timestamp* minTimestamp,
+                                   dbcommon::Timestamp* maxTimestamp) const = 0;
+
+ protected:
+  const Statistics* stripeStats;
+};
+
+class COBlockTask {
+ public:
+  COBlockTask(uint64_t offset, uint64_t beginRowId, uint64_t rowCount)
+      : offset(offset),
+        beginRowId(beginRowId),
+        rowCount(rowCount),
+        taskBeginRowId(beginRowId),
+        taskRowCount(rowCount),
+        lastTaskBeginRowId(0),
+        lastTaskRowCount(0),
+        intersected(false) {}
+
+  COBlockTask(uint64_t offset, uint64_t beginRowId, uint64_t rowCount,
+              uint64_t taskBeginRowId, uint64_t taskRowCount)
+      : offset(offset),
+        beginRowId(beginRowId),
+        rowCount(rowCount),
+        taskBeginRowId(taskBeginRowId),
+        taskRowCount(taskRowCount),
+        lastTaskBeginRowId(0),
+        lastTaskRowCount(0),
+        intersected(false) {
+    LOG_DEBUG("CO block task %llu %llu %llu %llu %llu", offset, beginRowId,
+              rowCount, taskBeginRowId, taskRowCount);
+  }
+
+  typedef std::unique_ptr<COBlockTask> uptr;
+
+ public:
+  inline uint64_t getEndRowId() const { return beginRowId + rowCount - 1; }
+  inline uint64_t getTaskEndRowId() const {
+    return taskBeginRowId + taskRowCount - 1;
+  }
+  inline uint64_t getLastTaskEndRowId() const {
+    return lastTaskBeginRowId + lastTaskRowCount - 1;
+  }
+
+  inline void resetIntersection() {
+    intersected = false;
+    lastTaskBeginRowId = taskBeginRowId;
+    lastTaskRowCount = taskRowCount;
+    taskRowCount = 0;
+  }
+
+  inline void resetUnionAll() {
+    lastTaskBeginRowId = taskBeginRowId;
+    lastTaskRowCount = taskRowCount;
+  }
+
+  inline void intersect(const COBlockTask& srcTask) {
+    if (srcTask.getTaskEndRowId() < lastTaskBeginRowId ||
+        srcTask.taskBeginRowId > this->getLastTaskEndRowId()) {
+      if (!intersected) {
+        if (srcTask.getEndRowId() < this->lastTaskBeginRowId) {
+          // does not touch existing job, so restore original version
+          taskBeginRowId = lastTaskBeginRowId;
+          taskRowCount = lastTaskRowCount;
+          intersected = true;
+        } else if (srcTask.getEndRowId() <= this->getLastTaskEndRowId()) {
+          // restore partial job
+          taskBeginRowId = srcTask.getEndRowId() + 1;
+          taskRowCount = this->getLastTaskEndRowId() - taskBeginRowId + 1;
+          intersected = true;
+        }
+        return;
+      }
+    }
+
+    if (!intersected) {
+      // fix task begin row id, the source task may have smaller task begin row
+      // id, thus check to make sure this task has valid task begin row id. end
+      // row id has the same problem as well.
+      taskBeginRowId = srcTask.taskBeginRowId < taskBeginRowId
+                           ? taskBeginRowId
+                           : srcTask.taskBeginRowId;
+      uint64_t tmpTaskEndRowId = srcTask.getTaskEndRowId();
+      tmpTaskEndRowId = tmpTaskEndRowId > this->getLastTaskEndRowId()
+                            ? this->getLastTaskEndRowId()
+                            : tmpTaskEndRowId;
+      taskRowCount = tmpTaskEndRowId - taskBeginRowId + 1;
+      intersected = true;
+    } else {
+      // dont check begin row id again, as we expect srce tasks are processed
+      // in ascending order, and we use last task row id range to perform
+      // intersection
+      uint64_t tmpTaskEndRowId = srcTask.getTaskEndRowId();
+      tmpTaskEndRowId = tmpTaskEndRowId > this->getLastTaskEndRowId()
+                            ? this->getLastTaskEndRowId()
+                            : tmpTaskEndRowId;
+      taskRowCount = tmpTaskEndRowId - taskBeginRowId + 1;
+    }
+  }
+
+  inline void unionAll(const COBlockTask& srcTask) {
+    if (srcTask.getTaskEndRowId() < beginRowId ||
+        srcTask.taskBeginRowId > this->getEndRowId()) {
+      // skip this part, as no overlap in row id range
+      return;
+    }
+    // we always check its possible new begin rowid and it should not go out of
+    // current task range
+    taskBeginRowId = taskBeginRowId > srcTask.taskBeginRowId
+                         ? srcTask.taskBeginRowId
+                         : taskBeginRowId;
+    taskBeginRowId = taskBeginRowId < beginRowId ? beginRowId : taskBeginRowId;
+    // then is its end rowid
+    uint64_t tmpTaskEndRowId = srcTask.getTaskEndRowId();
+    tmpTaskEndRowId = tmpTaskEndRowId > this->getTaskEndRowId()
+                          ? tmpTaskEndRowId
+                          : this->getTaskEndRowId();
+    tmpTaskEndRowId = tmpTaskEndRowId > this->getEndRowId()
+                          ? this->getEndRowId()
+                          : tmpTaskEndRowId;
+    taskRowCount = tmpTaskEndRowId - taskBeginRowId + 1;
+  }
+
+ public:
+  uint64_t offset;
+  uint64_t beginRowId;
+  uint64_t rowCount;
+  uint64_t taskBeginRowId;
+  uint64_t taskRowCount;
+  uint64_t lastTaskBeginRowId;
+  uint64_t lastTaskRowCount;
+
+ private:
+  bool intersected;
+};
+
+class COBlockTaskList {
+ public:
+  COBlockTaskList();
+
+  void add(COBlockTask::uptr task) {
+    uint64_t taskBeginRowId = task->taskBeginRowId;
+    taskList[taskBeginRowId] = std::move(task);
+  }
+  void intersect(const COBlockTaskList& source);
+  void unionAll(const COBlockTaskList& source);
+
+  typedef std::unique_ptr<COBlockTaskList> uptr;
+
+ public:
+  std::map<uint64_t, COBlockTask::uptr> taskList;
+};
+
+class MinMaxPredicatesCO : public MinMaxPredicatesAbstract {
+ public:
+  MinMaxPredicatesCO(const univplan::UnivPlanExprPolyList* predicateExprs,
+                     const dbcommon::TupleDesc* tupleDesc)
+      : MinMaxPredicatesAbstract(predicateExprs, tupleDesc) {}
+  virtual ~MinMaxPredicatesCO() {}
+
+  // methods implemented by sub-class to provide customized data preparation
+  virtual void preparePredicatesForStrip() = 0;
+  virtual COBlockTask::uptr buildCOTaskFromCurrentStrip(int colId) = 0;
+
+  // methods of whole calculation framework
+  virtual void preparePredicates();
+  virtual void calculate(std::unordered_map<int, COBlockTaskList::uptr>* res);
+
+ protected:
+  // holding one strip's statistics
+  std::unique_ptr<univplan::Statistics> stripStatistics;
+  // holding one page level predicates to do actual calculation
+  std::unique_ptr<MinMaxPredicatesPage> predicatesForPages;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_MINMAX_MINMAX_PREDICATES_H_
diff --git a/depends/univplan/src/univplan/proto/universal-plan-catalog.proto b/depends/univplan/src/univplan/proto/universal-plan-catalog.proto
new file mode 100644
index 0000000..98de467
--- /dev/null
+++ b/depends/univplan/src/univplan/proto/universal-plan-catalog.proto
@@ -0,0 +1,49 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+syntax = "proto2";
+
+package univplan;
+
+option cc_generic_services = true;
+option java_generic_services = true;
+
+message UnivPlanColumn {
+	required string		columnName = 1;
+	required int32 		typeId = 2;
+	optional int32    scale1 = 3;
+	optional int32    scale2 = 4;
+	optional bool     isNullable = 5;
+	optional bytes    defaultVal = 6;
+	required int64    typeMod = 7 [default = -1];
+}
+
+enum UNIVPLANFORMATTYPE {
+  TEXT_FORMAT        = 1;
+  CSV_FORMAT         = 2;
+  ORC_FORMAT         = 3;
+  MAGMA_FORMAT       = 4;
+  MAGMA_LOCAL_FORMAT = 5;
+  INVALID_FORMAT     = 6;
+}
+
+//
+// Magma:
+//
+//  In case a Magma external table, location saves target table external
+//  name defined in Magma, in format :
+//      magma:///dbname/schemaname/tablename
+//  for the columns, MAGMA has its own catalog having complete column definition,
+//  thus, it is only required to fill basic column names and rough type content
+//
+
+message UnivPlanTable {
+	required int64					    tableId = 1;
+	required UNIVPLANFORMATTYPE	format = 2;
+	required string					    location = 3;
+	required bytes					    tableOptionsInJson = 4;
+	repeated UnivPlanColumn 		columns = 5;
+}
diff --git a/depends/univplan/src/univplan/proto/universal-plan-expr.proto b/depends/univplan/src/univplan/proto/universal-plan-expr.proto
new file mode 100644
index 0000000..8cef5e1
--- /dev/null
+++ b/depends/univplan/src/univplan/proto/universal-plan-expr.proto
@@ -0,0 +1,203 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+syntax = "proto2";
+
+package univplan;
+
+option cc_generic_services = true;
+option java_generic_services = true;
+
+enum UNIVPLANEXPRTYPE {
+  UNIVPLAN_EXPR_AGGREF = 1;
+  UNIVPLAN_EXPR_BOOLEXPR = 2;
+  UNIVPLAN_EXPR_CONST = 3;
+  UNIVPLAN_EXPR_FUNCEXPR = 4;
+  UNIVPLAN_EXPR_NULLTEST = 5;
+  UNIVPLAN_EXPR_OPEXPR = 6;
+  UNIVPLAN_EXPR_TARGETENTRY = 7;
+  UNIVPLAN_EXPR_VAR = 8;
+  UNIVPLAN_EXPR_BOOLEANTEST = 9;
+  UNIVPLAN_EXPR_CASEEXPR = 10;
+  UNIVPLAN_EXPR_CASEWHEN = 11;
+  UNIVPLAN_EXPR_SUBPLAN = 12;
+  UNIVPLAN_EXPR_PARAM = 13;
+  UNIVPLAN_EXPR_SCALARARRAYOPEXPR = 14;
+  UNIVPLAN_EXPR_COALESCEEXPR = 15;
+  UNIVPLAN_EXPR_NULLIFEXPR = 16;
+  UNIVPLAN_EXPR_DISTINCTEXPR = 17;
+}
+
+message UnivPlanOpExpr {
+  required int32              funcId = 1;
+  required int32              retType = 2;
+  repeated UnivPlanExprPoly   args = 3;
+}
+
+message UnivPlanFuncExpr {
+  required int32              funcId = 1;
+  required int32              retType = 2;
+  repeated UnivPlanExprPoly   args = 3;
+}
+
+enum NULLTESTTYPE {
+  NULLTESTTYPE_IS_NULL = 0;
+  NULLTESTTYPE_IS_NOT_NULL = 1;
+}
+
+message UnivPlanNullTest {
+  required UnivPlanExprPoly   arg = 1;
+  required NULLTESTTYPE       type = 2;
+}
+
+enum BOOLTESTTYPE {
+  BOOLTESTTYPE_IS_TRUE = 0;
+  BOOLTESTTYPE_IS_NOT_TRUE = 1;
+  BOOLTESTTYPE_IS_FALSE = 2;
+  BOOLTESTTYPE_IS_NOT_FALSE = 3;
+  BOOLTESTTYPE_IS_UNKNOWN = 4;
+  BOOLTESTTYPE_IS_NOT_UNKNOWN = 5;
+}
+
+message UnivPlanBooleanTest {
+  required UnivPlanExprPoly   arg = 1;
+  required BOOLTESTTYPE       type = 2;
+}
+
+enum BOOLEXPRTYPE {
+  BOOLEXPRTYPE_AND_EXPR = 0;
+  BOOLEXPRTYPE_OR_EXPR = 1;
+  BOOLEXPRTYPE_NOT_EXPR = 2;
+}
+
+message UnivPlanBoolExpr {
+  repeated UnivPlanExprPoly   args = 1;
+  required BOOLEXPRTYPE       type = 2;
+}
+
+message UnivPlanConst {
+  required int32              type = 1;
+  required bool               isNull = 2;
+  optional string             value = 3;
+  optional int64              typeMod = 4 [default = -1];
+}
+
+message UnivPlanVar {
+  required uint32             varNo = 1;
+  required int32              varAttNo = 2;
+  required int32              typeId = 3;
+  optional int64              typeMod = 4 [default = -1];
+}
+
+message UnivPlanAggref {
+  required int32              transFuncId = 1;
+  required int32              retType = 2;
+  required bool               transInitVal = 3;
+  optional int32              finalFuncId = 4;
+  repeated UnivPlanExprPoly   args = 5;
+  required int32              funcId = 6;
+}
+
+message UnivPlanTargetEntry {
+  required UnivPlanExprPoly   expression = 1;
+  required bool               resJunk = 2;
+  optional string             resName = 3;
+}
+
+message UnivPlanCaseExpr {
+  required int32              casetype = 1;
+  repeated UnivPlanExprPoly   args = 2;
+  required UnivPlanExprPoly   defresult = 3;
+}
+
+message UnivPlanCaseWhen {
+  required UnivPlanExprPoly   expr = 1;
+  required UnivPlanExprPoly   result = 2;
+}
+
+enum SUBLINKTYPE {
+  EXISTS_SUBLINK = 0;
+  ALL_SUBLINK = 1;
+  ANY_SUBLINK = 2;
+  ROWCOMPARE_SUBLINK = 3;
+  EXPR_SUBLINK = 4;
+  ARRAY_SUBLINK = 5;
+  NOT_EXISTS_SUBLINK = 6;
+}
+
+message UnivPlanSubPlan {
+  required SUBLINKTYPE subLinkType = 1;
+  required int32 planId = 2;
+  required int32 typeId = 3;
+  optional int64 typeMod = 4 [default = -1];
+  required bool useHashTable = 5;
+  required bool initPlan = 6;
+  repeated int32 setParam = 7;                // input param for param_exec
+  repeated int32 parentParam = 8;             // input param for subplan
+  repeated UnivPlanExprPoly args = 9;         // inputs for subplan
+  repeated int32 testexprParam = 10;          // input param for test expr
+  optional UnivPlanExprPoly testexpr = 11;    // test expr for ALL/ANY
+}
+
+enum PARAMKIND {
+  PARAM_EXTERN = 0;
+  PARAM_EXEC = 1;
+}
+
+message UnivPlanParam {
+  required PARAMKIND paramKind = 1;
+  required int32 paramId = 2;
+  required int32 typeId = 3;
+  optional int64 typeMod = 4 [default = -1];
+}
+
+message UnivPlanScalarArrayOpExpr {
+  required int32              funcId = 1;
+  required bool               useOr = 2;
+  repeated UnivPlanExprPoly   args = 3;
+}
+
+message UnivPlanCoalesceExpr {
+  required int32              coalesceType = 1;
+  required int32              coalesceTypeMod = 2;
+  repeated UnivPlanExprPoly   args = 3;
+}
+
+message UnivPlanNullIfExpr {
+  required int32              funcId = 1;
+  required int32              retType = 2;
+  required int32              typeMod = 3;
+  repeated UnivPlanExprPoly   args = 4;
+}
+
+message UnivPlanDistinctExpr {
+  required int32				 funcId = 1;
+  required int32				 retType = 2;
+  repeated UnivPlanExprPoly   args = 3;
+}
+
+message UnivPlanExprPoly {
+  required UNIVPLANEXPRTYPE   type = 1;
+  oneof value {
+    UnivPlanAggref            aggref = 2;
+    UnivPlanBoolExpr          boolexpr = 3;
+    UnivPlanConst             val = 4;
+    UnivPlanFuncExpr          funcexpr = 5;
+    UnivPlanNullTest          nulltest = 6;
+    UnivPlanOpExpr            opexpr = 7;
+    UnivPlanTargetEntry       targetentry = 8;
+    UnivPlanVar               var = 9;
+    UnivPlanBooleanTest       booltest = 10;
+    UnivPlanCaseExpr          caseexpr = 11;
+    UnivPlanCaseWhen          casewhen = 12;
+    UnivPlanSubPlan           subplan = 13;
+    UnivPlanParam             param = 14;
+    UnivPlanScalarArrayOpExpr scalarArrayOpexpr = 15;
+    UnivPlanCoalesceExpr      coalesceExpr = 16;
+    UnivPlanNullIfExpr        nullIfExpr = 17;
+    UnivPlanDistinctExpr      distinctExpr = 18;
+  }
+}
diff --git a/depends/univplan/src/univplan/proto/universal-plan.proto b/depends/univplan/src/univplan/proto/universal-plan.proto
new file mode 100644
index 0000000..246d000
--- /dev/null
+++ b/depends/univplan/src/univplan/proto/universal-plan.proto
@@ -0,0 +1,402 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+syntax = "proto2";
+
+package univplan;
+
+option cc_generic_services = true;
+option java_generic_services = true;
+
+import "univplan/proto/universal-plan-catalog.proto";
+import "univplan/proto/universal-plan-expr.proto";
+
+enum UNIVPLANNODETYPE {
+  UNIVPLAN_UNSET = 1;
+
+  UNIVPLAN_CONNECTOR = 2;
+  UNIVPLAN_SINK = 3;
+  UNIVPLAN_CONVERGE = 4;
+  UNIVPLAN_BROADCAST = 5;
+  UNIVPLAN_SHUFFLE = 6;
+  UNIVPLAN_AGG = 7;
+  UNIVPLAN_SCAN_SEQ = 8;
+  UNIVPLAN_SORT = 9;
+  UNIVPLAN_LIMIT = 10;
+  UNIVPLAN_APPEND = 11;
+  UNIVPLAN_NESTLOOP = 12;
+  UNIVPLAN_HASHJOIN = 13;
+  UNIVPLAN_MERGEJOIN = 14;
+  UNIVPLAN_MATERIAL = 15;
+  UNIVPLAN_RESULT = 16;
+  UNIVPLAN_HASH = 17;
+  UNIVPLAN_SUBQUERYSCAN = 18;
+  UNIVPLAN_UNIQUE = 19;
+  UNIVPLAN_INSERT = 20;
+  UNIVPLAN_SHAREINPUTSCAN = 21;
+
+  UNIVPLAN_EXT_GS_SCAN = 100;
+  UNIVPLAN_EXT_GS_FILTER = 101;
+  UNIVPLAN_EXT_GS_PROJ = 102;
+}
+
+message UnivPlanPlanNodePoly {
+  required UNIVPLANNODETYPE type = 1;
+  oneof value {
+    UnivPlanConnector connector = 2;
+    UnivPlanSink sink = 3;
+    UnivPlanConverge converge = 4;
+    UnivPlanBroadcast broadcast = 5;
+    UnivPlanShuffle shuffle = 6;
+    UnivPlanAgg agg = 7;
+    UnivPlanScanSeq scanSeq = 8;
+    UnivPlanSort sort = 9;
+    UnivPlanLimit limit = 10;
+    UnivPlanAppend append = 11;
+    UnivPlanNestLoop nestLoop = 12;
+    UnivPlanMergeJoin mergeJoin = 13;
+    UnivPlanHashJoin hashJoin = 14;
+    UnivPlanMaterial material = 15;
+    UnivPlanResult result = 16;
+    UnivPlanHash hash = 17;
+    UnivPlanSubqueryScan subqueryscan = 18;
+    UnivPlanUnique unique = 19;
+    UnivPlanInsert insert = 20;
+    UnivPlanShareInputScan shareinputscan = 21;
+
+    UnivPlanExtGSScan extGSScan = 100;
+    UnivPlanExtGSFilter extGSFilter = 101;
+    UnivPlanExtGSProj extGSProject = 102;
+  }
+}
+
+// The overall super node for plan nodes
+message UnivPlanPlanNode {
+  repeated UnivPlanExprPoly targetList = 1;     // Target list to be calculated
+  repeated UnivPlanExprPoly qualList = 2;       // qual conditions
+  optional UnivPlanPlanNodePoly leftPlan = 3;   // left plan tree
+  optional UnivPlanPlanNodePoly rightPlan = 4;  // right plan tree
+  repeated UnivPlanExprPoly initPlan = 5;       // un-correlated expr subselects
+  optional double planRows = 6;                 // estimated number of rows
+  optional int32  planRowWidth = 7;             // estimated row width in bytes
+  optional int64  operatorMemKB = 8;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SCAN NODES BEGIN
+///////////////////////////////////////////////////////////////////////////////
+
+// The scan task
+message UnivPlanScanTask {
+  // repeated UnivPlanScanFileSplit splits = 1;
+  optional bytes serializedSplits = 1;
+}
+
+message UnivPlanScanSeq {
+  required UnivPlanPlanNode super = 1;
+  required uint32 relId = 2;
+  optional bool readStatsOnly = 3;
+  repeated UnivPlanScanTask tasks = 4;
+  repeated int32 columnsToRead = 5;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SCAN NODES END
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// SINK NODES BEGIN
+///////////////////////////////////////////////////////////////////////////////
+
+enum UNIVPLANCONNECTORTYPE {
+  CONNECTORTYPE_INVALID = 0;
+  CONNECTORTYPE_SHUFFLE = 1;
+  CONNECTORTYPE_BROADCAST = 2;
+  CONNECTORTYPE_CONVERGE = 3;
+}
+
+message UnivPlanConnector {
+  required UnivPlanPlanNode super = 1;
+  required UNIVPLANCONNECTORTYPE type = 2;
+  optional int32 stageno = 3 [default = -1];
+  repeated UnivPlanExprPoly hashExpr = 4;
+  repeated int32 colIdx = 5;
+  repeated int32 sortFuncId = 6;
+  optional bool  magmaTable = 7 [default = false];
+  repeated int32 magmaMap = 8;
+  optional int32 rangeNum = 9 [default = 0];  // magma range num
+}
+
+// Sink
+message UnivPlanSink {
+  required UnivPlanPlanNode super = 1;
+  required UNIVPLANCONNECTORTYPE connectorType = 2;
+  required int32 sourceStageNo = 3;
+  required int32 currentStageNo = 4;
+  repeated int32 colIdx = 5;
+  repeated int32 sortFuncId = 6;
+}
+
+// Converge
+message UnivPlanConverge {
+  required UnivPlanPlanNode super = 1;
+  required int32 targetStageNo = 2;
+  required int32 currentStageNo = 3;
+}
+
+// Broadcast
+message UnivPlanBroadcast {
+  required UnivPlanPlanNode super = 1;
+  required int32 targetStageNo = 2;
+  required int32 currentStageNo = 3;
+}
+
+// Shuffle
+message UnivPlanShuffle {
+  required UnivPlanPlanNode super = 1;
+  required int32 targetStageNo = 2;
+  required int32 currentStageNo = 3;
+  repeated UnivPlanExprPoly hashExpr = 4;
+  optional bool  magmaTable = 5 [default = false];
+  repeated int32 magmaMap = 6;
+  optional int32 rangeNum = 9 [default = 0];  // magma range num
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// SINK NODES END
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// JOIN NODES BEGIN
+///////////////////////////////////////////////////////////////////////////////
+
+enum UNIVPLANJOINTYPE {
+  JOIN_INNER = 0;  // matching tuple pairs only
+  JOIN_LEFT = 1;   // pairs + unmatched LHS tuples
+  JOIN_RIGHT = 2;  // pairs + unmatched RHS tuples
+  JOIN_FULL = 3;   // pairs + unmatched LHS + unmatched RHS
+  JOIN_IN = 4;
+  JOIN_LASJ = 8;
+  JOIN_LASJ_NOTIN = 9;
+  JOIN_NOT_SUPPORTED = 10;
+}
+
+// NestLoop
+message UnivPlanNestLoop {
+  required UnivPlanPlanNode super = 1;
+  required UNIVPLANJOINTYPE type = 2;
+  repeated UnivPlanExprPoly joinQual = 3;
+}
+
+// HashJoin
+message UnivPlanHashJoin {
+  required UnivPlanPlanNode super = 1;
+  required UNIVPLANJOINTYPE type = 2;
+  repeated UnivPlanExprPoly joinQual = 3;
+  repeated UnivPlanExprPoly hashClauses = 4;
+  repeated UnivPlanExprPoly hashQualClauses = 5;
+}
+
+// MergeJoin
+message UnivPlanMergeJoin {
+  required UnivPlanPlanNode super = 1;
+  required UNIVPLANJOINTYPE type = 2;
+  repeated UnivPlanExprPoly joinQual = 3;
+  repeated UnivPlanExprPoly mergeClauses = 4;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JOIN NODES END
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// OTHER PLAN NODES BEGIN
+///////////////////////////////////////////////////////////////////////////////
+
+message UnivPlanAgg {
+  required UnivPlanPlanNode super = 1;
+  required int64 numGroups = 2;
+  repeated int32 groupColIndexes = 3;
+}
+
+message UnivPlanLimit {
+  required UnivPlanPlanNode super = 1;
+  optional UnivPlanExprPoly limitOffset = 2;
+  optional UnivPlanExprPoly limitCount = 3;
+}
+
+message UnivPlanAppend {
+  required UnivPlanPlanNode super = 1;
+  repeated UnivPlanPlanNodePoly appendPlans = 2;
+}
+
+message UnivPlanSort {
+  required UnivPlanPlanNode super = 1;
+  repeated int32 colIdx = 2;
+  repeated int32 sortFuncId = 3;
+  optional UnivPlanExprPoly limitOffset = 4;
+  optional UnivPlanExprPoly limitCount = 5;
+}
+
+enum UNIVPLANSHARETYPE {
+  SHARE_NOTSHARED = 0;
+  SHARE_MATERIAL = 1;
+  SHARE_MATERIAL_XSLICE = 2;
+  SHARE_SORT = 3;
+  SHARE_SORT_XSLICE = 4;
+  SHARE_NOT_SUPPORTED = 5;
+}
+
+message UnivPlanMaterial {
+  required UnivPlanPlanNode super = 1;
+  required UNIVPLANSHARETYPE share_type = 2;
+  required bool cdbStrict = 3;
+  optional int32 shared_id = 4;
+  optional int32 driver_slice = 5;  // slice id that will execute this material
+  optional int32 nsharer = 6;       // number of sharer
+  optional int32 nsharer_xslice = 7;  // number of sharer cross slice
+}
+
+message UnivPlanShareInputScan {
+    required UnivPlanPlanNode super = 1;
+    required UNIVPLANSHARETYPE shareType = 2;
+    required int32 sharedId = 3;
+    required int32 driverSlice = 4;
+}
+
+message UnivPlanResult {
+  required UnivPlanPlanNode super = 1;
+  repeated UnivPlanExprPoly resconstantqual = 2;
+}
+
+message UnivPlanHash {
+  required UnivPlanPlanNode super = 1;
+}
+
+message UnivPlanSubqueryScan {
+  required UnivPlanPlanNode super = 1;
+  optional UnivPlanPlanNodePoly subPlan = 2;
+}
+
+message UnivPlanUnique {
+  required UnivPlanPlanNode    super = 1;
+  repeated int32               uniqColIdxs = 2;
+}
+
+message UnivPlanInsert {
+  required UnivPlanPlanNode    super = 1;
+  required uint32 relId = 2;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OTHER PLAN NODES END
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// MAGMA NODES BEGIN
+///////////////////////////////////////////////////////////////////////////////
+enum ExternalScanType {
+  TableScan = 0;
+  MagmaIndexScan = 1;
+  MagmaIndexOnlyScan = 2;
+  MagmaBitmapScan = 3;
+}
+
+enum ExternalScanDirection {
+  BackwardScanDirection = -1;
+  NoMovementScanDirection = 0;
+  ForwardScanDirection = 1;
+}
+
+message UnivPlanExtGSScan {
+  required UnivPlanPlanNode super = 1;
+  required uint32 relId = 2;       // table def index
+  repeated int32 keyColIndex = 3;  // this two field for schema mapping
+  repeated int32 valColIndex = 4;
+  repeated int32 columnsToRead = 5;
+  optional UnivPlanExprPoly filter = 6;          // filter
+  repeated UnivPlanExprPoly filterByKeyCol = 7;  // filter for each col
+  repeated UnivPlanScanTask tasks = 8;           // use univplan scan task
+  // index scan info for magma
+  optional bool indexscan = 9 [default = false];
+  optional ExternalScanType type = 10;
+  optional ExternalScanDirection direction = 11;
+  optional string indexName = 12;
+  repeated UnivPlanExprPoly indexQual = 13;
+  optional bool readStatsOnly = 14 [default = false];
+}
+
+message UnivPlanExtGSFilter {
+  required UnivPlanPlanNode super = 1;
+  optional UnivPlanExprPoly filter = 2;  // filter for all columns
+}
+
+message UnivPlanExtGSProj {
+  required UnivPlanPlanNode super = 1;
+  repeated int32 columnIndexes = 2;  // required columns
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// MAGMA NODES END
+///////////////////////////////////////////////////////////////////////////////
+
+message UnivPlanRangeTblEntry {
+  required UnivPlanTable table = 1;
+}
+
+message UnivPlanListener {
+  required string address = 1;
+  required int32 port = 2;
+}
+
+message UnivPlanReceiver {
+  repeated UnivPlanListener listener = 1;
+}
+
+message UnivPlanParamInfo {
+  required int32 type = 1;
+  required bool isNull = 2;
+  optional string value = 3;
+}
+
+message UnivPlanTokenKey {
+  required string protocol = 1;
+  required string ip = 2;
+  required int32 port = 3;
+}
+
+message UnivPlanTokenEntry {
+  required UnivPlanTokenKey key = 1;
+  required string token = 2;
+}
+
+enum UNIVPLANCMDTYPE {
+  CMD_UNKNOWN = 0;
+  CMD_SELECT = 1;
+  CMD_UPDATE = 2;
+  CMD_INSERT = 3;
+  CMD_DELETE = 4;
+  CMD_UTILITY = 5;
+  CMD_NOTHING = 6;
+}
+
+// Overall container of one plan to execute
+message UnivPlanPlan {
+  required UnivPlanPlanNodePoly plan = 1;
+  repeated UnivPlanPlan childStages = 2;
+  repeated UnivPlanRangeTblEntry rangeTables = 3;
+  repeated UnivPlanReceiver receivers = 4;
+  optional int32 stageNo = 5;
+  optional bool doInstrument = 6;
+  repeated UnivPlanPlanNodePoly subplans = 7;
+  repeated UnivPlanParamInfo paramInfos = 8;
+  optional int32 nCrossLevelParams = 9 [default = 0];
+  repeated UnivPlanTokenEntry tokenMap = 10;
+  optional bytes snapshot = 11;
+  map<string, string> guc = 12;
+  map<string, string> commonValue = 13;
+  optional UNIVPLANCMDTYPE cmdType = 14 [default = CMD_SELECT];
+}
diff --git a/depends/univplan/src/univplan/testutil/univplan-proto-util.cc b/depends/univplan/src/univplan/testutil/univplan-proto-util.cc
new file mode 100644
index 0000000..de2dcf5
--- /dev/null
+++ b/depends/univplan/src/univplan/testutil/univplan-proto-util.cc
@@ -0,0 +1,507 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/testutil/univplan-proto-util.h"
+
+#include <memory>
+#include <string>
+
+#include "dbcommon/function/func-kind.cg.h"
+
+namespace univplan {
+
+UnivPlanProtoUtility::UnivPlanProtoUtility() {
+  this->univplan = univPlanNewInstance();
+}
+
+UnivPlanProtoUtility::~UnivPlanProtoUtility() {
+  univPlanFreeInstance(&univplan);
+}
+
+void UnivPlanProtoUtility::constructVarOpConstExpr(
+    int32_t pid, int32_t opFuncId, int32_t varNo, int32_t varAttNo,
+    dbcommon::TypeKind varType, dbcommon::TypeKind constType,
+    const char *buffer) {
+  univPlanNewExpr(univplan);
+  int32_t root = univPlanExprAddOpExpr(univplan, pid, opFuncId);
+  univPlanExprAddVar(univplan, root, varNo, varAttNo, varType, -1);
+  univPlanExprAddConst(univplan, root, constType, false, buffer, -1);
+}
+
+void UnivPlanProtoUtility::constructConstOpVarExpr(
+    int32_t pid, int32_t opFuncId, int32_t varNo, int32_t varAttNo,
+    dbcommon::TypeKind varType, dbcommon::TypeKind constType,
+    const char *buffer) {
+  univPlanNewExpr(univplan);
+  int32_t root = univPlanExprAddOpExpr(univplan, pid, opFuncId);
+  univPlanExprAddConst(univplan, root, constType, false, buffer, -1);
+  univPlanExprAddVar(univplan, root, varNo, varAttNo, varType, -1);
+}
+
+void UnivPlanProtoUtility::constructVarOpVarExpr(
+    int32_t pid, int32_t opFuncId, int32_t varNo1, int32_t varAttNo1,
+    dbcommon::TypeKind varType1, int32_t varNo2, int32_t varAttNo2,
+    dbcommon::TypeKind varType2) {
+  univPlanNewExpr(univplan);
+  int32_t root = univPlanExprAddOpExpr(univplan, pid, opFuncId);
+  univPlanExprAddVar(univplan, root, varNo1, varAttNo1, varType1, -1);
+  univPlanExprAddVar(univplan, root, varNo2, varAttNo2, varType2, -1);
+}
+
+void UnivPlanProtoUtility::constructConstOpConstExpr(
+    int32_t pid, int32_t opFuncId, dbcommon::TypeKind constType1,
+    const char *buffer1, dbcommon::TypeKind constType2, const char *buffer2) {
+  univPlanNewExpr(univplan);
+  int32_t root = univPlanExprAddOpExpr(univplan, pid, opFuncId);
+  univPlanExprAddConst(univplan, root, constType1, false, buffer1, -1);
+  univPlanExprAddConst(univplan, root, constType2, false, buffer2, -1);
+}
+
+void UnivPlanProtoUtility::constructFuncOpVarExpr(int32_t pid, int32_t opFuncId,
+                                                  int32_t varNo,
+                                                  int32_t varAttNo,
+                                                  dbcommon::TypeKind varType,
+                                                  int32_t mappingFuncId) {
+  univPlanNewExpr(univplan);
+  int32_t root = univPlanExprAddOpExpr(univplan, pid, opFuncId);
+  univPlanExprAddFuncExpr(univplan, root, mappingFuncId);
+  univPlanExprAddVar(univplan, root, varNo, varAttNo, varType, -1);
+}
+
+void UnivPlanProtoUtility::constructBoolExpr(
+    int32_t pid, int32_t opFuncId1, int32_t varNo1, int32_t varAttNo1,
+    dbcommon::TypeKind varType1, dbcommon::TypeKind constType1,
+    const char *buffer1, int32_t opFuncId2, int32_t varNo2, int32_t varAttNo2,
+    dbcommon::TypeKind varType2, dbcommon::TypeKind constType2,
+    const char *buffer2, int8_t boolType) {
+  univPlanNewExpr(univplan);
+  int32_t root =
+      univPlanExprAddBoolExpr(univplan, pid, UnivplanBoolExprType(boolType));
+
+  int32_t root1 = univPlanExprAddOpExpr(univplan, root, opFuncId1);
+  univPlanExprAddVar(univplan, root1, varNo1, varAttNo1, varType1, -1);
+  univPlanExprAddConst(univplan, root1, constType1, false, buffer1, -1);
+
+  int32_t root2 = univPlanExprAddOpExpr(univplan, root, opFuncId2);
+  univPlanExprAddVar(univplan, root2, varNo2, varAttNo2, varType2, -1);
+  univPlanExprAddConst(univplan, root2, constType2, false, buffer2, -1);
+}
+
+void UnivPlanProtoUtility::constructNullTestExpr(int32_t pid,
+                                                 int8_t nulltesttype,
+                                                 int32_t varNo,
+                                                 int32_t varAttNo,
+                                                 dbcommon::TypeKind varType) {
+  univPlanNewExpr(univplan);
+  int32_t root = univPlanExprAddNullTestExpr(
+      univplan, pid, UnivplanNullTestType(nulltesttype));
+  univPlanExprAddVar(univplan, root, varNo, varAttNo, varType, -1);
+}
+
+void UnivPlanProtoUtility::constructVarOpConstThenOpVarOpConstExpr(
+    int32_t pid, int32_t opFuncId, int32_t opFuncId1, int32_t varNo1,
+    int32_t varAttNo1, dbcommon::TypeKind varType1,
+    dbcommon::TypeKind constType1, const char *buffer1, int32_t opFuncId2,
+    int32_t varNo2, int32_t varAttNo2, dbcommon::TypeKind varType2,
+    dbcommon::TypeKind constType2, const char *buffer2) {
+  univPlanNewExpr(univplan);
+  int32_t root = univPlanExprAddOpExpr(univplan, pid, opFuncId);
+
+  int32_t root1 = univPlanExprAddOpExpr(univplan, root, opFuncId1);
+  univPlanExprAddVar(univplan, root1, varNo1, varAttNo1, varType1, -1);
+  univPlanExprAddConst(univplan, root1, constType1, false, buffer1, -1);
+
+  int32_t root2 = univPlanExprAddOpExpr(univplan, root, opFuncId2);
+  univPlanExprAddVar(univplan, root2, varNo2, varAttNo2, varType2, -1);
+  univPlanExprAddConst(univplan, root2, constType2, false, buffer2, -1);
+}
+
+void UnivPlanProtoUtility::constructVarTargetEntry(int32_t pid, int32_t varNo,
+                                                   int32_t varAttNo,
+                                                   dbcommon::TypeKind type) {
+  univPlanNewExpr(univplan);
+  univPlanExprAddVar(univplan, pid, varNo, varAttNo, type, -1);
+  univPlanTargetListAddTargetEntry(univplan, false);
+}
+
+void UnivPlanProtoUtility::constructConstTargetEntry(
+    int32_t pid, dbcommon::TypeKind constType, const char *buffer) {
+  univPlanNewExpr(univplan);
+  if (constType == dbcommon::TypeKind::ANYID)
+    univPlanExprAddConst(univplan, -1, dbcommon::TypeKind::TINYINTID, true,
+                         buffer, -1);
+  else
+    univPlanExprAddConst(univplan, -1, constType, false, buffer, -1);
+  univPlanTargetListAddTargetEntry(univplan, false);
+}
+
+void UnivPlanProtoUtility::constructConstOpConstTargetEntry(
+    int32_t pid, int32_t opFuncId, dbcommon::TypeKind constType1,
+    const char *buffer1, dbcommon::TypeKind constType2, const char *buffer2) {
+  univPlanNewExpr(univplan);
+  constructConstOpConstExpr(pid, opFuncId, constType1, buffer1, constType2,
+                            buffer2);
+  univPlanTargetListAddTargetEntry(univplan, false);
+}
+
+void UnivPlanProtoUtility::constructAggRefTargetEntry(
+    int32_t pid, int8_t aggstage, int32_t mappingFuncId, int32_t varNo,
+    int32_t varAttNo, dbcommon::TypeKind type) {
+  univPlanNewExpr(univplan);
+  int32_t uid;
+  if (aggstage == 1)  // AGGSTAGE_PARTIAL
+    uid = univPlanAggrefAddPartialStage(univplan, -1, mappingFuncId);
+  else if (aggstage == 3)  // AGGSTAGE_FINAL
+    uid = univPlanAggrefAddFinalStage(univplan, -1, mappingFuncId);
+  univPlanAggrefAddProxyVar(univplan, uid, varAttNo, mappingFuncId, -1);
+  univPlanTargetListAddTargetEntry(univplan, false);
+}
+
+void UnivPlanProtoUtility::constructNullTestTargetEntry(
+    int32_t pid, int8_t nulltesttype, int32_t varNo, int32_t varAttNo,
+    dbcommon::TypeKind varType) {
+  constructNullTestExpr(pid, nulltesttype, varNo, varAttNo, varType);
+  univPlanTargetListAddTargetEntry(univplan, false);
+}
+
+void UnivPlanProtoUtility::constructVarOpConstTargetEntry(
+    int32_t pid, int32_t opFuncId, int32_t varNo, int32_t varAttNo,
+    dbcommon::TypeKind varType, dbcommon::TypeKind constType,
+    const char *buffer) {
+  constructVarOpConstExpr(pid, opFuncId, varNo, varAttNo, varType, constType,
+                          buffer);
+  univPlanTargetListAddTargetEntry(univplan, false);
+}
+
+void UnivPlanProtoUtility::constructVarOpConstQualList(
+    int32_t pid, int32_t opFuncId, int32_t varNo, int32_t varAttNo,
+    dbcommon::TypeKind varType, dbcommon::TypeKind constType,
+    const char *buffer) {
+  constructVarOpConstExpr(pid, opFuncId, varNo, varAttNo, varType, constType,
+                          buffer);
+  univPlanQualListAddExpr(univplan);
+}
+
+void UnivPlanProtoUtility::constructConstOpVarQualList(
+    int32_t pid, int32_t opFuncId, int32_t varNo, int32_t varAttNo,
+    dbcommon::TypeKind varType, dbcommon::TypeKind constType,
+    const char *buffer) {
+  constructConstOpVarExpr(pid, opFuncId, varNo, varAttNo, varType, constType,
+                          buffer);
+  univPlanQualListAddExpr(univplan);
+}
+
+void UnivPlanProtoUtility::constructVarOpVarQualList(
+    int32_t pid, int32_t opFuncId, int32_t varNo1, int32_t varAttNo1,
+    dbcommon::TypeKind varType1, int32_t varNo2, int32_t varAttNo2,
+    dbcommon::TypeKind varType2) {
+  constructVarOpVarExpr(pid, opFuncId, varNo1, varAttNo1, varType1, varNo2,
+                        varAttNo2, varType2);
+  univPlanQualListAddExpr(univplan);
+}
+
+void UnivPlanProtoUtility::constructFuncOpVarQualList(
+    int32_t pid, int32_t opFuncId, int32_t varNo, int32_t varAttNo,
+    dbcommon::TypeKind varType, int32_t mappingFuncId) {
+  constructFuncOpVarExpr(pid, opFuncId, varNo, varAttNo, varType,
+                         mappingFuncId);
+  univPlanQualListAddExpr(univplan);
+}
+
+void UnivPlanProtoUtility::constructBoolQualList(
+    int32_t pid, int32_t opFuncId1, int32_t varNo1, int32_t varAttNo1,
+    dbcommon::TypeKind varType1, dbcommon::TypeKind constType1,
+    const char *buffer1, int32_t opFuncId2, int32_t varNo2, int32_t varAttNo2,
+    dbcommon::TypeKind varType2, dbcommon::TypeKind constType2,
+    const char *buffer2, int8_t boolType) {
+  constructBoolExpr(pid, opFuncId1, varNo1, varAttNo1, varType1, constType1,
+                    buffer1, opFuncId2, varNo2, varAttNo2, varType2, constType2,
+                    buffer2, boolType);
+  univPlanQualListAddExpr(univplan);
+}
+
+void UnivPlanProtoUtility::constructNullTestQualList(
+    int32_t pid, int8_t nulltesttype, int32_t varNo, int32_t varAttNo,
+    dbcommon::TypeKind varType) {
+  constructNullTestExpr(pid, nulltesttype, varNo, varAttNo, varType);
+  univPlanQualListAddExpr(univplan);
+}
+
+void UnivPlanProtoUtility::constructVarOpConstThenOpVarOpConstQualList(
+    int32_t pid, int32_t opFuncId, int32_t opFuncId1, int32_t varNo1,
+    int32_t varAttNo1, dbcommon::TypeKind varType1,
+    dbcommon::TypeKind constType1, const char *buffer1, int32_t opFuncId2,
+    int32_t varNo2, int32_t varAttNo2, dbcommon::TypeKind varType2,
+    dbcommon::TypeKind constType2, const char *buffer2) {
+  constructVarOpConstThenOpVarOpConstExpr(
+      pid, opFuncId, opFuncId1, varNo1, varAttNo1, varType1, constType1,
+      buffer1, opFuncId2, varNo2, varAttNo2, varType2, constType2, buffer2);
+  univPlanQualListAddExpr(univplan);
+}
+
+int32_t UnivPlanProtoUtility::constructSeqScan(int32_t pid, bool withQualList,
+                                               int8_t targetEntryType) {
+  int32_t uid = ::univPlanSeqScanNewInstance(univplan, pid);
+
+  constructVarTargetEntry(-1, 1, 1, dbcommon::TypeKind::INTID);
+  if (targetEntryType == 0) {
+    constructVarTargetEntry(-1, 1, 3, dbcommon::TypeKind::STRINGID);
+  } else if (targetEntryType == 1) {
+    constructVarTargetEntry(-1, 1, 2, dbcommon::TypeKind::INTID);
+    constructVarTargetEntry(-1, 1, 3, dbcommon::TypeKind::STRINGID);
+  } else if (targetEntryType == 2) {
+    constructNullTestTargetEntry(-1, 1, 1, 3, dbcommon::TypeKind::STRINGID);
+  } else if (targetEntryType == 3) {
+    constructVarOpConstTargetEntry(-1, dbcommon::INT_ADD_INT, 1, 1,
+                                   dbcommon::TypeKind::INTID,
+                                   dbcommon::TypeKind::INTID, "1");
+  } else if (targetEntryType == 4) {
+    constructVarOpConstTargetEntry(-1, dbcommon::STRING_EQUAL_STRING, 1, 3,
+                                   dbcommon::TypeKind::STRINGID,
+                                   dbcommon::TypeKind::STRINGID, "1");
+  } else if (targetEntryType == 5) {
+    constructConstTargetEntry(-1, dbcommon::TypeKind::BIGINTID, "1");
+  } else if (targetEntryType == 6) {
+    constructConstTargetEntry(-1, dbcommon::TypeKind::ANYID, "");
+  } else if (targetEntryType == 7) {
+    constructVarOpConstTargetEntry(-1, dbcommon::INT_ADD_INT, 1, 1,
+                                   dbcommon::TypeKind::INTID,
+                                   dbcommon::TypeKind::INTID, "1");
+    constructVarOpConstTargetEntry(-1, dbcommon::STRING_EQUAL_STRING, 1, 3,
+                                   dbcommon::TypeKind::STRINGID,
+                                   dbcommon::TypeKind::STRINGID, "1");
+  } else if (targetEntryType == 8) {
+    constructVarTargetEntry(-1, 1, 3, dbcommon::TypeKind::STRINGID);
+    constructVarTargetEntry(-1, 1, 2, dbcommon::TypeKind::INTID);
+  }
+
+  if (withQualList) {
+    constructVarOpConstQualList(-1, dbcommon::INT_GREATER_THAN_INT, 1, 2,
+                                dbcommon::TypeKind::INTID,
+                                dbcommon::TypeKind::INTID, "1");
+    constructVarOpVarQualList(-1, dbcommon::BIGINT_EQUAL_INT, 1, 1,
+                              dbcommon::TypeKind::INTID, 1, 2,
+                              dbcommon::TypeKind::INTID);
+    constructFuncOpVarQualList(-1, dbcommon::DOUBLE_LESS_THAN_DOUBLE, 1, 1,
+                               dbcommon::TypeKind::INTID,
+                               dbcommon::TINYINT_LESS_THAN_TINYINT);
+    constructBoolQualList(
+        -1, dbcommon::BIGINT_GREATER_THAN_INT, 1, 1, dbcommon::TypeKind::INTID,
+        dbcommon::TypeKind::INTID, "1", dbcommon::INT_LESS_THAN_INT, 1, 2,
+        dbcommon::TypeKind::INTID, dbcommon::TypeKind::INTID, "10");
+  }
+
+  univPlanSeqScanSetRelId(univplan, 1);
+
+  int32_t numCols = 2;
+  int32_t *columnsToRead =
+      reinterpret_cast<int32_t *>(malloc(numCols * sizeof(int32_t)));
+  columnsToRead[0] = 0;
+  columnsToRead[1] = 1;
+  univPlanSeqScanSetColumnsToRead(univplan, numCols, columnsToRead);
+  free(columnsToRead);
+
+  int64_t start[2] = {1, 2};
+  int64_t len[2] = {200, 100};
+  std::string fileName_buf[2] = {"/a", "/b"};
+  std::unique_ptr<const char *[]> fileName(new const char *[2]);
+  fileName[0] = fileName_buf[0].c_str();
+  fileName[1] = fileName_buf[1].c_str();
+  univPlanSeqScanAddTaskWithFileSplits(false, univplan, 1, fileName.get(),
+                                       start, len, NULL, NULL);
+  univPlanSeqScanAddTaskWithFileSplits(false, univplan, 2, fileName.get(),
+                                       start, len, NULL, NULL);
+
+  univPlanAddToPlanNode(univplan, true);
+  return uid;
+}
+
+int32_t UnivPlanProtoUtility::constructConnector(int32_t pid, int8_t ctype,
+                                                 bool allTargetEntry) {
+  int32_t uid = univPlanConnectorNewInstance(univplan, pid);
+  univPlanConnectorSetType(univplan, ConnectorType(ctype));
+
+  constructVarTargetEntry(-1, 1, 1, dbcommon::TypeKind::INTID);
+  if (allTargetEntry)
+    constructVarTargetEntry(-1, 1, 2, dbcommon::TypeKind::INTID);
+  constructVarTargetEntry(-1, 1, 3, dbcommon::TypeKind::STRINGID);
+
+  if (ctype == 0) {
+    univPlanNewExpr(univplan);
+    univPlanExprAddVar(univplan, -1, 1, 0, dbcommon::TypeKind::INTID, -1);
+    univPlanConnectorAddHashExpr(univplan);
+  }
+
+  univPlanAddToPlanNode(univplan, true);
+  return uid;
+}
+
+int32_t UnivPlanProtoUtility::constructSortConnector(int32_t pid,
+                                                     int8_t ctype) {
+  int32_t uid = univPlanConnectorNewInstance(univplan, pid);
+  univPlanConnectorSetType(univplan, ConnectorType(ctype));
+
+  constructVarTargetEntry(-1, 1, 1, dbcommon::TypeKind::INTID);
+  constructVarTargetEntry(-1, 1, 3, dbcommon::TypeKind::STRINGID);
+
+  int64_t numCols = 2;
+  int32_t *colIdx =
+      reinterpret_cast<int32_t *>(malloc(numCols * sizeof(int32_t)));
+  int32_t *mappingSortFuncId =
+      reinterpret_cast<int32_t *>(malloc(numCols * sizeof(int32_t)));
+  colIdx[0] = 1;
+  colIdx[1] = 2;
+  mappingSortFuncId[0] = dbcommon::BIGINT_LESS_THAN_BIGINT;
+  mappingSortFuncId[1] = dbcommon::INT_LESS_THAN_INT;
+  univPlanConnectorSetColIdx(univplan, numCols, colIdx);
+  univPlanConnectorSetSortFuncId(univplan, numCols, mappingSortFuncId);
+  free(colIdx);
+  free(mappingSortFuncId);
+
+  univPlanAddToPlanNode(univplan, true);
+  return uid;
+}
+
+int32_t UnivPlanProtoUtility::constructLimitBelow(int32_t pid, int64_t count,
+                                                  int64_t offset) {
+  int32_t uid = univPlanLimitNewInstance(univplan, pid);
+
+  constructVarTargetEntry(-1, 1, 1, dbcommon::TypeKind::INTID);
+  constructVarTargetEntry(-1, 1, 2, dbcommon::TypeKind::INTID);
+  constructVarTargetEntry(-1, 1, 3, dbcommon::TypeKind::STRINGID);
+
+  univPlanSetPlanNodeInfo(univplan, static_cast<double>(count + offset), 0, 0);
+
+  std::string countTmp = std::to_string(count);
+  char const *countBuf = countTmp.c_str();
+  std::string offsetTmp = std::to_string(offset);
+  char const *offsetBuf = offsetTmp.c_str();
+  if (count != -1) {
+    constructConstOpConstExpr(-1, dbcommon::BIGINT_ADD_BIGINT,
+                              dbcommon::BIGINTID, countBuf, dbcommon::BIGINTID,
+                              offsetBuf);
+    univPlanLimitAddLimitCount(univplan);
+  }
+
+  if (offset != -1) {
+    univPlanNewExpr(univplan);
+    univPlanExprAddConst(univplan, -1, dbcommon::BIGINTID, false, "0", -1);
+    univPlanLimitAddLimitOffset(univplan);
+  }
+
+  univPlanAddToPlanNode(univplan, true);
+  return uid;
+}
+
+int32_t UnivPlanProtoUtility::constructLimitTop(int32_t pid, int64_t count,
+                                                int64_t offset) {
+  int32_t uid = univPlanLimitNewInstance(univplan, pid);
+
+  constructVarTargetEntry(-1, 1, 1, dbcommon::TypeKind::INTID);
+  constructVarTargetEntry(-1, 1, 2, dbcommon::TypeKind::INTID);
+  constructVarTargetEntry(-1, 1, 3, dbcommon::TypeKind::STRINGID);
+
+  univPlanSetPlanNodeInfo(univplan, static_cast<double>(count + offset), 0, 0);
+
+  if (count != -1) {
+    univPlanNewExpr(univplan);
+    std::string countTmp = std::to_string(count);
+    char const *countBuf = countTmp.c_str();
+    univPlanExprAddConst(univplan, -1, dbcommon::BIGINTID, false, countBuf, -1);
+    univPlanLimitAddLimitCount(univplan);
+  }
+
+  if (offset != -1) {
+    univPlanNewExpr(univplan);
+    std::string offsetTmp = std::to_string(offset);
+    char const *offsetBuf = offsetTmp.c_str();
+    univPlanExprAddConst(univplan, -1, dbcommon::BIGINTID, false, offsetBuf,
+                         -1);
+    univPlanLimitAddLimitOffset(univplan);
+  }
+
+  univPlanAddToPlanNode(univplan, true);
+  return uid;
+}
+
+int32_t UnivPlanProtoUtility::constructAgg(int32_t pid, int8_t aggstage) {
+  int32_t uid = univPlanAggNewInstance(univplan, pid);
+
+  constructAggRefTargetEntry(-1, aggstage, dbcommon::COUNT, 1, 1,
+                             dbcommon::TypeKind::INTID);
+  constructVarTargetEntry(-1, 1, 2, dbcommon::TypeKind::INTID);
+  constructVarTargetEntry(-1, 1, 3, dbcommon::TypeKind::STRINGID);
+
+  int64_t numCols = 2;
+  int32_t *grpColIdx =
+      reinterpret_cast<int32_t *>(malloc(numCols * sizeof(int32_t)));
+  grpColIdx[0] = 1;
+  grpColIdx[1] = 3;
+  univPlanAggSetNumGroupsAndGroupColIndexes(univplan, 1000, numCols, grpColIdx);
+  free(grpColIdx);
+
+  univPlanAddToPlanNode(univplan, true);
+  return uid;
+}
+
+int32_t UnivPlanProtoUtility::constructSort(int32_t pid) {
+  int32_t uid = univPlanSortNewInstance(univplan, pid);
+
+  int64_t numCols = 2;
+  int32_t *colIdx =
+      reinterpret_cast<int32_t *>(malloc(numCols * sizeof(int32_t)));
+  int32_t *mappingSortFuncId =
+      reinterpret_cast<int32_t *>(malloc(numCols * sizeof(int32_t)));
+  colIdx[0] = 1;
+  colIdx[1] = 2;
+  mappingSortFuncId[0] = dbcommon::BIGINT_LESS_THAN_BIGINT;
+  mappingSortFuncId[1] = dbcommon::INT_LESS_THAN_INT;
+  univPlanSortSetColIdx(univplan, numCols, colIdx);
+  univPlanSortSetSortFuncId(univplan, numCols, mappingSortFuncId);
+  free(colIdx);
+  free(mappingSortFuncId);
+
+  univPlanAddToPlanNode(univplan, true);
+  return uid;
+}
+
+void UnivPlanProtoUtility::constructRangeTable() {
+  univPlanRangeTblEntryAddDummy(univplan);
+
+  char location[] = "/tmp";
+  char fmtOptsJson[] = "option1 string in json";
+  int32_t columnNum = 2;
+  int32_t columnDataType[2] = {dbcommon::TypeKind::INTID,
+                               dbcommon::TypeKind::STRINGID};
+  int64_t columnDataTypeMod[2] = {-1, -1};
+  std::string columnName_buf[2] = {"p1", "p2"};
+  std::unique_ptr<const char *[]> columnName(new const char *[2]);
+  columnName[0] = columnName_buf[0].c_str();
+  columnName[1] = columnName_buf[1].c_str();
+
+  univPlanRangeTblEntryAddTable(univplan, 2, UnivPlanOrcFormat, location,
+                                fmtOptsJson, columnNum, columnName.get(),
+                                columnDataType, columnDataTypeMod);
+}
+
+void UnivPlanProtoUtility::constructReceiver() {
+  std::string addr_buf1[1] = {"mdw"};
+  std::unique_ptr<const char *[]> addr1(new const char *[1]);
+  addr1[0] = addr_buf1[0].c_str();
+  int32_t port1[2] = {101};
+
+  std::string addr_buf2[2] = {"smdw", "smdw"};
+  std::unique_ptr<const char *[]> addr2(new const char *[2]);
+  addr2[0] = addr_buf2[0].c_str();
+  addr2[1] = addr_buf2[1].c_str();
+  int32_t port2[2] = {201, 203};
+
+  univPlanReceiverAddListeners(univplan, 1, addr1.get(), port1);
+  univPlanReceiverAddListeners(univplan, 2, addr2.get(), port2);
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/testutil/univplan-proto-util.h b/depends/univplan/src/univplan/testutil/univplan-proto-util.h
new file mode 100644
index 0000000..bc175a4
--- /dev/null
+++ b/depends/univplan/src/univplan/testutil/univplan-proto-util.h
@@ -0,0 +1,264 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_TESTUTIL_UNIVPLAN_PROTO_UTIL_H_
+#define UNIVPLAN_SRC_UNIVPLAN_TESTUTIL_UNIVPLAN_PROTO_UTIL_H_
+
+#include <string>
+#include <utility>
+
+#include "univplan/cwrapper/univplan-c.h"
+
+#include "dbcommon/log/logger.h"
+#include "dbcommon/type/type-kind.h"
+
+#include "univplan/common/stagize.h"
+#include "univplan/common/var-util.h"
+#include "univplan/univplanbuilder/univplanbuilder-expr-tree.h"
+#include "univplan/univplanbuilder/univplanbuilder-plan.h"
+#include "univplan/univplanbuilder/univplanbuilder-table.h"
+#include "univplan/univplanbuilder/univplanbuilder.h"
+
+struct UnivPlanC {
+  univplan::UnivPlanBuilder::uptr upb;
+  univplan::UnivPlanBuilderNode::uptr curNode;
+  univplan::UnivPlanBuilderExprTree::uptr curExpr;
+  std::string seriaizedPlan;
+  UnivPlanCatchedError error;
+  std::string debugString;
+  uint16_t totalStageNo;
+};
+
+typedef enum NodeTag {
+  T_Invalid = 0,
+  T_BoolExpr = 313,
+} NodeTag;
+
+typedef struct Expr {
+  NodeTag type;
+} Expr;
+
+typedef enum BoolExprType { AND_EXPR, OR_EXPR, NOT_EXPR } BoolExprType;
+
+struct ListCell {
+  union {
+    void *ptr_value;
+    int int_value;
+    unsigned int oid_value;
+  } data;
+  ListCell *next;
+};
+
+typedef struct List {
+  NodeTag type; /* T_List, T_IntList, or T_OidList */
+  int length;
+  ListCell *head;
+  ListCell *tail;
+} List;
+
+typedef struct BoolExpr {
+  Expr xpr;
+  BoolExprType boolop;
+  List *args;   /* arguments to this expression */
+  int location; /* token location, or -1 if unknown */
+} BoolExpr;
+
+typedef enum NullTestType { IS_NULL, IS_NOT_NULL } NullTestType;
+
+typedef struct NullTest {
+  Expr xpr;
+  Expr *arg;                 /* input expression */
+  NullTestType nulltesttype; /* IS NULL, IS NOT NULL */
+} NullTest;
+
+namespace univplan {
+class UnivPlanProtoUtility {
+ public:
+  UnivPlanProtoUtility();
+  ~UnivPlanProtoUtility();
+
+  // like p op const
+  void constructVarOpConstExpr(int32_t pid, int32_t opFuncId, int32_t varNo,
+                               int32_t varAttNo, dbcommon::TypeKind varType,
+                               dbcommon::TypeKind constType,
+                               const char *buffer);
+
+  // like const op p
+  void constructConstOpVarExpr(int32_t pid, int32_t opFuncId, int32_t varNo,
+                               int32_t varAttNo, dbcommon::TypeKind varType,
+                               dbcommon::TypeKind constType,
+                               const char *buffer);
+  // like p op q
+  void constructVarOpVarExpr(int32_t pid, int32_t opFuncId, int32_t varNo1,
+                             int32_t varAttNo1, dbcommon::TypeKind varType1,
+                             int32_t varNo2, int32_t varAttNo2,
+                             dbcommon::TypeKind varType2);
+
+  // like const op const
+  void constructConstOpConstExpr(int32_t pid, int32_t opFuncId,
+                                 dbcommon::TypeKind constType1,
+                                 const char *buffer1,
+                                 dbcommon::TypeKind constType2,
+                                 const char *buffer2);
+
+  // like func op p
+  void constructFuncOpVarExpr(int32_t pid, int32_t opFuncId, int32_t varNo,
+                              int32_t varAttNo, dbcommon::TypeKind varType,
+                              int32_t mappingFuncId);
+
+  // like p op const or q op const
+  void constructBoolExpr(int32_t pid, int32_t opFuncId1, int32_t varNo1,
+                         int32_t varAttNo1, dbcommon::TypeKind varType1,
+                         dbcommon::TypeKind constType1, const char *buffer1,
+                         int32_t opFuncId2, int32_t varNo2, int32_t varAttNo2,
+                         dbcommon::TypeKind varType2,
+                         dbcommon::TypeKind constType2, const char *buffer2,
+                         int8_t boolType = 1);
+
+  // like p is (not) null
+  void constructNullTestExpr(int32_t pid, int8_t nulltesttype, int32_t varNo,
+                             int32_t varAttNo, dbcommon::TypeKind varType);
+
+  // like (p op const) op (q op const)
+  void constructVarOpConstThenOpVarOpConstExpr(
+      int32_t pid, int32_t opFuncId, int32_t opFuncId1, int32_t varNo1,
+      int32_t varAttNo1, dbcommon::TypeKind varType1,
+      dbcommon::TypeKind constType1, const char *buffer1, int32_t opFuncId2,
+      int32_t varNo2, int32_t varAttNo2, dbcommon::TypeKind varType2,
+      dbcommon::TypeKind constType2, const char *buffer2);
+
+  // TargetEntry with var
+  void constructVarTargetEntry(int32_t pid, int32_t varNo, int32_t varAttNo,
+                               dbcommon::TypeKind type);
+
+  // TargetEntry with const
+  void constructConstTargetEntry(int32_t pid, dbcommon::TypeKind constType,
+                                 const char *buffer);
+
+  // TargetEntry with const op const
+  void constructConstOpConstTargetEntry(int32_t pid, int32_t opFuncId,
+                                        dbcommon::TypeKind constType1,
+                                        const char *buffer1,
+                                        dbcommon::TypeKind constType2,
+                                        const char *buffer2);
+
+  // TargetEntry with Aggref
+  void constructAggRefTargetEntry(int32_t pid, int8_t aggstage, int32_t varNo,
+                                  int32_t mappingFuncId, int32_t varAttNo,
+                                  dbcommon::TypeKind type);
+
+  // TargetEntry with NullTest
+  void constructNullTestTargetEntry(int32_t pid, int8_t nulltesttype,
+                                    int32_t varNo, int32_t varAttNo,
+                                    dbcommon::TypeKind varType);
+
+  // TargetEntry with p op const
+  void constructVarOpConstTargetEntry(int32_t pid, int32_t opFuncId,
+                                      int32_t varNo, int32_t varAttNo,
+                                      dbcommon::TypeKind varType,
+                                      dbcommon::TypeKind constType,
+                                      const char *buffer);
+
+  // QualList like p op const
+  void constructVarOpConstQualList(int32_t pid, int32_t opFuncId, int32_t varNo,
+                                   int32_t varAttNo, dbcommon::TypeKind varType,
+                                   dbcommon::TypeKind constType,
+                                   const char *buffer);
+
+  // QualList like const op p
+  void constructConstOpVarQualList(int32_t pid, int32_t opFuncId, int32_t varNo,
+                                   int32_t varAttNo, dbcommon::TypeKind varType,
+                                   dbcommon::TypeKind constType,
+                                   const char *buffer);
+
+  // QualList like p op q
+  void constructVarOpVarQualList(int32_t pid, int32_t opFuncId, int32_t varNo1,
+                                 int32_t varAttNo1, dbcommon::TypeKind varType1,
+                                 int32_t varNo2, int32_t varAttNo2,
+                                 dbcommon::TypeKind varType2);
+
+  // QualList like func op p
+  void constructFuncOpVarQualList(int32_t pid, int32_t opFuncId, int32_t varNo,
+                                  int32_t varAttNo, dbcommon::TypeKind varType,
+                                  int32_t mappingFuncId);
+
+  // QualList like p op const or q op const
+  void constructBoolQualList(int32_t pid, int32_t opFuncId1, int32_t varNo1,
+                             int32_t varAttNo1, dbcommon::TypeKind varType1,
+                             dbcommon::TypeKind constType1, const char *buffer1,
+                             int32_t opFuncId2, int32_t varNo2,
+                             int32_t varAttNo2, dbcommon::TypeKind varType2,
+                             dbcommon::TypeKind constType2, const char *buffer2,
+                             int8_t boolType = 1);
+
+  // QualList with NullTest
+  void constructNullTestQualList(int32_t pid, int8_t nulltesttype,
+                                 int32_t varNo, int32_t varAttNo,
+                                 dbcommon::TypeKind varType);
+
+  // QualList like p op const or q op const
+  void constructVarOpConstThenOpVarOpConstQualList(
+      int32_t pid, int32_t opFuncId, int32_t opFuncId1, int32_t varNo1,
+      int32_t varAttNo1, dbcommon::TypeKind varType1,
+      dbcommon::TypeKind constType1, const char *buffer1, int32_t opFuncId2,
+      int32_t varNo2, int32_t varAttNo2, dbcommon::TypeKind varType2,
+      dbcommon::TypeKind constType2, const char *buffer2);
+
+  int32_t constructSeqScan(int32_t pid, bool wihQualList,
+                           int8_t targetEntryType);
+
+  int32_t constructConnector(int32_t pid, int8_t ctype, bool allTargetEntry);
+
+  int32_t constructSortConnector(int32_t pid, int8_t ctype);
+
+  void constructRangeTable();
+
+  void constructReceiver();
+
+  // when count/limit = -1, means there is no count/limit
+  int32_t constructLimitBelow(int32_t pid, int64_t count, int64_t offset);
+
+  // when count/limit = -1, means there is no count/limit
+  int32_t constructLimitTop(int32_t pid, int64_t count, int64_t offset);
+
+  int32_t constructAgg(int32_t pid, int8_t aggstage);
+
+  int32_t constructSort(int32_t pid);
+
+  void univPlanFixVarType() { ::univPlanFixVarType(univplan); }
+
+  void univPlanStagize() { ::univPlanStagize(univplan); }
+
+  const char *univPlanSerialize(int32_t *size) {
+    return ::univPlanSerialize(univplan, size, true);
+  }
+
+  const char *univPlanGetJsonFormatedPlan() {
+    return ::univPlanGetJsonFormatedPlan(univplan);
+  }
+
+  void univPlanSetDoInstrument(bool doInstrument) {
+    ::univPlanSetDoInstrument(univplan, doInstrument);
+  }
+
+  int32_t univPlanSeqScanNewInstance(int32_t pid) {
+    return ::univPlanSeqScanNewInstance(univplan, pid);
+  }
+
+  void univPlanAddToPlanNodeTest(bool isleft) {
+    ::univPlanAddToPlanNode(univplan, isleft);
+  }
+
+  UnivPlanC *getUnivPlan() { return std::move(univplan); }
+
+ private:
+  UnivPlanC *univplan = nullptr;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_TESTUTIL_UNIVPLAN_PROTO_UTIL_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-agg.cc b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-agg.cc
new file mode 100644
index 0000000..6114538
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-agg.cc
@@ -0,0 +1,45 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/univplanbuilder/univplanbuilder-agg.h"
+
+namespace univplan {
+
+UnivPlanBuilderAgg::UnivPlanBuilderAgg() : UnivPlanBuilderNode() {
+  planNode.reset(new UnivPlanAgg());
+  ref = planNode.get();
+
+  ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+}
+
+UnivPlanBuilderAgg::~UnivPlanBuilderAgg() {}
+
+UnivPlanBuilderPlanNodePoly::uptr UnivPlanBuilderAgg::ownPlanNode() {
+  UnivPlanBuilderPlanNodePoly::uptr pn(
+      new UnivPlanBuilderPlanNodePoly(UNIVPLAN_AGG, planNode->super()));
+  pn->getPlanNodePoly()->set_allocated_agg(planNode.release());
+  return std::move(pn);
+}
+
+void UnivPlanBuilderAgg::from(const UnivPlanPlanNodePoly &node) {
+  assert(node.type() == UNIVPLAN_AGG);
+  ref->CopyFrom(node.agg());
+  baseRef = ref->mutable_super();
+  baseRef->clear_leftplan();
+  baseRef->clear_rightplan();
+}
+
+void UnivPlanBuilderAgg::setNumGroups(int64_t n) { ref->set_numgroups(n); }
+
+void UnivPlanBuilderAgg::setGroupColIndexes(
+    const std::vector<int32_t> &nArray) {
+  for (int i = 0; i < nArray.size(); ++i) {
+    ref->add_groupcolindexes(nArray[i]);
+  }
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-agg.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-agg.h
new file mode 100644
index 0000000..b4c83bf
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-agg.h
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_AGG_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_AGG_H_
+
+#include <vector>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderAgg : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderAgg();
+  virtual ~UnivPlanBuilderAgg();
+
+  typedef std::unique_ptr<UnivPlanBuilderAgg> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override;
+
+  void from(const UnivPlanPlanNodePoly &node) override;
+
+  void setNumGroups(int64_t n);
+  void setGroupColIndexes(const std::vector<int32_t> &nArray);
+
+ private:
+  UnivPlanAgg *ref;
+  std::unique_ptr<UnivPlanAgg> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_AGG_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-append.cc b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-append.cc
new file mode 100644
index 0000000..d7bc4fc
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-append.cc
@@ -0,0 +1,41 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2017, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/univplanbuilder/univplanbuilder-append.h"
+
+namespace univplan {
+
+UnivPlanBuilderAppend::UnivPlanBuilderAppend() : UnivPlanBuilderNode() {
+  planNode.reset(new UnivPlanAppend());
+  ref = planNode.get();
+
+  ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+}
+
+UnivPlanBuilderAppend::~UnivPlanBuilderAppend() {}
+
+UnivPlanBuilderPlanNodePoly::uptr UnivPlanBuilderAppend::ownPlanNode() {
+  UnivPlanBuilderPlanNodePoly::uptr pn(
+      new UnivPlanBuilderPlanNodePoly(UNIVPLAN_APPEND, planNode->super()));
+  pn->getPlanNodePoly()->set_allocated_append(planNode.release());
+  return std::move(pn);
+}
+
+void UnivPlanBuilderAppend::from(const UnivPlanPlanNodePoly &node) {
+  assert(node.type() == UNIVPLAN_APPEND);
+  ref->CopyFrom(node.append());
+  baseRef = ref->mutable_super();
+  baseRef->clear_leftplan();
+  baseRef->clear_rightplan();
+}
+
+void UnivPlanBuilderAppend::addAppendPlan(const UnivPlanPlanNodePoly &node) {
+  UnivPlanPlanNodePoly *poly = ref->add_appendplans();
+  poly->CopyFrom(node);
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-append.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-append.h
new file mode 100644
index 0000000..d9f99ba
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-append.h
@@ -0,0 +1,36 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2017, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_APPEND_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_APPEND_H_
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderAppend : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderAppend();
+  virtual ~UnivPlanBuilderAppend();
+
+  typedef std::unique_ptr<UnivPlanBuilderAppend> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override;
+
+  void from(const UnivPlanPlanNodePoly &node) override;
+
+  void addAppendPlan(const UnivPlanPlanNodePoly &node);
+
+ private:
+  UnivPlanAppend *ref;
+  std::unique_ptr<UnivPlanAppend> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_APPEND_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-column.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-column.h
new file mode 100644
index 0000000..250709b
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-column.h
@@ -0,0 +1,42 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_COLUMN_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_COLUMN_H_
+
+#include <string>
+
+#include "univplan/proto/universal-plan.pb.h"
+
+namespace univplan {
+
+class UnivPlanBuilderColumn {
+ public:
+  explicit UnivPlanBuilderColumn(UnivPlanColumn *column) : ref(column) {}
+
+  virtual ~UnivPlanBuilderColumn() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderColumn> uptr;
+
+  void setColumnName(const std::string &columnName) {
+    ref->set_columnname(columnName);
+  }
+
+  void setTypeId(int32_t typeId) { ref->set_typeid_(typeId); }
+  void setTypeMod(int64_t typeMod) { ref->set_typemod(typeMod); }
+
+  void setScale1(int32_t scale) { ref->set_scale1(scale); }
+  void setScale2(int32_t scale) { ref->set_scale2(scale); }
+  void setIsNullable(bool nullable) { ref->set_isnullable(nullable); }
+
+ private:
+  UnivPlanColumn *ref = nullptr;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_COLUMN_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-connector.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-connector.h
new file mode 100644
index 0000000..1527fe8
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-connector.h
@@ -0,0 +1,86 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_CONNECTOR_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_CONNECTOR_H_
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderConnector : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderConnector() : UnivPlanBuilderNode() {
+    planNode.reset(new UnivPlanConnector);
+    ref = planNode.get();
+
+    ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+  }
+  virtual ~UnivPlanBuilderConnector() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderConnector> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override {
+    UnivPlanBuilderPlanNodePoly::uptr pn(
+        new UnivPlanBuilderPlanNodePoly(UNIVPLAN_CONNECTOR, planNode->super()));
+    pn->getPlanNodePoly()->set_allocated_connector(planNode.release());
+    return std::move(pn);
+  }
+
+  void from(const UnivPlanPlanNodePoly &node) override {
+    assert(node.type() == UNIVPLAN_CONNECTOR);
+    ref->CopyFrom(node.connector());
+    baseRef = ref->mutable_super();
+    baseRef->clear_leftplan();
+    baseRef->clear_rightplan();
+  }
+
+  void setConnectorType(UNIVPLANCONNECTORTYPE type) { ref->set_type(type); }
+
+  void setStageNo(int stageNo) { ref->set_stageno(stageNo); }
+
+  void setMagmaTable(bool stageNo) { ref->set_magmatable(stageNo); }
+
+  void setMagmaMap(int *map) {
+    int rangeNum = ref->rangenum();
+    for (int i = 0; i < rangeNum; ++i) {
+      ref->add_magmamap(map[i]);
+    }
+  }
+
+  void setRangeNum(int rangeNum) { ref->set_rangenum(rangeNum); }
+
+  void setColIdx(const std::vector<int32_t> &nArray) {
+    for (int i = 0; i < nArray.size(); ++i) {
+      ref->add_colidx(nArray[i]);
+    }
+  }
+
+  void setSortFuncId(const std::vector<int32_t> &nArray) {
+    for (int i = 0; i < nArray.size(); ++i) {
+      ref->add_sortfuncid(nArray[i]);
+    }
+  }
+
+  void addHashExpr(UnivPlanBuilderExprTree::uptr exprTree) {
+    assert(ref != nullptr);
+    ref->mutable_hashexpr()->AddAllocated(exprTree->ownExprPoly().release());
+  }
+
+ private:
+  UnivPlanConnector *ref;
+  std::unique_ptr<UnivPlanConnector> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_CONNECTOR_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-expr-node.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-expr-node.h
new file mode 100644
index 0000000..e3a2943
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-expr-node.h
@@ -0,0 +1,724 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXPR_NODE_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXPR_NODE_H_
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-expr-poly.h"
+
+namespace univplan {
+
+class UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderExprNode> uptr;
+
+  UnivPlanBuilderExprNode() {}
+
+  UnivPlanBuilderExprNode(int32_t pid, int32_t uid) : pid(pid), uid(uid) {}
+
+  virtual ~UnivPlanBuilderExprNode() {}
+
+  // Create a UnivPlanBuilderExprPoly instance and transfer out the ownership.
+  virtual std::unique_ptr<UnivPlanBuilderExprPoly> getExprPolyBuilder() = 0;
+
+  virtual UnivPlanBuilderExprNode &addArgs(UnivPlanBuilderExprPoly::uptr arg) {
+    LOG_ERROR(ERRCODE_INTERNAL_ERROR, "add args not implemented");
+  }
+
+  int32_t pid = -1;
+  int32_t uid = -1;
+};
+
+class UnivPlanBuilderVar final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderVar> uptr;
+
+  UnivPlanBuilderVar() : node_(new UnivPlanVar), ref_(node_.get()) {}
+
+  UnivPlanBuilderVar(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanVar),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_VAR));
+    exprPoly->getExprPoly()->set_allocated_var(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderVar &setVarNo(uint32_t varNo) {
+    ref_->set_varno(varNo);
+    return *this;
+  }
+
+  UnivPlanBuilderVar &setVarAttNo(int32_t varAttNo) {
+    ref_->set_varattno(varAttNo);
+    return *this;
+  }
+
+  UnivPlanBuilderVar &setTypeId(int32_t typeId) {
+    ref_->set_typeid_(typeId);
+    return *this;
+  }
+
+  UnivPlanBuilderVar &setTypeMod(int64_t typeMod) {
+    ref_->set_typemod(typeMod);
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanVar> node_;
+  UnivPlanVar *ref_;
+};
+
+class UnivPlanBuilderConst final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderConst> uptr;
+
+  UnivPlanBuilderConst() : node_(new UnivPlanConst), ref_(node_.get()) {}
+
+  UnivPlanBuilderConst(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanConst),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_CONST));
+    exprPoly->getExprPoly()->set_allocated_val(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderConst &setType(int32_t type) {
+    ref_->set_type(type);
+    return *this;
+  }
+
+  UnivPlanBuilderConst &setTypeMod(int64_t typeMod) {
+    ref_->set_typemod(typeMod);
+    return *this;
+  }
+
+  UnivPlanBuilderConst &setIsNull(bool isNull) {
+    ref_->set_isnull(isNull);
+    return *this;
+  }
+
+  UnivPlanBuilderConst &setValue(const std::string &value) {
+    ref_->set_value(value);
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanConst> node_;
+  UnivPlanConst *ref_;
+};
+
+class UnivPlanBuilderOpExpr final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderOpExpr> uptr;
+
+  UnivPlanBuilderOpExpr() : node_(new UnivPlanOpExpr), ref_(node_.get()) {}
+
+  UnivPlanBuilderOpExpr(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanOpExpr),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_OPEXPR));
+    exprPoly->getExprPoly()->set_allocated_opexpr(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderExprNode &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    return *this;
+  }
+
+  UnivPlanBuilderOpExpr &setRetType(int32_t retType) {
+    ref_->set_rettype(retType);
+    return *this;
+  }
+
+  UnivPlanBuilderOpExpr &setFuncId(int32_t funcId) {
+    ref_->set_funcid(funcId);
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanOpExpr> node_;
+  UnivPlanOpExpr *ref_;
+};
+
+class UnivPlanBuilderFuncExpr final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderFuncExpr> uptr;
+
+  UnivPlanBuilderFuncExpr() : node_(new UnivPlanFuncExpr), ref_(node_.get()) {}
+
+  UnivPlanBuilderFuncExpr(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanFuncExpr),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_FUNCEXPR));
+    exprPoly->getExprPoly()->set_allocated_funcexpr(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderFuncExpr &setFuncId(int32_t funcId) {
+    ref_->set_funcid(funcId);
+    return *this;
+  }
+
+  UnivPlanBuilderFuncExpr &setRetType(int32_t retType) {
+    ref_->set_rettype(retType);
+    return *this;
+  }
+
+  UnivPlanBuilderExprNode &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanFuncExpr> node_;
+  UnivPlanFuncExpr *ref_;
+};
+
+class UnivPlanBuilderAggref final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderAggref> uptr;
+
+  UnivPlanBuilderAggref() : node_(new UnivPlanAggref), ref_(node_.get()) {}
+
+  UnivPlanBuilderAggref(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanAggref),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_AGGREF));
+    exprPoly->getExprPoly()->set_allocated_aggref(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderAggref &setFuncId(int32_t funcId) {
+    ref_->set_funcid(funcId);
+
+    return *this;
+  }
+
+  UnivPlanBuilderAggref &setTransFuncId(int32_t funcId) {
+    ref_->set_transfuncid(funcId);
+    return *this;
+  }
+
+  UnivPlanBuilderAggref &setFinalFuncId(int32_t funcId) {
+    ref_->set_finalfuncid(funcId);
+    return *this;
+  }
+
+  UnivPlanBuilderAggref &setRetType(int32_t retType) {
+    ref_->set_rettype(retType);
+    return *this;
+  }
+
+  UnivPlanBuilderAggref &setTransInitVal(bool transInitVal) {
+    ref_->set_transinitval(transInitVal);
+    return *this;
+  }
+
+  UnivPlanBuilderExprNode &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanAggref> node_;
+  UnivPlanAggref *ref_;
+};
+
+class UnivPlanBuilderBoolExpr final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderBoolExpr> uptr;
+
+  UnivPlanBuilderBoolExpr() : node_(new UnivPlanBoolExpr), ref_(node_.get()) {}
+
+  UnivPlanBuilderBoolExpr(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanBoolExpr),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_BOOLEXPR));
+    exprPoly->getExprPoly()->set_allocated_boolexpr(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderBoolExpr &setType(BOOLEXPRTYPE type) {
+    ref_->set_type(type);
+    return *this;
+  }
+
+  UnivPlanBuilderExprNode &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanBoolExpr> node_;
+  UnivPlanBoolExpr *ref_;
+};
+
+class UnivPlanBuilderNullTest final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderNullTest> uptr;
+
+  UnivPlanBuilderNullTest() : node_(new UnivPlanNullTest), ref_(node_.get()) {}
+
+  UnivPlanBuilderNullTest(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanNullTest),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_NULLTEST));
+    exprPoly->getExprPoly()->set_allocated_nulltest(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderNullTest &setType(NULLTESTTYPE type) {
+    ref_->set_type(type);
+    return *this;
+  }
+
+  UnivPlanBuilderExprNode &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->set_allocated_arg(arg->ownExprPoly().release());
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanNullTest> node_;
+  UnivPlanNullTest *ref_;
+};
+
+class UnivPlanBuilderBooleanTest final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderBooleanTest> uptr;
+
+  UnivPlanBuilderBooleanTest()
+      : node_(new UnivPlanBooleanTest), ref_(node_.get()) {}
+
+  UnivPlanBuilderBooleanTest(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanBooleanTest),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_BOOLEANTEST));
+    exprPoly->getExprPoly()->set_allocated_booltest(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderBooleanTest &setType(BOOLTESTTYPE type) {
+    ref_->set_type(type);
+    return *this;
+  }
+
+  UnivPlanBuilderExprNode &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->set_allocated_arg(arg->ownExprPoly().release());
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanBooleanTest> node_;
+  UnivPlanBooleanTest *ref_;
+};
+
+class UnivPlanBuilderCaseExpr final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderCaseExpr> uptr;
+
+  UnivPlanBuilderCaseExpr() : node_(new UnivPlanCaseExpr), ref_(node_.get()) {}
+
+  UnivPlanBuilderCaseExpr(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanCaseExpr),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_CASEEXPR));
+    exprPoly->getExprPoly()->set_allocated_caseexpr(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderCaseExpr &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    if (addingDefresult_) return setDefresult(std::move(arg));
+    ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    return *this;
+  }
+
+  UnivPlanBuilderCaseExpr &setCasetype(int32_t casetype) {
+    ref_->set_casetype(casetype);
+    return *this;
+  }
+
+  void setAddingDefresult() { addingDefresult_ = true; }
+
+  UnivPlanBuilderCaseExpr &setDefresult(UnivPlanBuilderExprPoly::uptr arg) {
+    ref_->set_allocated_defresult(arg->ownExprPoly().release());
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanCaseExpr> node_;
+  UnivPlanCaseExpr *ref_;
+  bool addingDefresult_ = false;
+};
+
+class UnivPlanBuilderCaseWhen final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderCaseWhen> uptr;
+
+  UnivPlanBuilderCaseWhen() : node_(new UnivPlanCaseWhen), ref_(node_.get()) {}
+
+  UnivPlanBuilderCaseWhen(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanCaseWhen),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_CASEWHEN));
+    exprPoly->getExprPoly()->set_allocated_casewhen(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderCaseWhen &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    if (addingResult_) return setResult(std::move(arg));
+    ref_->set_allocated_expr(arg->ownExprPoly().release());
+    return *this;
+  }
+
+  void setAddingResult() { addingResult_ = true; }
+
+  UnivPlanBuilderCaseWhen &setResult(UnivPlanBuilderExprPoly::uptr arg) {
+    ref_->set_allocated_result(arg->ownExprPoly().release());
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanCaseWhen> node_;
+  UnivPlanCaseWhen *ref_;
+  bool addingResult_ = false;
+};
+
+class UnivPlanBuilderSubPlan final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderSubPlan> uptr;
+
+  UnivPlanBuilderSubPlan() : node_(new UnivPlanSubPlan), ref_(node_.get()) {}
+
+  UnivPlanBuilderSubPlan(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanSubPlan),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_SUBPLAN));
+    exprPoly->getExprPoly()->set_allocated_subplan(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderSubPlan &setSubLinkType(SUBLINKTYPE subLinkType) {
+    ref_->set_sublinktype(subLinkType);
+    return *this;
+  }
+
+  UnivPlanBuilderSubPlan &setPlanId(int32_t planId) {
+    ref_->set_planid(planId);
+    return *this;
+  }
+
+  UnivPlanBuilderSubPlan &setTypeId(int32_t typeId) {
+    ref_->set_typeid_(typeId);
+    return *this;
+  }
+
+  UnivPlanBuilderSubPlan &setTypeMod(int64_t typeMod) {
+    ref_->set_typemod(typeMod);
+    return *this;
+  }
+
+  UnivPlanBuilderSubPlan &setUseHashTable(bool useHashTable) {
+    ref_->set_usehashtable(useHashTable);
+    return *this;
+  }
+
+  UnivPlanBuilderSubPlan &setInitPlan(bool initPlan) {
+    ref_->set_initplan(initPlan);
+    return *this;
+  }
+
+  UnivPlanBuilderSubPlan &addSetParam(int32_t setParam) {
+    ref_->add_setparam(setParam);
+    return *this;
+  }
+
+  UnivPlanBuilderSubPlan &addParParam(int32_t parParam) {
+    ref_->add_parentparam(parParam);
+    return *this;
+  }
+
+  UnivPlanBuilderSubPlan &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    if (addingTestexpr_) {
+      ref_->set_allocated_testexpr(arg->ownExprPoly().release());
+    } else {
+      ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    }
+    return *this;
+  }
+
+  void setAddingTestexpr() { addingTestexpr_ = true; }
+
+  UnivPlanBuilderSubPlan &addTestexprParam(int32_t testexprParam) {
+    ref_->add_testexprparam(testexprParam);
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanSubPlan> node_;
+  UnivPlanSubPlan *ref_;
+  bool addingTestexpr_ = false;
+};
+
+class UnivPlanBuilderParam final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderParam> uptr;
+
+  UnivPlanBuilderParam() : node_(new UnivPlanParam), ref_(node_.get()) {}
+
+  UnivPlanBuilderParam(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanParam),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_PARAM));
+    exprPoly->getExprPoly()->set_allocated_param(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderParam &setParamKind(PARAMKIND paramKind) {
+    ref_->set_paramkind(paramKind);
+    return *this;
+  }
+
+  UnivPlanBuilderParam &setParamId(int32_t paramId) {
+    ref_->set_paramid(paramId);
+    return *this;
+  }
+
+  UnivPlanBuilderParam &setTypeId(int32_t typeId) {
+    ref_->set_typeid_(typeId);
+    return *this;
+  }
+
+  UnivPlanBuilderParam &setTypeMod(int64_t typeMod) {
+    ref_->set_typemod(typeMod);
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanParam> node_;
+  UnivPlanParam *ref_;
+};
+
+class UnivPlanBuilderScalarArrayOpExpr final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderOpExpr> uptr;
+
+  UnivPlanBuilderScalarArrayOpExpr()
+      : node_(new UnivPlanScalarArrayOpExpr), ref_(node_.get()) {}
+
+  UnivPlanBuilderScalarArrayOpExpr(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanScalarArrayOpExpr),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_SCALARARRAYOPEXPR));
+    exprPoly->getExprPoly()->set_allocated_scalararrayopexpr(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderExprNode &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    return *this;
+  }
+
+  UnivPlanBuilderScalarArrayOpExpr &setUseOr(bool useOr) {
+    ref_->set_useor(useOr);
+    return *this;
+  }
+
+  UnivPlanBuilderScalarArrayOpExpr &setFuncId(int32_t funcId) {
+    ref_->set_funcid(funcId);
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanScalarArrayOpExpr> node_;
+  UnivPlanScalarArrayOpExpr *ref_;
+};
+
+class UnivPlanBuilderCoalesceExpr final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderCoalesceExpr> uptr;
+
+  UnivPlanBuilderCoalesceExpr()
+      : node_(new UnivPlanCoalesceExpr), ref_(node_.get()) {}
+
+  UnivPlanBuilderCoalesceExpr(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanCoalesceExpr),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_COALESCEEXPR));
+    exprPoly->getExprPoly()->set_allocated_coalesceexpr(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderCoalesceExpr &addArgs(
+      UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    return *this;
+  }
+
+  UnivPlanBuilderCoalesceExpr &setCoalesceType(int32_t coalesceType) {
+    ref_->set_coalescetype(coalesceType);
+    return *this;
+  }
+
+  UnivPlanBuilderCoalesceExpr &setCoalesceTypeMod(int32_t coalesceTypeMod) {
+    ref_->set_coalescetypemod(coalesceTypeMod);
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanCoalesceExpr> node_;
+  UnivPlanCoalesceExpr *ref_;
+};
+
+class UnivPlanBuilderNullIfExpr final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderNullIfExpr> uptr;
+
+  UnivPlanBuilderNullIfExpr()
+      : node_(new UnivPlanNullIfExpr), ref_(node_.get()) {}
+
+  UnivPlanBuilderNullIfExpr(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanNullIfExpr),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_NULLIFEXPR));
+    exprPoly->getExprPoly()->set_allocated_nullifexpr(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderNullIfExpr &addArgs(
+      UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    return *this;
+  }
+
+  UnivPlanBuilderNullIfExpr &setRetType(int32_t retType) {
+    ref_->set_rettype(retType);
+    return *this;
+  }
+
+  UnivPlanBuilderNullIfExpr &setTypeMod(int32_t typeMod) {
+    ref_->set_typemod(typeMod);
+    return *this;
+  }
+
+  UnivPlanBuilderNullIfExpr &setFuncId(int32_t funcId) {
+    ref_->set_funcid(funcId);
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanNullIfExpr> node_;
+  UnivPlanNullIfExpr *ref_;
+};
+
+class UnivPlanBuilderDistinctExpr final : public UnivPlanBuilderExprNode {
+ public:
+  typedef std::unique_ptr<UnivPlanBuilderDistinctExpr> uptr;
+
+  UnivPlanBuilderDistinctExpr()
+      : node_(new UnivPlanDistinctExpr), ref_(node_.get()) {}
+
+  UnivPlanBuilderDistinctExpr(int32_t pid, int32_t uid)
+      : UnivPlanBuilderExprNode(pid, uid),
+        node_(new UnivPlanDistinctExpr),
+        ref_(node_.get()) {}
+
+  UnivPlanBuilderExprPoly::uptr getExprPolyBuilder() override {
+    UnivPlanBuilderExprPoly::uptr exprPoly(
+        new UnivPlanBuilderExprPoly(UNIVPLAN_EXPR_DISTINCTEXPR));
+    exprPoly->getExprPoly()->set_allocated_distinctexpr(node_.release());
+    return exprPoly;
+  }
+
+  UnivPlanBuilderExprNode &addArgs(UnivPlanBuilderExprPoly::uptr arg) override {
+    ref_->mutable_args()->AddAllocated(arg->ownExprPoly().release());
+    return *this;
+  }
+
+  UnivPlanBuilderDistinctExpr &setRetType(int32_t retType) {
+    ref_->set_rettype(retType);
+    return *this;
+  }
+
+  UnivPlanBuilderDistinctExpr &setFuncId(int32_t funcId) {
+    ref_->set_funcid(funcId);
+    return *this;
+  }
+
+ private:
+  std::unique_ptr<UnivPlanDistinctExpr> node_;
+  UnivPlanDistinctExpr *ref_;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXPR_NODE_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-expr-poly.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-expr-poly.h
new file mode 100644
index 0000000..1cf9ee1
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-expr-poly.h
@@ -0,0 +1,42 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXPR_POLY_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXPR_POLY_H_
+
+#include "dbcommon/log/logger.h"
+
+#include "univplan/proto/universal-plan.pb.h"
+
+namespace univplan {
+
+class UnivPlanBuilderExprPoly {
+ public:
+  explicit UnivPlanBuilderExprPoly(UNIVPLANEXPRTYPE type) {
+    exprPoly.reset(new UnivPlanExprPoly());
+    ref = exprPoly.get();
+    ref->set_type(type);
+  }
+
+  virtual ~UnivPlanBuilderExprPoly() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderExprPoly> uptr;
+
+  UnivPlanExprPoly *getExprPoly() { return ref; }
+
+  std::unique_ptr<UnivPlanExprPoly> ownExprPoly() {
+    return std::move(exprPoly);
+  }
+
+ private:
+  UnivPlanExprPoly *ref;
+  std::unique_ptr<UnivPlanExprPoly> exprPoly;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXPR_POLY_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-expr-tree.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-expr-tree.h
new file mode 100644
index 0000000..78e2376
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-expr-tree.h
@@ -0,0 +1,93 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXPR_TREE_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXPR_TREE_H_
+
+#include <map>
+#include <memory>
+#include <utility>
+
+#include "univplan/common/univplan-type.h"
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-expr-node.h"
+
+namespace univplan {
+class UnivPlanBuilderExprTree {
+ public:
+  UnivPlanBuilderExprTree() {}
+  typedef std::unique_ptr<UnivPlanBuilderExprTree> uptr;
+
+  std::unique_ptr<UnivPlanExprPoly> ownExprPoly() { return std::move(root); }
+  void setRoot(UnivPlanBuilderExprPoly::uptr exprPoly) {
+    root = std::move(exprPoly->ownExprPoly());
+  }
+
+  int32_t getUid() { return nodeCounter++; }
+
+  // Create a new UnivPlanBuilderExprNode
+  // @param pid Parent ID for the new UnivPlanBuilderExprNode
+  template <typename UnivPlanBuilderExprNode>
+  std::unique_ptr<UnivPlanBuilderExprNode> ExprNodeFactory(int32_t pid) {
+    return std::unique_ptr<UnivPlanBuilderExprNode>(
+        new UnivPlanBuilderExprNode(pid, getUid()));
+  }
+
+  void addExprNode(UnivPlanBuilderExprNode::uptr bld) {
+    UnivPlanBuilderExprPoly::uptr pn = bld->getExprPolyBuilder();
+    int32_t uid = bld->uid;  // required field
+    int32_t pid = bld->pid;  // required field
+
+    // Check if this node has node id set already
+    if (uid < 0)
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "UnivPlanBuilderExprTree::addExprNode uid is negative");
+
+    // Check if the id is unique
+    if (idToExprNode.find(uid) != idToExprNode.end())
+      LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                "UnivPlanBuilderExprTree::addExprNode uid is duplicate");
+
+    // Use hash table to track this node quickly
+    idToExprNode[uid] = std::move(bld);
+
+    if (pid < 0) {
+      // If this node has no parent id, that means this node is a root, it is
+      // not allowed to have more than one root plan node.
+
+      // Set as a root plan node
+      setRoot(std::move(pn));
+
+    } else {
+      // If this node has a parent id, that means this node should be connected
+      // to its expected parent node.
+
+      // Find its parent node if its parent id is specified
+      if (idToExprNode.find(pid) == idToExprNode.end())
+        LOG_ERROR(ERRCODE_INTERNAL_ERROR,
+                  "UnivPlanBuilderExprTree::addExprNode unexpected parent id "
+                  "%d found",
+                  pid);
+
+      // add to parent node
+      idToExprNode[pid]->addArgs(std::move(pn));
+    }
+  }
+
+  UnivPlanBuilderExprNode* getExprNode(int32_t uid) {
+    return idToExprNode[uid].get();
+  }
+
+ private:
+  std::unique_ptr<UnivPlanExprPoly> root = nullptr;
+  std::map<int32_t, UnivPlanBuilderExprNode::uptr> idToExprNode;
+  int32_t nodeCounter = 0;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXPR_TREE_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-filter.cc b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-filter.cc
new file mode 100644
index 0000000..338752c
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-filter.cc
@@ -0,0 +1,43 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/univplanbuilder/univplanbuilder-ext-gs-filter.h"
+
+namespace univplan {
+
+UnivPlanBuilderExtGSFilter::UnivPlanBuilderExtGSFilter()
+    : UnivPlanBuilderNode() {
+  planNode.reset(new UnivPlanExtGSFilter());
+  ref = planNode.get();
+
+  ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+}
+
+UnivPlanBuilderExtGSFilter::~UnivPlanBuilderExtGSFilter() {}
+
+void UnivPlanBuilderExtGSFilter::setExpr(
+    UnivPlanBuilderExprPoly::uptr exprPoly) {
+  ref->set_allocated_filter(exprPoly->ownExprPoly().release());
+}
+
+std::unique_ptr<UnivPlanBuilderPlanNodePoly>
+UnivPlanBuilderExtGSFilter::ownPlanNode() {
+  UnivPlanBuilderPlanNodePoly::uptr pn(new UnivPlanBuilderPlanNodePoly(
+      UNIVPLAN_EXT_GS_FILTER, planNode->super()));
+  pn->getPlanNodePoly()->set_allocated_extgsfilter(planNode.release());
+  return std::move(pn);
+}
+
+void UnivPlanBuilderExtGSFilter::from(const UnivPlanPlanNodePoly &node) {
+  assert(node.type() == UNIVPLAN_EXT_GS_FILTER);
+  ref->CopyFrom(node.extgsfilter());
+  baseRef = ref->mutable_super();
+  baseRef->clear_leftplan();
+  baseRef->clear_rightplan();
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-filter.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-filter.h
new file mode 100644
index 0000000..e147485
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-filter.h
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXT_GS_FILTER_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXT_GS_FILTER_H_
+
+#include <memory>
+#include <vector>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderExtGSFilter : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderExtGSFilter();
+  virtual ~UnivPlanBuilderExtGSFilter();
+
+  typedef std::unique_ptr<UnivPlanBuilderExtGSFilter> uptr;
+
+  std::unique_ptr<UnivPlanBuilderPlanNodePoly> ownPlanNode() override;
+
+  void from(const UnivPlanPlanNodePoly &node) override;
+
+  void setExpr(UnivPlanBuilderExprPoly::uptr exprPoly);
+
+ private:
+  UnivPlanExtGSFilter *ref;
+  std::unique_ptr<UnivPlanExtGSFilter> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXT_GS_FILTER_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-proj.cc b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-proj.cc
new file mode 100644
index 0000000..2af0368
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-proj.cc
@@ -0,0 +1,45 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/univplanbuilder/univplanbuilder-ext-gs-proj.h"
+
+namespace univplan {
+
+UnivPlanBuilderExtGSProject::UnivPlanBuilderExtGSProject()
+    : UnivPlanBuilderNode() {
+  planNode.reset(new UnivPlanExtGSProj());
+  ref = planNode.get();
+
+  ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+}
+
+UnivPlanBuilderExtGSProject::~UnivPlanBuilderExtGSProject() {}
+
+void UnivPlanBuilderExtGSProject::setColumnIndexes(
+    const std::vector<int32_t> &colIndexes) {
+  for (int i = 0; i < colIndexes.size(); ++i) {
+    ref->add_columnindexes(colIndexes[i]);
+  }
+}
+
+std::unique_ptr<UnivPlanBuilderPlanNodePoly>
+UnivPlanBuilderExtGSProject::ownPlanNode() {
+  UnivPlanBuilderPlanNodePoly::uptr pn(
+      new UnivPlanBuilderPlanNodePoly(UNIVPLAN_EXT_GS_PROJ, planNode->super()));
+  pn->getPlanNodePoly()->set_allocated_extgsproject(planNode.release());
+  return std::move(pn);
+}
+
+void UnivPlanBuilderExtGSProject::from(const UnivPlanPlanNodePoly &node) {
+  assert(node.type() == UNIVPLAN_EXT_GS_PROJ);
+  ref->CopyFrom(node.extgsproject());
+  baseRef = ref->mutable_super();
+  baseRef->clear_leftplan();
+  baseRef->clear_rightplan();
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-proj.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-proj.h
new file mode 100644
index 0000000..4a55d5e
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-proj.h
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXT_GS_PROJ_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXT_GS_PROJ_H_
+
+#include <memory>
+#include <vector>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderExtGSProject : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderExtGSProject();
+  virtual ~UnivPlanBuilderExtGSProject();
+
+  typedef std::unique_ptr<UnivPlanBuilderExtGSProject> uptr;
+
+  std::unique_ptr<UnivPlanBuilderPlanNodePoly> ownPlanNode() override;
+
+  void from(const UnivPlanPlanNodePoly &node) override;
+
+  void setColumnIndexes(const std::vector<int32_t> &colIndexes);
+
+ private:
+  UnivPlanExtGSProj *ref;
+  std::unique_ptr<UnivPlanExtGSProj> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXT_GS_PROJ_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-scan.cc b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-scan.cc
new file mode 100644
index 0000000..f566bb8
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-scan.cc
@@ -0,0 +1,91 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/univplanbuilder/univplanbuilder-ext-gs-scan.h"
+
+#include <utility>
+#include <vector>
+
+namespace univplan {
+
+UnivPlanBuilderExtGSScan::UnivPlanBuilderExtGSScan() : UnivPlanBuilderNode() {
+  planNode.reset(new UnivPlanExtGSScan());
+  ref = planNode.get();
+
+  ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+}
+
+UnivPlanBuilderExtGSScan::~UnivPlanBuilderExtGSScan() {}
+
+std::unique_ptr<UnivPlanBuilderPlanNodePoly>
+UnivPlanBuilderExtGSScan::ownPlanNode() {
+  UnivPlanBuilderPlanNodePoly::uptr pn(
+      new UnivPlanBuilderPlanNodePoly(UNIVPLAN_EXT_GS_SCAN, planNode->super()));
+  pn->getPlanNodePoly()->set_allocated_extgsscan(planNode.release());
+  return std::move(pn);
+}
+
+void UnivPlanBuilderExtGSScan::from(const UnivPlanPlanNodePoly &node) {
+  assert(node.type() == UNIVPLAN_EXT_GS_SCAN);
+  ref->CopyFrom(node.extgsscan());
+  baseRef = ref->mutable_super();
+  baseRef->clear_leftplan();
+  baseRef->clear_rightplan();
+}
+
+void UnivPlanBuilderExtGSScan::setScanRelId(uint32_t id) { ref->set_relid(id); }
+
+void UnivPlanBuilderExtGSScan::setScanIndex(bool index = false) {
+  ref->set_indexscan(index);
+}
+
+void UnivPlanBuilderExtGSScan::setIndexScanType(ExternalScanType type) {
+  ref->set_type(univplan::ExternalScanType(type));
+}
+
+void UnivPlanBuilderExtGSScan::setDirectionType(
+    ExternalScanDirection direction) {
+  ref->set_direction(univplan::ExternalScanDirection(direction));
+}
+
+void UnivPlanBuilderExtGSScan::setIndexName(const char *indexName) {
+  ref->set_indexname(indexName);
+}
+
+void UnivPlanBuilderExtGSScan::addIndexQual(
+    UnivPlanBuilderExprTree::uptr exprTree) {
+  ref->mutable_indexqual()->AddAllocated(exprTree->ownExprPoly().release());
+}
+
+void UnivPlanBuilderExtGSScan::setColumnsToRead(
+    const std::vector<int32_t> &nArray) {
+  for (int i = 0; i < nArray.size(); ++i) {
+    ref->add_columnstoread(nArray[i]);
+  }
+}
+
+void UnivPlanBuilderExtGSScan::setKeyColumnIndexes(
+    const std::vector<int32_t> &nArray) {
+  for (int i = 0; i < nArray.size(); ++i) {
+    ref->add_keycolindex(nArray[i]);
+  }
+}
+
+void UnivPlanBuilderExtGSScan::setFilterExpr(
+    UnivPlanBuilderExprTree::uptr expr) {
+  ref->set_allocated_filter(expr->ownExprPoly().release());
+}
+
+std::unique_ptr<UnivPlanBuilderScanTask>
+UnivPlanBuilderExtGSScan::addScanTaskAndGetBuilder() {
+  UnivPlanScanTask *task = ref->add_tasks();
+  std::unique_ptr<UnivPlanBuilderScanTask> res(
+      new UnivPlanBuilderScanTask(task));
+  return std::move(res);
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-scan.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-scan.h
new file mode 100644
index 0000000..3afea9c
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-ext-gs-scan.h
@@ -0,0 +1,50 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXT_GS_SCAN_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXT_GS_SCAN_H_
+
+#include <memory>
+#include <vector>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+#include "univplan/univplanbuilder/univplanbuilder-scan-task.h"
+
+namespace univplan {
+
+class UnivPlanBuilderExtGSScan : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderExtGSScan();
+  virtual ~UnivPlanBuilderExtGSScan();
+
+  typedef std::unique_ptr<UnivPlanBuilderExtGSScan> uptr;
+
+  std::unique_ptr<UnivPlanBuilderPlanNodePoly> ownPlanNode() override;
+
+  void from(const UnivPlanPlanNodePoly &node) override;
+
+  void setScanRelId(uint32_t id);
+  void setColumnsToRead(const std::vector<int32_t> &nArray);
+  void setKeyColumnIndexes(const std::vector<int32_t> &nArray);
+  void setFilterExpr(UnivPlanBuilderExprTree::uptr expr);
+  std::unique_ptr<UnivPlanBuilderScanTask> addScanTaskAndGetBuilder();
+  // set magma index info
+  void setScanIndex(bool index);
+  void setIndexScanType(ExternalScanType type);
+  void setDirectionType(ExternalScanDirection direction);
+  void setIndexName(const char *indexName);
+  void addIndexQual(UnivPlanBuilderExprTree::uptr exprTree);
+
+ private:
+  UnivPlanExtGSScan *ref;
+  std::unique_ptr<UnivPlanExtGSScan> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_EXT_GS_SCAN_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-hash.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-hash.h
new file mode 100644
index 0000000..3ee61d6
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-hash.h
@@ -0,0 +1,52 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_HASH_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_HASH_H_
+
+#include <memory>
+#include <utility>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderHash : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderHash() : UnivPlanBuilderNode() {
+    planNode.reset(new UnivPlanHash());
+    ref = planNode.get();
+    ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+  }
+  virtual ~UnivPlanBuilderHash() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderHash> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override {
+    UnivPlanBuilderPlanNodePoly::uptr pn(
+        new UnivPlanBuilderPlanNodePoly(UNIVPLAN_HASH, planNode->super()));
+    pn->getPlanNodePoly()->set_allocated_hash(planNode.release());
+    return std::move(pn);
+  }
+
+  void from(const UnivPlanPlanNodePoly &node) override {
+    assert(node.type() == UNIVPLAN_HASH);
+    ref->CopyFrom(node.hash());
+    baseRef = ref->mutable_super();
+    baseRef->clear_leftplan();
+    baseRef->clear_rightplan();
+  }
+
+ private:
+  UnivPlanHash *ref;
+  std::unique_ptr<UnivPlanHash> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_HASH_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-hashjoin.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-hashjoin.h
new file mode 100644
index 0000000..9137d15
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-hashjoin.h
@@ -0,0 +1,67 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_HASHJOIN_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_HASHJOIN_H_
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderHashJoin : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderHashJoin() : UnivPlanBuilderNode() {
+    planNode.reset(new UnivPlanHashJoin());
+    ref = planNode.get();
+    ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+  }
+  virtual ~UnivPlanBuilderHashJoin() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderHashJoin> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override {
+    UnivPlanBuilderPlanNodePoly::uptr pn(
+        new UnivPlanBuilderPlanNodePoly(UNIVPLAN_HASHJOIN, planNode->super()));
+    pn->getPlanNodePoly()->set_allocated_hashjoin(planNode.release());
+    return std::move(pn);
+  }
+
+  void from(const UnivPlanPlanNodePoly &node) override {
+    assert(node.type() == UNIVPLAN_HASHJOIN);
+    ref->CopyFrom(node.hashjoin());
+    baseRef = ref->mutable_super();
+    baseRef->clear_leftplan();
+    baseRef->clear_rightplan();
+  }
+
+  void addJoinQual(UnivPlanBuilderExprTree::uptr exprTree) {
+    assert(ref != nullptr);
+    ref->mutable_joinqual()->AddAllocated(exprTree->ownExprPoly().release());
+  }
+
+  void addHashClause(UnivPlanBuilderExprTree::uptr exprTree) {
+    assert(ref != nullptr);
+    ref->mutable_hashclauses()->AddAllocated(exprTree->ownExprPoly().release());
+  }
+
+  void addHashQualClause(UnivPlanBuilderExprTree::uptr exprTree) {
+    assert(ref != nullptr);
+    ref->mutable_hashqualclauses()->AddAllocated(
+        exprTree->ownExprPoly().release());
+  }
+
+  void setJoinType(UNIVPLANJOINTYPE type) { ref->set_type(type); }
+
+ private:
+  UnivPlanHashJoin *ref;
+  std::unique_ptr<UnivPlanHashJoin> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_HASHJOIN_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-insert.cc b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-insert.cc
new file mode 100644
index 0000000..6ca7771
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-insert.cc
@@ -0,0 +1,38 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/univplanbuilder/univplanbuilder-insert.h"
+
+namespace univplan {
+
+UnivPlanBuilderInsert::UnivPlanBuilderInsert() : UnivPlanBuilderNode() {
+  planNode.reset(new UnivPlanInsert());
+  ref = planNode.get();
+
+  ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+}
+
+UnivPlanBuilderInsert::~UnivPlanBuilderInsert() {}
+
+UnivPlanBuilderPlanNodePoly::uptr UnivPlanBuilderInsert::ownPlanNode() {
+  UnivPlanBuilderPlanNodePoly::uptr pn(
+      new UnivPlanBuilderPlanNodePoly(UNIVPLAN_INSERT, planNode->super()));
+  pn->getPlanNodePoly()->set_allocated_insert(planNode.release());
+  return std::move(pn);
+}
+
+void UnivPlanBuilderInsert::from(const UnivPlanPlanNodePoly &node) {
+  assert(node.type() == UNIVPLAN_INSERT);
+  ref->CopyFrom(node.insert());
+  baseRef = ref->mutable_super();
+  baseRef->clear_leftplan();
+  baseRef->clear_rightplan();
+}
+
+void UnivPlanBuilderInsert::setInsertRelId(uint32_t id) { ref->set_relid(id); }
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-insert.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-insert.h
new file mode 100644
index 0000000..576ceb4
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-insert.h
@@ -0,0 +1,36 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_INSERT_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_INSERT_H_
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderInsert : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderInsert();
+  virtual ~UnivPlanBuilderInsert();
+
+  typedef std::unique_ptr<UnivPlanBuilderInsert> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override;
+
+  void from(const UnivPlanPlanNodePoly &node) override;
+
+  void setInsertRelId(uint32_t id);
+
+ private:
+  UnivPlanInsert *ref;
+  std::unique_ptr<UnivPlanInsert> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_INSERT_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-limit.cc b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-limit.cc
new file mode 100644
index 0000000..0ccf800
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-limit.cc
@@ -0,0 +1,45 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2017, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/univplanbuilder/univplanbuilder-limit.h"
+
+namespace univplan {
+
+UnivPlanBuilderLimit::UnivPlanBuilderLimit() : UnivPlanBuilderNode() {
+  planNode.reset(new UnivPlanLimit());
+  ref = planNode.get();
+
+  ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+}
+
+UnivPlanBuilderLimit::~UnivPlanBuilderLimit() {}
+
+UnivPlanBuilderPlanNodePoly::uptr UnivPlanBuilderLimit::ownPlanNode() {
+  UnivPlanBuilderPlanNodePoly::uptr pn(
+      new UnivPlanBuilderPlanNodePoly(UNIVPLAN_LIMIT, planNode->super()));
+  pn->getPlanNodePoly()->set_allocated_limit(planNode.release());
+  return std::move(pn);
+}
+
+void UnivPlanBuilderLimit::from(const UnivPlanPlanNodePoly &node) {
+  assert(node.type() == UNIVPLAN_LIMIT);
+  ref->CopyFrom(node.limit());
+  baseRef = ref->mutable_super();
+  baseRef->clear_leftplan();
+  baseRef->clear_rightplan();
+}
+
+void UnivPlanBuilderLimit::setLimitOffset(
+    UnivPlanBuilderExprTree::uptr offset) {
+  ref->set_allocated_limitoffset(offset->ownExprPoly().release());
+}
+
+void UnivPlanBuilderLimit::setLimitCount(UnivPlanBuilderExprTree::uptr count) {
+  ref->set_allocated_limitcount(count->ownExprPoly().release());
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-limit.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-limit.h
new file mode 100644
index 0000000..40cbd9a
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-limit.h
@@ -0,0 +1,40 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2017, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_LIMIT_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_LIMIT_H_
+
+#include <vector>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderLimit : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderLimit();
+  virtual ~UnivPlanBuilderLimit();
+
+  typedef std::unique_ptr<UnivPlanBuilderLimit> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override;
+
+  void from(const UnivPlanPlanNodePoly &node) override;
+
+  void setLimitOffset(UnivPlanBuilderExprTree::uptr limitOffset);
+
+  void setLimitCount(UnivPlanBuilderExprTree::uptr limitCount);
+
+ private:
+  UnivPlanLimit *ref;
+  std::unique_ptr<UnivPlanLimit> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_LIMIT_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-listener.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-listener.h
new file mode 100644
index 0000000..f7baf20
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-listener.h
@@ -0,0 +1,36 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_LISTENER_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_LISTENER_H_
+
+#include <string>
+
+#include "univplan/proto/universal-plan.pb.h"
+
+namespace univplan {
+
+class UnivPlanBuilderListener {
+ public:
+  explicit UnivPlanBuilderListener(UnivPlanListener *listener)
+      : ref(listener) {}
+
+  virtual ~UnivPlanBuilderListener() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderListener> uptr;
+
+  void setAddress(const std::string &addr) { ref->set_address(addr); }
+
+  void setPort(int32_t port) { ref->set_port(port); }
+
+ private:
+  UnivPlanListener *ref;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_LISTENER_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-material.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-material.h
new file mode 100644
index 0000000..039ebf3
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-material.h
@@ -0,0 +1,82 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_MATERIAL_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_MATERIAL_H_
+
+#include <memory>
+#include <utility>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderMaterial : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderMaterial() : UnivPlanBuilderNode() {
+    planNode.reset(new UnivPlanMaterial());
+    ref = planNode.get();
+    ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+  }
+  virtual ~UnivPlanBuilderMaterial() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderMaterial> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override {
+    UnivPlanBuilderPlanNodePoly::uptr pn(
+        new UnivPlanBuilderPlanNodePoly(UNIVPLAN_MATERIAL, planNode->super()));
+    pn->getPlanNodePoly()->set_allocated_material(planNode.release());
+    return std::move(pn);
+  }
+
+  void from(const UnivPlanPlanNodePoly& node) override {
+    assert(node.type() == UNIVPLAN_MATERIAL);
+    ref->CopyFrom(node.material());
+    baseRef = ref->mutable_super();
+    baseRef->clear_leftplan();
+    baseRef->clear_rightplan();
+  }
+
+  UnivPlanBuilderMaterial& setShareType(UNIVPLANSHARETYPE type) {
+    ref->set_share_type(type);
+    return *this;
+  }
+
+  UnivPlanBuilderMaterial& setCdbStrict(bool cdbStrict) {
+    ref->set_cdbstrict(cdbStrict);
+    return *this;
+  }
+
+  UnivPlanBuilderMaterial& setShareId(int32_t shareId) {
+    ref->set_shared_id(shareId);
+    return *this;
+  }
+
+  UnivPlanBuilderMaterial& setDriverSlice(int32_t driverSlice) {
+    ref->set_driver_slice(driverSlice);
+    return *this;
+  }
+
+  UnivPlanBuilderMaterial& setNSharer(int32_t nsharer) {
+    ref->set_nsharer(nsharer);
+    return *this;
+  }
+
+  UnivPlanBuilderMaterial& setNSharerXSlice(int32_t xslice) {
+    ref->set_nsharer_xslice(xslice);
+    return *this;
+  }
+
+ private:
+  UnivPlanMaterial* ref;
+  std::unique_ptr<UnivPlanMaterial> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_MATERIAL_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-mergejoin.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-mergejoin.h
new file mode 100644
index 0000000..33774d7
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-mergejoin.h
@@ -0,0 +1,62 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_MERGEJOIN_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_MERGEJOIN_H_
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderMergeJoin : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderMergeJoin() : UnivPlanBuilderNode() {
+    planNode.reset(new UnivPlanMergeJoin());
+    ref = planNode.get();
+    ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+  }
+  virtual ~UnivPlanBuilderMergeJoin() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderMergeJoin> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override {
+    UnivPlanBuilderPlanNodePoly::uptr pn(
+        new UnivPlanBuilderPlanNodePoly(UNIVPLAN_MERGEJOIN, planNode->super()));
+    pn->getPlanNodePoly()->set_allocated_mergejoin(planNode.release());
+    return std::move(pn);
+  }
+
+  void from(const UnivPlanPlanNodePoly &node) override {
+    assert(node.type() == UNIVPLAN_MERGEJOIN);
+    ref->CopyFrom(node.mergejoin());
+    baseRef = ref->mutable_super();
+    baseRef->clear_leftplan();
+    baseRef->clear_rightplan();
+  }
+
+  void addJoinQual(UnivPlanBuilderExprTree::uptr exprTree) {
+    assert(ref != nullptr);
+    ref->mutable_joinqual()->AddAllocated(exprTree->ownExprPoly().release());
+  }
+
+  void addMergeClause(UnivPlanBuilderExprTree::uptr exprTree) {
+    assert(ref != nullptr);
+    ref->mutable_mergeclauses()->AddAllocated(
+        exprTree->ownExprPoly().release());
+  }
+
+  void setJoinType(UNIVPLANJOINTYPE type) { ref->set_type(type); }
+
+ private:
+  UnivPlanMergeJoin *ref;
+  std::unique_ptr<UnivPlanMergeJoin> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_MERGEJOIN_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-nestloop.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-nestloop.h
new file mode 100644
index 0000000..7e7a3cb
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-nestloop.h
@@ -0,0 +1,56 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_NESTLOOP_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_NESTLOOP_H_
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderNestLoop : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderNestLoop() : UnivPlanBuilderNode() {
+    planNode.reset(new UnivPlanNestLoop());
+    ref = planNode.get();
+    ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+  }
+  virtual ~UnivPlanBuilderNestLoop() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderNestLoop> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override {
+    UnivPlanBuilderPlanNodePoly::uptr pn(
+        new UnivPlanBuilderPlanNodePoly(UNIVPLAN_NESTLOOP, planNode->super()));
+    pn->getPlanNodePoly()->set_allocated_nestloop(planNode.release());
+    return std::move(pn);
+  }
+
+  void from(const UnivPlanPlanNodePoly &node) override {
+    assert(node.type() == UNIVPLAN_NESTLOOP);
+    ref->CopyFrom(node.nestloop());
+    baseRef = ref->mutable_super();
+    baseRef->clear_leftplan();
+    baseRef->clear_rightplan();
+  }
+
+  void addJoinQual(UnivPlanBuilderExprTree::uptr exprTree) {
+    assert(ref != nullptr);
+    ref->mutable_joinqual()->AddAllocated(exprTree->ownExprPoly().release());
+  }
+
+  void setJoinType(UNIVPLANJOINTYPE type) { ref->set_type(type); }
+
+ private:
+  UnivPlanNestLoop *ref;
+  std::unique_ptr<UnivPlanNestLoop> planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_NESTLOOP_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-node.cc b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-node.cc
new file mode 100644
index 0000000..13fdd40
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-node.cc
@@ -0,0 +1,61 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+#include <utility>
+
+namespace univplan {
+
+void UnivPlanBuilderNode::setNodeLeftPlan(
+    UnivPlanBuilderPlanNodePoly::uptr pn) {
+  assert(baseRef != nullptr);
+  baseRef->set_allocated_leftplan(pn->ownPlanNodePoly().release());
+}
+
+void UnivPlanBuilderNode::setNodeRightPlan(
+    UnivPlanBuilderPlanNodePoly::uptr pn) {
+  assert(baseRef != nullptr);
+  baseRef->set_allocated_rightplan(pn->ownPlanNodePoly().release());
+}
+
+void UnivPlanBuilderNode::setNodePlanRows(double planRows) {
+  assert(baseRef != nullptr);
+  baseRef->set_planrows(planRows);
+}
+
+void UnivPlanBuilderNode::setNodePlanRowWidth(int32_t planRowWidth) {
+  assert(baseRef != nullptr);
+  baseRef->set_planrowwidth(planRowWidth);
+}
+
+void UnivPlanBuilderNode::setNodePlanOperatorMemKB(uint64_t operatorMemKB) {
+  baseRef->set_operatormemkb(operatorMemKB);
+}
+
+UnivPlanBuilderTargetEntry::uptr
+UnivPlanBuilderNode::addTargetEntryAndGetBuilder() {
+  assert(baseRef != nullptr);
+  UnivPlanExprPoly *exprTree = baseRef->add_targetlist();
+  exprTree->set_type(UNIVPLAN_EXPR_TARGETENTRY);
+  UnivPlanTargetEntry *targetEntry = exprTree->mutable_targetentry();
+  UnivPlanBuilderTargetEntry::uptr bld(
+      new UnivPlanBuilderTargetEntry(targetEntry));
+  return std::move(bld);
+}
+
+void UnivPlanBuilderNode::addQualList(UnivPlanBuilderExprTree::uptr exprTree) {
+  assert(baseRef != nullptr);
+  baseRef->mutable_quallist()->AddAllocated(exprTree->ownExprPoly().release());
+}
+
+void UnivPlanBuilderNode::addInitplan(UnivPlanBuilderExprTree::uptr exprTree) {
+  assert(baseRef != nullptr);
+  baseRef->mutable_initplan()->AddAllocated(exprTree->ownExprPoly().release());
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-node.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-node.h
new file mode 100644
index 0000000..422f425
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-node.h
@@ -0,0 +1,59 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_NODE_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_NODE_H_
+
+#include <memory>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-expr-tree.h"
+#include "univplan/univplanbuilder/univplanbuilder-plan-node-poly.h"
+#include "univplan/univplanbuilder/univplanbuilder-target-entry.h"
+
+namespace univplan {
+
+class UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderNode() {
+    basePlanNode.reset(new UnivPlanPlanNode());
+    baseRef = basePlanNode.get();
+  }
+  virtual ~UnivPlanBuilderNode() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderNode> uptr;
+
+  void setNodeLeftPlan(UnivPlanBuilderPlanNodePoly::uptr pn);
+  void setNodeRightPlan(UnivPlanBuilderPlanNodePoly::uptr pn);
+
+  void setNodePlanRows(double planRows);
+
+  void setNodePlanRowWidth(int32_t planRowWidth);
+
+  void setNodePlanOperatorMemKB(uint64_t operatorMemKB);
+
+  virtual std::unique_ptr<UnivPlanBuilderPlanNodePoly> ownPlanNode() = 0;
+
+  // copy from the plannode content without left and right child
+  virtual void from(const UnivPlanPlanNodePoly &node) = 0;
+
+  UnivPlanBuilderTargetEntry::uptr addTargetEntryAndGetBuilder();
+  void addQualList(UnivPlanBuilderExprTree::uptr exprTree);
+  void addInitplan(UnivPlanBuilderExprTree::uptr exprTree);
+
+ public:
+  int32_t uid = -1;
+  int32_t pid = -1;
+
+ protected:
+  std::unique_ptr<UnivPlanPlanNode> basePlanNode;
+  UnivPlanPlanNode *baseRef = nullptr;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_NODE_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-paraminfo.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-paraminfo.h
new file mode 100644
index 0000000..69f2779
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-paraminfo.h
@@ -0,0 +1,47 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_PARAMINFO_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_PARAMINFO_H_
+
+#include <string>
+
+#include "univplan/proto/universal-plan.pb.h"
+
+namespace univplan {
+
+class UnivPlanBuilderParamInfo {
+ public:
+  explicit UnivPlanBuilderParamInfo(UnivPlanParamInfo *paramInfo)
+      : ref_(paramInfo) {}
+
+  virtual ~UnivPlanBuilderParamInfo() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderParamInfo> uptr;
+
+  UnivPlanBuilderParamInfo &setType(int32_t type) {
+    ref_->set_type(type);
+    return *this;
+  }
+
+  UnivPlanBuilderParamInfo &setIsNull(bool isNull) {
+    ref_->set_isnull(isNull);
+    return *this;
+  }
+
+  UnivPlanBuilderParamInfo &setValue(const std::string &value) {
+    ref_->set_value(value);
+    return *this;
+  }
+
+ private:
+  UnivPlanParamInfo *ref_;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_PARAMINFO_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-plan-node-poly.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-plan-node-poly.h
new file mode 100644
index 0000000..319a9e3
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-plan-node-poly.h
@@ -0,0 +1,48 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_PLAN_NODE_POLY_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_PLAN_NODE_POLY_H_
+
+#include <memory>
+#include <utility>
+
+#include "univplan/proto/universal-plan.pb.h"
+
+namespace univplan {
+
+class UnivPlanBuilderPlanNodePoly {
+ public:
+  UnivPlanBuilderPlanNodePoly(UNIVPLANNODETYPE type,
+                              const UnivPlanPlanNode &planNode)
+      : planNode(planNode) {
+    pn.reset(new UnivPlanPlanNodePoly());
+    ref = pn.get();
+    ref->set_type(type);
+  }
+
+  virtual ~UnivPlanBuilderPlanNodePoly() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderPlanNodePoly> uptr;
+
+  UnivPlanPlanNodePoly *getPlanNodePoly() { return ref; }
+
+  std::unique_ptr<UnivPlanPlanNodePoly> ownPlanNodePoly() {
+    return std::move(pn);
+  }
+
+  const UnivPlanPlanNode &getPlanNode() { return planNode; }
+
+ private:
+  UnivPlanPlanNodePoly *ref;
+  std::unique_ptr<UnivPlanPlanNodePoly> pn;
+  const UnivPlanPlanNode &planNode;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_PLAN_NODE_POLY_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-plan.cc b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-plan.cc
new file mode 100644
index 0000000..7f82c4b
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-plan.cc
@@ -0,0 +1,141 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#include "univplan/univplanbuilder/univplanbuilder-plan.h"
+
+#include <utility>
+
+#include "dbcommon/log/logger.h"
+#include "univplan/univplanbuilder/univplanbuilder-plan-node-poly.h"
+
+namespace univplan {
+
+void UnivPlanBuilderPlan::setPlanNode(UnivPlanBuilderPlanNodePoly::uptr pn) {
+  ref->set_allocated_plan(pn->ownPlanNodePoly().release());
+}
+
+void UnivPlanBuilderPlan::setSubplanNode(UnivPlanBuilderPlanNodePoly::uptr pn) {
+  ref->mutable_subplans()->AddAllocated(pn->ownPlanNodePoly().release());
+}
+
+void UnivPlanBuilderPlan::setStageNo(int32_t stageNo) {
+  ref->set_stageno(stageNo);
+}
+
+void UnivPlanBuilderPlan::setTokenEntry(std::string protocol, std::string host,
+                                        int port, std::string token) {
+  UnivPlanTokenEntry *tokenEntry = ref->add_tokenmap();
+  tokenEntry->set_token(token);
+  auto key = tokenEntry->mutable_key();
+  key->set_protocol(protocol);
+  key->set_ip(host);
+  key->set_port(port);
+}
+
+void UnivPlanBuilderPlan::setSnapshot(const std::string &snapshot) {
+  ref->set_snapshot(snapshot);
+}
+
+void UnivPlanBuilderPlan::addGuc(const std::string &name,
+                                 const std::string &value) {
+  (*ref->mutable_guc())[name] = value;
+}
+
+void UnivPlanBuilderPlan::addCommonValue(const std::string &key,
+                                         const std::string &value,
+                                         std::string *newKey) {
+  // if key exists, add suffix to avoid overwriting exisiting values, newKey
+  // saves newly assigned key, if newKey is nullptr, original key is used
+  std::string tmpKey = key;
+  bool dup = false;
+  if (newKey != nullptr) {
+    uint64_t counter = 0;
+    while (true) {
+      *newKey = key + std::to_string(counter);
+      if (ref->commonvalue().find(*newKey) == ref->commonvalue().end()) {
+        tmpKey = *newKey;
+        break;  // found new key
+      } else if (ref->commonvalue().at(*newKey) == value) {
+        tmpKey = *newKey;
+        dup = true;
+        break;  // found duplicate value, no need to allocate new key
+      }
+      counter++;
+    }
+  }
+  if (!dup) {
+    (*ref->mutable_commonvalue())[tmpKey] = value;
+    LOG_DEBUG("set key %s into common values of plan size %lu", tmpKey.c_str(),
+              value.size());
+  } else {
+    LOG_DEBUG("found duplicate key %s", tmpKey.c_str());
+  }
+}
+
+void UnivPlanBuilderPlan::setDoInstrument(bool doInstrument) {
+  ref->set_doinstrument(doInstrument);
+}
+
+void UnivPlanBuilderPlan::setNCrossLevelParams(int32_t nCrossLevelParams) {
+  ref->set_ncrosslevelparams(nCrossLevelParams);
+}
+
+void UnivPlanBuilderPlan::setCmdType(UNIVPLANCMDTYPE cmdType) {
+  ref->set_cmdtype(cmdType);
+}
+
+// xxx only called from stagize, need sync with univplanplan's fields
+void UnivPlanBuilderPlan::from(const UnivPlanPlan &from) {
+  // plan not set
+  ref->set_stageno(from.stageno());
+  if (from.snapshot().empty() == false) ref->set_snapshot(from.snapshot());
+  ref->set_doinstrument(from.doinstrument());
+  ref->set_ncrosslevelparams(from.ncrosslevelparams());
+  ref->set_cmdtype(from.cmdtype());
+  for (int i = 0; i < from.rangetables_size(); i++)
+    ref->add_rangetables()->CopyFrom(from.rangetables(i));
+  for (int i = 0; i < from.tokenmap_size(); i++)
+    ref->add_tokenmap()->CopyFrom(from.tokenmap(i));
+  for (int i = 0; i < from.receivers_size(); i++)
+    ref->add_receivers()->CopyFrom(from.receivers(i));
+  for (int i = 0; i < from.paraminfos_size(); ++i)
+    ref->add_paraminfos()->CopyFrom(from.paraminfos(i));
+  for (auto ent : from.guc()) (*ref->mutable_guc())[ent.first] = ent.second;
+  for (auto ent : from.commonvalue())
+    (*ref->mutable_commonvalue())[ent.first] = ent.second;
+
+  // childStage not set
+}
+
+UnivPlanBuilderRangeTblEntry::uptr
+UnivPlanBuilderPlan::addRangeTblEntryAndGetBuilder() {
+  UnivPlanRangeTblEntry *entry = ref->add_rangetables();
+  UnivPlanBuilderRangeTblEntry::uptr bld(
+      new UnivPlanBuilderRangeTblEntry(entry));
+  return std::move(bld);
+}
+
+UnivPlanBuilderReceiver::uptr UnivPlanBuilderPlan::addReceiverAndGetBuilder() {
+  UnivPlanReceiver *receiver = ref->add_receivers();
+  UnivPlanBuilderReceiver::uptr bld(new UnivPlanBuilderReceiver(receiver));
+  return std::move(bld);
+}
+
+UnivPlanBuilderParamInfo::uptr
+UnivPlanBuilderPlan::addParamInfoAndGetBuilder() {
+  UnivPlanParamInfo *paramInfo = ref->add_paraminfos();
+  UnivPlanBuilderParamInfo::uptr bld(new UnivPlanBuilderParamInfo(paramInfo));
+  return std::move(bld);
+}
+
+UnivPlanBuilderPlan::uptr UnivPlanBuilderPlan::addChildStageAndGetBuilder() {
+  UnivPlanPlan *child = ref->add_childstages();
+  UnivPlanBuilderPlan::uptr bld(new UnivPlanBuilderPlan(child));
+  return std::move(bld);
+}
+
+}  // namespace univplan
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-plan.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-plan.h
new file mode 100644
index 0000000..d21bfe3
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-plan.h
@@ -0,0 +1,74 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_PLAN_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_PLAN_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+#include "univplan/univplanbuilder/univplanbuilder-paraminfo.h"
+#include "univplan/univplanbuilder/univplanbuilder-range-tbl-entry.h"
+#include "univplan/univplanbuilder/univplanbuilder-receiver.h"
+
+namespace univplan {
+
+class UnivPlanBuilderPlan {
+ public:
+  UnivPlanBuilderPlan() {
+    plan.reset(new UnivPlanPlan());
+    ref = plan.get();
+  }
+
+  explicit UnivPlanBuilderPlan(UnivPlanPlan *plan) : ref(plan) {}
+
+  virtual ~UnivPlanBuilderPlan() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderPlan> uptr;
+
+  UnivPlanPlan *getPlan() { return ref; }
+  UnivPlanPlan *ownPlan() { return plan.release(); }
+
+  // set root node of the plan
+  void setPlanNode(UnivPlanBuilderPlanNodePoly::uptr pn);
+  void setSubplanNode(UnivPlanBuilderPlanNodePoly::uptr pn);
+  bool isSettingSubplan() { return ref->has_plan(); }
+
+  void setStageNo(int32_t stageNo);
+  void setDoInstrument(bool doInstrument);
+  void setNCrossLevelParams(int32_t nCrossLevelParams);
+  void setCmdType(UNIVPLANCMDTYPE cmdType);
+
+  void from(const UnivPlanPlan &from);
+  void setTokenEntry(std::string protocol, std::string host, int port,
+                     std::string token);
+  void setSnapshot(const std::string &snapshot);
+
+  void addGuc(const std::string &name, const std::string &value);
+
+  void addCommonValue(const std::string &key, const std::string &value,
+                      std::string *newKey);
+
+  UnivPlanBuilderRangeTblEntry::uptr addRangeTblEntryAndGetBuilder();
+
+  UnivPlanBuilderReceiver::uptr addReceiverAndGetBuilder();
+
+  UnivPlanBuilderParamInfo::uptr addParamInfoAndGetBuilder();
+
+  UnivPlanBuilderPlan::uptr addChildStageAndGetBuilder();
+
+ private:
+  UnivPlanPlan *ref;
+  std::unique_ptr<UnivPlanPlan> plan;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_PLAN_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-range-tbl-entry.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-range-tbl-entry.h
new file mode 100644
index 0000000..183b813
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-range-tbl-entry.h
@@ -0,0 +1,40 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_RANGE_TBL_ENTRY_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_RANGE_TBL_ENTRY_H_
+
+#include "univplan/proto/universal-plan.pb.h"
+
+namespace univplan {
+
+class UnivPlanBuilderRangeTblEntry {
+ public:
+  UnivPlanBuilderRangeTblEntry() {
+    node.reset(new UnivPlanRangeTblEntry());
+    ref = node.get();
+  }
+
+  explicit UnivPlanBuilderRangeTblEntry(UnivPlanRangeTblEntry *rangeTblEntry)
+      : ref(rangeTblEntry) {}
+
+  virtual ~UnivPlanBuilderRangeTblEntry() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderRangeTblEntry> uptr;
+
+  void setTable(std::unique_ptr<UnivPlanTable> table) {
+    ref->set_allocated_table(table.release());
+  }
+
+ private:
+  UnivPlanRangeTblEntry *ref;
+  std::unique_ptr<UnivPlanRangeTblEntry> node;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_RANGE_TBL_ENTRY_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-receiver.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-receiver.h
new file mode 100644
index 0000000..0bc3f6b
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-receiver.h
@@ -0,0 +1,39 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2016, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_RECEIVER_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_RECEIVER_H_
+
+#include <string>
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-listener.h"
+
+namespace univplan {
+
+class UnivPlanBuilderReceiver {
+ public:
+  explicit UnivPlanBuilderReceiver(UnivPlanReceiver *receiver)
+      : ref(receiver) {}
+
+  virtual ~UnivPlanBuilderReceiver() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderReceiver> uptr;
+
+  UnivPlanBuilderListener::uptr addPlanListenerAndGetBuilder() {
+    UnivPlanListener *listener = ref->add_listener();
+    UnivPlanBuilderListener::uptr bld(new UnivPlanBuilderListener(listener));
+    return std::move(bld);
+  }
+
+ private:
+  UnivPlanReceiver *ref;
+};
+
+}  // namespace univplan
+
+#endif  // UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_RECEIVER_H_
diff --git a/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-result.h b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-result.h
new file mode 100644
index 0000000..bfff8fb
--- /dev/null
+++ b/depends/univplan/src/univplan/univplanbuilder/univplanbuilder-result.h
@@ -0,0 +1,55 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright 2018, Oushu Inc.
+// All rights reserved.
+//
+// Author:
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_RESULT_H_
+#define UNIVPLAN_SRC_UNIVPLAN_UNIVPLANBUILDER_UNIVPLANBUILDER_RESULT_H_
+
+#include "univplan/proto/universal-plan.pb.h"
+#include "univplan/univplanbuilder/univplanbuilder-node.h"
+
+namespace univplan {
+
+class UnivPlanBuilderResult : public UnivPlanBuilderNode {
+ public:
+  UnivPlanBuilderResult() : UnivPlanBuilderNode() {
+    planNode.reset(new UnivPlanResult());
+    ref = planNode.get();
+    ref->set_allocated_super(UnivPlanBuilderNode::basePlanNode.release());
+  }
+  virtual ~UnivPlanBuilderResult() {}
+
+  typedef std::unique_ptr<UnivPlanBuilderResult> uptr;
+
+  UnivPlanBuilderPlanNodePoly::uptr ownPlanNode() override {
+    UnivPlanBuilderPlanNodePoly::uptr pn(
+        new UnivPlanBuilderPlanNodePoly(UNIVPLAN_RESULT, planNode->super()));
+    pn->getPlanNodePoly()->set_allocated_result(planNode.release());
+    return std::move(pn);
+  }
+
+  void from(const UnivPlanPlanNodePoly &node) override {
+    assert(node.type() == UNIVPLAN_RESULT);
... 5347 lines suppressed ...