Merge master into db_policy_store branch
diff --git a/bin/sentry.sh b/bin/sentry.sh
deleted file mode 100644
index 76d550b..0000000
--- a/bin/sentry.sh
+++ /dev/null
@@ -1,112 +0,0 @@
-#!/bin/bash
-#
-#
-# 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.
-#
-
-################################
-# functions
-################################
-
-info() {
-  local msg=$1
-  echo "Info: $msg" >&2
-}
-
-warn() {
-  local msg=$1
-  echo "Warning: $msg" >&2
-}
-
-error() {
-  local msg=$1
-  local exit_code=$2
-
-  echo "Error: $msg" >&2
-
-  if [ -n "$exit_code" ] ; then
-    exit $exit_code
-  fi
-}
-
-################################
-# main
-################################
-
-# set default params
-SENTRY_CLASSPATH=""
-
-if [ -z "${SENTRY_HOME}" ]; then
-  SENTRY_HOME=$(cd $(dirname $0)/..; pwd)
-fi
-
-if [ -f ${SENTRY_HOME}/etc/sentry-env.sh ]
-then
-  . ${SENTRY_HOME}/etc/sentry-env.sh
-fi
-
-# prepend $SENTRY_HOME/lib jars to the specified classpath (if any)
-if [ -n "${SENTRY_CLASSPATH}" ] ; then
-  SENTRY_CLASSPATH="${SENTRY_HOME}/lib/*:$SENTRY_CLASSPATH"
-else
-  SENTRY_CLASSPATH="${SENTRY_HOME}/lib/*"
-fi
-
-# find java
-if [ -z "${JAVA_HOME}" ] ; then
-  warn "JAVA_HOME is not set!"
-  # Try to use Bigtop to autodetect JAVA_HOME if it's available
-  if [ -e /usr/libexec/bigtop-detect-javahome ] ; then
-    . /usr/libexec/bigtop-detect-javahome
-  elif [ -e /usr/lib/bigtop-utils/bigtop-detect-javahome ] ; then
-    . /usr/lib/bigtop-utils/bigtop-detect-javahome
-  fi
-
-  # Using java from path if bigtop is not installed or couldn't find it
-  if [ -z "${JAVA_HOME}" ] ; then
-    JAVA_DEFAULT=$(type -p java)
-    [ -n "$JAVA_DEFAULT" ] || error "Unable to find java executable. Is it in your PATH?" 1
-    JAVA_HOME=$(cd $(dirname $JAVA_DEFAULT)/..; pwd)
-  fi
-fi
-
-# look for hadoop libs
-HADOOP_IN_PATH=$(PATH="${HADOOP_HOME:-${HADOOP_PREFIX}}/bin:$PATH" \
-    which hadoop 2>/dev/null)
-if [ ! -f "${HADOOP_IN_PATH}" ]; then
-  error "Cannot find Hadoop command in path"
-fi
-
-info "Including Hadoop libraries found via ($HADOOP_IN_PATH)"
-
-# determine hadoop classpath
-HADOOP_CLASSPATH=$($HADOOP_IN_PATH classpath)
-
-# hack up and filter hadoop classpath
-ELEMENTS=$(sed -e 's/:/ /g' <<<${HADOOP_CLASSPATH})
-for ELEMENT in $ELEMENTS; do
-  for PIECE in $(echo $ELEMENT); do
-    if [[ $PIECE =~ slf4j-(api|log4j12).*\.jar ]]; then
-      info "Excluding $PIECE from classpath"
-      continue
-    else
-      SENTRY_CLASSPATH="$SENTRY_CLASSPATH:$PIECE"
-    fi
-  done
-done
-exec $JAVA_HOME/bin/java $SENTRY_OPTS -cp "$SENTRY_CLASSPATH" org.apache.sentry.SentryMain "$@"
diff --git a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java
index eb54807..5ff7764 100644
--- a/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java
+++ b/sentry-binding/sentry-binding-hive/src/main/java/org/apache/sentry/binding/hive/HiveAuthzBindingHook.java
@@ -227,10 +227,16 @@
       return getCanonicalDb();
     }
   }
-  private AccessURI extractPartition(ASTNode ast) throws SemanticException {
-    if(ast.getChildCount() > 2) {
-      return parseURI(BaseSemanticAnalyzer.
-          unescapeSQLString(ast.getChild(2).getChild(0).getText()));
+
+  @VisibleForTesting
+  protected static AccessURI extractPartition(ASTNode ast) throws SemanticException {
+    for (int i = 0; i < ast.getChildCount(); i++) {
+      ASTNode child = (ASTNode)ast.getChild(i);
+      if (child.getToken().getType() == HiveParser.TOK_PARTITIONLOCATION &&
+          child.getChildCount() == 1) {
+        return parseURI(BaseSemanticAnalyzer.
+          unescapeSQLString(child.getChild(0).getText()));
+      }
     }
     return null;
   }
diff --git a/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/TestHiveAuthzBindingHook.java b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/TestHiveAuthzBindingHook.java
new file mode 100644
index 0000000..9dd4774
--- /dev/null
+++ b/sentry-binding/sentry-binding-hive/src/test/java/org/apache/sentry/binding/hive/TestHiveAuthzBindingHook.java
@@ -0,0 +1,86 @@
+/*
+ * 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.sentry.binding.hive;
+
+import org.apache.hadoop.hive.conf.HiveConf;
+import org.apache.hadoop.hive.ql.parse.ASTNode;
+import org.apache.hadoop.hive.ql.parse.ParseDriver;
+import org.apache.hadoop.hive.ql.parse.ParseUtils;
+import org.apache.hadoop.hive.ql.session.SessionState;
+import org.apache.sentry.core.model.db.AccessURI;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestHiveAuthzBindingHook {
+  private static final Logger LOG = LoggerFactory
+      .getLogger(TestHiveAuthzBindingHook.class);
+
+  private ParseDriver parseDriver;
+  private HiveConf conf;
+
+  @Before
+  public void setupTest() throws Exception {
+    conf = new HiveConf();
+    SessionState.start(conf);
+    parseDriver = new ParseDriver();
+  }
+
+  @Test
+  public void testAddPartition() throws Exception {
+    ASTNode ast = parse("alter table parted add partition (day='Monday')");
+    LOG.info("AST: " + ast.toStringTree());
+    AccessURI partitionLocation = HiveAuthzBindingHook.extractPartition(ast);
+    Assert.assertNull("Query without part location should not return location",
+        partitionLocation);
+  }
+  @Test
+  public void testAddPartitionWithLocation() throws Exception {
+    ASTNode ast = parse("alter table parted add partition (day='Monday') location 'file:/'");
+    LOG.info("AST: " + ast.toStringTree());
+    AccessURI partitionLocation = HiveAuthzBindingHook.extractPartition(ast);
+    Assert.assertNotNull("Query with part location must return location",
+        partitionLocation);
+    Assert.assertEquals("file:///", partitionLocation.getName());
+  }
+
+  @Test
+  public void testAddPartitionIfNotExists() throws Exception {
+    ASTNode ast = parse("alter table parted add if not exists partition (day='Monday')");
+    LOG.info("AST: " + ast.toStringTree());
+    AccessURI partitionLocation = HiveAuthzBindingHook.extractPartition(ast);
+    Assert.assertNull("Query without part location should not return location",
+        partitionLocation);
+  }
+  @Test
+  public void testAddPartitionIfNotExistsWithLocation() throws Exception {
+    ASTNode ast = parse("alter table parted add if not exists partition (day='Monday')" +
+        " location 'file:/'");
+    LOG.info("AST: " + ast.toStringTree());
+    AccessURI partitionLocation = HiveAuthzBindingHook.extractPartition(ast);
+    Assert.assertNotNull("Query with part location must return location",
+        partitionLocation);
+    Assert.assertEquals("file:///", partitionLocation.getName());
+  }
+
+  private ASTNode parse(String command) throws Exception {
+    return ParseUtils.findRootNonNullToken(parseDriver.parse(command));
+  }
+
+}
\ No newline at end of file
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUriPermissions.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUriPermissions.java
index 7fd2470..d9330cb 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUriPermissions.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/TestUriPermissions.java
@@ -133,8 +133,11 @@
     userConn = context.createConnection(USER1_1);
     userStmt = context.createStatement(userConn);
     userStmt.execute("use " + dbName);
-    userStmt.execute("ALTER TABLE " + tabName + " ADD PARTITION (dt = '21-Dec-2012') " +
+    userStmt.execute("ALTER TABLE " + tabName + " ADD IF NOT EXISTS PARTITION (dt = '21-Dec-2012') " +
             " LOCATION '" + tabDir + "'");
+    userStmt.execute("ALTER TABLE " + tabName + " DROP PARTITION (dt = '21-Dec-2012')");
+    userStmt.execute("ALTER TABLE " + tabName + " ADD PARTITION (dt = '21-Dec-2012') " +
+        " LOCATION '" + tabDir + "'");
     // negative test user1 cannot alter partition location
     context.assertAuthzException(userStmt,
         "ALTER TABLE " + tabName + " PARTITION (dt = '21-Dec-2012') " + " SET LOCATION '" + tabDir + "'");
@@ -150,6 +153,8 @@
     // positive test, user2 can alter managed partitions
     userStmt.execute("ALTER TABLE " + tabName + " ADD PARTITION (dt = '22-Dec-2012')");
     userStmt.execute("ALTER TABLE " + tabName + " DROP PARTITION (dt = '22-Dec-2012')");
+    userStmt.execute("ALTER TABLE " + tabName + " ADD IF NOT EXISTS PARTITION (dt = '22-Dec-2012')");
+    userStmt.execute("ALTER TABLE " + tabName + " DROP PARTITION (dt = '22-Dec-2012')");
     userConn.close();
 
     // negative test: user3 doesn't have privilege to add/drop partitions