blob: 66b06eac02d5c6fece45a3bf64a4ea2079569ebf [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.impala.service;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.impala.testutil.ImpalaJdbcClient;
import org.apache.impala.testutil.TestUtils;
import org.apache.impala.util.Metrics;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
/**
* JdbcTest
*
* Basic JDBC metadata test. It exercises getTables, getCatalogs, getSchemas,
* getTableTypes, getColumnNames.
*
*/
public class JdbcTest extends JdbcTestBase {
public JdbcTest(String connectionType) { super(connectionType); }
@Before
public void setUp() throws Exception {
con_ = createConnection(ImpalaJdbcClient.getNoAuthConnectionStr(connectionType_));
}
@Test
public void testMetaDataGetTables() throws SQLException {
// map from tablename search pattern to actual table name.
Map<String, String> tests = new HashMap<String, String>();
tests.put("alltypes", "alltypes");
tests.put("%all_ypes", "alltypes");
String[][] tblTypes = {null, {"TABLE"}};
for (String tblNamePattern: tests.keySet()) {
for (String[] tblType: tblTypes) {
ResultSet rs = con_.getMetaData().getTables("", "functional",
tblNamePattern, tblType);
assertTrue(rs.next());
// TABLE_NAME is the 3rd column.
String resultTableName = rs.getString("TABLE_NAME");
assertEquals(rs.getString(3), resultTableName);
assertEquals("Table mismatch", tests.get(tblNamePattern), resultTableName);
String tableType = rs.getString("TABLE_TYPE");
assertEquals("table", tableType.toLowerCase());
assertFalse(rs.next());
rs.close();
}
}
for (String[] tblType: tblTypes) {
ResultSet rs = con_.getMetaData().getTables(null, null, null, tblType);
// Should return at least one value.
assertTrue(rs.next());
rs.close();
rs = con_.getMetaData().getTables(null, null, null, tblType);
assertTrue(rs.next());
rs.close();
}
}
@Test
public void testMetaDataGetCatalogs() throws SQLException {
// Hive/Impala does not have catalogs.
ResultSet rs = con_.getMetaData().getCatalogs();
ResultSetMetaData resMeta = rs.getMetaData();
assertEquals(1, resMeta.getColumnCount());
assertEquals("TABLE_CAT", resMeta.getColumnName(1));
assertFalse(rs.next());
}
@Test
public void testMetaDataGetSchemas() throws SQLException {
// There is only one schema: "default".
ResultSet rs = con_.getMetaData().getSchemas("", "d_f%");
ResultSetMetaData resMeta = rs.getMetaData();
assertEquals(2, resMeta.getColumnCount());
assertEquals("TABLE_SCHEM", resMeta.getColumnName(1));
assertEquals("TABLE_CATALOG", resMeta.getColumnName(2));
assertTrue(rs.next());
assertEquals(rs.getString(1).toLowerCase(), "default");
assertFalse(rs.next());
rs.close();
}
@Test
public void testMetaDataGetTableTypes() throws SQLException {
ResultSet rs = con_.getMetaData().getTableTypes();
assertTrue(rs.next());
assertEquals(rs.getString(1).toLowerCase(), "table");
assertTrue(rs.next());
assertEquals(rs.getString(1).toLowerCase(), "view");
assertFalse(rs.next());
rs.close();
}
@Test
public void testMetaDataGetColumns() throws Exception {
// It should return alltypessmall.string_col.
ResultSet rs = con_.getMetaData().getColumns(null,
"functional", "alltypessmall", "s%rin%");
// validate the metadata for the getColumnNames result set
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals("TABLE_CAT", rsmd.getColumnName(1));
assertTrue(rs.next());
String columnname = rs.getString("COLUMN_NAME");
int ordinalPos = rs.getInt("ORDINAL_POSITION");
assertEquals("Incorrect column name", "string_col", columnname);
assertEquals("Incorrect ordinal position", 12, ordinalPos);
assertEquals("Incorrect type", Types.VARCHAR, rs.getInt("DATA_TYPE"));
assertFalse(rs.next());
rs.close();
// validate bool_col
rs = con_.getMetaData().getColumns(null, "functional", "alltypessmall", "bool_col");
assertTrue(rs.next());
assertEquals("Incorrect type", Types.BOOLEAN, rs.getInt("DATA_TYPE"));
assertFalse(rs.next());
rs.close();
// validate tinyint_col
rs = con_.getMetaData().getColumns(null, "functional", "alltypessmall",
"tinyint_col");
assertTrue(rs.next());
assertEquals("Incorrect type", Types.TINYINT, rs.getInt("DATA_TYPE"));
assertEquals(3, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertFalse(rs.next());
rs.close();
// validate smallint_col
rs = con_.getMetaData().getColumns(null, "functional", "alltypessmall",
"smallint_col");
assertTrue(rs.next());
assertEquals("Incorrect type", Types.SMALLINT, rs.getInt("DATA_TYPE"));
assertEquals(5, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertFalse(rs.next());
rs.close();
// validate int_col
rs = con_.getMetaData().getColumns(null, "functional", "alltypessmall", "int_col");
assertTrue(rs.next());
assertEquals("Incorrect type", Types.INTEGER, rs.getInt("DATA_TYPE"));
assertEquals(10, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertFalse(rs.next());
rs.close();
// validate bigint_col
rs = con_.getMetaData().getColumns(null, "functional", "alltypessmall",
"bigint_col");
assertTrue(rs.next());
assertEquals("Incorrect type", Types.BIGINT, rs.getInt("DATA_TYPE"));
assertEquals(19, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertFalse(rs.next());
rs.close();
// validate float_col
rs = con_.getMetaData().getColumns(null, "functional", "alltypessmall", "float_col");
assertTrue(rs.next());
assertEquals("Incorrect type", Types.FLOAT, rs.getInt("DATA_TYPE"));
assertEquals(7, rs.getInt("COLUMN_SIZE"));
assertEquals(7, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertFalse(rs.next());
rs.close();
// validate double_col
rs = con_.getMetaData().getColumns(null, "functional", "alltypessmall",
"double_col");
assertTrue(rs.next());
assertEquals("Incorrect type", Types.DOUBLE, rs.getInt("DATA_TYPE"));
assertEquals(15, rs.getInt("COLUMN_SIZE"));
assertEquals(15, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertFalse(rs.next());
rs.close();
// validate timestamp_col
rs = con_.getMetaData().getColumns(null, "functional", "alltypessmall",
"timestamp_col");
assertTrue(rs.next());
assertEquals("Incorrect type", Types.TIMESTAMP, rs.getInt("DATA_TYPE"));
assertEquals(29, rs.getInt("COLUMN_SIZE"));
assertEquals(9, rs.getInt("DECIMAL_DIGITS"));
// Use getString() to check the value is null (and not 0).
assertEquals(null, rs.getString("NUM_PREC_RADIX"));
assertFalse(rs.next());
rs.close();
// validate null column name returns all columns.
rs = con_.getMetaData().getColumns(null, "functional", "alltypessmall", null);
int numCols = 0;
while (rs.next()) {
++numCols;
}
assertEquals(13, numCols);
rs.close();
// validate date_col
rs = con_.getMetaData().getColumns(null, "functional", "date_tbl",
"date_col");
assertTrue(rs.next());
assertEquals("Incorrect type", Types.DATE, rs.getInt("DATA_TYPE"));
assertEquals(10, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
// Use getString() to check the value is null (and not 0).
assertEquals(null, rs.getString("NUM_PREC_RADIX"));
assertFalse(rs.next());
rs.close();
// validate DECIMAL columns
rs = con_.getMetaData().getColumns(null, "functional", "decimal_tbl", null);
assertTrue(rs.next());
assertEquals("Incorrect type", Types.DECIMAL, rs.getInt("DATA_TYPE"));
assertEquals(9, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.DECIMAL, rs.getInt("DATA_TYPE"));
assertEquals(10, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.DECIMAL, rs.getInt("DATA_TYPE"));
assertEquals(20, rs.getInt("COLUMN_SIZE"));
assertEquals(10, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.DECIMAL, rs.getInt("DATA_TYPE"));
assertEquals(38, rs.getInt("COLUMN_SIZE"));
assertEquals(38, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.DECIMAL, rs.getInt("DATA_TYPE"));
assertEquals(10, rs.getInt("COLUMN_SIZE"));
assertEquals(5, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.DECIMAL, rs.getInt("DATA_TYPE"));
assertEquals(9, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(10, rs.getInt("NUM_PREC_RADIX"));
assertFalse(rs.next());
rs.close();
// validate CHAR/VARCHAR columns
rs = con_.getMetaData().getColumns(null, "functional", "chars_tiny", null);
assertTrue(rs.next());
assertEquals("Incorrect type", Types.CHAR, rs.getInt("DATA_TYPE"));
assertEquals(5, rs.getInt("COLUMN_SIZE"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.CHAR, rs.getInt("DATA_TYPE"));
assertEquals(140, rs.getInt("COLUMN_SIZE"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.VARCHAR, rs.getInt("DATA_TYPE"));
assertEquals(32, rs.getInt("COLUMN_SIZE"));
assertFalse(rs.next());
rs.close();
// Validate complex types STRUCT/MAP/ARRAY.
// To be consistent with Hive's behavior, the TYPE_NAME field is populated
// with the primitive type name for scalar types, and with the full toSql()
// for complex types. The resulting type names are somewhat inconsistent,
// because nested types are printed differently than top-level types, e.g.:
// toSql() TYPE_NAME
// DECIMAL(10,10) --> DECIMAL
// CHAR(10) --> CHAR
// VARCHAR(10) --> VARCHAR
// ARRAY<DECIMAL(10,10)> --> ARRAY<DECIMAL(10,10)>
// ARRAY<CHAR(10)> --> ARRAY<CHAR(10)>
// ARRAY<VARCHAR(10)> --> ARRAY<VARCHAR(10)>
addTestTable("create table default.jdbc_complex_type_test (" +
"s struct<f1:int,f2:char(4),f3:varchar(5),f4:decimal(10,10)>," +
"a1 array<int>," +
"a2 array<char(4)>," +
"a3 array<varchar(5)>," +
"a4 array<decimal(10,10)>," +
"m1 map<int,string>," +
"m2 map<string,char(4)>," +
"m3 map<bigint,varchar(5)>," +
"m4 map<boolean,decimal(10,10)>)");
rs = con_.getMetaData().getColumns(null, "default", "jdbc_complex_type_test", null);
assertTrue(rs.next());
assertEquals("Incorrect type", Types.STRUCT, rs.getInt("DATA_TYPE"));
assertEquals("Incorrect type name",
"STRUCT<f1:INT,f2:CHAR(4),f3:VARCHAR(5),f4:DECIMAL(10,10)>",
rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(0, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.ARRAY, rs.getInt("DATA_TYPE"));
assertEquals("Incorrect type name", "ARRAY<INT>", rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(0, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.ARRAY, rs.getInt("DATA_TYPE"));
assertEquals("Incorrect type name", "ARRAY<CHAR(4)>", rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(0, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.ARRAY, rs.getInt("DATA_TYPE"));
assertEquals("Incorrect type name", "ARRAY<VARCHAR(5)>", rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(0, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.ARRAY, rs.getInt("DATA_TYPE"));
assertEquals("Incorrect type name", "ARRAY<DECIMAL(10,10)>",
rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(0, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.ARRAY, rs.getInt("DATA_TYPE"));
assertEquals("Incorrect type name", "MAP<INT,STRING>", rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(0, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.ARRAY, rs.getInt("DATA_TYPE"));
assertEquals("Incorrect type name", "MAP<STRING,CHAR(4)>",
rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(0, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.ARRAY, rs.getInt("DATA_TYPE"));
assertEquals("Incorrect type name", "MAP<BIGINT,VARCHAR(5)>",
rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(0, rs.getInt("NUM_PREC_RADIX"));
assertTrue(rs.next());
assertEquals("Incorrect type", Types.ARRAY, rs.getInt("DATA_TYPE"));
assertEquals("Incorrect type name", "MAP<BOOLEAN,DECIMAL(10,10)>",
rs.getString("TYPE_NAME"));
assertEquals(0, rs.getInt("COLUMN_SIZE"));
assertEquals(0, rs.getInt("DECIMAL_DIGITS"));
assertEquals(0, rs.getInt("NUM_PREC_RADIX"));
rs.close();
}
@Test
public void testMetaDataGetColumnComments() throws Exception {
addTestTable("create table default.jdbc_column_comments_test (" +
"a int comment 'column comment') comment 'table comment'");
ResultSet rs = con_.getMetaData().getTables(
null, "default", "jdbc_column_comments_test", null);
assertTrue(rs.next());
assertEquals("Incorrect table name", "jdbc_column_comments_test",
rs.getString("TABLE_NAME"));
String remarks = rs.getString("REMARKS");
// getTables() won't trigger full meta loading for tables. So for unloaded tables,
// the 'remarks' field is left empty. getColumns() loads the table metadata, so later
// getTables() calls will return 'remarks' correctly.
assertTrue("Incorrect table comment: " + remarks,
remarks.equals("") || remarks.equals("table comment"));
rs = con_.getMetaData().getColumns(
null, "default", "jdbc_column_comments_test", null);
assertTrue(rs.next());
assertEquals("Incorrect column comment", "column comment", rs.getString("REMARKS"));
rs = con_.getMetaData().getTables(
null, "default", "jdbc_column_comments_test", null);
assertTrue(rs.next());
assertEquals("Incorrect table name", "jdbc_column_comments_test",
rs.getString("TABLE_NAME"));
// if this is a catalog-v2 cluster the getTables call does not load the localTable
// since it does not request columns. See IMPALA-8606 for more details
if (!TestUtils.isCatalogV2Enabled("localhost", 25020)) {
assertEquals("Incorrect table comment", "table comment", rs.getString("REMARKS"));
}
}
@Test
public void testMetadataGetPrimaryKeys() throws Exception {
List<String> pkList = new ArrayList<>(Arrays.asList("id", "year"));
ResultSet rs = con_.getMetaData().getPrimaryKeys(null, "functional", "parent_table");
ResultSetMetaData md = rs.getMetaData();
assertEquals("Incorrect number of columns seen", 6, md.getColumnCount());
// TODO (IMPALA-9158): Remove this check.
if (!TestUtils.isCatalogV2Enabled("localhost", 25020)) {
int pkCount = 0;
while (rs.next()) {
pkCount++;
assertEquals("", rs.getString("TABLE_CAT"));
assertEquals("functional", rs.getString("TABLE_SCHEM"));
assertEquals("parent_table", rs.getString("TABLE_NAME"));
assertTrue(pkList.contains(rs.getString("COLUMN_NAME")));
assertTrue(rs.getString("PK_NAME").length() > 0);
}
assertEquals(2, pkCount);
}
}
@Test
public void testMetadataGetCrossReference() throws Exception {
ResultSet rs = con_.getMetaData().getCrossReference(null, "functional",
"parent_table", null,
"functional", "child_table");
ResultSetMetaData md = rs.getMetaData();
assertEquals("Incorrect number of columns seen for primary key.",
14, md.getColumnCount());
// TODO (IMPALA-9158): Remove this check.
if (!TestUtils.isCatalogV2Enabled("localhost", 25020)) {
List<String> colList = new ArrayList<>(Arrays.asList("id", "year"));
int fkCount = 0;
while (rs.next()) {
fkCount++;
assertEquals("", rs.getString("PKTABLE_CAT"));
assertEquals("functional", rs.getString("PKTABLE_SCHEM"));
assertEquals("parent_table", rs.getString("PKTABLE_NAME"));
assertTrue(colList.contains(rs.getString("PKCOLUMN_NAME")));
assertTrue(rs.getString("FK_NAME").length() > 0);
assertEquals("", rs.getString("FKTABLE_CAT"));
assertEquals("functional", rs.getString("FKTABLE_SCHEM"));
assertEquals("child_table", rs.getString("FKTABLE_NAME"));
assertTrue(colList.contains(rs.getString("FKCOLUMN_NAME")));
}
assertEquals(2, fkCount);
}
}
@Test
public void testDecimalGetColumnTypes() throws SQLException {
// Table has 5 decimal columns
ResultSet rs = con_.createStatement().executeQuery(
"select * from functional.decimal_tbl");
assertEquals(rs.getMetaData().getColumnType(1), Types.DECIMAL);
assertEquals(rs.getMetaData().getPrecision(1), 9);
assertEquals(rs.getMetaData().getScale(1), 0);
assertEquals(rs.getMetaData().getColumnType(2), Types.DECIMAL);
assertEquals(rs.getMetaData().getPrecision(2), 10);
assertEquals(rs.getMetaData().getScale(2), 0);
assertEquals(rs.getMetaData().getColumnType(3), Types.DECIMAL);
assertEquals(rs.getMetaData().getPrecision(3), 20);
assertEquals(rs.getMetaData().getScale(3), 10);
assertEquals(rs.getMetaData().getColumnType(4), Types.DECIMAL);
assertEquals(rs.getMetaData().getPrecision(4), 38);
assertEquals(rs.getMetaData().getScale(4), 38);
assertEquals(rs.getMetaData().getColumnType(5), Types.DECIMAL);
assertEquals(rs.getMetaData().getPrecision(5), 10);
assertEquals(rs.getMetaData().getScale(5), 5);
assertEquals(rs.getMetaData().getColumnType(6), Types.DECIMAL);
assertEquals(rs.getMetaData().getPrecision(6), 9);
assertEquals(rs.getMetaData().getScale(6), 0);
rs.close();
}
@Test
public void testDateGetColumnTypes() throws SQLException {
// Table has 1 int column and 2 date columns.
ResultSet rs = con_.createStatement().executeQuery(
"select * from functional.date_tbl");
assertEquals(rs.getMetaData().getColumnType(1), Types.INTEGER);
// Get the designated column's specified column size.
assertEquals(rs.getMetaData().getPrecision(1), 10);
// Gets the designated column's number of digits to right of the decimal point.
assertEquals(rs.getMetaData().getScale(1), 0);
assertEquals(rs.getMetaData().getColumnType(2), Types.DATE);
assertEquals(rs.getMetaData().getPrecision(2), 10);
assertEquals(rs.getMetaData().getScale(2), 0);
assertEquals(rs.getMetaData().getColumnType(3), Types.DATE);
assertEquals(rs.getMetaData().getPrecision(3), 10);
assertEquals(rs.getMetaData().getScale(3), 0);
rs.close();
}
/**
* Validate the Metadata for the result set of a metadata getColumnNames call.
*/
@Test
public void testMetaDataGetColumnsMetaData() throws SQLException {
ResultSet rs = con_.getMetaData().getColumns(null, "functional", "alltypes", null);
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals("TABLE_CAT", rsmd.getColumnName(1));
assertEquals(Types.VARCHAR, rsmd.getColumnType(1));
assertEquals(Integer.MAX_VALUE, rsmd.getColumnDisplaySize(1));
assertEquals("ORDINAL_POSITION", rsmd.getColumnName(17));
assertEquals(Types.INTEGER, rsmd.getColumnType(17));
assertEquals(11, rsmd.getColumnDisplaySize(17));
}
@Test
public void testMetaDataGetFunctions() throws SQLException {
// Look up the 'substring' function.
// We support 2 overloaded version of it.
ResultSet rs = con_.getMetaData().getFunctions(
null, null, "substring");
int numFound = 0;
while (rs.next()) {
String funcName = rs.getString("FUNCTION_NAME");
assertEquals("Incorrect function name", "substring", funcName.toLowerCase());
String dbName = rs.getString("FUNCTION_SCHEM");
assertEquals("Incorrect function name", "_impala_builtins", dbName.toLowerCase());
String fnSignature = rs.getString("SPECIFIC_NAME");
assertTrue(fnSignature.startsWith("substring("));
++numFound;
}
assertEquals(numFound, 2);
rs.close();
// substring is not in default db
rs = con_.getMetaData().getFunctions(null, "default", "substring");
assertFalse(rs.next());
rs.close();
}
@Test
public void testUtilityFunctions() throws SQLException {
ResultSet rs = con_.createStatement().executeQuery("select user()");
try {
// We expect exactly one result row with a NULL inside the first column.
// The user() function returns NULL because we currently cannot set the user
// when establishing the Jdbc connection.
assertTrue(rs.next());
assertNull(rs.getString(1));
assertFalse(rs.next());
} finally {
rs.close();
}
}
@Test
public void testSelectNull() throws SQLException {
// Regression test for IMPALA-914.
ResultSet rs = con_.createStatement().executeQuery("select NULL");
// Expect the column to be of type BOOLEAN to be compatible with Hive.
assertEquals(rs.getMetaData().getColumnType(1), Types.BOOLEAN);
try {
// We expect exactly one result row with a NULL inside the first column.
assertTrue(rs.next());
assertNull(rs.getString(1));
assertFalse(rs.next());
} finally {
rs.close();
}
}
@Test
public void testConcurrentSessionMixedIdleTimeout() throws Exception {
// Test for concurrent idle sessions' expiration with mixed timeout durations.
Metrics metrics = new Metrics();
List<Integer> timeoutPeriods = Arrays.asList(0, 3, 15);
List<Connection> connections = new ArrayList<>();
List<Long> lastTimeSessionActive = new ArrayList<>();
for (int timeout : timeoutPeriods) {
connections.add(
createConnection(ImpalaJdbcClient.getNoAuthConnectionStr(connectionType_)));
}
Long numOpenSessions = (Long)metrics.getMetric(
"impala-server.num-open-hiveserver2-sessions");
Long numExpiredSessions = (Long)metrics.getMetric(
"impala-server.num-sessions-expired");
for (int i = 0; i < connections.size(); ++i) {
Connection connection = connections.get(i);
Integer timeout = timeoutPeriods.get(i);
connection.createStatement().executeQuery("SELECT 1+2");
connection.createStatement().executeQuery("SET IDLE_SESSION_TIMEOUT=" +
Integer.toString(timeout));
lastTimeSessionActive.add(System.currentTimeMillis() / 1000);
}
assertEquals(numOpenSessions, (Long)metrics.getMetric(
"impala-server.num-open-hiveserver2-sessions"));
assertEquals(numExpiredSessions, (Long)metrics.getMetric(
"impala-server.num-sessions-expired"));
for (int timeout : timeoutPeriods) {
// Let's expire a session by sleeping,
// while renewing the remainders by issuing a query
// (except for the 0 timeout, which should never expire)
int timeoutToleranceMs = 1500;
int sleepPeriodMs = timeout * 1000 + timeoutToleranceMs;
Thread.sleep(sleepPeriodMs);
for (int i = 0; i < connections.size(); ++i) {
Connection connection = connections.get(i);
if (connection != null) {
Integer timeoutPeriod = timeoutPeriods.get(i);
long now = System.currentTimeMillis() / 1000;
boolean sessionIsValid = timeoutPeriod == 0 ||
timeoutPeriod > now - lastTimeSessionActive.get(i);
try (ResultSet rs = connection.createStatement().executeQuery("SELECT 1+2")) {
assertTrue(sessionIsValid);
lastTimeSessionActive.set(i, now);
}
catch (SQLException exception) {
assertFalse(sessionIsValid);
connection.close();
connections.set(i, null);
numOpenSessions -= 1;
numExpiredSessions += 1;
}
}
}
assertEquals(numOpenSessions, (Long)metrics.getMetric(
"impala-server.num-open-hiveserver2-sessions"));
assertEquals(numExpiredSessions, (Long)metrics.getMetric(
"impala-server.num-sessions-expired"));
}
assertNotNull("Connection with 0 timeout should not be null", connections.get(0));
connections.get(0).close();
connections.set(0, null);
for (Connection connection : connections) {
assertNull("Connection is not null", connection);
}
}
}