You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hive.apache.org by we...@apache.org on 2016/10/18 22:17:17 UTC
hive git commit: HIVE-14878 : integrate MM tables into ACID: add
separate ACID type (Wei Zheng) [Forced Update!]
Repository: hive
Updated Branches:
refs/heads/hive-14535 c7fb2dbaa -> b6571eaef (forced update)
HIVE-14878 : integrate MM tables into ACID: add separate ACID type (Wei Zheng)
Project: http://git-wip-us.apache.org/repos/asf/hive/repo
Commit: http://git-wip-us.apache.org/repos/asf/hive/commit/b6571eae
Tree: http://git-wip-us.apache.org/repos/asf/hive/tree/b6571eae
Diff: http://git-wip-us.apache.org/repos/asf/hive/diff/b6571eae
Branch: refs/heads/hive-14535
Commit: b6571eaef2659672a9d3cdf36e2fa6f2168f8063
Parents: 9ecffcb
Author: Wei Zheng <we...@apache.org>
Authored: Tue Oct 18 15:13:20 2016 -0700
Committer: Wei Zheng <we...@apache.org>
Committed: Tue Oct 18 15:14:33 2016 -0700
----------------------------------------------------------------------
.../org/apache/hadoop/hive/conf/HiveConf.java | 10 +-
.../TransactionalValidationListener.java | 39 ++++---
.../hadoop/hive/ql/exec/FileSinkOperator.java | 15 ++-
.../apache/hadoop/hive/ql/exec/MoveTask.java | 3 +-
.../org/apache/hadoop/hive/ql/io/AcidUtils.java | 44 ++++++-
.../hadoop/hive/ql/parse/SemanticAnalyzer.java | 34 +++---
.../queries/clientpositive/mm_insertonly_acid.q | 16 +++
.../clientpositive/mm_insertonly_acid.q.out | 115 +++++++++++++++++++
8 files changed, 236 insertions(+), 40 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hive/blob/b6571eae/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
----------------------------------------------------------------------
diff --git a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
index 23314ed..ccc29f8 100644
--- a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
+++ b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java
@@ -1787,10 +1787,12 @@ public class HiveConf extends Configuration {
HIVE_TXN_OPERATIONAL_PROPERTIES("hive.txn.operational.properties", 0,
"Sets the operational properties that control the appropriate behavior for various\n"
- + "versions of the Hive ACID subsystem. Setting it to zero will turn on the legacy mode\n"
- + "for ACID, while setting it to one will enable a split-update feature found in the newer\n"
- + "version of Hive ACID subsystem. Mostly it is intended to be used as an internal property\n"
- + "for future versions of ACID. (See HIVE-14035 for details.)"),
+ + "versions of the Hive ACID subsystem. Mostly it is intended to be used as an internal property\n"
+ + "for future versions of ACID. (See HIVE-14035 for details.)\n"
+ + "0: Turn on the legacy mode for ACID\n"
+ + "1: Enable split-update feature found in the newer version of Hive ACID subsystem\n"
+ + "2: Hash-based merge, which combines delta files using GRACE hash join based approach (not implemented)\n"
+ + "3: Make the table 'quarter-acid' as it only supports insert. But it doesn't require ORC or bucketing."),
HIVE_MAX_OPEN_TXNS("hive.max.open.txns", 100000, "Maximum number of open transactions. If \n" +
"current open transactions reach this limit, future open transaction requests will be \n" +
http://git-wip-us.apache.org/repos/asf/hive/blob/b6571eae/metastore/src/java/org/apache/hadoop/hive/metastore/TransactionalValidationListener.java
----------------------------------------------------------------------
diff --git a/metastore/src/java/org/apache/hadoop/hive/metastore/TransactionalValidationListener.java b/metastore/src/java/org/apache/hadoop/hive/metastore/TransactionalValidationListener.java
index 0f08f43..f942479 100644
--- a/metastore/src/java/org/apache/hadoop/hive/metastore/TransactionalValidationListener.java
+++ b/metastore/src/java/org/apache/hadoop/hive/metastore/TransactionalValidationListener.java
@@ -40,6 +40,7 @@ public final class TransactionalValidationListener extends MetaStorePreEventList
// These constants are also imported by org.apache.hadoop.hive.ql.io.AcidUtils.
public static final String DEFAULT_TRANSACTIONAL_PROPERTY = "default";
public static final String LEGACY_TRANSACTIONAL_PROPERTY = "legacy";
+ public static final String INSERTONLY_TRANSACTIONAL_PROPERTY = "insert_only";
TransactionalValidationListener(Configuration conf) {
super(conf);
@@ -105,8 +106,11 @@ public final class TransactionalValidationListener extends MetaStorePreEventList
}
if ("true".equalsIgnoreCase(transactionalValue)) {
if (!conformToAcid(newTable)) {
- throw new MetaException("The table must be bucketed and stored using an ACID compliant" +
- " format (such as ORC)");
+ // INSERT_ONLY tables don't have to conform to ACID requirement like ORC or bucketing
+ if (transactionalPropertiesValue == null || !"insert_only".equalsIgnoreCase(transactionalPropertiesValue)) {
+ throw new MetaException("The table must be bucketed and stored using an ACID compliant" +
+ " format (such as ORC)");
+ }
}
if (newTable.getTableType().equals(TableType.EXTERNAL_TABLE.toString())) {
@@ -172,32 +176,40 @@ public final class TransactionalValidationListener extends MetaStorePreEventList
if (parameters == null || parameters.isEmpty()) {
return;
}
- String transactionalValue = null;
- boolean transactionalPropFound = false;
+ String transactional = null;
+ String transactionalProperties = null;
Set<String> keys = new HashSet<>(parameters.keySet());
for(String key : keys) {
- if(hive_metastoreConstants.TABLE_IS_TRANSACTIONAL.equalsIgnoreCase(key)) {
- transactionalPropFound = true;
- transactionalValue = parameters.get(key);
+ // Get the "transactional" tblproperties value
+ if (hive_metastoreConstants.TABLE_IS_TRANSACTIONAL.equalsIgnoreCase(key)) {
+ transactional = parameters.get(key);
parameters.remove(key);
}
+
+ // Get the "transactional_properties" tblproperties value
+ if (hive_metastoreConstants.TABLE_TRANSACTIONAL_PROPERTIES.equalsIgnoreCase(key)) {
+ transactionalProperties = parameters.get(key);
+ }
}
- if (!transactionalPropFound) {
+ if (transactional == null) {
return;
}
- if ("false".equalsIgnoreCase(transactionalValue)) {
+ if ("false".equalsIgnoreCase(transactional)) {
// just drop transactional=false. For backward compatibility in case someone has scripts
// with transactional=false
LOG.info("'transactional'='false' is no longer a valid property and will be ignored");
return;
}
- if ("true".equalsIgnoreCase(transactionalValue)) {
+ if ("true".equalsIgnoreCase(transactional)) {
if (!conformToAcid(newTable)) {
- throw new MetaException("The table must be bucketed and stored using an ACID compliant" +
- " format (such as ORC)");
+ // INSERT_ONLY tables don't have to conform to ACID requirement like ORC or bucketing
+ if (transactionalProperties == null || !"insert_only".equalsIgnoreCase(transactionalProperties)) {
+ throw new MetaException("The table must be bucketed and stored using an ACID compliant" +
+ " format (such as ORC)");
+ }
}
if (newTable.getTableType().equals(TableType.EXTERNAL_TABLE.toString())) {
@@ -211,7 +223,7 @@ public final class TransactionalValidationListener extends MetaStorePreEventList
return;
}
- // transactional prop is found, but the value is not in expected range
+ // transactional is found, but the value is not in expected range
throw new MetaException("'transactional' property of TBLPROPERTIES may only have value 'true'");
}
@@ -277,6 +289,7 @@ public final class TransactionalValidationListener extends MetaStorePreEventList
switch (transactionalProperties) {
case DEFAULT_TRANSACTIONAL_PROPERTY:
case LEGACY_TRANSACTIONAL_PROPERTY:
+ case INSERTONLY_TRANSACTIONAL_PROPERTY:
isValid = true;
break;
default:
http://git-wip-us.apache.org/repos/asf/hive/blob/b6571eae/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
index ef6473a..c54187f 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/FileSinkOperator.java
@@ -678,7 +678,8 @@ public class FileSinkOperator extends TerminalOperator<FileSinkDesc> implements
Utilities.copyTableJobPropertiesToConf(conf.getTableInfo(), jc);
// only create bucket files only if no dynamic partitions,
// buckets of dynamic partitions will be created for each newly created partition
- if (conf.getWriteType() == AcidUtils.Operation.NOT_ACID) {
+ if (conf.getWriteType() == AcidUtils.Operation.NOT_ACID ||
+ conf.getWriteType() == AcidUtils.Operation.INSERT_ONLY) {
fsp.outWriters[filesIdx] = HiveFileFormatUtils.getHiveRecordWriter(jc, conf.getTableInfo(),
outputClass, conf, fsp.outPaths[filesIdx], reporter);
// If the record writer provides stats, get it from there instead of the serde
@@ -821,7 +822,8 @@ public class FileSinkOperator extends TerminalOperator<FileSinkDesc> implements
// for a given operator branch prediction should work quite nicely on it.
// RecordUpdateer expects to get the actual row, not a serialized version of it. Thus we
// pass the row rather than recordValue.
- if (conf.getWriteType() == AcidUtils.Operation.NOT_ACID) {
+ if (conf.getWriteType() == AcidUtils.Operation.NOT_ACID ||
+ conf.getWriteType() == AcidUtils.Operation.INSERT_ONLY) {
rowOutWriters[writerOffset].write(recordValue);
} else if (conf.getWriteType() == AcidUtils.Operation.INSERT) {
fpaths.updaters[writerOffset].insert(conf.getTransactionId(), row);
@@ -865,7 +867,8 @@ public class FileSinkOperator extends TerminalOperator<FileSinkDesc> implements
protected boolean areAllTrue(boolean[] statsFromRW) {
// If we are doing an acid operation they will always all be true as RecordUpdaters always
// collect stats
- if (conf.getWriteType() != AcidUtils.Operation.NOT_ACID) {
+ if (conf.getWriteType() != AcidUtils.Operation.NOT_ACID &&
+ conf.getWriteType() != AcidUtils.Operation.INSERT_ONLY) {
return true;
}
for(boolean b : statsFromRW) {
@@ -1008,7 +1011,8 @@ public class FileSinkOperator extends TerminalOperator<FileSinkDesc> implements
// stats from the record writer and store in the previous fsp that is cached
if (conf.isGatherStats() && isCollectRWStats) {
SerDeStats stats = null;
- if (conf.getWriteType() == AcidUtils.Operation.NOT_ACID) {
+ if (conf.getWriteType() == AcidUtils.Operation.NOT_ACID ||
+ conf.getWriteType() == AcidUtils.Operation.INSERT_ONLY) {
RecordWriter outWriter = prevFsp.outWriters[0];
if (outWriter != null) {
stats = ((StatsProvidingRecordWriter) outWriter).getStats();
@@ -1112,7 +1116,8 @@ public class FileSinkOperator extends TerminalOperator<FileSinkDesc> implements
// record writer already gathers the statistics, it can simply return the
// accumulated statistics which will be aggregated in case of spray writers
if (conf.isGatherStats() && isCollectRWStats) {
- if (conf.getWriteType() == AcidUtils.Operation.NOT_ACID) {
+ if (conf.getWriteType() == AcidUtils.Operation.NOT_ACID ||
+ conf.getWriteType() == AcidUtils.Operation.INSERT_ONLY) {
for (int idx = 0; idx < fsp.outWriters.length; idx++) {
RecordWriter outWriter = fsp.outWriters[idx];
if (outWriter != null) {
http://git-wip-us.apache.org/repos/asf/hive/blob/b6571eae/ql/src/java/org/apache/hadoop/hive/ql/exec/MoveTask.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/MoveTask.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/MoveTask.java
index f2b8ca3..74a650d 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/exec/MoveTask.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/MoveTask.java
@@ -389,7 +389,8 @@ public class MoveTask extends Task<MoveWork> implements Serializable {
db.loadSinglePartition(tbd.getSourcePath(), tbd.getTable().getTableName(),
tbd.getPartitionSpec(), tbd.getReplace(),
tbd.getInheritTableSpecs(), isSkewedStoredAsDirs(tbd), work.isSrcLocal(),
- work.getLoadTableWork().getWriteType() != AcidUtils.Operation.NOT_ACID,
+ (work.getLoadTableWork().getWriteType() != AcidUtils.Operation.NOT_ACID &&
+ work.getLoadTableWork().getWriteType() != AcidUtils.Operation.INSERT_ONLY),
hasFollowingStatsTask(), tbd.getMmWriteId());
Partition partn = db.getPartition(table, tbd.getPartitionSpec(), false);
http://git-wip-us.apache.org/repos/asf/hive/blob/b6571eae/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java b/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java
index 7351bbe..ecbc216 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/io/AcidUtils.java
@@ -275,8 +275,9 @@ public class AcidUtils {
return result;
}
+ // INSERT_ONLY is a special operation which we only support INSERT operations, no UPDATE/DELETE
public enum Operation {
- NOT_ACID, INSERT, UPDATE, DELETE;
+ NOT_ACID, INSERT, UPDATE, DELETE, INSERT_ONLY
}
/**
@@ -344,8 +345,11 @@ public class AcidUtils {
public static final String SPLIT_UPDATE_STRING = "split_update";
public static final int HASH_BASED_MERGE_BIT = 0x02;
public static final String HASH_BASED_MERGE_STRING = "hash_merge";
+ public static final int INSERT_ONLY_BIT = 0x03;
+ public static final String INSERT_ONLY_STRING = "insert_only";
public static final String DEFAULT_VALUE_STRING = TransactionalValidationListener.DEFAULT_TRANSACTIONAL_PROPERTY;
public static final String LEGACY_VALUE_STRING = TransactionalValidationListener.LEGACY_TRANSACTIONAL_PROPERTY;
+ public static final String INSERTONLY_VALUE_STRING = TransactionalValidationListener.INSERTONLY_TRANSACTIONAL_PROPERTY;
private AcidOperationalProperties() {
}
@@ -374,6 +378,17 @@ public class AcidUtils {
}
/**
+ * Returns an acidOperationalProperties object for tables that uses ACID framework but only
+ * supports INSERT operation and does not require ORC or bucketing
+ * @return the acidOperationalProperties object
+ */
+ public static AcidOperationalProperties getInsertOnly() {
+ AcidOperationalProperties obj = new AcidOperationalProperties();
+ obj.setInsertOnly(true);
+ return obj;
+ }
+
+ /**
* Returns an acidOperationalProperties object that is represented by an encoded string.
* @param propertiesStr an encoded string representing the acidOperationalProperties.
* @return the acidOperationalProperties object.
@@ -388,6 +403,9 @@ public class AcidUtils {
if (propertiesStr.equalsIgnoreCase(LEGACY_VALUE_STRING)) {
return AcidOperationalProperties.getLegacy();
}
+ if (propertiesStr.equalsIgnoreCase(INSERTONLY_VALUE_STRING)) {
+ return AcidOperationalProperties.getInsertOnly();
+ }
AcidOperationalProperties obj = new AcidOperationalProperties();
String[] options = propertiesStr.split("\\|");
for (String option : options) {
@@ -448,6 +466,12 @@ public class AcidUtils {
return this;
}
+ public AcidOperationalProperties setInsertOnly(boolean isInsertOnly) {
+ description = (isInsertOnly
+ ? (description | INSERT_ONLY_BIT) : (description & ~INSERT_ONLY_BIT));
+ return this;
+ }
+
public boolean isSplitUpdate() {
return (description & SPLIT_UPDATE_BIT) > 0;
}
@@ -456,6 +480,10 @@ public class AcidUtils {
return (description & HASH_BASED_MERGE_BIT) > 0;
}
+ public boolean isInsertOnly() {
+ return (description & INSERT_ONLY_BIT) > 0;
+ }
+
public int toInt() {
return description;
}
@@ -469,6 +497,9 @@ public class AcidUtils {
if (isHashBasedMerge()) {
str.append("|" + HASH_BASED_MERGE_STRING);
}
+ if (isInsertOnly()) {
+ str.append("|" + INSERT_ONLY_STRING);
+ }
return str.toString();
}
}
@@ -1078,6 +1109,17 @@ public class AcidUtils {
}
/**
+ * Checks if a table is an ACID table that only supports INSERT, but not UPDATE/DELETE
+ * @param table table
+ * @return true if table is an INSERT_ONLY table, false otherwise
+ */
+ public static boolean isInsertOnlyTable(Table table) {
+ String transactionalProp = table.getProperty(hive_metastoreConstants.TABLE_TRANSACTIONAL_PROPERTIES);
+ return transactionalProp != null &&
+ AcidUtils.AcidOperationalProperties.INSERT_ONLY_STRING.equals(transactionalProp);
+ }
+
+ /**
* Sets the acidOperationalProperties in the configuration object argument.
* @param conf Mutable configuration object
* @param properties An acidOperationalProperties object to initialize from.
http://git-wip-us.apache.org/repos/asf/hive/blob/b6571eae/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
----------------------------------------------------------------------
diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
index 62faf89..f74c0a9 100644
--- a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
+++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java
@@ -6455,7 +6455,8 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer {
nullOrder.append(sortOrder == BaseSemanticAnalyzer.HIVE_COLUMN_ORDER_ASC ? 'a' : 'z');
}
input = genReduceSinkPlan(input, partnCols, sortCols, order.toString(), nullOrder.toString(),
- maxReducers, (AcidUtils.isAcidTable(dest_tab) ? getAcidType() : AcidUtils.Operation.NOT_ACID));
+ maxReducers, (AcidUtils.isAcidTable(dest_tab) ?
+ getAcidType(dest_tab, table_desc.getOutputFileFormatClass()) : AcidUtils.Operation.NOT_ACID));
reduceSinkOperatorsAddedByEnforceBucketingSorting.add((ReduceSinkOperator)input.getParentOperators().get(0));
ctx.setMultiFileSpray(multiFileSpray);
ctx.setNumFiles(numFiles);
@@ -6588,8 +6589,8 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer {
if (!isNonNativeTable) {
AcidUtils.Operation acidOp = AcidUtils.Operation.NOT_ACID;
if (destTableIsAcid) {
- acidOp = getAcidType(table_desc.getOutputFileFormatClass());
- checkAcidConstraints(qb, table_desc, dest_tab);
+ acidOp = getAcidType(dest_tab, table_desc.getOutputFileFormatClass());
+ checkAcidConstraints(qb, table_desc, dest_tab, acidOp);
}
try {
mmWriteId = getMmWriteId(dest_tab, isMmTable);
@@ -6648,8 +6649,8 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer {
dest_part.isStoredAsSubDirectories(), conf);
AcidUtils.Operation acidOp = AcidUtils.Operation.NOT_ACID;
if (destTableIsAcid) {
- acidOp = getAcidType(table_desc.getOutputFileFormatClass());
- checkAcidConstraints(qb, table_desc, dest_tab);
+ acidOp = getAcidType(dest_tab, table_desc.getOutputFileFormatClass());
+ checkAcidConstraints(qb, table_desc, dest_tab, acidOp);
}
try {
mmWriteId = getMmWriteId(dest_tab, isMmTable);
@@ -6945,7 +6946,7 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer {
fileSinkDesc.setHiveServerQuery(SessionState.get().isHiveServerQuery());
// If this is an insert, update, or delete on an ACID table then mark that so the
// FileSinkOperator knows how to properly write to it.
- if (destTableIsAcid) {
+ if (destTableIsAcid && !AcidUtils.isInsertOnlyTable(dest_part.getTable())) {
AcidUtils.Operation wt = updating() ? AcidUtils.Operation.UPDATE :
(deleting() ? AcidUtils.Operation.DELETE : AcidUtils.Operation.INSERT);
fileSinkDesc.setWriteType(wt);
@@ -7141,7 +7142,7 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer {
// This method assumes you have already decided that this is an Acid write. Don't call it if
// that isn't true.
private void checkAcidConstraints(QB qb, TableDesc tableDesc,
- Table table) throws SemanticException {
+ Table table, AcidUtils.Operation acidOp) throws SemanticException {
String tableName = tableDesc.getTableName();
if (!qb.getParseInfo().isInsertIntoTable(tableName)) {
LOG.debug("Couldn't find table " + tableName + " in insertIntoTable");
@@ -7158,15 +7159,14 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer {
*/
conf.set(AcidUtils.CONF_ACID_KEY, "true");
- if (table.getNumBuckets() < 1) {
- throw new SemanticException(ErrorMsg.ACID_OP_ON_NONACID_TABLE, table.getTableName());
- }
- if (table.getSortCols() != null && table.getSortCols().size() > 0) {
- throw new SemanticException(ErrorMsg.ACID_NO_SORTED_BUCKETS, table.getTableName());
+ if (!Operation.NOT_ACID.equals(acidOp) && !Operation.INSERT_ONLY.equals(acidOp)) {
+ if (table.getNumBuckets() < 1) {
+ throw new SemanticException(ErrorMsg.ACID_OP_ON_NONACID_TABLE, table.getTableName());
+ }
+ if (table.getSortCols() != null && table.getSortCols().size() > 0) {
+ throw new SemanticException(ErrorMsg.ACID_NO_SORTED_BUCKETS, table.getTableName());
+ }
}
-
-
-
}
/**
@@ -13118,9 +13118,11 @@ public class SemanticAnalyzer extends BaseSemanticAnalyzer {
AcidUtils.Operation.INSERT);
}
- private AcidUtils.Operation getAcidType(Class<? extends OutputFormat> of) {
+ private AcidUtils.Operation getAcidType(Table table, Class<? extends OutputFormat> of) {
if (SessionState.get() == null || !SessionState.get().getTxnMgr().supportsAcid()) {
return AcidUtils.Operation.NOT_ACID;
+ } else if (AcidUtils.isInsertOnlyTable(table)) {
+ return AcidUtils.Operation.INSERT_ONLY;
} else if (isAcidOutputFormat(of)) {
return getAcidType();
} else {
http://git-wip-us.apache.org/repos/asf/hive/blob/b6571eae/ql/src/test/queries/clientpositive/mm_insertonly_acid.q
----------------------------------------------------------------------
diff --git a/ql/src/test/queries/clientpositive/mm_insertonly_acid.q b/ql/src/test/queries/clientpositive/mm_insertonly_acid.q
new file mode 100644
index 0000000..7da99c5
--- /dev/null
+++ b/ql/src/test/queries/clientpositive/mm_insertonly_acid.q
@@ -0,0 +1,16 @@
+set hive.mapred.mode=nonstrict;
+set hive.explain.user=false;
+set hive.fetch.task.conversion=none;
+set hive.exec.dynamic.partition.mode=nonstrict;
+set hive.support.concurrency=true;
+set hive.txn.manager=org.apache.hadoop.hive.ql.lockmgr.DbTxnManager;
+
+
+drop table qtr_acid;
+create table qtr_acid (key int) partitioned by (p int) tblproperties ("transactional"="true", "transactional_properties"="insert_only");
+insert into table qtr_acid partition(p='123') select distinct key from src where key > 0 order by key asc limit 10;
+insert into table qtr_acid partition(p='456') select distinct key from src where key > 0 order by key desc limit 10;
+explain
+select * from qtr_acid order by key;
+select * from qtr_acid order by key;
+drop table qtr_acid;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/hive/blob/b6571eae/ql/src/test/results/clientpositive/mm_insertonly_acid.q.out
----------------------------------------------------------------------
diff --git a/ql/src/test/results/clientpositive/mm_insertonly_acid.q.out b/ql/src/test/results/clientpositive/mm_insertonly_acid.q.out
new file mode 100644
index 0000000..6f7d198
--- /dev/null
+++ b/ql/src/test/results/clientpositive/mm_insertonly_acid.q.out
@@ -0,0 +1,115 @@
+PREHOOK: query: drop table qtr_acid
+PREHOOK: type: DROPTABLE
+POSTHOOK: query: drop table qtr_acid
+POSTHOOK: type: DROPTABLE
+PREHOOK: query: create table qtr_acid (key int) partitioned by (p int) tblproperties ("transactional"="true", "transactional_properties"="insert_only")
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@qtr_acid
+POSTHOOK: query: create table qtr_acid (key int) partitioned by (p int) tblproperties ("transactional"="true", "transactional_properties"="insert_only")
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@qtr_acid
+PREHOOK: query: insert into table qtr_acid partition(p='123') select distinct key from src where key > 0 order by key asc limit 10
+PREHOOK: type: QUERY
+PREHOOK: Input: default@src
+PREHOOK: Output: default@qtr_acid@p=123
+POSTHOOK: query: insert into table qtr_acid partition(p='123') select distinct key from src where key > 0 order by key asc limit 10
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@src
+POSTHOOK: Output: default@qtr_acid@p=123
+POSTHOOK: Lineage: qtr_acid PARTITION(p=123).key EXPRESSION [(src)src.FieldSchema(name:key, type:string, comment:default), ]
+PREHOOK: query: insert into table qtr_acid partition(p='456') select distinct key from src where key > 0 order by key desc limit 10
+PREHOOK: type: QUERY
+PREHOOK: Input: default@src
+PREHOOK: Output: default@qtr_acid@p=456
+POSTHOOK: query: insert into table qtr_acid partition(p='456') select distinct key from src where key > 0 order by key desc limit 10
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@src
+POSTHOOK: Output: default@qtr_acid@p=456
+POSTHOOK: Lineage: qtr_acid PARTITION(p=456).key EXPRESSION [(src)src.FieldSchema(name:key, type:string, comment:default), ]
+PREHOOK: query: explain
+select * from qtr_acid order by key
+PREHOOK: type: QUERY
+POSTHOOK: query: explain
+select * from qtr_acid order by key
+POSTHOOK: type: QUERY
+STAGE DEPENDENCIES:
+ Stage-1 is a root stage
+ Stage-0 depends on stages: Stage-1
+
+STAGE PLANS:
+ Stage: Stage-1
+ Map Reduce
+ Map Operator Tree:
+ TableScan
+ alias: qtr_acid
+ Statistics: Num rows: 16 Data size: 67 Basic stats: COMPLETE Column stats: NONE
+ Select Operator
+ expressions: key (type: int), p (type: int)
+ outputColumnNames: _col0, _col1
+ Statistics: Num rows: 16 Data size: 67 Basic stats: COMPLETE Column stats: NONE
+ Reduce Output Operator
+ key expressions: _col0 (type: int)
+ sort order: +
+ Statistics: Num rows: 16 Data size: 67 Basic stats: COMPLETE Column stats: NONE
+ value expressions: _col1 (type: int)
+ Reduce Operator Tree:
+ Select Operator
+ expressions: KEY.reducesinkkey0 (type: int), VALUE._col0 (type: int)
+ outputColumnNames: _col0, _col1
+ Statistics: Num rows: 16 Data size: 67 Basic stats: COMPLETE Column stats: NONE
+ File Output Operator
+ compressed: false
+ Statistics: Num rows: 16 Data size: 67 Basic stats: COMPLETE Column stats: NONE
+ table:
+ input format: org.apache.hadoop.mapred.SequenceFileInputFormat
+ output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
+ serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
+
+ Stage: Stage-0
+ Fetch Operator
+ limit: -1
+ Processor Tree:
+ ListSink
+
+PREHOOK: query: select * from qtr_acid order by key
+PREHOOK: type: QUERY
+PREHOOK: Input: default@qtr_acid
+PREHOOK: Input: default@qtr_acid@p=123
+PREHOOK: Input: default@qtr_acid@p=456
+#### A masked pattern was here ####
+POSTHOOK: query: select * from qtr_acid order by key
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@qtr_acid
+POSTHOOK: Input: default@qtr_acid@p=123
+POSTHOOK: Input: default@qtr_acid@p=456
+#### A masked pattern was here ####
+9 456
+10 123
+11 123
+85 456
+86 456
+87 456
+90 456
+92 456
+95 456
+96 456
+97 456
+98 456
+100 123
+103 123
+104 123
+105 123
+111 123
+113 123
+114 123
+116 123
+PREHOOK: query: drop table qtr_acid
+PREHOOK: type: DROPTABLE
+PREHOOK: Input: default@qtr_acid
+PREHOOK: Output: default@qtr_acid
+POSTHOOK: query: drop table qtr_acid
+POSTHOOK: type: DROPTABLE
+POSTHOOK: Input: default@qtr_acid
+POSTHOOK: Output: default@qtr_acid