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 4694) +++ ql/src/java/org/apache/hadoop/hive/ql/exec/DDLTask.java (working copy) @@ -203,6 +203,13 @@ Table tbl = db.getTable(addPartitionDesc.getDbName(), addPartitionDesc.getTableName()); + // 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()); } else { Index: ql/src/java/org/apache/hadoop/hive/ql/plan/AddPartitionDesc.java =================================================================== --- ql/src/java/org/apache/hadoop/hive/ql/plan/AddPartitionDesc.java (revision 4694) +++ 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; /** @@ -34,14 +35,16 @@ * @param tableName table to add to. * @param partSpec 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; } /** @@ -100,4 +103,17 @@ 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 4694) +++ ql/src/java/org/apache/hadoop/hive/ql/parse/Hive.g (working copy) @@ -303,8 +303,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 4694) +++ ql/src/java/org/apache/hadoop/hive/ql/parse/DDLSemanticAnalyzer.java (working copy) @@ -491,16 +491,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); + tblName, currentPart, currentLocation, ifNotExists); rootTasks.add(TaskFactory.get(new DDLWork(getInputs(), getOutputs(), addPartitionDesc), conf)); } //create new partition, set values @@ -520,7 +524,7 @@ if(currentPart != null) { AddPartitionDesc addPartitionDesc = new AddPartitionDesc(MetaStoreUtils.DEFAULT_DATABASE_NAME, - tblName, currentPart, currentLocation); + tblName, currentPart, currentLocation, ifNotExists); rootTasks.add(TaskFactory.get(new DDLWork(getInputs(), getOutputs(), addPartitionDesc), conf)); } }