HAWQ-1775. Add Vector/TupleBatch/ExprContext empty()
diff --git a/depends/dbcommon/src/dbcommon/common/tuple-batch.cc b/depends/dbcommon/src/dbcommon/common/tuple-batch.cc
index b4c92d0..455b0a9 100644
--- a/depends/dbcommon/src/dbcommon/common/tuple-batch.cc
+++ b/depends/dbcommon/src/dbcommon/common/tuple-batch.cc
@@ -562,7 +562,7 @@
   int colNum = getNumOfColumns();
   int sysColNum = getNumOfSysColumns();
 
-  if (getNumOfRows() == 0)
+  if (this->empty())
     LOG_ERROR(ERRCODE_INTERNAL_ERROR,
               "Should not serialize an empty tuple batch");
 
@@ -620,7 +620,7 @@
     std::unique_ptr<NodeDeserializer> deserializer(new NodeDeserializer(data));
     deserializer->setCursor(cursor);
 
-    if (this->getNumOfRows() == 0) {
+    if (this->empty()){
       rgId = deserializer->read<uint16_t>();
       numOfRowsPlain = deserializer->read<uint32_t>();
       colNum = deserializer->read<uint32_t>();
@@ -691,7 +691,7 @@
     std::unique_ptr<NodeDeserializer> deserializer(new NodeDeserializer(data));
     deserializer->setCursor(cursor);
 
-    if (this->getNumOfRows() == 0) {
+    if (this->empty()){
       rgId = deserializer->read<uint16_t>();
       numOfRowsPlain = deserializer->read<uint32_t>();
       colNum = deserializer->read<uint32_t>();
diff --git a/depends/dbcommon/src/dbcommon/common/tuple-batch.h b/depends/dbcommon/src/dbcommon/common/tuple-batch.h
index 15019e2..5ba2cb7 100644
--- a/depends/dbcommon/src/dbcommon/common/tuple-batch.h
+++ b/depends/dbcommon/src/dbcommon/common/tuple-batch.h
@@ -66,6 +66,9 @@
     return selected_ ? selected_->size() : this->numOfRowsPlain;
   }
 
+  // Returns whether the TupleBatch is empty (i.e. whether its size is 0).
+  bool empty() const { return getNumOfRows() == 0; }
+
   uint32_t getNumOfRowsPlain() const { return this->numOfRowsPlain; }
 
   uint16_t getRgId() const { return this->rgId; }
diff --git a/depends/dbcommon/src/dbcommon/common/vector.h b/depends/dbcommon/src/dbcommon/common/vector.h
index c2d2408..f317ad5 100644
--- a/depends/dbcommon/src/dbcommon/common/vector.h
+++ b/depends/dbcommon/src/dbcommon/common/vector.h
@@ -195,6 +195,9 @@
   // @return The number of rows/elements in the vector
   virtual uint64_t getNumOfRowsPlain() const = 0;
 
+  // Returns whether the Vector is empty (i.e. whether its size is 0).
+  bool empty() const { return getNumOfRows() == 0; }
+
   // Whether all elements are selected.
   // @return A bool value indicating whether all elements are selected
   bool allSelected() const {
diff --git a/depends/dbcommon/src/dbcommon/hash/hash-keys.cc b/depends/dbcommon/src/dbcommon/hash/hash-keys.cc
index 0e411c4..5b848fb 100644
--- a/depends/dbcommon/src/dbcommon/hash/hash-keys.cc
+++ b/depends/dbcommon/src/dbcommon/hash/hash-keys.cc
@@ -52,7 +52,7 @@
   }
   batch->setNumOfRows(hashCells.size());
   for (auto colIdx = 0; colIdx < inputTupleDesc_.getNumOfColumns(); colIdx++) {
-    if (batch->getColumn(colIdx)->getNumOfRows() == 0)
+    if (batch->getColumn(colIdx)->empty())
       batch->setColumn(colIdx, std::unique_ptr<Vector>(nullptr), true);
   }
 
diff --git a/depends/dbcommon/src/dbcommon/utils/bool-buffer.h b/depends/dbcommon/src/dbcommon/utils/bool-buffer.h
index e8d14a8..dc2f1e8 100644
--- a/depends/dbcommon/src/dbcommon/utils/bool-buffer.h
+++ b/depends/dbcommon/src/dbcommon/utils/bool-buffer.h
@@ -78,6 +78,33 @@
     }
   }
 
+  // update the external data address and size (in #bools)
+  // @param d The external data
+  // @param dataSize The size of of the external data (in #bools).
+  // @return void
+  // note: it do not change the buffer size at all, you should
+  //       assure enough memory space before call this method
+  void updateBitData(size_t idx, const char *data, size_t numBools) {
+    assert(buffer_.getOwnData());
+    assert(size() >= idx + numBools);
+    size_t bitBytes = numBools / CHAR_BIT;
+    // when this numBits > 1, reserve only can alloc 8 bytes,
+    // so buffer overflow
+    uint64_t *nulls = reinterpret_cast<uint64_t *>(buffer_.data() + idx);
+    for (size_t i = 0; i < bitBytes; ++i) {
+      nulls[i] = bit_to_bytes[static_cast<uint8_t>(data[i])];
+    }
+
+    uint32_t pos = idx + bitBytes * CHAR_BIT;
+    bool *pNulls = reinterpret_cast<bool *>(buffer_.data() + pos);
+    size_t left = numBools - bitBytes * CHAR_BIT;
+    uint8_t lastByte = static_cast<uint8_t>(data[bitBytes]);
+    assert(left < CHAR_BIT);
+    for (size_t i = 0; i < left; ++i) {
+      pNulls[i] = (lastByte >> i) & 0x1;
+    }
+  }
+
   const char *getBitData() const {
     if (!bitBuffer_.getOwnData()) bitBuffer_.reset(true);
     bitBuffer_.resize(bitDataSizeInBytes());
diff --git a/depends/univplan/src/univplan/common/expression.h b/depends/univplan/src/univplan/common/expression.h
index 1f87c3a..fefc835 100644
--- a/depends/univplan/src/univplan/common/expression.h
+++ b/depends/univplan/src/univplan/common/expression.h
@@ -93,6 +93,8 @@
     return 1;
   }
 
+  bool empty() { return getNumOfRows() == 0; }
+
   dbcommon::SelectList *getSelectList() {
     if (innerBatch && innerBatch->getSelected())
       return innerBatch->getSelected();