You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by sa...@apache.org on 2019/10/09 17:24:38 UTC

[hive] branch master updated: HIVE-21924: Split text files even if header/footer exists (Mustafa Iman, reviewed by Sankar Hariappan)

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

sankarh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new c104e8b  HIVE-21924: Split text files even if header/footer exists (Mustafa Iman, reviewed by Sankar Hariappan)
c104e8b is described below

commit c104e8bfab957702dc012a8b4ac6a944669f8a3a
Author: Mustafa Iman <mu...@cloudera.com>
AuthorDate: Wed Oct 9 22:54:10 2019 +0530

    HIVE-21924: Split text files even if header/footer exists (Mustafa Iman, reviewed by Sankar Hariappan)
    
    Signed-off-by: Sankar Hariappan <sa...@apache.org>
---
 data/files/header_footer_table_4/0001.txt          |   7 +
 data/files/header_footer_table_4/0002.txt          |   7 +
 .../test/resources/testconfiguration.properties    |   2 +
 .../hive/ql/io/HiveContextAwareRecordReader.java   |   3 +-
 .../apache/hadoop/hive/ql/io/HiveInputFormat.java  |  58 +-
 .../hadoop/hive/ql/io/SkippingTextInputFormat.java | 224 ++++++
 .../apache/hadoop/hive/ql/io/LineBufferTest.java   |  66 ++
 .../file_with_header_footer_aggregation.q          |  98 +++
 ql/src/test/queries/clientpositive/skiphf_aggr2.q  |  25 +
 .../llap/file_with_header_footer_aggregation.q.out | 849 +++++++++++++++++++++
 .../results/clientpositive/llap/skiphf_aggr2.q.out | 123 +++
 11 files changed, 1436 insertions(+), 26 deletions(-)

diff --git a/data/files/header_footer_table_4/0001.txt b/data/files/header_footer_table_4/0001.txt
new file mode 100644
index 0000000..878e3cc
--- /dev/null
+++ b/data/files/header_footer_table_4/0001.txt
@@ -0,0 +1,7 @@
+header_int,header_name,header_choice
+12,alex,daily
+3,barry,yearly
+5,chelsea,monthly
+8,xavier,monthly
+footer_int,footer_name,footer_choice
+footer2_int,footer2_name,footer2_choice
\ No newline at end of file
diff --git a/data/files/header_footer_table_4/0002.txt b/data/files/header_footer_table_4/0002.txt
new file mode 100644
index 0000000..dd27f0e
--- /dev/null
+++ b/data/files/header_footer_table_4/0002.txt
@@ -0,0 +1,7 @@
+header_int,header_name,header_choice
+9,derek,yearly
+11,ethan,monthly
+1,faith,yearly
+21,yves,daily
+footer_int,footer_name,footer_choice
+footer2_int,footer2_name,footer2_choice
\ No newline at end of file
diff --git a/itests/src/test/resources/testconfiguration.properties b/itests/src/test/resources/testconfiguration.properties
index eb7bcab..0d5ef33 100644
--- a/itests/src/test/resources/testconfiguration.properties
+++ b/itests/src/test/resources/testconfiguration.properties
@@ -398,6 +398,7 @@ minillap.query.files=acid_bucket_pruning.q,\
   reduce_deduplicate_distinct.q, \
   remote_script.q,\
   file_with_header_footer.q,\
+  file_with_header_footer_aggregation.q,\
   external_table_purge.q,\
   external_table_with_space_in_location_path.q,\
   import_exported_table.q,\
@@ -956,6 +957,7 @@ minillaplocal.query.files=\
   smb_mapjoin_15.q,\
   vectorized_nested_mapjoin.q,\
   skiphf_aggr.q,\
+  skiphf_aggr2.q,\
   multi_insert_lateral_view.q,\
   smb_mapjoin_4.q,\
   cbo_udf_udaf.q,\
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/io/HiveContextAwareRecordReader.java b/ql/src/java/org/apache/hadoop/hive/ql/io/HiveContextAwareRecordReader.java
index 7f3ef37..38b226f 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/io/HiveContextAwareRecordReader.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/io/HiveContextAwareRecordReader.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.hadoop.mapred.TextInputFormat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.hadoop.fs.FileSystem;
@@ -340,7 +341,7 @@ public abstract class HiveContextAwareRecordReader<K extends WritableComparable,
           part = null;
         }
         TableDesc table = (part == null) ? null : part.getTableDesc();
-        if (table != null) {
+        if (table != null && !TextInputFormat.class.isAssignableFrom(part.getInputFileFormatClass())) {
           headerCount = Utilities.getHeaderCount(table);
           footerCount = Utilities.getFooterCount(table, jobConf);
         }
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/io/HiveInputFormat.java b/ql/src/java/org/apache/hadoop/hive/ql/io/HiveInputFormat.java
index 7e71c77..c97c961 100755
--- a/ql/src/java/org/apache/hadoop/hive/ql/io/HiveInputFormat.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/io/HiveInputFormat.java
@@ -18,40 +18,22 @@
 
 package org.apache.hadoop.hive.ql.io;
 
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import org.apache.hadoop.hive.common.FileUtils;
-import org.apache.hadoop.hive.common.StringInternUtils;
-import org.apache.hadoop.hive.common.ValidTxnWriteIdList;
-import org.apache.hadoop.hive.common.ValidWriteIdList;
-import org.apache.hadoop.hive.ql.exec.SerializationUtilities;
-import org.apache.hive.common.util.HiveStringUtils;
-import org.apache.hive.common.util.Ref;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.hadoop.conf.Configurable;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hive.common.FileUtils;
+import org.apache.hadoop.hive.common.StringInternUtils;
+import org.apache.hadoop.hive.common.ValidTxnWriteIdList;
+import org.apache.hadoop.hive.common.ValidWriteIdList;
 import org.apache.hadoop.hive.conf.HiveConf;
 import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
 import org.apache.hadoop.hive.io.HiveIOExceptionHandlerUtil;
 import org.apache.hadoop.hive.llap.io.api.LlapIo;
 import org.apache.hadoop.hive.llap.io.api.LlapProxy;
 import org.apache.hadoop.hive.ql.exec.Operator;
+import org.apache.hadoop.hive.ql.exec.SerializationUtilities;
 import org.apache.hadoop.hive.ql.exec.TableScanOperator;
 import org.apache.hadoop.hive.ql.exec.Utilities;
 import org.apache.hadoop.hive.ql.exec.vector.VectorizedRowBatch;
@@ -77,8 +59,27 @@ import org.apache.hadoop.mapred.JobConf;
 import org.apache.hadoop.mapred.JobConfigurable;
 import org.apache.hadoop.mapred.RecordReader;
 import org.apache.hadoop.mapred.Reporter;
+import org.apache.hadoop.mapred.TextInputFormat;
 import org.apache.hadoop.util.StringUtils;
+import org.apache.hive.common.util.HiveStringUtils;
+import org.apache.hive.common.util.Ref;
 import org.apache.hive.common.util.ReflectionUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * HiveInputFormat is a parameterized InputFormat which looks at the path name
@@ -497,8 +498,15 @@ public class HiveInputFormat<K extends WritableComparable, V extends Writable>
       headerCount = Utilities.getHeaderCount(table);
       footerCount = Utilities.getFooterCount(table, conf);
       if (headerCount != 0 || footerCount != 0) {
-        // Input file has header or footer, cannot be splitted.
-        HiveConf.setLongVar(conf, ConfVars.MAPREDMINSPLITSIZE, Long.MAX_VALUE);
+        if (TextInputFormat.class.isAssignableFrom(inputFormatClass)) {
+          SkippingTextInputFormat skippingTextInputFormat = new SkippingTextInputFormat();
+          skippingTextInputFormat.configure(conf, headerCount, footerCount);
+          inputFormat = skippingTextInputFormat;
+        } else {
+          // if the input is not text and contains header/footer we have no way of
+          // splitting them.
+          HiveConf.setLongVar(conf, ConfVars.MAPREDMINSPLITSIZE, Long.MAX_VALUE);
+        }
       }
     }
 
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/io/SkippingTextInputFormat.java b/ql/src/java/org/apache/hadoop/hive/ql/io/SkippingTextInputFormat.java
new file mode 100644
index 0000000..7e936d5
--- /dev/null
+++ b/ql/src/java/org/apache/hadoop/hive/ql/io/SkippingTextInputFormat.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hive.ql.io;
+
+import org.apache.hadoop.fs.FSDataInputStream;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.mapred.FileSplit;
+import org.apache.hadoop.mapred.JobConf;
+import org.apache.hadoop.mapred.TextInputFormat;
+
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * SkippingInputFormat is a header/footer aware input format. It truncates
+ * splits identified by TextInputFormat. Header and footers are removed
+ * from the splits.
+ */
+public class SkippingTextInputFormat extends TextInputFormat {
+
+  private final Map<Path, Long> startIndexMap = new ConcurrentHashMap<Path, Long>();
+  private final Map<Path, Long> endIndexMap = new ConcurrentHashMap<Path, Long>();
+  private JobConf conf;
+  private int headerCount;
+  private int footerCount;
+
+  @Override
+  public void configure(JobConf conf) {
+    this.conf = conf;
+    super.configure(conf);
+  }
+
+  public void configure(JobConf conf, int headerCount, int footerCount) {
+    configure(conf);
+    this.headerCount = headerCount;
+    this.footerCount = footerCount;
+  }
+
+  @Override
+  protected FileSplit makeSplit(Path file, long start, long length, String[] hosts) {
+    return makeSplitInternal(file, start, length, hosts, null);
+  }
+
+  @Override
+  protected FileSplit makeSplit(Path file, long start, long length, String[] hosts, String[] inMemoryHosts) {
+    return makeSplitInternal(file, start, length, hosts, inMemoryHosts);
+  }
+
+  private FileSplit makeSplitInternal(Path file, long start, long length, String[] hosts, String[] inMemoryHosts) {
+    long cachedStart;
+    long cachedEnd;
+    try {
+      cachedStart = getCachedStartIndex(file);
+      cachedEnd = getCachedEndIndex(file);
+    } catch (IOException e) {
+      LOG.warn("Could not detect header/footer", e);
+      return new NullRowsInputFormat.DummyInputSplit(file);
+    }
+    if (cachedStart > start + length) {
+      return new NullRowsInputFormat.DummyInputSplit(file);
+    }
+    if (cachedStart > start) {
+      length = length - (cachedStart - start);
+      start = cachedStart;
+    }
+    if (cachedEnd < start) {
+      return new NullRowsInputFormat.DummyInputSplit(file);
+    }
+    if (cachedEnd < start + length) {
+      length = cachedEnd - start;
+    }
+    if (inMemoryHosts == null) {
+      return super.makeSplit(file, start, length, hosts);
+    } else {
+      return super.makeSplit(file, start, length, hosts, inMemoryHosts);
+    }
+  }
+
+  private long getCachedStartIndex(Path path) throws IOException {
+    if (headerCount == 0) {
+      return 0;
+    }
+    Long startIndexForFile = startIndexMap.get(path);
+    if (startIndexForFile == null) {
+      FileSystem fileSystem;
+      FSDataInputStream fis = null;
+      fileSystem = path.getFileSystem(conf);
+      try {
+        fis = fileSystem.open(path);
+        for (int j = 0; j < headerCount; j++) {
+          if (fis.readLine() == null) {
+            startIndexMap.put(path, Long.MAX_VALUE);
+            return Long.MAX_VALUE;
+          }
+        }
+        // Readers skip the entire first row if the start index of the
+        // split is not zero. We are setting the start of the index as
+        // the last byte of the previous row so the last line of header
+        // is discarded instead of the first valid input row.
+        startIndexForFile = fis.getPos() - 1;
+      } finally {
+        if (fis != null) {
+          fis.close();
+        }
+      }
+      startIndexMap.put(path, startIndexForFile);
+    }
+    return startIndexForFile;
+  }
+
+  private long getCachedEndIndex(Path path) throws IOException {
+    Long endIndexForFile = endIndexMap.get(path);
+    if (endIndexForFile == null) {
+      final long bufferSectionSize = 5 * 1024;
+      FileSystem fileSystem = path.getFileSystem(conf);
+      long endOfFile = fileSystem.getFileStatus(path).getLen();
+      if (footerCount == 0) {
+        endIndexForFile = endOfFile;
+      } else {
+        long bufferSectionEnd = endOfFile; // first byte that is not included in the section
+        long bufferSectionStart = Math.max(0, bufferSectionEnd - bufferSectionSize);
+
+        // we need 'footer count' lines and one space for EOF
+        LineBuffer buffer = new LineBuffer(footerCount + 1);
+        FSDataInputStream fis = null;
+        try {
+          fis = fileSystem.open(path);
+          while (bufferSectionEnd > bufferSectionStart) {
+            fis.seek(bufferSectionStart);
+            long pos = fis.getPos();
+            while (pos < bufferSectionEnd) {
+              if (fis.readLine() == null) {
+                // if there is not enough lines in this section, check the previous
+                // section. If this is the beginning section, there are simply not
+                // enough lines in the file.
+                break;
+              }
+              pos = fis.getPos();
+              buffer.consume(pos, bufferSectionEnd);
+            }
+            if (buffer.getRemainingLineCount() == 0) {
+              // if we consumed all the required line ends, that means the buffer now
+              // contains the index of the first byte of the footer.
+              break;
+            } else {
+              bufferSectionEnd = bufferSectionStart;
+              bufferSectionStart = Math.max(0, bufferSectionEnd - bufferSectionSize);
+            }
+          }
+          if (buffer.getRemainingLineCount() == 0) {
+            // buffer.getFirstLineStart() is the first byte of the footer. So the split
+            // must end before this.
+            endIndexForFile = buffer.getFirstLineStart() - 1;
+          } else {
+            // there were not enough lines in the file to consume all footer rows.
+            endIndexForFile = Long.MIN_VALUE;
+          }
+        } finally {
+          if (fis != null) {
+            fis.close();
+          }
+        }
+      }
+      endIndexMap.put(path, endIndexForFile);
+    }
+    return endIndexForFile;
+  }
+
+  static class LineBuffer {
+    private final Queue<Long> queue = new ArrayDeque<Long>();
+    private int remainingLineEnds;
+    private long lowPosition = Long.MAX_VALUE;
+
+    LineBuffer(int requiredLines) {
+      this.remainingLineEnds = requiredLines;
+    }
+
+    public void consume(long position, long sectionEnd) {
+      if (position > sectionEnd) {
+        return;
+      }
+      if (position < lowPosition) {
+        remainingLineEnds -= queue.size();
+        queue.clear();
+        queue.add(position);
+        lowPosition = position;
+      } else if (position > lowPosition) {
+        if (queue.size() == remainingLineEnds) {
+          queue.poll();
+        }
+        queue.add(position);
+        lowPosition = queue.peek();
+      }
+    }
+
+    public int getRemainingLineCount() {
+      return remainingLineEnds - queue.size();
+    }
+
+    public long getFirstLineStart() {
+      return lowPosition;
+    }
+  }
+}
diff --git a/ql/src/test/org/apache/hadoop/hive/ql/io/LineBufferTest.java b/ql/src/test/org/apache/hadoop/hive/ql/io/LineBufferTest.java
new file mode 100644
index 0000000..9cbdeef
--- /dev/null
+++ b/ql/src/test/org/apache/hadoop/hive/ql/io/LineBufferTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hive.ql.io;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * LineEndBuffer simple unit test.
+ */
+public class LineBufferTest {
+
+  @Test
+  public void testLineEndBuffer() {
+    SkippingTextInputFormat.LineBuffer buffer;
+    buffer = new SkippingTextInputFormat.LineBuffer(3);
+    buffer.consume(200, 200);
+    buffer.consume(100, 200);
+    buffer.consume(100, 100);
+    buffer.consume(50, 100);
+    assertEquals(0, buffer.getRemainingLineCount());
+    assertEquals(50, buffer.getFirstLineStart());
+
+    buffer = new SkippingTextInputFormat.LineBuffer(3);
+    buffer.consume(200, 200);
+    buffer.consume(150, 200);
+    buffer.consume(100, 200);
+    assertEquals(0, buffer.getRemainingLineCount());
+    assertEquals(100, buffer.getFirstLineStart());
+
+    buffer = new SkippingTextInputFormat.LineBuffer(3);
+    buffer.consume(200, 200);
+    assertEquals(2, buffer.getRemainingLineCount());
+    buffer.consume(100, 100);
+    assertEquals(1, buffer.getRemainingLineCount());
+    buffer.consume(50, 100);
+    assertEquals(0, buffer.getRemainingLineCount());
+    assertEquals(50, buffer.getFirstLineStart());
+
+    buffer = new SkippingTextInputFormat.LineBuffer(3);
+    buffer.consume(200, 200);
+    assertEquals(2, buffer.getRemainingLineCount());
+    buffer.consume(50, 100);
+    assertEquals(1, buffer.getRemainingLineCount());
+    buffer.consume(25, 100);
+    assertEquals(0, buffer.getRemainingLineCount());
+    assertEquals(25, buffer.getFirstLineStart());
+  }
+}
diff --git a/ql/src/test/queries/clientpositive/file_with_header_footer_aggregation.q b/ql/src/test/queries/clientpositive/file_with_header_footer_aggregation.q
new file mode 100644
index 0000000..f66e1dc
--- /dev/null
+++ b/ql/src/test/queries/clientpositive/file_with_header_footer_aggregation.q
@@ -0,0 +1,98 @@
+set hive.mapred.mode=nonstrict;
+
+dfs ${system:test.dfs.mkdir} ${system:test.tmp.dir};
+dfs -copyFromLocal ../../data/files/header_footer_table_4  ${system:test.tmp.dir}/header_footer_table_4;
+
+CREATE TABLE numbrs (numbr int);
+INSERT INTO numbrs VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (NULL);
+CREATE EXTERNAL TABLE header_footer_table_4 (header_int int, header_name string, header_choice varchar(10)) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '${system:test.tmp.dir}/header_footer_table_4' tblproperties ("skip.header.line.count"="1", "skip.footer.line.count"="2");
+
+SELECT * FROM header_footer_table_4;
+
+SELECT * FROM header_footer_table_4 ORDER BY header_int LIMIT 8;
+
+-- should return nothing as title is correctly skipped
+SELECT * FROM header_footer_table_4 WHERE header_choice = 'header_choice';
+SELECT * FROM header_footer_table_4 WHERE header_choice = 'monthly';
+SELECT COUNT(*) FROM header_footer_table_4;
+
+-- shpuld return nothing
+SELECT * FROM header_footer_table_4 WHERE header_choice is NULL;
+
+
+SELECT AVG(header_int) FROM header_footer_table_4 GROUP BY header_choice;
+
+-- should not include any header and footer
+SELECT * FROM header_footer_table_4 A, header_footer_table_4 B ORDER BY A.header_int, B.header_int;
+
+-- no join variant should include header or footer
+SELECT header_name, header_int FROM header_footer_table_4 LEFT JOIN numbrs ON numbr = header_int;
+SELECT header_name, header_int FROM header_footer_table_4 RIGHT JOIN numbrs ON numbr = header_int;
+SELECT header_name, header_int FROM header_footer_table_4 INNER JOIN numbrs ON numbr = header_int;
+SELECT header_name, header_int FROM header_footer_table_4 FULL JOIN numbrs ON numbr = header_int;
+
+
+SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice;
+
+
+SELECT DISTINCT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice;
+
+
+SELECT header_name, header_choice FROM header_footer_table_4 ORDER BY header_int LIMIT 8;
+
+-- create table from existing text file should not feed header or footer to the new table
+CREATE TABLE transition (title VARCHAR(10), name VARCHAR(10)) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' STORED AS TEXTFILE LOCATION '${system:test.tmp.dir}/header_footer_table_transition';
+INSERT INTO transition SELECT header_choice, header_name FROM header_footer_table_4;
+SELECT * FROM transition A, transition B ORDER BY A.title, A.name, B.title, B.name;
+
+CREATE TABLE transition2 (header_choice VARCHAR(10), sum_header_int int) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' STORED AS TEXTFILE LOCATION '${system:test.tmp.dir}/test/header_footer_table_transition2';
+INSERT INTO transition2 SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice;
+SELECT * FROM transition2 A, transition2 B ORDER BY A.sum_header_int, A.header_choice, B.sum_header_int, B.header_choice;
+
+DROP TABLE transition;
+DROP TABLE transition2;
+
+-- turn off fetch conversion. This disables the additional header/footer handling logic in fetch operator.
+set hive.fetch.task.conversion=none;
+
+SELECT * FROM header_footer_table_4;
+
+SELECT * FROM header_footer_table_4 ORDER BY header_int LIMIT 8;
+
+-- should return nothing as title is correctly skipped
+SELECT * FROM header_footer_table_4 WHERE header_choice = 'header_choice';
+SELECT * FROM header_footer_table_4 WHERE header_choice = 'monthly';
+SELECT COUNT(*) FROM header_footer_table_4;
+
+-- shpuld return nothing
+SELECT * FROM header_footer_table_4 WHERE header_choice is NULL;
+
+
+SELECT AVG(header_int) FROM header_footer_table_4 GROUP BY header_choice;
+
+-- should not include any header and footer
+SELECT * FROM header_footer_table_4 A, header_footer_table_4 B ORDER BY A.header_int, B.header_int;
+
+-- no join variant should include header or footer
+SELECT header_name, header_int FROM header_footer_table_4 LEFT JOIN numbrs ON numbr = header_int;
+SELECT header_name, header_int FROM header_footer_table_4 RIGHT JOIN numbrs ON numbr = header_int;
+SELECT header_name, header_int FROM header_footer_table_4 INNER JOIN numbrs ON numbr = header_int;
+SELECT header_name, header_int FROM header_footer_table_4 FULL JOIN numbrs ON numbr = header_int;
+
+
+SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice;
+
+
+SELECT DISTINCT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice;
+
+
+SELECT header_name, header_choice FROM header_footer_table_4 ORDER BY header_int LIMIT 8;
+
+-- create table from existing text file should not feed header or footer to the new table
+CREATE TABLE transition (title VARCHAR(10), name VARCHAR(10)) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' STORED AS TEXTFILE LOCATION '${system:test.tmp.dir}/header_footer_table_transition';
+INSERT INTO transition SELECT header_choice, header_name FROM header_footer_table_4;
+SELECT * FROM transition A, transition B ORDER BY A.title, A.name, B.title, B.name;
+
+CREATE TABLE transition2 (header_choice VARCHAR(10), sum_header_int int) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' STORED AS TEXTFILE LOCATION '${system:test.tmp.dir}/test/header_footer_table_transition2';
+INSERT INTO transition2 SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice;
+SELECT * FROM transition2 A, transition2 B ORDER BY A.sum_header_int, A.header_choice, B.sum_header_int, B.header_choice;
diff --git a/ql/src/test/queries/clientpositive/skiphf_aggr2.q b/ql/src/test/queries/clientpositive/skiphf_aggr2.q
new file mode 100644
index 0000000..478baef
--- /dev/null
+++ b/ql/src/test/queries/clientpositive/skiphf_aggr2.q
@@ -0,0 +1,25 @@
+SET hive.fetch.task.conversion=none;
+-- no footer
+DROP TABLE IF EXISTS hf1;
+CREATE TABLE hf1 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.header.line.count'='1');
+INSERT OVERWRITE TABLE hf1 VALUES ('x','y'),('a','b'),('c','d');
+SELECT * FROM hf1;
+
+-- no header
+DROP TABLE IF EXISTS hf2;
+CREATE TABLE hf2 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.footer.line.count'='2');
+INSERT OVERWRITE TABLE hf2 VALUES ('x','y'),('a','b'),('c','d');
+SELECT * FROM hf2;
+
+-- only header, no data
+DROP TABLE IF EXISTS hf3;
+CREATE TABLE hf3 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.header.line.count'='3');
+INSERT OVERWRITE TABLE hf3 VALUES ('x','y'),('a','b'),('c','d');
+SELECT * FROM hf3;
+
+-- header and footer, no data
+DROP TABLE IF EXISTS hf4;
+CREATE TABLE hf4 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.header.line.count'='1','skip.footer.line.count'='2');
+INSERT OVERWRITE TABLE hf4 VALUES ('x','y'),('a','b'),('c','d');
+SELECT * FROM hf4;
+
diff --git a/ql/src/test/results/clientpositive/llap/file_with_header_footer_aggregation.q.out b/ql/src/test/results/clientpositive/llap/file_with_header_footer_aggregation.q.out
new file mode 100644
index 0000000..0dc4892
--- /dev/null
+++ b/ql/src/test/results/clientpositive/llap/file_with_header_footer_aggregation.q.out
@@ -0,0 +1,849 @@
+PREHOOK: query: CREATE TABLE numbrs (numbr int)
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@numbrs
+POSTHOOK: query: CREATE TABLE numbrs (numbr int)
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@numbrs
+PREHOOK: query: INSERT INTO numbrs VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (NULL)
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@numbrs
+POSTHOOK: query: INSERT INTO numbrs VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (NULL)
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@numbrs
+POSTHOOK: Lineage: numbrs.numbr SCRIPT []
+#### A masked pattern was here ####
+PREHOOK: type: CREATETABLE
+PREHOOK: Input: hdfs://### HDFS PATH ###
+PREHOOK: Output: database:default
+PREHOOK: Output: default@header_footer_table_4
+#### A masked pattern was here ####
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Input: hdfs://### HDFS PATH ###
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@header_footer_table_4
+PREHOOK: query: SELECT * FROM header_footer_table_4
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+12	alex	daily
+3	barry	yearly
+5	chelsea	monthly
+8	xavier	monthly
+9	derek	yearly
+11	ethan	monthly
+1	faith	yearly
+21	yves	daily
+PREHOOK: query: SELECT * FROM header_footer_table_4 ORDER BY header_int LIMIT 8
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 ORDER BY header_int LIMIT 8
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1	faith	yearly
+3	barry	yearly
+5	chelsea	monthly
+8	xavier	monthly
+9	derek	yearly
+11	ethan	monthly
+12	alex	daily
+21	yves	daily
+PREHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice = 'header_choice'
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice = 'header_choice'
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+PREHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice = 'monthly'
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice = 'monthly'
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+5	chelsea	monthly
+8	xavier	monthly
+11	ethan	monthly
+PREHOOK: query: SELECT COUNT(*) FROM header_footer_table_4
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT COUNT(*) FROM header_footer_table_4
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+8
+PREHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice is NULL
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice is NULL
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+PREHOOK: query: SELECT AVG(header_int) FROM header_footer_table_4 GROUP BY header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT AVG(header_int) FROM header_footer_table_4 GROUP BY header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+8.0
+16.5
+4.333333333333333
+Warning: Shuffle Join MERGEJOIN[11][tables = [$hdt$_0, $hdt$_1]] in Stage 'Reducer 2' is a cross product
+PREHOOK: query: SELECT * FROM header_footer_table_4 A, header_footer_table_4 B ORDER BY A.header_int, B.header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 A, header_footer_table_4 B ORDER BY A.header_int, B.header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1	faith	yearly	1	faith	yearly
+1	faith	yearly	3	barry	yearly
+1	faith	yearly	5	chelsea	monthly
+1	faith	yearly	8	xavier	monthly
+1	faith	yearly	9	derek	yearly
+1	faith	yearly	11	ethan	monthly
+1	faith	yearly	12	alex	daily
+1	faith	yearly	21	yves	daily
+3	barry	yearly	1	faith	yearly
+3	barry	yearly	3	barry	yearly
+3	barry	yearly	5	chelsea	monthly
+3	barry	yearly	8	xavier	monthly
+3	barry	yearly	9	derek	yearly
+3	barry	yearly	11	ethan	monthly
+3	barry	yearly	12	alex	daily
+3	barry	yearly	21	yves	daily
+5	chelsea	monthly	1	faith	yearly
+5	chelsea	monthly	3	barry	yearly
+5	chelsea	monthly	5	chelsea	monthly
+5	chelsea	monthly	8	xavier	monthly
+5	chelsea	monthly	9	derek	yearly
+5	chelsea	monthly	11	ethan	monthly
+5	chelsea	monthly	12	alex	daily
+5	chelsea	monthly	21	yves	daily
+8	xavier	monthly	1	faith	yearly
+8	xavier	monthly	3	barry	yearly
+8	xavier	monthly	5	chelsea	monthly
+8	xavier	monthly	8	xavier	monthly
+8	xavier	monthly	9	derek	yearly
+8	xavier	monthly	11	ethan	monthly
+8	xavier	monthly	12	alex	daily
+8	xavier	monthly	21	yves	daily
+9	derek	yearly	1	faith	yearly
+9	derek	yearly	3	barry	yearly
+9	derek	yearly	5	chelsea	monthly
+9	derek	yearly	8	xavier	monthly
+9	derek	yearly	9	derek	yearly
+9	derek	yearly	11	ethan	monthly
+9	derek	yearly	12	alex	daily
+9	derek	yearly	21	yves	daily
+11	ethan	monthly	1	faith	yearly
+11	ethan	monthly	3	barry	yearly
+11	ethan	monthly	5	chelsea	monthly
+11	ethan	monthly	8	xavier	monthly
+11	ethan	monthly	9	derek	yearly
+11	ethan	monthly	11	ethan	monthly
+11	ethan	monthly	12	alex	daily
+11	ethan	monthly	21	yves	daily
+12	alex	daily	1	faith	yearly
+12	alex	daily	3	barry	yearly
+12	alex	daily	5	chelsea	monthly
+12	alex	daily	8	xavier	monthly
+12	alex	daily	9	derek	yearly
+12	alex	daily	11	ethan	monthly
+12	alex	daily	12	alex	daily
+12	alex	daily	21	yves	daily
+21	yves	daily	1	faith	yearly
+21	yves	daily	3	barry	yearly
+21	yves	daily	5	chelsea	monthly
+21	yves	daily	8	xavier	monthly
+21	yves	daily	9	derek	yearly
+21	yves	daily	11	ethan	monthly
+21	yves	daily	12	alex	daily
+21	yves	daily	21	yves	daily
+PREHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 LEFT JOIN numbrs ON numbr = header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Input: default@numbrs
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 LEFT JOIN numbrs ON numbr = header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Input: default@numbrs
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+faith	1
+barry	3
+chelsea	5
+xavier	8
+derek	9
+ethan	11
+alex	12
+yves	21
+PREHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 RIGHT JOIN numbrs ON numbr = header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Input: default@numbrs
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 RIGHT JOIN numbrs ON numbr = header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Input: default@numbrs
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+NULL	NULL
+faith	1
+NULL	NULL
+barry	3
+NULL	NULL
+chelsea	5
+NULL	NULL
+NULL	NULL
+xavier	8
+derek	9
+NULL	NULL
+ethan	11
+alex	12
+PREHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 INNER JOIN numbrs ON numbr = header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Input: default@numbrs
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 INNER JOIN numbrs ON numbr = header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Input: default@numbrs
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+faith	1
+barry	3
+chelsea	5
+xavier	8
+derek	9
+ethan	11
+alex	12
+PREHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 FULL JOIN numbrs ON numbr = header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Input: default@numbrs
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 FULL JOIN numbrs ON numbr = header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Input: default@numbrs
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+NULL	NULL
+faith	1
+NULL	NULL
+barry	3
+NULL	NULL
+chelsea	5
+NULL	NULL
+NULL	NULL
+xavier	8
+derek	9
+NULL	NULL
+ethan	11
+alex	12
+yves	21
+PREHOOK: query: SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+monthly	24
+daily	33
+yearly	13
+PREHOOK: query: SELECT DISTINCT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT DISTINCT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+monthly	24
+daily	33
+yearly	13
+PREHOOK: query: SELECT header_name, header_choice FROM header_footer_table_4 ORDER BY header_int LIMIT 8
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_choice FROM header_footer_table_4 ORDER BY header_int LIMIT 8
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+faith	yearly
+barry	yearly
+chelsea	monthly
+xavier	monthly
+derek	yearly
+ethan	monthly
+alex	daily
+yves	daily
+#### A masked pattern was here ####
+PREHOOK: type: CREATETABLE
+PREHOOK: Input: hdfs://### HDFS PATH ###
+PREHOOK: Output: database:default
+PREHOOK: Output: default@transition
+#### A masked pattern was here ####
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Input: hdfs://### HDFS PATH ###
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@transition
+PREHOOK: query: INSERT INTO transition SELECT header_choice, header_name FROM header_footer_table_4
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: default@transition
+POSTHOOK: query: INSERT INTO transition SELECT header_choice, header_name FROM header_footer_table_4
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: default@transition
+POSTHOOK: Lineage: transition.name EXPRESSION [(header_footer_table_4)header_footer_table_4.FieldSchema(name:header_name, type:string, comment:null), ]
+POSTHOOK: Lineage: transition.title SIMPLE [(header_footer_table_4)header_footer_table_4.FieldSchema(name:header_choice, type:varchar(10), comment:null), ]
+Warning: Shuffle Join MERGEJOIN[11][tables = [$hdt$_0, $hdt$_1]] in Stage 'Reducer 2' is a cross product
+PREHOOK: query: SELECT * FROM transition A, transition B ORDER BY A.title, A.name, B.title, B.name
+PREHOOK: type: QUERY
+PREHOOK: Input: default@transition
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM transition A, transition B ORDER BY A.title, A.name, B.title, B.name
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@transition
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+daily	alex	daily	alex
+daily	alex	daily	yves
+daily	alex	monthly	chelsea
+daily	alex	monthly	ethan
+daily	alex	monthly	xavier
+daily	alex	yearly	barry
+daily	alex	yearly	derek
+daily	alex	yearly	faith
+daily	yves	daily	alex
+daily	yves	daily	yves
+daily	yves	monthly	chelsea
+daily	yves	monthly	ethan
+daily	yves	monthly	xavier
+daily	yves	yearly	barry
+daily	yves	yearly	derek
+daily	yves	yearly	faith
+monthly	chelsea	daily	alex
+monthly	chelsea	daily	yves
+monthly	chelsea	monthly	chelsea
+monthly	chelsea	monthly	ethan
+monthly	chelsea	monthly	xavier
+monthly	chelsea	yearly	barry
+monthly	chelsea	yearly	derek
+monthly	chelsea	yearly	faith
+monthly	ethan	daily	alex
+monthly	ethan	daily	yves
+monthly	ethan	monthly	chelsea
+monthly	ethan	monthly	ethan
+monthly	ethan	monthly	xavier
+monthly	ethan	yearly	barry
+monthly	ethan	yearly	derek
+monthly	ethan	yearly	faith
+monthly	xavier	daily	alex
+monthly	xavier	daily	yves
+monthly	xavier	monthly	chelsea
+monthly	xavier	monthly	ethan
+monthly	xavier	monthly	xavier
+monthly	xavier	yearly	barry
+monthly	xavier	yearly	derek
+monthly	xavier	yearly	faith
+yearly	barry	daily	alex
+yearly	barry	daily	yves
+yearly	barry	monthly	chelsea
+yearly	barry	monthly	ethan
+yearly	barry	monthly	xavier
+yearly	barry	yearly	barry
+yearly	barry	yearly	derek
+yearly	barry	yearly	faith
+yearly	derek	daily	alex
+yearly	derek	daily	yves
+yearly	derek	monthly	chelsea
+yearly	derek	monthly	ethan
+yearly	derek	monthly	xavier
+yearly	derek	yearly	barry
+yearly	derek	yearly	derek
+yearly	derek	yearly	faith
+yearly	faith	daily	alex
+yearly	faith	daily	yves
+yearly	faith	monthly	chelsea
+yearly	faith	monthly	ethan
+yearly	faith	monthly	xavier
+yearly	faith	yearly	barry
+yearly	faith	yearly	derek
+yearly	faith	yearly	faith
+#### A masked pattern was here ####
+PREHOOK: type: CREATETABLE
+PREHOOK: Input: hdfs://### HDFS PATH ###
+PREHOOK: Output: database:default
+PREHOOK: Output: default@transition2
+#### A masked pattern was here ####
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Input: hdfs://### HDFS PATH ###
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@transition2
+PREHOOK: query: INSERT INTO transition2 SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: default@transition2
+POSTHOOK: query: INSERT INTO transition2 SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: default@transition2
+POSTHOOK: Lineage: transition2.header_choice SIMPLE [(header_footer_table_4)header_footer_table_4.FieldSchema(name:header_choice, type:varchar(10), comment:null), ]
+POSTHOOK: Lineage: transition2.sum_header_int EXPRESSION [(header_footer_table_4)header_footer_table_4.FieldSchema(name:header_int, type:int, comment:null), ]
+Warning: Shuffle Join MERGEJOIN[11][tables = [$hdt$_0, $hdt$_1]] in Stage 'Reducer 2' is a cross product
+PREHOOK: query: SELECT * FROM transition2 A, transition2 B ORDER BY A.sum_header_int, A.header_choice, B.sum_header_int, B.header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@transition2
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM transition2 A, transition2 B ORDER BY A.sum_header_int, A.header_choice, B.sum_header_int, B.header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@transition2
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+yearly	13	yearly	13
+yearly	13	monthly	24
+yearly	13	daily	33
+monthly	24	yearly	13
+monthly	24	monthly	24
+monthly	24	daily	33
+daily	33	yearly	13
+daily	33	monthly	24
+daily	33	daily	33
+PREHOOK: query: DROP TABLE transition
+PREHOOK: type: DROPTABLE
+PREHOOK: Input: default@transition
+PREHOOK: Output: default@transition
+POSTHOOK: query: DROP TABLE transition
+POSTHOOK: type: DROPTABLE
+POSTHOOK: Input: default@transition
+POSTHOOK: Output: default@transition
+PREHOOK: query: DROP TABLE transition2
+PREHOOK: type: DROPTABLE
+PREHOOK: Input: default@transition2
+PREHOOK: Output: default@transition2
+POSTHOOK: query: DROP TABLE transition2
+POSTHOOK: type: DROPTABLE
+POSTHOOK: Input: default@transition2
+POSTHOOK: Output: default@transition2
+PREHOOK: query: SELECT * FROM header_footer_table_4
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+12	alex	daily
+3	barry	yearly
+5	chelsea	monthly
+8	xavier	monthly
+9	derek	yearly
+11	ethan	monthly
+1	faith	yearly
+21	yves	daily
+PREHOOK: query: SELECT * FROM header_footer_table_4 ORDER BY header_int LIMIT 8
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 ORDER BY header_int LIMIT 8
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1	faith	yearly
+3	barry	yearly
+5	chelsea	monthly
+8	xavier	monthly
+9	derek	yearly
+11	ethan	monthly
+12	alex	daily
+21	yves	daily
+PREHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice = 'header_choice'
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice = 'header_choice'
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+PREHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice = 'monthly'
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice = 'monthly'
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+5	chelsea	monthly
+8	xavier	monthly
+11	ethan	monthly
+PREHOOK: query: SELECT COUNT(*) FROM header_footer_table_4
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT COUNT(*) FROM header_footer_table_4
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+8
+PREHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice is NULL
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 WHERE header_choice is NULL
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+PREHOOK: query: SELECT AVG(header_int) FROM header_footer_table_4 GROUP BY header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT AVG(header_int) FROM header_footer_table_4 GROUP BY header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+8.0
+16.5
+4.333333333333333
+Warning: Shuffle Join MERGEJOIN[11][tables = [$hdt$_0, $hdt$_1]] in Stage 'Reducer 2' is a cross product
+PREHOOK: query: SELECT * FROM header_footer_table_4 A, header_footer_table_4 B ORDER BY A.header_int, B.header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM header_footer_table_4 A, header_footer_table_4 B ORDER BY A.header_int, B.header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1	faith	yearly	1	faith	yearly
+1	faith	yearly	3	barry	yearly
+1	faith	yearly	5	chelsea	monthly
+1	faith	yearly	8	xavier	monthly
+1	faith	yearly	9	derek	yearly
+1	faith	yearly	11	ethan	monthly
+1	faith	yearly	12	alex	daily
+1	faith	yearly	21	yves	daily
+3	barry	yearly	1	faith	yearly
+3	barry	yearly	3	barry	yearly
+3	barry	yearly	5	chelsea	monthly
+3	barry	yearly	8	xavier	monthly
+3	barry	yearly	9	derek	yearly
+3	barry	yearly	11	ethan	monthly
+3	barry	yearly	12	alex	daily
+3	barry	yearly	21	yves	daily
+5	chelsea	monthly	1	faith	yearly
+5	chelsea	monthly	3	barry	yearly
+5	chelsea	monthly	5	chelsea	monthly
+5	chelsea	monthly	8	xavier	monthly
+5	chelsea	monthly	9	derek	yearly
+5	chelsea	monthly	11	ethan	monthly
+5	chelsea	monthly	12	alex	daily
+5	chelsea	monthly	21	yves	daily
+8	xavier	monthly	1	faith	yearly
+8	xavier	monthly	3	barry	yearly
+8	xavier	monthly	5	chelsea	monthly
+8	xavier	monthly	8	xavier	monthly
+8	xavier	monthly	9	derek	yearly
+8	xavier	monthly	11	ethan	monthly
+8	xavier	monthly	12	alex	daily
+8	xavier	monthly	21	yves	daily
+9	derek	yearly	1	faith	yearly
+9	derek	yearly	3	barry	yearly
+9	derek	yearly	5	chelsea	monthly
+9	derek	yearly	8	xavier	monthly
+9	derek	yearly	9	derek	yearly
+9	derek	yearly	11	ethan	monthly
+9	derek	yearly	12	alex	daily
+9	derek	yearly	21	yves	daily
+11	ethan	monthly	1	faith	yearly
+11	ethan	monthly	3	barry	yearly
+11	ethan	monthly	5	chelsea	monthly
+11	ethan	monthly	8	xavier	monthly
+11	ethan	monthly	9	derek	yearly
+11	ethan	monthly	11	ethan	monthly
+11	ethan	monthly	12	alex	daily
+11	ethan	monthly	21	yves	daily
+12	alex	daily	1	faith	yearly
+12	alex	daily	3	barry	yearly
+12	alex	daily	5	chelsea	monthly
+12	alex	daily	8	xavier	monthly
+12	alex	daily	9	derek	yearly
+12	alex	daily	11	ethan	monthly
+12	alex	daily	12	alex	daily
+12	alex	daily	21	yves	daily
+21	yves	daily	1	faith	yearly
+21	yves	daily	3	barry	yearly
+21	yves	daily	5	chelsea	monthly
+21	yves	daily	8	xavier	monthly
+21	yves	daily	9	derek	yearly
+21	yves	daily	11	ethan	monthly
+21	yves	daily	12	alex	daily
+21	yves	daily	21	yves	daily
+PREHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 LEFT JOIN numbrs ON numbr = header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Input: default@numbrs
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 LEFT JOIN numbrs ON numbr = header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Input: default@numbrs
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+faith	1
+barry	3
+chelsea	5
+xavier	8
+derek	9
+ethan	11
+alex	12
+yves	21
+PREHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 RIGHT JOIN numbrs ON numbr = header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Input: default@numbrs
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 RIGHT JOIN numbrs ON numbr = header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Input: default@numbrs
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+NULL	NULL
+faith	1
+NULL	NULL
+barry	3
+NULL	NULL
+chelsea	5
+NULL	NULL
+NULL	NULL
+xavier	8
+derek	9
+NULL	NULL
+ethan	11
+alex	12
+PREHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 INNER JOIN numbrs ON numbr = header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Input: default@numbrs
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 INNER JOIN numbrs ON numbr = header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Input: default@numbrs
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+faith	1
+barry	3
+chelsea	5
+xavier	8
+derek	9
+ethan	11
+alex	12
+PREHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 FULL JOIN numbrs ON numbr = header_int
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Input: default@numbrs
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_int FROM header_footer_table_4 FULL JOIN numbrs ON numbr = header_int
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Input: default@numbrs
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+NULL	NULL
+faith	1
+NULL	NULL
+barry	3
+NULL	NULL
+chelsea	5
+NULL	NULL
+NULL	NULL
+xavier	8
+derek	9
+NULL	NULL
+ethan	11
+alex	12
+yves	21
+PREHOOK: query: SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+monthly	24
+daily	33
+yearly	13
+PREHOOK: query: SELECT DISTINCT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT DISTINCT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+monthly	24
+daily	33
+yearly	13
+PREHOOK: query: SELECT header_name, header_choice FROM header_footer_table_4 ORDER BY header_int LIMIT 8
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT header_name, header_choice FROM header_footer_table_4 ORDER BY header_int LIMIT 8
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+faith	yearly
+barry	yearly
+chelsea	monthly
+xavier	monthly
+derek	yearly
+ethan	monthly
+alex	daily
+yves	daily
+#### A masked pattern was here ####
+PREHOOK: type: CREATETABLE
+PREHOOK: Input: hdfs://### HDFS PATH ###
+PREHOOK: Output: database:default
+PREHOOK: Output: default@transition
+#### A masked pattern was here ####
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Input: hdfs://### HDFS PATH ###
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@transition
+PREHOOK: query: INSERT INTO transition SELECT header_choice, header_name FROM header_footer_table_4
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: default@transition
+POSTHOOK: query: INSERT INTO transition SELECT header_choice, header_name FROM header_footer_table_4
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: default@transition
+POSTHOOK: Lineage: transition.name EXPRESSION [(header_footer_table_4)header_footer_table_4.FieldSchema(name:header_name, type:string, comment:null), ]
+POSTHOOK: Lineage: transition.title SIMPLE [(header_footer_table_4)header_footer_table_4.FieldSchema(name:header_choice, type:varchar(10), comment:null), ]
+Warning: Shuffle Join MERGEJOIN[11][tables = [$hdt$_0, $hdt$_1]] in Stage 'Reducer 2' is a cross product
+PREHOOK: query: SELECT * FROM transition A, transition B ORDER BY A.title, A.name, B.title, B.name
+PREHOOK: type: QUERY
+PREHOOK: Input: default@transition
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM transition A, transition B ORDER BY A.title, A.name, B.title, B.name
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@transition
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+daily	alex	daily	alex
+daily	alex	daily	yves
+daily	alex	monthly	chelsea
+daily	alex	monthly	ethan
+daily	alex	monthly	xavier
+daily	alex	yearly	barry
+daily	alex	yearly	derek
+daily	alex	yearly	faith
+daily	yves	daily	alex
+daily	yves	daily	yves
+daily	yves	monthly	chelsea
+daily	yves	monthly	ethan
+daily	yves	monthly	xavier
+daily	yves	yearly	barry
+daily	yves	yearly	derek
+daily	yves	yearly	faith
+monthly	chelsea	daily	alex
+monthly	chelsea	daily	yves
+monthly	chelsea	monthly	chelsea
+monthly	chelsea	monthly	ethan
+monthly	chelsea	monthly	xavier
+monthly	chelsea	yearly	barry
+monthly	chelsea	yearly	derek
+monthly	chelsea	yearly	faith
+monthly	ethan	daily	alex
+monthly	ethan	daily	yves
+monthly	ethan	monthly	chelsea
+monthly	ethan	monthly	ethan
+monthly	ethan	monthly	xavier
+monthly	ethan	yearly	barry
+monthly	ethan	yearly	derek
+monthly	ethan	yearly	faith
+monthly	xavier	daily	alex
+monthly	xavier	daily	yves
+monthly	xavier	monthly	chelsea
+monthly	xavier	monthly	ethan
+monthly	xavier	monthly	xavier
+monthly	xavier	yearly	barry
+monthly	xavier	yearly	derek
+monthly	xavier	yearly	faith
+yearly	barry	daily	alex
+yearly	barry	daily	yves
+yearly	barry	monthly	chelsea
+yearly	barry	monthly	ethan
+yearly	barry	monthly	xavier
+yearly	barry	yearly	barry
+yearly	barry	yearly	derek
+yearly	barry	yearly	faith
+yearly	derek	daily	alex
+yearly	derek	daily	yves
+yearly	derek	monthly	chelsea
+yearly	derek	monthly	ethan
+yearly	derek	monthly	xavier
+yearly	derek	yearly	barry
+yearly	derek	yearly	derek
+yearly	derek	yearly	faith
+yearly	faith	daily	alex
+yearly	faith	daily	yves
+yearly	faith	monthly	chelsea
+yearly	faith	monthly	ethan
+yearly	faith	monthly	xavier
+yearly	faith	yearly	barry
+yearly	faith	yearly	derek
+yearly	faith	yearly	faith
+#### A masked pattern was here ####
+PREHOOK: type: CREATETABLE
+PREHOOK: Input: hdfs://### HDFS PATH ###
+PREHOOK: Output: database:default
+PREHOOK: Output: default@transition2
+#### A masked pattern was here ####
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Input: hdfs://### HDFS PATH ###
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@transition2
+PREHOOK: query: INSERT INTO transition2 SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@header_footer_table_4
+PREHOOK: Output: default@transition2
+POSTHOOK: query: INSERT INTO transition2 SELECT header_choice, SUM(header_int) FROM header_footer_table_4 GROUP BY header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@header_footer_table_4
+POSTHOOK: Output: default@transition2
+POSTHOOK: Lineage: transition2.header_choice SIMPLE [(header_footer_table_4)header_footer_table_4.FieldSchema(name:header_choice, type:varchar(10), comment:null), ]
+POSTHOOK: Lineage: transition2.sum_header_int EXPRESSION [(header_footer_table_4)header_footer_table_4.FieldSchema(name:header_int, type:int, comment:null), ]
+Warning: Shuffle Join MERGEJOIN[11][tables = [$hdt$_0, $hdt$_1]] in Stage 'Reducer 2' is a cross product
+PREHOOK: query: SELECT * FROM transition2 A, transition2 B ORDER BY A.sum_header_int, A.header_choice, B.sum_header_int, B.header_choice
+PREHOOK: type: QUERY
+PREHOOK: Input: default@transition2
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: SELECT * FROM transition2 A, transition2 B ORDER BY A.sum_header_int, A.header_choice, B.sum_header_int, B.header_choice
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@transition2
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+yearly	13	yearly	13
+yearly	13	monthly	24
+yearly	13	daily	33
+monthly	24	yearly	13
+monthly	24	monthly	24
+monthly	24	daily	33
+daily	33	yearly	13
+daily	33	monthly	24
+daily	33	daily	33
diff --git a/ql/src/test/results/clientpositive/llap/skiphf_aggr2.q.out b/ql/src/test/results/clientpositive/llap/skiphf_aggr2.q.out
new file mode 100644
index 0000000..ba33a10
--- /dev/null
+++ b/ql/src/test/results/clientpositive/llap/skiphf_aggr2.q.out
@@ -0,0 +1,123 @@
+PREHOOK: query: DROP TABLE IF EXISTS hf1
+PREHOOK: type: DROPTABLE
+POSTHOOK: query: DROP TABLE IF EXISTS hf1
+POSTHOOK: type: DROPTABLE
+PREHOOK: query: CREATE TABLE hf1 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.header.line.count'='1')
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@hf1
+POSTHOOK: query: CREATE TABLE hf1 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.header.line.count'='1')
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@hf1
+PREHOOK: query: INSERT OVERWRITE TABLE hf1 VALUES ('x','y'),('a','b'),('c','d')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@hf1
+POSTHOOK: query: INSERT OVERWRITE TABLE hf1 VALUES ('x','y'),('a','b'),('c','d')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@hf1
+POSTHOOK: Lineage: hf1.a SCRIPT []
+POSTHOOK: Lineage: hf1.b SCRIPT []
+PREHOOK: query: SELECT * FROM hf1
+PREHOOK: type: QUERY
+PREHOOK: Input: default@hf1
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT * FROM hf1
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@hf1
+#### A masked pattern was here ####
+a	b
+c	d
+PREHOOK: query: DROP TABLE IF EXISTS hf2
+PREHOOK: type: DROPTABLE
+POSTHOOK: query: DROP TABLE IF EXISTS hf2
+POSTHOOK: type: DROPTABLE
+PREHOOK: query: CREATE TABLE hf2 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.footer.line.count'='2')
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@hf2
+POSTHOOK: query: CREATE TABLE hf2 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.footer.line.count'='2')
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@hf2
+PREHOOK: query: INSERT OVERWRITE TABLE hf2 VALUES ('x','y'),('a','b'),('c','d')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@hf2
+POSTHOOK: query: INSERT OVERWRITE TABLE hf2 VALUES ('x','y'),('a','b'),('c','d')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@hf2
+POSTHOOK: Lineage: hf2.a SCRIPT []
+POSTHOOK: Lineage: hf2.b SCRIPT []
+PREHOOK: query: SELECT * FROM hf2
+PREHOOK: type: QUERY
+PREHOOK: Input: default@hf2
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT * FROM hf2
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@hf2
+#### A masked pattern was here ####
+x	y
+PREHOOK: query: DROP TABLE IF EXISTS hf3
+PREHOOK: type: DROPTABLE
+POSTHOOK: query: DROP TABLE IF EXISTS hf3
+POSTHOOK: type: DROPTABLE
+PREHOOK: query: CREATE TABLE hf3 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.header.line.count'='3')
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@hf3
+POSTHOOK: query: CREATE TABLE hf3 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.header.line.count'='3')
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@hf3
+PREHOOK: query: INSERT OVERWRITE TABLE hf3 VALUES ('x','y'),('a','b'),('c','d')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@hf3
+POSTHOOK: query: INSERT OVERWRITE TABLE hf3 VALUES ('x','y'),('a','b'),('c','d')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@hf3
+POSTHOOK: Lineage: hf3.a SCRIPT []
+POSTHOOK: Lineage: hf3.b SCRIPT []
+PREHOOK: query: SELECT * FROM hf3
+PREHOOK: type: QUERY
+PREHOOK: Input: default@hf3
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT * FROM hf3
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@hf3
+#### A masked pattern was here ####
+PREHOOK: query: DROP TABLE IF EXISTS hf4
+PREHOOK: type: DROPTABLE
+POSTHOOK: query: DROP TABLE IF EXISTS hf4
+POSTHOOK: type: DROPTABLE
+PREHOOK: query: CREATE TABLE hf4 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.header.line.count'='1','skip.footer.line.count'='2')
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@hf4
+POSTHOOK: query: CREATE TABLE hf4 (a string, b string) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' TBLPROPERTIES('skip.header.line.count'='1','skip.footer.line.count'='2')
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@hf4
+PREHOOK: query: INSERT OVERWRITE TABLE hf4 VALUES ('x','y'),('a','b'),('c','d')
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@hf4
+POSTHOOK: query: INSERT OVERWRITE TABLE hf4 VALUES ('x','y'),('a','b'),('c','d')
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@hf4
+POSTHOOK: Lineage: hf4.a SCRIPT []
+POSTHOOK: Lineage: hf4.b SCRIPT []
+PREHOOK: query: SELECT * FROM hf4
+PREHOOK: type: QUERY
+PREHOOK: Input: default@hf4
+#### A masked pattern was here ####
+POSTHOOK: query: SELECT * FROM hf4
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@hf4
+#### A masked pattern was here ####