| /* |
| * 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 static org.apache.drill.exec.util.StoragePluginTestUtils.DFS_TMP_SCHEMA; |
| import static org.junit.Assert.assertEquals; |
| |
| import java.util.Map; |
| |
| import org.apache.drill.categories.SqlTest; |
| import org.apache.drill.categories.UnlikelyTest; |
| import org.apache.drill.exec.ExecConstants; |
| import org.apache.drill.exec.proto.UserBitShared; |
| import org.apache.drill.exec.rpc.user.QueryDataBatch; |
| import org.apache.drill.exec.store.StorageStrategy; |
| import com.google.common.collect.Maps; |
| import org.apache.drill.test.BaseTestQuery; |
| import org.apache.hadoop.fs.FileSystem; |
| import org.apache.hadoop.fs.Path; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| |
| @Category(SqlTest.class) |
| public class TestCTAS extends BaseTestQuery { |
| @Test // DRILL-2589 |
| @Category(UnlikelyTest.class) |
| public void withDuplicateColumnsInDef1() throws Exception { |
| ctasErrorTestHelper("CREATE TABLE dfs.tmp.%s AS SELECT region_id, region_id FROM cp.`region.json`", |
| String.format("Duplicate column name [%s]", "region_id") |
| ); |
| } |
| |
| @Test // DRILL-2589 |
| @Category(UnlikelyTest.class) |
| public void withDuplicateColumnsInDef2() throws Exception { |
| ctasErrorTestHelper("CREATE TABLE dfs.tmp.%s AS SELECT region_id, sales_city, sales_city FROM cp.`region.json`", |
| String.format("Duplicate column name [%s]", "sales_city") |
| ); |
| } |
| |
| @Test // DRILL-2589 |
| @Category(UnlikelyTest.class) |
| public void withDuplicateColumnsInDef3() throws Exception { |
| ctasErrorTestHelper( |
| "CREATE TABLE dfs.tmp.%s(regionid, regionid) " + |
| "AS SELECT region_id, sales_city FROM cp.`region.json`", |
| String.format("Duplicate column name [%s]", "regionid") |
| ); |
| } |
| |
| @Test // DRILL-2589 |
| @Category(UnlikelyTest.class) |
| public void withDuplicateColumnsInDef4() throws Exception { |
| ctasErrorTestHelper( |
| "CREATE TABLE dfs.tmp.%s(regionid, salescity, salescity) " + |
| "AS SELECT region_id, sales_city, sales_city FROM cp.`region.json`", |
| String.format("Duplicate column name [%s]", "salescity") |
| ); |
| } |
| |
| @Test // DRILL-2589 |
| @Category(UnlikelyTest.class) |
| public void withDuplicateColumnsInDef5() throws Exception { |
| ctasErrorTestHelper( |
| "CREATE TABLE dfs.tmp.%s(regionid, salescity, SalesCity) " + |
| "AS SELECT region_id, sales_city, sales_city FROM cp.`region.json`", |
| String.format("Duplicate column name [%s]", "SalesCity") |
| ); |
| } |
| |
| @Test // DRILL-2589 |
| public void whenInEqualColumnCountInTableDefVsInTableQuery() throws Exception { |
| ctasErrorTestHelper( |
| "CREATE TABLE dfs.tmp.%s(regionid, salescity) " + |
| "AS SELECT region_id, sales_city, sales_region FROM cp.`region.json`", |
| "table's field list and the table's query field list have different counts." |
| ); |
| } |
| |
| @Test // DRILL-2589 |
| public void whenTableQueryColumnHasStarAndTableFiledListIsSpecified() throws Exception { |
| ctasErrorTestHelper( |
| "CREATE TABLE dfs.tmp.%s(regionid, salescity) " + |
| "AS SELECT region_id, * FROM cp.`region.json`", |
| "table's query field list has a '*', which is invalid when table's field list is specified." |
| ); |
| } |
| |
| @Test // DRILL-2422 |
| @Category(UnlikelyTest.class) |
| public void createTableWhenATableWithSameNameAlreadyExists() throws Exception{ |
| final String newTblName = "createTableWhenTableAlreadyExists"; |
| final String ctasQuery = String.format("CREATE TABLE dfs.tmp.%s AS SELECT * from cp.`region.json`", newTblName); |
| |
| test(ctasQuery); |
| errorMsgTestHelper(ctasQuery, String.format("A table or view with given name [%s] already exists in schema [dfs.tmp]", newTblName)); |
| } |
| |
| @Test // DRILL-2422 |
| @Category(UnlikelyTest.class) |
| public void createTableWhenAViewWithSameNameAlreadyExists() throws Exception{ |
| final String newTblName = "createTableWhenAViewWithSameNameAlreadyExists"; |
| |
| try { |
| test("CREATE VIEW dfs.tmp.%s AS SELECT * from cp.`region.json`", newTblName); |
| |
| final String ctasQuery = String.format("CREATE TABLE dfs.tmp.%s AS SELECT * FROM cp.`employee.json`", newTblName); |
| |
| errorMsgTestHelper(ctasQuery, |
| String.format("A table or view with given name [%s] already exists in schema [%s]", |
| newTblName, "dfs.tmp")); |
| } finally { |
| test("DROP VIEW dfs.tmp.%s", newTblName); |
| } |
| } |
| |
| @Test |
| public void ctasPartitionWithEmptyList() throws Exception { |
| final String newTblName = "ctasPartitionWithEmptyList"; |
| final String ctasQuery = String.format("CREATE TABLE dfs.tmp.%s PARTITION BY AS SELECT * from cp.`region.json`", newTblName); |
| |
| errorMsgTestHelper(ctasQuery,"PARSE ERROR: Encountered \"AS\""); |
| } |
| |
| @Test // DRILL-3377 |
| public void partitionByCtasColList() throws Exception { |
| final String newTblName = "partitionByCtasColList"; |
| |
| test("CREATE TABLE dfs.tmp.%s (cnt, rkey) PARTITION BY (cnt) " + |
| "AS SELECT count(*), n_regionkey from cp.`tpch/nation.parquet` group by n_regionkey", newTblName); |
| |
| testBuilder() |
| .sqlQuery("select cnt, rkey from dfs.tmp.%s", newTblName) |
| .unOrdered() |
| .sqlBaselineQuery("select count(*) as cnt, n_regionkey as rkey from cp.`tpch/nation.parquet` group by n_regionkey") |
| .build() |
| .run(); |
| } |
| |
| @Test // DRILL-3374 |
| public void partitionByCtasFromView() throws Exception { |
| final String newTblName = "partitionByCtasFromView"; |
| final String newView = "partitionByCtasColListView"; |
| |
| test("create or replace view dfs.tmp.%s (col_int, col_varchar) " + |
| "AS select cast(n_nationkey as int), cast(n_name as varchar(30)) from cp.`tpch/nation.parquet`", newView); |
| test("CREATE TABLE dfs.tmp.%s PARTITION BY (col_int) AS SELECT * from dfs.tmp.%s", |
| newTblName, newView); |
| |
| testBuilder() |
| .sqlQuery("select col_int, col_varchar from dfs.tmp.%s", newTblName) |
| .unOrdered() |
| .sqlBaselineQuery("select cast(n_nationkey as int) as col_int, cast(n_name as varchar(30)) as col_varchar " + |
| "from cp.`tpch/nation.parquet`") |
| .build() |
| .run(); |
| |
| test("DROP VIEW dfs.tmp.%s", newView); |
| } |
| |
| @Test // DRILL-3382 |
| public void ctasWithQueryOrderby() throws Exception { |
| final String newTblName = "ctasWithQueryOrderby"; |
| |
| test("CREATE TABLE dfs.tmp.%s AS SELECT n_nationkey, n_name, n_comment from " + |
| "cp.`tpch/nation.parquet` order by n_nationkey", newTblName); |
| |
| testBuilder() |
| .sqlQuery("select n_nationkey, n_name, n_comment from dfs.tmp.%s", newTblName) |
| .ordered() |
| .sqlBaselineQuery("select n_nationkey, n_name, n_comment from cp.`tpch/nation.parquet` order by n_nationkey") |
| .build() |
| .run(); |
| } |
| |
| @Test // DRILL-4392 |
| public void ctasWithPartition() throws Exception { |
| final String newTblName = "nation_ctas"; |
| |
| test("CREATE TABLE dfs.tmp.%s partition by (n_regionkey) AS " + |
| "SELECT n_nationkey, n_regionkey from cp.`tpch/nation.parquet` order by n_nationkey limit 1", newTblName); |
| |
| testBuilder() |
| .sqlQuery("select * from dfs.tmp.%s", newTblName) |
| .ordered() |
| .sqlBaselineQuery("select n_nationkey, n_regionkey from cp.`tpch/nation.parquet` order by n_nationkey limit 1") |
| .build() |
| .run(); |
| } |
| |
| @Test |
| public void testPartitionByForAllTypes() throws Exception { |
| final String location = "partitioned_tables_with_nulls"; |
| final String ctasQuery = "create table %s partition by (%s) as %s"; |
| final String tablePath = "dfs.tmp.`%s/%s_%s`"; |
| |
| // key - new table suffix, value - data query |
| final Map<String, String> variations = Maps.newHashMap(); |
| variations.put("required", "select * from cp.`parquet/alltypes_required.parquet`"); |
| variations.put("optional", "select * from cp.`parquet/alltypes_optional.parquet`"); |
| variations.put("nulls_only", "select * from cp.`parquet/alltypes_optional.parquet` where %s is null"); |
| |
| final QueryDataBatch result = testSqlWithResults("select * from cp.`parquet/alltypes_required.parquet` limit 0").get(0); |
| for (UserBitShared.SerializedField field : result.getHeader().getDef().getFieldList()) { |
| final String fieldName = field.getNamePart().getName(); |
| |
| for (Map.Entry<String, String> variation : variations.entrySet()) { |
| final String table = String.format(tablePath, location, fieldName, variation.getKey()); |
| final String dataQuery = String.format(variation.getValue(), fieldName); |
| test(ctasQuery, table, fieldName, dataQuery, fieldName); |
| testBuilder() |
| .sqlQuery("select * from %s", table) |
| .unOrdered() |
| .sqlBaselineQuery(dataQuery) |
| .build() |
| .run(); |
| } |
| } |
| |
| result.release(); |
| } |
| |
| @Test |
| public void createTableWithCustomUmask() throws Exception { |
| test("use dfs.tmp"); |
| String tableName = "with_custom_permission"; |
| StorageStrategy storageStrategy = new StorageStrategy("000", false); |
| FileSystem fs = getLocalFileSystem(); |
| try { |
| test("alter session set `%s` = '%s'", ExecConstants.PERSISTENT_TABLE_UMASK, storageStrategy.getUmask()); |
| test("create table %s as select 'A' from (values(1))", tableName); |
| Path tableLocation = new Path(dirTestWatcher.getDfsTestTmpDir().getAbsolutePath(), tableName); |
| assertEquals("Directory permission should match", |
| storageStrategy.getFolderPermission(), fs.getFileStatus(tableLocation).getPermission()); |
| assertEquals("File permission should match", |
| storageStrategy.getFilePermission(), fs.listLocatedStatus(tableLocation).next().getPermission()); |
| } finally { |
| resetSessionOption(ExecConstants.PERSISTENT_TABLE_UMASK); |
| test("drop table if exists %s", tableName); |
| } |
| } |
| |
| @Test // DRILL-5952 |
| public void testCreateTableIfNotExistsWhenTableWithSameNameAlreadyExists() throws Exception{ |
| final String newTblName = "createTableIfNotExistsWhenATableWithSameNameAlreadyExists"; |
| |
| try { |
| String ctasQuery = String.format("CREATE TABLE %s.%s AS SELECT * from cp.`region.json`", DFS_TMP_SCHEMA, newTblName); |
| |
| test(ctasQuery); |
| |
| ctasQuery = |
| String.format("CREATE TABLE IF NOT EXISTS %s.%s AS SELECT * FROM cp.`employee.json`", DFS_TMP_SCHEMA, newTblName); |
| |
| testBuilder() |
| .sqlQuery(ctasQuery) |
| .unOrdered() |
| .baselineColumns("ok", "summary") |
| .baselineValues(false, String.format("A table or view with given name [%s] already exists in schema [%s]", newTblName, DFS_TMP_SCHEMA)) |
| .go(); |
| } finally { |
| test("DROP TABLE IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName); |
| } |
| } |
| |
| @Test // DRILL-5952 |
| public void testCreateTableIfNotExistsWhenViewWithSameNameAlreadyExists() throws Exception{ |
| final String newTblName = "createTableIfNotExistsWhenAViewWithSameNameAlreadyExists"; |
| |
| try { |
| String ctasQuery = String.format("CREATE VIEW %s.%s AS SELECT * from cp.`region.json`", DFS_TMP_SCHEMA, newTblName); |
| |
| test(ctasQuery); |
| |
| ctasQuery = |
| String.format("CREATE TABLE IF NOT EXISTS %s.%s AS SELECT * FROM cp.`employee.json`", DFS_TMP_SCHEMA, newTblName); |
| |
| testBuilder() |
| .sqlQuery(ctasQuery) |
| .unOrdered() |
| .baselineColumns("ok", "summary") |
| .baselineValues(false, String.format("A table or view with given name [%s] already exists in schema [%s]", newTblName, DFS_TMP_SCHEMA)) |
| .go(); |
| } finally { |
| test("DROP VIEW IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName); |
| } |
| } |
| |
| @Test // DRILL-5952 |
| public void testCreateTableIfNotExistsWhenTableWithSameNameDoesNotExist() throws Exception{ |
| final String newTblName = "createTableIfNotExistsWhenATableWithSameNameDoesNotExist"; |
| |
| try { |
| String ctasQuery = String.format("CREATE TABLE IF NOT EXISTS %s.%s AS SELECT * FROM cp.`employee.json`", DFS_TMP_SCHEMA, newTblName); |
| |
| test(ctasQuery); |
| |
| } finally { |
| test("DROP TABLE IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName); |
| } |
| } |
| |
| @Test |
| public void testCTASWithEmptyJson() throws Exception { |
| final String newTblName = "tbl4444"; |
| try { |
| test(String.format("CREATE TABLE %s.%s AS SELECT * FROM cp.`project/pushdown/empty.json`", DFS_TMP_SCHEMA, newTblName)); |
| } finally { |
| test("DROP TABLE IF EXISTS %s.%s", DFS_TMP_SCHEMA, newTblName); |
| } |
| } |
| |
| @Test |
| public void testTableIsCreatedWithinWorkspace() throws Exception { |
| String tableName = "table_created_within_workspace"; |
| try { |
| test("CREATE TABLE `%s`.`%s` AS SELECT * FROM cp.`region.json`", DFS_TMP_SCHEMA, "/" + tableName); |
| testBuilder() |
| .sqlQuery("SELECT region_id FROM `%s`.`%s` LIMIT 1", DFS_TMP_SCHEMA, tableName) |
| .unOrdered() |
| .baselineColumns("region_id") |
| .baselineValues(0L) |
| .go(); |
| } finally { |
| test("DROP TABLE IF EXISTS `%s`.`%s`", DFS_TMP_SCHEMA, tableName); |
| } |
| } |
| |
| @Test |
| public void testTableIsFoundWithinWorkspaceWhenNameStartsWithSlash() throws Exception { |
| String tableName = "table_found_within_workspace"; |
| try { |
| test("CREATE TABLE `%s`.`%s` AS SELECT * FROM cp.`region.json`", DFS_TMP_SCHEMA, tableName); |
| testBuilder() |
| .sqlQuery("SELECT region_id FROM `%s`.`%s` LIMIT 1", DFS_TMP_SCHEMA, "/" + tableName) |
| .unOrdered() |
| .baselineColumns("region_id") |
| .baselineValues(0L) |
| .go(); |
| } finally { |
| test("DROP TABLE IF EXISTS `%s`.`%s`", DFS_TMP_SCHEMA, tableName); |
| } |
| } |
| |
| private static void ctasErrorTestHelper(final String ctasSql, final String expErrorMsg) throws Exception { |
| final String createTableSql = String.format(ctasSql, "testTableName"); |
| errorMsgTestHelper(createTableSql, expErrorMsg); |
| } |
| } |