blob: 637e51a3df5dc2e2549c92d32cf1aa3580397bac [file] [log] [blame]
/**
* 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.hive.jdbc;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hive.conf.HiveConf;
import org.apache.hadoop.hive.conf.HiveConf.ConfVars;
import org.apache.hive.jdbc.miniHS2.MiniHS2;
import org.apache.hive.jdbc.miniHS2.MiniHS2.MiniClusterType;
import org.apache.hive.service.cli.HiveSQLException;
import org.apache.hive.service.cli.session.HiveSessionHook;
import org.apache.hive.service.cli.session.HiveSessionHookContext;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestJdbcWithMiniMr {
public static final String TEST_TAG = "miniHS2.miniMr.tag";
public static final String TEST_TAG_VALUE = "miniHS2.miniMr.value";
public static class MiniMrTestSessionHook implements HiveSessionHook {
@Override
public void run(HiveSessionHookContext sessionHookContext) throws HiveSQLException {
sessionHookContext.getSessionConf().set(TEST_TAG, TEST_TAG_VALUE);
}
}
private static MiniHS2 miniHS2 = null;
private static HiveConf conf;
private static Path dataFilePath;
private static String dbName = "mrTestDb";
private Connection hs2Conn = null;
private Statement stmt;
@BeforeClass
public static void beforeTest() throws Exception {
Class.forName(MiniHS2.getJdbcDriverName());
conf = new HiveConf();
conf.setBoolVar(ConfVars.HIVE_SUPPORT_CONCURRENCY, false);
String dataFileDir = conf.get("test.data.files").replace('\\', '/')
.replace("c:", "");
dataFilePath = new Path(dataFileDir, "kv1.txt");
DriverManager.setLoginTimeout(0);
conf.setBoolVar(HiveConf.ConfVars.HIVE_SUPPORT_CONCURRENCY, false);
miniHS2 = new MiniHS2(conf, MiniClusterType.MR);
Map<String, String> overlayProps = new HashMap<String, String>();
overlayProps.put(ConfVars.HIVE_SERVER2_SESSION_HOOK.varname,
MiniMrTestSessionHook.class.getName());
miniHS2.start(overlayProps);
createDb();
}
// setup DB
private static void createDb() throws Exception {
Connection conn = DriverManager.
getConnection(miniHS2.getJdbcURL(), System.getProperty("user.name"), "bar");
Statement stmt2 = conn.createStatement();
stmt2.execute("DROP DATABASE IF EXISTS " + dbName + " CASCADE");
stmt2.execute("CREATE DATABASE " + dbName);
stmt2.close();
conn.close();
}
@Before
public void setUp() throws Exception {
hs2Conn = DriverManager.getConnection(miniHS2.getJdbcURL(dbName),
System.getProperty("user.name"), "bar");
stmt = hs2Conn.createStatement();
stmt.execute("USE " + dbName);
}
@After
public void tearDown() throws Exception {
if (hs2Conn != null) {
hs2Conn.close();
}
}
@AfterClass
public static void afterTest() throws Exception {
if (miniHS2 != null && miniHS2.isStarted()) {
miniHS2.stop();
}
}
/**
* Verify that the connection to HS2 with MiniMr is successful
* @throws Exception
*/
@Test
public void testConnection() throws Exception {
// the session hook should set the property
verifyProperty(TEST_TAG, TEST_TAG_VALUE);
}
/**
* Run nonMr query
* @throws Exception
*/
@Test
public void testNonMrQuery() throws Exception {
String tableName = "testTab1";
String resultVal = "val_238";
String queryStr = "SELECT * FROM " + tableName;
testKvQuery(tableName, queryStr, resultVal);
}
/**
* Run nonMr query
* @throws Exception
*/
@Test
public void testMrQuery() throws Exception {
String tableName = "testTab2";
String resultVal = "val_238";
String queryStr = "SELECT * FROM " + tableName +
" where value = '" + resultVal + "'";
testKvQuery(tableName, queryStr, resultVal);
}
@Test
public void testPermFunc() throws Exception {
// This test assumes the hive-contrib JAR has been built as part of the Hive build.
// Also dependent on the UDFExampleAdd class within that JAR.
String udfClassName = "org.apache.hadoop.hive.contrib.udf.example.UDFExampleAdd";
String mvnRepo = System.getProperty("maven.local.repository");
String hiveVersion = System.getProperty("hive.version");
String jarFileName = "hive-contrib-" + hiveVersion + ".jar";
String[] pathParts = {
"org", "apache", "hive",
"hive-contrib", hiveVersion, jarFileName
};
// Create path to hive-contrib JAR on local filesystem
Path contribJarPath = new Path(mvnRepo);
for (String pathPart : pathParts) {
contribJarPath = new Path(contribJarPath, pathPart);
}
FileSystem localFs = FileSystem.getLocal(conf);
assertTrue("Hive contrib JAR exists at " + contribJarPath, localFs.exists(contribJarPath));
String hdfsJarPathStr = "hdfs:///" + jarFileName;
Path hdfsJarPath = new Path(hdfsJarPathStr);
// Copy JAR to DFS
FileSystem dfs = miniHS2.getDFS().getFileSystem();
dfs.copyFromLocalFile(contribJarPath, hdfsJarPath);
assertTrue("Verify contrib JAR copied to HDFS at " + hdfsJarPath, dfs.exists(hdfsJarPath));
// Register function
String queryStr = "CREATE FUNCTION example_add AS '" + udfClassName + "'"
+ " USING JAR '" + hdfsJarPathStr + "'";
stmt.execute(queryStr);
// Call describe
ResultSet res;
res = stmt.executeQuery("DESCRIBE FUNCTION " + dbName + ".example_add");
checkForNotExist(res);
// Use UDF in query
String tableName = "testTab3";
setupKv1Tabs(tableName);
res = stmt.executeQuery("SELECT EXAMPLE_ADD(1, 2) FROM " + tableName + " LIMIT 1");
assertTrue("query has results", res.next());
assertEquals(3, res.getInt(1));
assertFalse("no more results", res.next());
// A new connection should be able to call describe/use function without issue
Connection conn2 = DriverManager.getConnection(miniHS2.getJdbcURL(dbName),
System.getProperty("user.name"), "bar");
Statement stmt2 = conn2.createStatement();
stmt2.execute("USE " + dbName);
res = stmt2.executeQuery("DESCRIBE FUNCTION " + dbName + ".example_add");
checkForNotExist(res);
res = stmt2.executeQuery("SELECT " + dbName + ".example_add(1, 1) FROM " + tableName + " LIMIT 1");
assertTrue("query has results", res.next());
assertEquals(2, res.getInt(1));
assertFalse("no more results", res.next());
stmt.execute("DROP TABLE " + tableName);
}
@Test
public void testTempTable() throws Exception {
// Create temp table with current connection
String tempTableName = "tmp1";
stmt.execute("CREATE TEMPORARY TABLE " + tempTableName + " (key string, value string)");
stmt.execute("load data local inpath '"
+ dataFilePath.toString() + "' into table " + tempTableName);
String resultVal = "val_238";
String queryStr = "SELECT * FROM " + tempTableName +
" where value = '" + resultVal + "'";
verifyResult(queryStr, resultVal, 2);
// Test getTables()
DatabaseMetaData md = hs2Conn.getMetaData();
assertTrue(md.getConnection() == hs2Conn);
ResultSet rs = md.getTables(null, null, tempTableName, null);
boolean foundTable = false;
while (rs.next()) {
String tableName = rs.getString(3);
if (tableName.equalsIgnoreCase(tempTableName)) {
assertFalse("Table not found yet", foundTable);
foundTable = true;
}
}
assertTrue("Found temp table", foundTable);
// Test getTables() with no table name pattern
rs = md.getTables(null, null, null, null);
foundTable = false;
while (rs.next()) {
String tableName = rs.getString(3);
if (tableName.equalsIgnoreCase(tempTableName)) {
assertFalse("Table not found yet", foundTable);
foundTable = true;
}
}
assertTrue("Found temp table", foundTable);
// Test getColumns()
rs = md.getColumns(null, null, tempTableName, null);
assertTrue("First row", rs.next());
assertTrue(rs.getString(3).equalsIgnoreCase(tempTableName));
assertTrue(rs.getString(4).equalsIgnoreCase("key"));
assertEquals(Types.VARCHAR, rs.getInt(5));
assertTrue("Second row", rs.next());
assertTrue(rs.getString(3).equalsIgnoreCase(tempTableName));
assertTrue(rs.getString(4).equalsIgnoreCase("value"));
assertEquals(Types.VARCHAR, rs.getInt(5));
// A second connection should not be able to see the table
Connection conn2 = DriverManager.getConnection(miniHS2.getJdbcURL(dbName),
System.getProperty("user.name"), "bar");
Statement stmt2 = conn2.createStatement();
stmt2.execute("USE " + dbName);
boolean gotException = false;
try {
ResultSet res;
res = stmt2.executeQuery(queryStr);
} catch (SQLException err) {
// This is expected to fail.
assertTrue("Expecting table not found error, instead got: " + err,
err.getMessage().contains("Table not found"));
gotException = true;
}
assertTrue("Exception while querying non-existing temp table", gotException);
}
private void checkForNotExist(ResultSet res) throws Exception {
int numRows = 0;
while (res.next()) {
numRows++;
String strVal = res.getString(1);
assertEquals("Should not find 'not exist'", -1, strVal.toLowerCase().indexOf("not exist"));
}
assertTrue("Rows returned from describe function", numRows > 0);
}
/**
* Verify if the given property contains the expected value
* @param propertyName
* @param expectedValue
* @throws Exception
*/
private void verifyProperty(String propertyName, String expectedValue) throws Exception {
Statement stmt = hs2Conn .createStatement();
ResultSet res = stmt.executeQuery("set " + propertyName);
assertTrue(res.next());
String results[] = res.getString(1).split("=");
assertEquals("Property should be set", results.length, 2);
assertEquals("Property should be set", expectedValue, results[1]);
}
// create tables, verify query
private void testKvQuery(String tableName, String queryStr, String resultVal)
throws SQLException {
setupKv1Tabs(tableName);
verifyResult(queryStr, resultVal, 2);
stmt.execute("DROP TABLE " + tableName);
}
// create table and pupulate with kv1.txt
private void setupKv1Tabs(String tableName) throws SQLException {
Statement stmt = hs2Conn.createStatement();
// create table
stmt.execute("CREATE TABLE " + tableName
+ " (under_col INT COMMENT 'the under column', value STRING)"
+ " COMMENT ' test table'");
// load data
stmt.execute("load data local inpath '"
+ dataFilePath.toString() + "' into table " + tableName);
}
// run given query and validate expecated result
private void verifyResult(String queryStr, String expString, int colPos)
throws SQLException {
ResultSet res = stmt.executeQuery(queryStr);
assertTrue(res.next());
assertEquals(expString, res.getString(colPos));
res.close();
}
}