blob: 02efcee5eca873d427889e4a1792eea4c42daa99 [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.drill.exec.sql;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.drill.categories.SqlTest;
import org.apache.drill.common.expression.SchemaPath;
import org.apache.drill.exec.record.RecordBatchLoader;
import org.apache.drill.exec.record.VectorWrapper;
import org.apache.drill.exec.rpc.user.QueryDataBatch;
import org.apache.drill.exec.store.dfs.FileSystemConfig;
import org.apache.drill.exec.vector.NullableVarCharVector;
import org.apache.drill.test.BaseTestQuery;
import org.apache.drill.test.TestBuilder;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
import static org.apache.drill.exec.store.ischema.InfoSchemaConstants.CATS_COL_CATALOG_CONNECT;
import static org.apache.drill.exec.store.ischema.InfoSchemaConstants.CATS_COL_CATALOG_DESCRIPTION;
import static org.apache.drill.exec.store.ischema.InfoSchemaConstants.CATS_COL_CATALOG_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Contains tests for
* -- InformationSchema
* -- Queries on InformationSchema such as SHOW TABLES, SHOW SCHEMAS or DESCRIBE table
* -- USE schema
*/
@Category(SqlTest.class)
public class TestInfoSchema extends BaseTestQuery {
private static final String TEST_SUB_DIR = "testSubDir";
private static final ObjectMapper mapper = new ObjectMapper().enable(INDENT_OUTPUT);
@BeforeClass
public static void setupFiles() {
dirTestWatcher.copyFileToRoot(Paths.get("sample-data"));
dirTestWatcher.makeRootSubDir(Paths.get(TEST_SUB_DIR));
}
@Test
public void selectFromAllTables() throws Exception{
test("select * from INFORMATION_SCHEMA.SCHEMATA");
test("select * from INFORMATION_SCHEMA.CATALOGS");
test("select * from INFORMATION_SCHEMA.VIEWS");
test("select * from INFORMATION_SCHEMA.`TABLES`");
test("select * from INFORMATION_SCHEMA.COLUMNS");
test("select * from INFORMATION_SCHEMA.`FILES`");
test("select * from INFORMATION_SCHEMA.`PARTITIONS`");
}
@Test
public void catalogs() throws Exception {
testBuilder()
.sqlQuery("SELECT * FROM INFORMATION_SCHEMA.CATALOGS")
.unOrdered()
.baselineColumns(CATS_COL_CATALOG_NAME, CATS_COL_CATALOG_DESCRIPTION, CATS_COL_CATALOG_CONNECT)
.baselineValues("DRILL", "The internal metadata used by Drill", "")
.go();
}
@Test
public void showTablesFromDb() throws Exception{
List<String[]> expected = Arrays.asList(
new String[]{"information_schema", "VIEWS"},
new String[]{"information_schema", "COLUMNS"},
new String[]{"information_schema", "TABLES"},
new String[]{"information_schema", "CATALOGS"},
new String[]{"information_schema", "SCHEMATA"},
new String[]{"information_schema", "FILES"},
new String[]{"information_schema", "PARTITIONS"});
TestBuilder t1 = testBuilder()
.sqlQuery("SHOW TABLES FROM INFORMATION_SCHEMA")
.unOrdered()
.baselineColumns("TABLE_SCHEMA", "TABLE_NAME");
for (String[] expectedRow : expected) {
t1.baselineValues(expectedRow);
}
t1.go();
TestBuilder t2 = testBuilder()
.sqlQuery("SHOW TABLES IN INFORMATION_SCHEMA")
.unOrdered()
.baselineColumns("TABLE_SCHEMA", "TABLE_NAME");
for (String[] expectedRow : expected) {
t2.baselineValues(expectedRow);
}
t2.go();
}
@Test
public void showTablesFromDbWhere() throws Exception{
testBuilder()
.sqlQuery("SHOW TABLES FROM INFORMATION_SCHEMA WHERE TABLE_NAME='VIEWS'")
.unOrdered()
.baselineColumns("TABLE_SCHEMA", "TABLE_NAME")
.baselineValues("information_schema", "VIEWS")
.go();
}
@Test
public void showTablesLike() throws Exception{
testBuilder()
.sqlQuery("SHOW TABLES LIKE '%CH%'")
.unOrdered()
.optionSettingQueriesForTestQuery("USE INFORMATION_SCHEMA")
.baselineColumns("TABLE_SCHEMA", "TABLE_NAME")
.baselineValues("information_schema", "SCHEMATA")
.go();
}
@Test
public void showDatabases() throws Exception{
List<String> expected = Arrays.asList("dfs.default", "dfs.root", "dfs.tmp", "cp.default", "sys", "information_schema");
TestBuilder t1 = testBuilder()
.sqlQuery("SHOW DATABASES")
.unOrdered()
.baselineColumns("SCHEMA_NAME");
expected.forEach(t1::baselineValues);
t1.go();
TestBuilder t2 = testBuilder()
.sqlQuery("SHOW SCHEMAS")
.unOrdered()
.baselineColumns("SCHEMA_NAME");
expected.forEach(t2::baselineValues);
t2.go();
}
@Test
public void showDatabasesWhere() throws Exception{
testBuilder()
.sqlQuery("SHOW DATABASES WHERE SCHEMA_NAME='dfs.tmp'")
.unOrdered()
.baselineColumns("SCHEMA_NAME")
.baselineValues("dfs.tmp")
.go();
}
@Test
public void showDatabasesLike() throws Exception{
testBuilder()
.sqlQuery("SHOW DATABASES LIKE '%y%'")
.unOrdered()
.baselineColumns("SCHEMA_NAME")
.baselineValues("sys")
.go();
}
@Test
public void describeTable() throws Exception{
testBuilder()
.sqlQuery("DESCRIBE CATALOGS")
.unOrdered()
.optionSettingQueriesForTestQuery("USE INFORMATION_SCHEMA")
.baselineColumns("COLUMN_NAME", "DATA_TYPE", "IS_NULLABLE")
.baselineValues("CATALOG_NAME", "CHARACTER VARYING", "NO")
.baselineValues("CATALOG_DESCRIPTION", "CHARACTER VARYING", "NO")
.baselineValues("CATALOG_CONNECT", "CHARACTER VARYING", "NO")
.go();
}
@Test
public void describeTableWithTableKeyword() throws Exception {
test("USE INFORMATION_SCHEMA");
testBuilder()
.sqlQuery("DESCRIBE TABLE CATALOGS")
.unOrdered()
.sqlBaselineQuery("DESCRIBE CATALOGS")
.go();
}
@Test
public void describeTableWithSchema() throws Exception{
testBuilder()
.sqlQuery("DESCRIBE INFORMATION_SCHEMA.`TABLES`")
.unOrdered()
.baselineColumns("COLUMN_NAME", "DATA_TYPE", "IS_NULLABLE")
.baselineValues("TABLE_CATALOG", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_SCHEMA", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_NAME", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_TYPE", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_SOURCE", "CHARACTER VARYING", "NO")
.baselineValues("LOCATION", "CHARACTER VARYING", "NO")
.baselineValues("NUM_ROWS", "BIGINT", "NO")
.baselineValues("LAST_MODIFIED_TIME", "TIMESTAMP", "NO")
.go();
}
@Test
public void describeTableWithSchemaAndTableKeyword() throws Exception {
testBuilder()
.sqlQuery("DESCRIBE TABLE INFORMATION_SCHEMA.`TABLES`")
.unOrdered()
.sqlBaselineQuery("DESCRIBE INFORMATION_SCHEMA.`TABLES`")
.go();
}
@Test
public void describeWhenSameTableNameExistsInMultipleSchemas() throws Exception{
try {
test("USE dfs.tmp");
test("CREATE OR REPLACE VIEW `TABLES` AS SELECT full_name FROM cp.`employee.json`");
testBuilder()
.sqlQuery("DESCRIBE `TABLES`")
.unOrdered()
.optionSettingQueriesForTestQuery("USE dfs.tmp")
.baselineColumns("COLUMN_NAME", "DATA_TYPE", "IS_NULLABLE")
.baselineValues("full_name", "ANY", "YES")
.go();
testBuilder()
.sqlQuery("DESCRIBE INFORMATION_SCHEMA.`TABLES`")
.unOrdered()
.baselineColumns("COLUMN_NAME", "DATA_TYPE", "IS_NULLABLE")
.baselineValues("TABLE_CATALOG", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_SCHEMA", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_NAME", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_TYPE", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_SOURCE", "CHARACTER VARYING", "NO")
.baselineValues("LOCATION", "CHARACTER VARYING", "NO")
.baselineValues("NUM_ROWS", "BIGINT", "NO")
.baselineValues("LAST_MODIFIED_TIME", "TIMESTAMP", "NO")
.go();
} finally {
test("DROP VIEW IF EXISTS dfs.tmp.`TABLES`");
}
}
@Test
public void describeWhenSameTableNameExistsInMultipleSchemasWithTableKeyword() throws Exception {
try {
test("USE dfs.tmp");
test("CREATE OR REPLACE VIEW `TABLES` AS SELECT full_name FROM cp.`employee.json`");
testBuilder()
.sqlQuery("DESCRIBE TABLE `TABLES`")
.unOrdered()
.sqlBaselineQuery("DESCRIBE `TABLES`")
.go();
testBuilder()
.sqlQuery("DESCRIBE TABLE INFORMATION_SCHEMA.`TABLES`")
.unOrdered()
.sqlBaselineQuery("DESCRIBE INFORMATION_SCHEMA.`TABLES`")
.go();
} finally {
test("DROP VIEW IF EXISTS dfs.tmp.`TABLES`");
}
}
@Test
public void describeTableWithColumnName() throws Exception{
testBuilder()
.sqlQuery("DESCRIBE `TABLES` TABLE_CATALOG")
.unOrdered()
.optionSettingQueriesForTestQuery("USE INFORMATION_SCHEMA")
.baselineColumns("COLUMN_NAME", "DATA_TYPE", "IS_NULLABLE")
.baselineValues("TABLE_CATALOG", "CHARACTER VARYING", "NO")
.go();
}
@Test
public void describeTableWithColumnNameAndTableKeyword() throws Exception {
test("USE INFORMATION_SCHEMA");
testBuilder()
.sqlQuery("DESCRIBE TABLE `TABLES` TABLE_CATALOG")
.unOrdered()
.sqlBaselineQuery("DESCRIBE `TABLES` TABLE_CATALOG")
.go();
}
@Test
public void describeTableWithSchemaAndColumnName() throws Exception{
testBuilder()
.sqlQuery("DESCRIBE INFORMATION_SCHEMA.`TABLES` TABLE_CATALOG")
.unOrdered()
.baselineColumns("COLUMN_NAME", "DATA_TYPE", "IS_NULLABLE")
.baselineValues("TABLE_CATALOG", "CHARACTER VARYING", "NO")
.go();
}
@Test
public void describeTableWithSchemaAndColumnNameAndTableKeyword() throws Exception {
testBuilder()
.sqlQuery("DESCRIBE TABLE INFORMATION_SCHEMA.`TABLES` TABLE_CATALOG")
.unOrdered()
.sqlBaselineQuery("DESCRIBE INFORMATION_SCHEMA.`TABLES` TABLE_CATALOG")
.go();
}
@Test
public void describeTableWithColQualifier() throws Exception{
testBuilder()
.sqlQuery("DESCRIBE COLUMNS 'TABLE%'")
.unOrdered()
.optionSettingQueriesForTestQuery("USE INFORMATION_SCHEMA")
.baselineColumns("COLUMN_NAME", "DATA_TYPE", "IS_NULLABLE")
.baselineValues("TABLE_CATALOG", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_SCHEMA", "CHARACTER VARYING", "NO")
.baselineValues("TABLE_NAME", "CHARACTER VARYING", "NO")
.go();
}
@Test
public void describeTableWithSchemaAndColQualifier() throws Exception{
testBuilder()
.sqlQuery("DESCRIBE INFORMATION_SCHEMA.SCHEMATA 'SCHEMA%'")
.unOrdered()
.baselineColumns("COLUMN_NAME", "DATA_TYPE", "IS_NULLABLE")
.baselineValues("SCHEMA_NAME", "CHARACTER VARYING", "NO")
.baselineValues("SCHEMA_OWNER", "CHARACTER VARYING", "NO")
.go();
}
@Test
public void defaultSchemaDfs() throws Exception{
testBuilder()
.sqlQuery("SELECT R_REGIONKEY FROM `sample-data/region.parquet` LIMIT 1")
.unOrdered()
.optionSettingQueriesForTestQuery("USE dfs")
.baselineColumns("R_REGIONKEY")
.baselineValues(0L)
.go();
}
@Test
public void defaultSchemaClasspath() throws Exception{
testBuilder()
.sqlQuery("SELECT full_name FROM `employee.json` LIMIT 1")
.unOrdered()
.optionSettingQueriesForTestQuery("USE cp")
.baselineColumns("full_name")
.baselineValues("Sheri Nowmer")
.go();
}
@Test
public void queryFromNonDefaultSchema() throws Exception{
testBuilder()
.sqlQuery("SELECT full_name FROM cp.`employee.json` LIMIT 1")
.unOrdered()
.optionSettingQueriesForTestQuery("USE dfs")
.baselineColumns("full_name")
.baselineValues("Sheri Nowmer")
.go();
}
@Test
public void useSchema() throws Exception{
testBuilder()
.sqlQuery("USE dfs.`default`")
.unOrdered()
.baselineColumns("ok", "summary")
.baselineValues(true, "Default schema changed to [dfs.default]")
.go();
}
@Test
public void useSubSchemaWithinSchema() throws Exception{
testBuilder()
.sqlQuery("USE dfs")
.unOrdered()
.baselineColumns("ok", "summary")
.baselineValues(true, "Default schema changed to [dfs]")
.go();
testBuilder()
.sqlQuery("USE tmp")
.unOrdered()
.baselineColumns("ok", "summary")
.baselineValues(true, "Default schema changed to [dfs.tmp]")
.go();
testBuilder()
.sqlQuery("USE dfs.`default`")
.unOrdered()
.baselineColumns("ok", "summary")
.baselineValues(true, "Default schema changed to [dfs.default]")
.go();
}
@Test
public void useSchemaNegative() throws Exception{
errorMsgTestHelper("USE invalid.schema",
"Schema [invalid.schema] is not valid with respect to either root schema or current default schema.");
}
// Tests using backticks around the complete schema path
// select * from `dfs.tmp`.`/tmp/nation.parquet`;
@Test
public void completeSchemaRef1() throws Exception {
test("SELECT * FROM `cp.default`.`employee.json` limit 2");
}
@Test
public void describeSchemaSyntax() throws Exception {
test("describe schema dfs");
test("describe schema dfs.`default`");
test("describe database dfs.`default`");
}
@Test
public void describePartialSchema() throws Exception {
test("use dfs");
test("describe schema tmp");
}
@Test
public void describeSchemaOutput() throws Exception {
final List<QueryDataBatch> result = testSqlWithResults("describe schema dfs.tmp");
assertEquals(1, result.size());
final QueryDataBatch batch = result.get(0);
final RecordBatchLoader loader = new RecordBatchLoader(getDrillbitContext().getAllocator());
loader.load(batch.getHeader().getDef(), batch.getData());
// check schema column value
final VectorWrapper schemaValueVector = loader.getValueAccessorById(
NullableVarCharVector.class,
loader.getValueVectorId(SchemaPath.getCompoundPath("schema")).getFieldIds());
String schema = schemaValueVector.getValueVector().getAccessor().getObject(0).toString();
assertEquals("dfs.tmp", schema);
// check properties column value
final VectorWrapper propertiesValueVector = loader.getValueAccessorById(
NullableVarCharVector.class,
loader.getValueVectorId(SchemaPath.getCompoundPath("properties")).getFieldIds());
String properties = propertiesValueVector.getValueVector().getAccessor().getObject(0).toString();
final Map configMap = mapper.readValue(properties, Map.class);
// check some stable properties existence
assertTrue(configMap.containsKey("connection"));
assertTrue(configMap.containsKey("config"));
assertTrue(configMap.containsKey("formats"));
assertFalse(configMap.containsKey("workspaces"));
// check some stable properties values
assertEquals("file", configMap.get("type"));
final FileSystemConfig testConfig = (FileSystemConfig) bits[0].getContext().getStorage().getPlugin("dfs").getConfig();
final String tmpSchemaLocation = testConfig.getWorkspaces().get("tmp").getLocation();
assertEquals(tmpSchemaLocation, configMap.get("location"));
batch.release();
loader.clear();
}
@Test
public void describeSchemaInvalid() throws Exception {
errorMsgTestHelper("describe schema invalid.schema", "Invalid schema name [invalid.schema]");
}
}