Index: ql/src/test/results/clientpositive/add_part_exist.q.out =================================================================== --- ql/src/test/results/clientpositive/add_part_exist.q.out (revision 0) +++ ql/src/test/results/clientpositive/add_part_exist.q.out (revision 0) @@ -0,0 +1,56 @@ +PREHOOK: query: CREATE TABLE add_part_test (key STRING, value STRING) PARTITIONED BY (ds STRING) +PREHOOK: type: CREATETABLE +POSTHOOK: query: CREATE TABLE add_part_test (key STRING, value STRING) PARTITIONED BY (ds STRING) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: default@add_part_test +PREHOOK: query: SHOW PARTITIONS add_part_test +PREHOOK: type: SHOWPARTITIONS +POSTHOOK: query: SHOW PARTITIONS add_part_test +POSTHOOK: type: SHOWPARTITIONS +PREHOOK: query: ALTER TABLE add_part_test ADD PARTITION (ds='2010-01-01') +PREHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: query: ALTER TABLE add_part_test ADD PARTITION (ds='2010-01-01') +POSTHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: Output: default@add_part_test@ds=2010-01-01 +PREHOOK: query: SHOW PARTITIONS add_part_test +PREHOOK: type: SHOWPARTITIONS +POSTHOOK: query: SHOW PARTITIONS add_part_test +POSTHOOK: type: SHOWPARTITIONS +ds=2010-01-01 +PREHOOK: query: ALTER TABLE add_part_test ADD IF NOT EXISTS PARTITION (ds='2010-01-01') +PREHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: query: ALTER TABLE add_part_test ADD IF NOT EXISTS PARTITION (ds='2010-01-01') +POSTHOOK: type: ALTERTABLE_ADDPARTS +PREHOOK: query: SHOW PARTITIONS add_part_test +PREHOOK: type: SHOWPARTITIONS +POSTHOOK: query: SHOW PARTITIONS add_part_test +POSTHOOK: type: SHOWPARTITIONS +ds=2010-01-01 +PREHOOK: query: ALTER TABLE add_part_test ADD IF NOT EXISTS PARTITION (ds='2010-01-02') +PREHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: query: ALTER TABLE add_part_test ADD IF NOT EXISTS PARTITION (ds='2010-01-02') +POSTHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: Output: default@add_part_test@ds=2010-01-02 +PREHOOK: query: SHOW PARTITIONS add_part_test +PREHOOK: type: SHOWPARTITIONS +POSTHOOK: query: SHOW PARTITIONS add_part_test +POSTHOOK: type: SHOWPARTITIONS +ds=2010-01-01 +ds=2010-01-02 +PREHOOK: query: ALTER TABLE add_part_test ADD IF NOT EXISTS PARTITION (ds='2010-01-01') PARTITION (ds='2010-01-02') PARTITION (ds='2010-01-03') +PREHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: query: ALTER TABLE add_part_test ADD IF NOT EXISTS PARTITION (ds='2010-01-01') PARTITION (ds='2010-01-02') PARTITION (ds='2010-01-03') +POSTHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: Output: default@add_part_test@ds=2010-01-03 +PREHOOK: query: SHOW PARTITIONS add_part_test +PREHOOK: type: SHOWPARTITIONS +POSTHOOK: query: SHOW PARTITIONS add_part_test +POSTHOOK: type: SHOWPARTITIONS +ds=2010-01-01 +ds=2010-01-02 +ds=2010-01-03 +PREHOOK: query: DROP TABLE add_part_test +PREHOOK: type: DROPTABLE +POSTHOOK: query: DROP TABLE add_part_test +POSTHOOK: type: DROPTABLE +POSTHOOK: Output: default@add_part_test Index: ql/src/test/queries/clientpositive/add_part_exist.q =================================================================== --- ql/src/test/queries/clientpositive/add_part_exist.q (revision 0) +++ ql/src/test/queries/clientpositive/add_part_exist.q (revision 0) @@ -0,0 +1,16 @@ +CREATE TABLE add_part_test (key STRING, value STRING) PARTITIONED BY (ds STRING); +SHOW PARTITIONS add_part_test; + +ALTER TABLE add_part_test ADD PARTITION (ds='2010-01-01'); +SHOW PARTITIONS add_part_test; + +ALTER TABLE add_part_test ADD IF NOT EXISTS PARTITION (ds='2010-01-01'); +SHOW PARTITIONS add_part_test; + +ALTER TABLE add_part_test ADD IF NOT EXISTS PARTITION (ds='2010-01-02'); +SHOW PARTITIONS add_part_test; + +ALTER TABLE add_part_test ADD IF NOT EXISTS PARTITION (ds='2010-01-01') PARTITION (ds='2010-01-02') PARTITION (ds='2010-01-03'); +SHOW PARTITIONS add_part_test; + +DROP TABLE add_part_test; Index: ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java =================================================================== --- ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java (revision 4735) +++ ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java (working copy) @@ -219,6 +219,13 @@ if (tbl.isView()) { throw new HiveException("Cannot use ALTER TABLE on a view"); } + + // If the add partition was created with IF NOT EXISTS, then we should + // not throw an error if the specified part does exist. + Partition checkPart = db.getPartition(tbl, addPartitionDesc.getPartSpec(), false); + if(checkPart != null && addPartitionDesc.getIfNotExists()) { + return 0; + } if (addPartitionDesc.getLocation() == null) { db.createPartition(tbl, addPartitionDesc.getPartSpec()); Index: ql/src/java/org/apache/hadoop/hive/ql/plan/AddPartitionDesc.java =================================================================== --- ql/src/java/org/apache/hadoop/hive/ql/plan/AddPartitionDesc.java (revision 4735) +++ ql/src/java/org/apache/hadoop/hive/ql/plan/AddPartitionDesc.java (working copy) @@ -27,6 +27,7 @@ String tableName; String dbName; String location; + boolean ifNotExists; Map partSpec; /** @@ -38,14 +39,17 @@ * partition specification. * @param location * partition location, relative to table location. + * @param ifNotExists + * if true, the partition is only added if it doesn't exist */ public AddPartitionDesc(String dbName, String tableName, - Map partSpec, String location) { + Map partSpec, String location, boolean ifNotExists) { super(); this.dbName = dbName; this.tableName = tableName; this.partSpec = partSpec; this.location = location; + this.ifNotExists = ifNotExists; } /** @@ -108,4 +112,18 @@ this.partSpec = partSpec; } + /** + * @return if the partition should only be added if it doesn't exist already + */ + public boolean getIfNotExists() { + return this.ifNotExists; + } + + /** + * @param ifNotExists + * if the part should be added only if it doesn't exist + */ + public void setIfNotExists(boolean ifNotExists) { + this.ifNotExists = ifNotExists; + } } \ No newline at end of file Index: ql/src/java/org/apache/hadoop/hive/ql/parse/Hive.g =================================================================== --- ql/src/java/org/apache/hadoop/hive/ql/parse/Hive.g (revision 4735) +++ ql/src/java/org/apache/hadoop/hive/ql/parse/Hive.g (working copy) @@ -307,8 +307,8 @@ alterStatementSuffixAddPartitions @init { msgs.push("add partition statement"); } @after { msgs.pop(); } - : Identifier KW_ADD partitionSpec partitionLocation? (partitionSpec partitionLocation?)* - -> ^(TOK_ALTERTABLE_ADDPARTS Identifier (partitionSpec partitionLocation?)+) + : Identifier KW_ADD ifNotExists? partitionSpec partitionLocation? (partitionSpec partitionLocation?)* + -> ^(TOK_ALTERTABLE_ADDPARTS Identifier ifNotExists? (partitionSpec partitionLocation?)+) ; partitionLocation Index: ql/src/java/org/apache/hadoop/hive/ql/parse/DDLSemanticAnalyzer.java =================================================================== --- ql/src/java/org/apache/hadoop/hive/ql/parse/DDLSemanticAnalyzer.java (revision 4735) +++ ql/src/java/org/apache/hadoop/hive/ql/parse/DDLSemanticAnalyzer.java (working copy) @@ -521,16 +521,20 @@ String currentLocation = null; Map currentPart = null; + boolean ifNotExists = false; int numCh = ast.getChildCount(); for (int num = 1; num < numCh; num++) { CommonTree child = (CommonTree) ast.getChild(num); switch (child.getToken().getType()) { + case HiveParser.TOK_IFNOTEXISTS: + ifNotExists = true; + break; case HiveParser.TOK_PARTSPEC: if (currentPart != null) { AddPartitionDesc addPartitionDesc = new AddPartitionDesc( MetaStoreUtils.DEFAULT_DATABASE_NAME, tblName, currentPart, - currentLocation); + currentLocation, ifNotExists); rootTasks.add(TaskFactory.get(new DDLWork(getInputs(), getOutputs(), addPartitionDesc), conf)); } @@ -551,7 +555,7 @@ if (currentPart != null) { AddPartitionDesc addPartitionDesc = new AddPartitionDesc( MetaStoreUtils.DEFAULT_DATABASE_NAME, tblName, currentPart, - currentLocation); + currentLocation, ifNotExists); rootTasks.add(TaskFactory.get(new DDLWork(getInputs(), getOutputs(), addPartitionDesc), conf)); }