All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.prestosql.tests.hive.TestHivePartitionSchemaEvolution Maven / Gradle / Ivy

/*
 * Licensed 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 io.prestosql.tests.hive;

import com.google.inject.name.Named;
import io.airlift.log.Logger;
import io.prestosql.tempto.BeforeTestWithContext;
import io.prestosql.tempto.assertions.QueryAssert;
import io.prestosql.tempto.query.QueryExecutionException;
import io.prestosql.tests.hive.util.TemporaryHiveTable;
import org.testng.annotations.Test;

import javax.inject.Inject;

import java.sql.SQLException;
import java.util.function.Supplier;

import static io.prestosql.tempto.assertions.QueryAssert.Row.row;
import static io.prestosql.tempto.assertions.QueryAssert.assertThat;
import static io.prestosql.tests.hive.util.TemporaryHiveTable.randomTableSuffix;
import static io.prestosql.tests.hive.util.TemporaryHiveTable.temporaryHiveTable;
import static io.prestosql.tests.utils.JdbcDriverUtils.setSessionProperty;
import static io.prestosql.tests.utils.QueryExecutors.onHive;
import static io.prestosql.tests.utils.QueryExecutors.onPresto;
import static java.lang.String.format;

public class TestHivePartitionSchemaEvolution
        extends HiveProductTest
{
    private static final Logger log = Logger.get(TestHivePartitionSchemaEvolution.class);

    @Inject
    @Named("databases.hive.enforce_non_transactional_tables")
    private boolean createTablesAsAcid;

    @BeforeTestWithContext
    public void useColumnMappingByName()
            throws SQLException
    {
        setSessionProperty(onPresto().getConnection(), "hive.parquet_use_column_names", "true");
        setSessionProperty(onPresto().getConnection(), "hive.orc_use_column_names", "true");
        setSessionProperty(onPresto().getConnection(), "hive.partition_use_column_names", "true");
    }

    @Test
    public void testParquet()
    {
        test(() -> createTable("PARQUET"));
    }

    @Test
    public void testOrc()
    {
        test(() -> createTable("ORC"));
    }

    private void test(Supplier temporaryHiveTableSupplier)
    {
        try (TemporaryHiveTable table = temporaryHiveTableSupplier.get()) {
            // dropping column on table, simulates creating a column on partition
            // adding column on table, simulates dropping a column on partition

            // partition is adding a column at the start
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (float_column float, varchar_column varchar(20))", row(1.1, "jeden", 1));

            // partition is adding a column in the middle
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (int_column int, varchar_column varchar(20))", row(1, "jeden", 1));

            // partition is adding a column at the end
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (int_column int, float_column float)", row(1, 1.1, 1));

            // partition is dropping a column at the start
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (tiny_column tinyint, int_column int, float_column float, varchar_column varchar(20))", row(null, 1, 1.1, "jeden", 1));

            // partition is dropping a column in the middle
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (int_column int, tiny_column tinyint, float_column float, varchar_column varchar(20))", row(1, null, 1.1, "jeden", 1));

            // partition is dropping a column at the end
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (int_column int, float_column float, varchar_column varchar(20), tiny_column tinyint)", row(1, 1.1, "jeden", null, 1));

            // partition is dropping and adding column in the middle
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (int_column int, tiny_column tinyint, varchar_column varchar(20))", row(1, null, "jeden", 1));

            // partition is adding coercions
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (int_column bigint, float_column double, varchar_column varchar(20))", row(1, 1.1, "jeden", 1));

            // partition is swapping columns with coercions
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (varchar_column varchar(20), float_column double, int_column bigint)", row("jeden", 1.1, 1, 1));

            // partition is swapping columns and partition with coercions and is adding a column
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (float_column double, int_column bigint)", row(1.1, 1, 1));

            // partition is swapping columns and partition with coercions and is removing a column
            testEvolution(table, "ALTER TABLE %s REPLACE COLUMNS (varchar_column varchar(20), tiny_column tinyint, float_column double, int_column bigint)", row("jeden", null, 1.1, 1, 1));
        }
    }

    private void testEvolution(TemporaryHiveTable table, String sql, QueryAssert.Row row)
    {
        if (tryExecuteOnHive(format(sql, table.getName()))) {
            assertThat(onPresto().executeQuery("SELECT * FROM " + table.getName()))
                    .contains(row);
        }
    }

    private static boolean tryExecuteOnHive(String sql)
    {
        try {
            onHive().executeQuery(sql);
            return true;
        }
        catch (QueryExecutionException e) {
            String message = e.getMessage();
            if (message.contains("Unable to alter table. The following columns have types incompatible with the existing columns in their respective positions")
                    || message.contains("Replacing columns cannot drop columns")
                    || message.contains("Replace columns is not supported for")) {
                log.warn("Unable to execute: %s, due: %s", sql, message);
                return false;
            }
            throw e;
        }
    }

    private TemporaryHiveTable createTable(String format)
    {
        String tableName = "schema_evolution_" + randomTableSuffix();
        tryExecuteOnHive(format(
                "CREATE TABLE %s (" +
                        "  int_column int," +
                        "  float_column float," +
                        "  varchar_column varchar(20)" +
                        ") " +
                        "PARTITIONED BY (partition_column bigint) " +
                        "STORED AS %s " +
                        (createTablesAsAcid ? "TBLPROPERTIES ('transactional_properties' = 'none', 'transactional' = 'false')" : ""),
                tableName,
                format));
        TemporaryHiveTable temporaryHiveTable = temporaryHiveTable(tableName);
        try {
            onPresto().executeQuery(format("INSERT INTO %s VALUES (1, 1.1, 'jeden', 1)", tableName));
        }
        catch (Exception e) {
            temporaryHiveTable.closeQuietly(e);
            throw e;
        }
        return temporaryHiveTable;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy